8199712: Flight Recorder
authoregahlin
Tue, 15 May 2018 20:24:34 +0200
changeset 50113 caf115bb98ad
parent 50112 7a2a740815b7
child 50114 d2cfda6a00de
8199712: Flight Recorder Reviewed-by: coleenp, ihse, erikj, dsamersoff, mseledtsov, egahlin, mgronlun Contributed-by: erik.gahlin@oracle.com, markus.gronlund@oracle.com
make/CompileJavaModules.gmk
make/autoconf/hotspot.m4
make/autoconf/libraries.m4
make/common/Modules.gmk
make/copy/Copy-jdk.jfr.gmk
make/hotspot/gensrc/GenerateSources.gmk
make/hotspot/gensrc/GensrcJfr.gmk
make/hotspot/gensrc/GensrcJvmti.gmk
make/hotspot/lib/JvmFeatures.gmk
make/hotspot/src/classes/build/tools/projectcreator/BuildConfig.java
make/jprt.properties
make/nashorn/project.properties
make/nb_native/nbproject/configurations.xml
src/hotspot/cpu/aarch64/vm_version_ext_aarch64.cpp
src/hotspot/cpu/aarch64/vm_version_ext_aarch64.hpp
src/hotspot/cpu/arm/vm_version_ext_arm.cpp
src/hotspot/cpu/arm/vm_version_ext_arm.hpp
src/hotspot/cpu/sparc/vm_version_ext_sparc.cpp
src/hotspot/cpu/sparc/vm_version_ext_sparc.hpp
src/hotspot/cpu/x86/rdtsc_x86.cpp
src/hotspot/cpu/x86/rdtsc_x86.hpp
src/hotspot/cpu/x86/vm_version_ext_x86.cpp
src/hotspot/cpu/x86/vm_version_ext_x86.hpp
src/hotspot/os/bsd/os_perf_bsd.cpp
src/hotspot/os/linux/os_perf_linux.cpp
src/hotspot/os/solaris/os_perf_solaris.cpp
src/hotspot/os/windows/os_perf_windows.cpp
src/hotspot/os/windows/pdh_interface.cpp
src/hotspot/os/windows/pdh_interface.hpp
src/hotspot/os_cpu/solaris_x86/os_solaris_x86.inline.hpp
src/hotspot/share/c1/c1_Compiler.cpp
src/hotspot/share/c1/c1_GraphBuilder.cpp
src/hotspot/share/c1/c1_LIRGenerator.cpp
src/hotspot/share/c1/c1_LIRGenerator.hpp
src/hotspot/share/c1/c1_Runtime1.cpp
src/hotspot/share/ci/ciEnv.cpp
src/hotspot/share/ci/ciMethod.cpp
src/hotspot/share/ci/ciMethod.hpp
src/hotspot/share/classfile/classFileParser.cpp
src/hotspot/share/classfile/classLoaderData.cpp
src/hotspot/share/classfile/classLoaderData.hpp
src/hotspot/share/classfile/klassFactory.cpp
src/hotspot/share/classfile/moduleEntry.cpp
src/hotspot/share/classfile/moduleEntry.hpp
src/hotspot/share/classfile/packageEntry.cpp
src/hotspot/share/classfile/packageEntry.hpp
src/hotspot/share/classfile/systemDictionary.cpp
src/hotspot/share/classfile/vmSymbols.cpp
src/hotspot/share/classfile/vmSymbols.hpp
src/hotspot/share/code/codeCache.cpp
src/hotspot/share/compiler/compileBroker.cpp
src/hotspot/share/compiler/compileBroker.hpp
src/hotspot/share/gc/g1/g1CollectedHeap.hpp
src/hotspot/share/gc/g1/g1EvacStats.cpp
src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp
src/hotspot/share/gc/g1/g1FullGCCompactTask.cpp
src/hotspot/share/gc/g1/g1FullGCCompactTask.hpp
src/hotspot/share/gc/g1/g1FullGCPrepareTask.cpp
src/hotspot/share/gc/g1/g1FullGCPrepareTask.hpp
src/hotspot/share/gc/g1/g1FullGCTask.cpp
src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp
src/hotspot/share/gc/g1/g1HeapRegionEventSender.cpp
src/hotspot/share/gc/g1/g1HeapRegionEventSender.hpp
src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp
src/hotspot/share/gc/g1/g1RemSet.cpp
src/hotspot/share/gc/g1/heapRegionTracer.cpp
src/hotspot/share/gc/shared/ageTableTracer.cpp
src/hotspot/share/gc/shared/allocTracer.cpp
src/hotspot/share/gc/shared/copyFailedInfo.hpp
src/hotspot/share/gc/shared/gcConfiguration.cpp
src/hotspot/share/gc/shared/gcConfiguration.hpp
src/hotspot/share/gc/shared/gcTimer.cpp
src/hotspot/share/gc/shared/gcTrace.cpp
src/hotspot/share/gc/shared/gcTraceSend.cpp
src/hotspot/share/gc/shared/objectCountEventSender.cpp
src/hotspot/share/gc/shared/objectCountEventSender.hpp
src/hotspot/share/gc/shared/weakProcessor.cpp
src/hotspot/share/jfr/dcmd/jfrDcmds.cpp
src/hotspot/share/jfr/dcmd/jfrDcmds.hpp
src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp
src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.hpp
src/hotspot/share/jfr/instrumentation/jfrJvmtiAgent.cpp
src/hotspot/share/jfr/instrumentation/jfrJvmtiAgent.hpp
src/hotspot/share/jfr/jfr.cpp
src/hotspot/share/jfr/jfr.hpp
src/hotspot/share/jfr/jfrEvents.hpp
src/hotspot/share/jfr/jni/jfrGetAllEventClasses.cpp
src/hotspot/share/jfr/jni/jfrGetAllEventClasses.hpp
src/hotspot/share/jfr/jni/jfrJavaCall.cpp
src/hotspot/share/jfr/jni/jfrJavaCall.hpp
src/hotspot/share/jfr/jni/jfrJavaSupport.cpp
src/hotspot/share/jfr/jni/jfrJavaSupport.hpp
src/hotspot/share/jfr/jni/jfrJniMethod.cpp
src/hotspot/share/jfr/jni/jfrJniMethod.hpp
src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp
src/hotspot/share/jfr/jni/jfrJniMethodRegistration.hpp
src/hotspot/share/jfr/jni/jfrUpcalls.cpp
src/hotspot/share/jfr/jni/jfrUpcalls.hpp
src/hotspot/share/jfr/leakprofiler/chains/bfsClosure.cpp
src/hotspot/share/jfr/leakprofiler/chains/bfsClosure.hpp
src/hotspot/share/jfr/leakprofiler/chains/bitset.cpp
src/hotspot/share/jfr/leakprofiler/chains/bitset.hpp
src/hotspot/share/jfr/leakprofiler/chains/dfsClosure.cpp
src/hotspot/share/jfr/leakprofiler/chains/dfsClosure.hpp
src/hotspot/share/jfr/leakprofiler/chains/edge.cpp
src/hotspot/share/jfr/leakprofiler/chains/edge.hpp
src/hotspot/share/jfr/leakprofiler/chains/edgeQueue.cpp
src/hotspot/share/jfr/leakprofiler/chains/edgeQueue.hpp
src/hotspot/share/jfr/leakprofiler/chains/edgeStore.cpp
src/hotspot/share/jfr/leakprofiler/chains/edgeStore.hpp
src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.cpp
src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.hpp
src/hotspot/share/jfr/leakprofiler/chains/objectSampleMarker.hpp
src/hotspot/share/jfr/leakprofiler/chains/rootSetClosure.cpp
src/hotspot/share/jfr/leakprofiler/chains/rootSetClosure.hpp
src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp
src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp
src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleDescription.cpp
src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleDescription.hpp
src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp
src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.hpp
src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp
src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.hpp
src/hotspot/share/jfr/leakprofiler/emitEventOperation.cpp
src/hotspot/share/jfr/leakprofiler/emitEventOperation.hpp
src/hotspot/share/jfr/leakprofiler/leakProfiler.cpp
src/hotspot/share/jfr/leakprofiler/leakProfiler.hpp
src/hotspot/share/jfr/leakprofiler/sampling/objectSample.hpp
src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.cpp
src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.hpp
src/hotspot/share/jfr/leakprofiler/sampling/sampleList.cpp
src/hotspot/share/jfr/leakprofiler/sampling/sampleList.hpp
src/hotspot/share/jfr/leakprofiler/sampling/samplePriorityQueue.cpp
src/hotspot/share/jfr/leakprofiler/sampling/samplePriorityQueue.hpp
src/hotspot/share/jfr/leakprofiler/startOperation.hpp
src/hotspot/share/jfr/leakprofiler/stopOperation.hpp
src/hotspot/share/jfr/leakprofiler/utilities/granularTimer.cpp
src/hotspot/share/jfr/leakprofiler/utilities/granularTimer.hpp
src/hotspot/share/jfr/leakprofiler/utilities/rootType.hpp
src/hotspot/share/jfr/leakprofiler/utilities/saveRestore.cpp
src/hotspot/share/jfr/leakprofiler/utilities/saveRestore.hpp
src/hotspot/share/jfr/leakprofiler/utilities/unifiedOop.hpp
src/hotspot/share/jfr/metadata/GenerateJfrFiles.java
src/hotspot/share/jfr/metadata/jfrSerializer.hpp
src/hotspot/share/jfr/metadata/metadata.xml
src/hotspot/share/jfr/metadata/metadata.xsd
src/hotspot/share/jfr/periodic/jfrModuleEvent.cpp
src/hotspot/share/jfr/periodic/jfrModuleEvent.hpp
src/hotspot/share/jfr/periodic/jfrOSInterface.cpp
src/hotspot/share/jfr/periodic/jfrOSInterface.hpp
src/hotspot/share/jfr/periodic/jfrPeriodic.cpp
src/hotspot/share/jfr/periodic/jfrThreadCPULoadEvent.cpp
src/hotspot/share/jfr/periodic/jfrThreadCPULoadEvent.hpp
src/hotspot/share/jfr/periodic/jfrThreadDumpEvent.cpp
src/hotspot/share/jfr/periodic/jfrThreadDumpEvent.hpp
src/hotspot/share/jfr/periodic/sampling/jfrCallTrace.cpp
src/hotspot/share/jfr/periodic/sampling/jfrCallTrace.hpp
src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp
src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.hpp
src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointBlob.cpp
src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointBlob.hpp
src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp
src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.hpp
src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.cpp
src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.hpp
src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp
src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.hpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrThreadGroup.cpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrThreadGroup.hpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrThreadState.cpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrThreadState.hpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.hpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.cpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.hpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.hpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetWriter.hpp
src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.cpp
src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.hpp
src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp
src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdBits.inline.hpp
src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.cpp
src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp
src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp
src/hotspot/share/jfr/recorder/jfrEventSetting.cpp
src/hotspot/share/jfr/recorder/jfrEventSetting.hpp
src/hotspot/share/jfr/recorder/jfrEventSetting.inline.hpp
src/hotspot/share/jfr/recorder/jfrRecorder.cpp
src/hotspot/share/jfr/recorder/jfrRecorder.hpp
src/hotspot/share/jfr/recorder/repository/jfrChunkSizeNotifier.cpp
src/hotspot/share/jfr/recorder/repository/jfrChunkSizeNotifier.hpp
src/hotspot/share/jfr/recorder/repository/jfrChunkState.cpp
src/hotspot/share/jfr/recorder/repository/jfrChunkState.hpp
src/hotspot/share/jfr/recorder/repository/jfrChunkWriter.cpp
src/hotspot/share/jfr/recorder/repository/jfrChunkWriter.hpp
src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp
src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.hpp
src/hotspot/share/jfr/recorder/repository/jfrRepository.cpp
src/hotspot/share/jfr/recorder/repository/jfrRepository.hpp
src/hotspot/share/jfr/recorder/service/jfrEvent.cpp
src/hotspot/share/jfr/recorder/service/jfrEvent.hpp
src/hotspot/share/jfr/recorder/service/jfrMemorySizer.cpp
src/hotspot/share/jfr/recorder/service/jfrMemorySizer.hpp
src/hotspot/share/jfr/recorder/service/jfrOptionSet.cpp
src/hotspot/share/jfr/recorder/service/jfrOptionSet.hpp
src/hotspot/share/jfr/recorder/service/jfrPostBox.cpp
src/hotspot/share/jfr/recorder/service/jfrPostBox.hpp
src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp
src/hotspot/share/jfr/recorder/service/jfrRecorderService.hpp
src/hotspot/share/jfr/recorder/service/jfrRecorderThread.cpp
src/hotspot/share/jfr/recorder/service/jfrRecorderThread.hpp
src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp
src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.cpp
src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.hpp
src/hotspot/share/jfr/recorder/storage/jfrBuffer.cpp
src/hotspot/share/jfr/recorder/storage/jfrBuffer.hpp
src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.hpp
src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.inline.hpp
src/hotspot/share/jfr/recorder/storage/jfrMemorySpaceRetrieval.hpp
src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp
src/hotspot/share/jfr/recorder/storage/jfrStorage.hpp
src/hotspot/share/jfr/recorder/storage/jfrStorageControl.cpp
src/hotspot/share/jfr/recorder/storage/jfrStorageControl.hpp
src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.hpp
src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.inline.hpp
src/hotspot/share/jfr/recorder/storage/jfrVirtualMemory.cpp
src/hotspot/share/jfr/recorder/storage/jfrVirtualMemory.hpp
src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp
src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.hpp
src/hotspot/share/jfr/recorder/stringpool/jfrStringPoolBuffer.cpp
src/hotspot/share/jfr/recorder/stringpool/jfrStringPoolBuffer.hpp
src/hotspot/share/jfr/recorder/stringpool/jfrStringPoolWriter.cpp
src/hotspot/share/jfr/recorder/stringpool/jfrStringPoolWriter.hpp
src/hotspot/share/jfr/support/jfrAllocationTracer.cpp
src/hotspot/share/jfr/support/jfrAllocationTracer.hpp
src/hotspot/share/jfr/support/jfrEventClass.cpp
src/hotspot/share/jfr/support/jfrEventClass.hpp
src/hotspot/share/jfr/support/jfrFlush.cpp
src/hotspot/share/jfr/support/jfrFlush.hpp
src/hotspot/share/jfr/support/jfrIntrinsics.hpp
src/hotspot/share/jfr/support/jfrKlassExtension.hpp
src/hotspot/share/jfr/support/jfrStackTraceMark.cpp
src/hotspot/share/jfr/support/jfrStackTraceMark.hpp
src/hotspot/share/jfr/support/jfrThreadExtension.hpp
src/hotspot/share/jfr/support/jfrThreadId.hpp
src/hotspot/share/jfr/support/jfrThreadLocal.cpp
src/hotspot/share/jfr/support/jfrThreadLocal.hpp
src/hotspot/share/jfr/support/jfrTraceIdExtension.hpp
src/hotspot/share/jfr/utilities/jfrAllocation.cpp
src/hotspot/share/jfr/utilities/jfrAllocation.hpp
src/hotspot/share/jfr/utilities/jfrBigEndian.hpp
src/hotspot/share/jfr/utilities/jfrDoublyLinkedList.hpp
src/hotspot/share/jfr/utilities/jfrHashtable.hpp
src/hotspot/share/jfr/utilities/jfrIterator.hpp
src/hotspot/share/jfr/utilities/jfrJavaLog.cpp
src/hotspot/share/jfr/utilities/jfrJavaLog.hpp
src/hotspot/share/jfr/utilities/jfrLogTagSets.hpp
src/hotspot/share/jfr/utilities/jfrRefCountPointer.hpp
src/hotspot/share/jfr/utilities/jfrResourceManager.hpp
src/hotspot/share/jfr/utilities/jfrSpinlockHelper.hpp
src/hotspot/share/jfr/utilities/jfrTime.cpp
src/hotspot/share/jfr/utilities/jfrTime.hpp
src/hotspot/share/jfr/utilities/jfrTimeConverter.cpp
src/hotspot/share/jfr/utilities/jfrTimeConverter.hpp
src/hotspot/share/jfr/utilities/jfrTryLock.hpp
src/hotspot/share/jfr/utilities/jfrTypes.hpp
src/hotspot/share/jfr/writers/jfrBigEndianWriter.hpp
src/hotspot/share/jfr/writers/jfrEncoders.hpp
src/hotspot/share/jfr/writers/jfrEncoding.hpp
src/hotspot/share/jfr/writers/jfrEventWriterHost.hpp
src/hotspot/share/jfr/writers/jfrEventWriterHost.inline.hpp
src/hotspot/share/jfr/writers/jfrJavaEventWriter.cpp
src/hotspot/share/jfr/writers/jfrJavaEventWriter.hpp
src/hotspot/share/jfr/writers/jfrMemoryWriterHost.hpp
src/hotspot/share/jfr/writers/jfrMemoryWriterHost.inline.hpp
src/hotspot/share/jfr/writers/jfrNativeEventWriter.hpp
src/hotspot/share/jfr/writers/jfrPosition.hpp
src/hotspot/share/jfr/writers/jfrPosition.inline.hpp
src/hotspot/share/jfr/writers/jfrStorageAdapter.hpp
src/hotspot/share/jfr/writers/jfrStorageHost.hpp
src/hotspot/share/jfr/writers/jfrStorageHost.inline.hpp
src/hotspot/share/jfr/writers/jfrStreamWriterHost.hpp
src/hotspot/share/jfr/writers/jfrStreamWriterHost.inline.hpp
src/hotspot/share/jfr/writers/jfrWriterHost.hpp
src/hotspot/share/jfr/writers/jfrWriterHost.inline.hpp
src/hotspot/share/logging/logTag.hpp
src/hotspot/share/memory/metaspaceTracer.cpp
src/hotspot/share/oops/arrayKlass.cpp
src/hotspot/share/oops/instanceKlass.hpp
src/hotspot/share/oops/klass.cpp
src/hotspot/share/oops/klass.hpp
src/hotspot/share/oops/method.hpp
src/hotspot/share/opto/bytecodeInfo.cpp
src/hotspot/share/opto/c2compiler.cpp
src/hotspot/share/opto/compile.hpp
src/hotspot/share/opto/graphKit.cpp
src/hotspot/share/opto/library_call.cpp
src/hotspot/share/prims/jni.cpp
src/hotspot/share/prims/jvm.cpp
src/hotspot/share/prims/nativeLookup.cpp
src/hotspot/share/prims/unsafe.cpp
src/hotspot/share/runtime/arguments.cpp
src/hotspot/share/runtime/biasedLocking.cpp
src/hotspot/share/runtime/flags/jvmFlag.cpp
src/hotspot/share/runtime/globals.cpp
src/hotspot/share/runtime/globals.hpp
src/hotspot/share/runtime/java.cpp
src/hotspot/share/runtime/jniHandles.cpp
src/hotspot/share/runtime/mutexLocker.cpp
src/hotspot/share/runtime/mutexLocker.hpp
src/hotspot/share/runtime/objectMonitor.cpp
src/hotspot/share/runtime/objectMonitor.hpp
src/hotspot/share/runtime/os_perf.hpp
src/hotspot/share/runtime/safepoint.cpp
src/hotspot/share/runtime/sharedRuntime.cpp
src/hotspot/share/runtime/sweeper.cpp
src/hotspot/share/runtime/synchronizer.cpp
src/hotspot/share/runtime/thread.cpp
src/hotspot/share/runtime/thread.hpp
src/hotspot/share/runtime/vmStructs.cpp
src/hotspot/share/runtime/vmStructs_trace.hpp
src/hotspot/share/runtime/vmThread.cpp
src/hotspot/share/runtime/vm_operations.cpp
src/hotspot/share/trace/noTraceBackend.hpp
src/hotspot/share/trace/trace.dtd
src/hotspot/share/trace/trace.xml
src/hotspot/share/trace/traceBackend.cpp
src/hotspot/share/trace/traceBackend.hpp
src/hotspot/share/trace/traceDataTypes.hpp
src/hotspot/share/trace/traceEvent.hpp
src/hotspot/share/trace/traceEventClasses.xsl
src/hotspot/share/trace/traceEventIds.xsl
src/hotspot/share/trace/traceMacros.hpp
src/hotspot/share/trace/traceStream.cpp
src/hotspot/share/trace/traceStream.hpp
src/hotspot/share/trace/traceTime.hpp
src/hotspot/share/trace/traceTypes.xsl
src/hotspot/share/trace/traceevents.xml
src/hotspot/share/trace/tracerelationdecls.xml
src/hotspot/share/trace/tracetypes.xml
src/hotspot/share/trace/tracing.hpp
src/hotspot/share/trace/tracingExport.cpp
src/hotspot/share/trace/tracingExport.hpp
src/hotspot/share/trace/xinclude.mod
src/hotspot/share/trace/xsl_util.xsl
src/hotspot/share/utilities/hashtable.cpp
src/hotspot/share/utilities/macros.hpp
src/hotspot/share/utilities/spinYield.cpp
src/hotspot/share/utilities/ticks.cpp
src/hotspot/share/utilities/ticks.hpp
src/hotspot/share/utilities/ticks.inline.hpp
src/hotspot/share/utilities/vmError.cpp
src/java.base/share/classes/module-info.java
src/java.management/share/classes/module-info.java
src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VMOps.java
src/jdk.jfr/share/classes/jdk/jfr/AnnotationElement.java
src/jdk.jfr/share/classes/jdk/jfr/BooleanFlag.java
src/jdk.jfr/share/classes/jdk/jfr/Category.java
src/jdk.jfr/share/classes/jdk/jfr/Configuration.java
src/jdk.jfr/share/classes/jdk/jfr/ContentType.java
src/jdk.jfr/share/classes/jdk/jfr/DataAmount.java
src/jdk.jfr/share/classes/jdk/jfr/Description.java
src/jdk.jfr/share/classes/jdk/jfr/Enabled.java
src/jdk.jfr/share/classes/jdk/jfr/Event.java
src/jdk.jfr/share/classes/jdk/jfr/EventFactory.java
src/jdk.jfr/share/classes/jdk/jfr/EventSettings.java
src/jdk.jfr/share/classes/jdk/jfr/EventType.java
src/jdk.jfr/share/classes/jdk/jfr/Experimental.java
src/jdk.jfr/share/classes/jdk/jfr/FlightRecorder.java
src/jdk.jfr/share/classes/jdk/jfr/FlightRecorderListener.java
src/jdk.jfr/share/classes/jdk/jfr/FlightRecorderPermission.java
src/jdk.jfr/share/classes/jdk/jfr/Frequency.java
src/jdk.jfr/share/classes/jdk/jfr/Label.java
src/jdk.jfr/share/classes/jdk/jfr/MemoryAddress.java
src/jdk.jfr/share/classes/jdk/jfr/MetadataDefinition.java
src/jdk.jfr/share/classes/jdk/jfr/Name.java
src/jdk.jfr/share/classes/jdk/jfr/Percentage.java
src/jdk.jfr/share/classes/jdk/jfr/Period.java
src/jdk.jfr/share/classes/jdk/jfr/Recording.java
src/jdk.jfr/share/classes/jdk/jfr/RecordingState.java
src/jdk.jfr/share/classes/jdk/jfr/Registered.java
src/jdk.jfr/share/classes/jdk/jfr/Relational.java
src/jdk.jfr/share/classes/jdk/jfr/SettingControl.java
src/jdk.jfr/share/classes/jdk/jfr/SettingDefinition.java
src/jdk.jfr/share/classes/jdk/jfr/SettingDescriptor.java
src/jdk.jfr/share/classes/jdk/jfr/StackTrace.java
src/jdk.jfr/share/classes/jdk/jfr/Threshold.java
src/jdk.jfr/share/classes/jdk/jfr/Timespan.java
src/jdk.jfr/share/classes/jdk/jfr/Timestamp.java
src/jdk.jfr/share/classes/jdk/jfr/TransitionFrom.java
src/jdk.jfr/share/classes/jdk/jfr/TransitionTo.java
src/jdk.jfr/share/classes/jdk/jfr/Unsigned.java
src/jdk.jfr/share/classes/jdk/jfr/ValueDescriptor.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/ChunkParser.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/ConstantMap.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/EventParser.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/LongMap.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/ObjectFactory.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/Parser.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/ParserFactory.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedClass.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedClassLoader.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedEvent.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedFrame.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedMethod.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedStackTrace.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedThread.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedThreadGroup.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingFile.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/TimeConverter.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/package-info.java
src/jdk.jfr/share/classes/jdk/jfr/events/AbstractJDKEvent.java
src/jdk.jfr/share/classes/jdk/jfr/events/ActiveRecordingEvent.java
src/jdk.jfr/share/classes/jdk/jfr/events/ActiveSettingEvent.java
src/jdk.jfr/share/classes/jdk/jfr/events/ErrorThrownEvent.java
src/jdk.jfr/share/classes/jdk/jfr/events/ExceptionStatisticsEvent.java
src/jdk.jfr/share/classes/jdk/jfr/events/ExceptionThrownEvent.java
src/jdk.jfr/share/classes/jdk/jfr/events/FileForceEvent.java
src/jdk.jfr/share/classes/jdk/jfr/events/FileReadEvent.java
src/jdk.jfr/share/classes/jdk/jfr/events/FileWriteEvent.java
src/jdk.jfr/share/classes/jdk/jfr/events/SocketReadEvent.java
src/jdk.jfr/share/classes/jdk/jfr/events/SocketWriteEvent.java
src/jdk.jfr/share/classes/jdk/jfr/internal/ASMToolkit.java
src/jdk.jfr/share/classes/jdk/jfr/internal/AnnotationConstruct.java
src/jdk.jfr/share/classes/jdk/jfr/internal/Bits.java
src/jdk.jfr/share/classes/jdk/jfr/internal/ChunkInputStream.java
src/jdk.jfr/share/classes/jdk/jfr/internal/ChunksChannel.java
src/jdk.jfr/share/classes/jdk/jfr/internal/Control.java
src/jdk.jfr/share/classes/jdk/jfr/internal/Cutoff.java
src/jdk.jfr/share/classes/jdk/jfr/internal/EventClassBuilder.java
src/jdk.jfr/share/classes/jdk/jfr/internal/EventControl.java
src/jdk.jfr/share/classes/jdk/jfr/internal/EventHandlerCreator.java
src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java
src/jdk.jfr/share/classes/jdk/jfr/internal/EventWriter.java
src/jdk.jfr/share/classes/jdk/jfr/internal/EventWriterMethod.java
src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java
src/jdk.jfr/share/classes/jdk/jfr/internal/JVMSupport.java
src/jdk.jfr/share/classes/jdk/jfr/internal/JVMUpcalls.java
src/jdk.jfr/share/classes/jdk/jfr/internal/LogLevel.java
src/jdk.jfr/share/classes/jdk/jfr/internal/LogTag.java
src/jdk.jfr/share/classes/jdk/jfr/internal/Logger.java
src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataDescriptor.java
src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataHandler.java
src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataReader.java
src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java
src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataWriter.java
src/jdk.jfr/share/classes/jdk/jfr/internal/Options.java
src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformEventType.java
src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecorder.java
src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java
src/jdk.jfr/share/classes/jdk/jfr/internal/PrivateAccess.java
src/jdk.jfr/share/classes/jdk/jfr/internal/Repository.java
src/jdk.jfr/share/classes/jdk/jfr/internal/RepositoryChunk.java
src/jdk.jfr/share/classes/jdk/jfr/internal/RequestEngine.java
src/jdk.jfr/share/classes/jdk/jfr/internal/SecuritySupport.java
src/jdk.jfr/share/classes/jdk/jfr/internal/SettingsManager.java
src/jdk.jfr/share/classes/jdk/jfr/internal/ShutdownHook.java
src/jdk.jfr/share/classes/jdk/jfr/internal/StringPool.java
src/jdk.jfr/share/classes/jdk/jfr/internal/Type.java
src/jdk.jfr/share/classes/jdk/jfr/internal/TypeLibrary.java
src/jdk.jfr/share/classes/jdk/jfr/internal/Utils.java
src/jdk.jfr/share/classes/jdk/jfr/internal/WriteableUserPath.java
src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/Command.java
src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/Execute.java
src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/HelpCommand.java
src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/JSONWriter.java
src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/PrettyWriter.java
src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/PrintCommand.java
src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/ReconstructCommand.java
src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/SplitCommand.java
src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/StructuredWriter.java
src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/SummaryCommand.java
src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/XMLWriter.java
src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java
src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RecordingInput.java
src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/AbstractDCmd.java
src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdCheck.java
src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdConfigure.java
src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdDump.java
src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdException.java
src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java
src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStop.java
src/jdk.jfr/share/classes/jdk/jfr/internal/handlers/EventHandler.java
src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/ConstructorTracerWriter.java
src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/ConstructorWriter.java
src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/FileChannelImplInstrumentor.java
src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/FileInputStreamInstrumentor.java
src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/FileOutputStreamInstrumentor.java
src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/JDKEvents.java
src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/JIClassInstrumentation.java
src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/JIInliner.java
src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/JIInstrumentationMethod.java
src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/JIInstrumentationTarget.java
src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/JIMethodCallInliner.java
src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/JIMethodInliningAdapter.java
src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/JIMethodMergeAdapter.java
src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/JITypeMapping.java
src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/RandomAccessFileInstrumentor.java
src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/SocketChannelImplInstrumentor.java
src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/SocketInputStreamInstrumentor.java
src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/SocketOutputStreamInstrumentor.java
src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/ThrowableTracer.java
src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/JFC.java
src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/JFCParser.java
src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/JFCParserHandler.java
src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/jfc.xsd
src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/package-info.java
src/jdk.jfr/share/classes/jdk/jfr/internal/management/ManagementSupport.java
src/jdk.jfr/share/classes/jdk/jfr/internal/settings/BooleanValue.java
src/jdk.jfr/share/classes/jdk/jfr/internal/settings/CutoffSetting.java
src/jdk.jfr/share/classes/jdk/jfr/internal/settings/EnabledSetting.java
src/jdk.jfr/share/classes/jdk/jfr/internal/settings/PeriodSetting.java
src/jdk.jfr/share/classes/jdk/jfr/internal/settings/StackTraceSetting.java
src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThresholdSetting.java
src/jdk.jfr/share/classes/jdk/jfr/internal/test/WhiteBox.java
src/jdk.jfr/share/classes/jdk/jfr/package-info.java
src/jdk.jfr/share/classes/module-info.java
src/jdk.jfr/share/conf/jfr/default.jfc
src/jdk.jfr/share/conf/jfr/profile.jfc
src/jdk.management.jfr/share/classes/jdk/management/jfr/ConfigurationInfo.java
src/jdk.management.jfr/share/classes/jdk/management/jfr/EventTypeInfo.java
src/jdk.management.jfr/share/classes/jdk/management/jfr/FlightRecorderMXBean.java
src/jdk.management.jfr/share/classes/jdk/management/jfr/FlightRecorderMXBeanImpl.java
src/jdk.management.jfr/share/classes/jdk/management/jfr/MBeanUtils.java
src/jdk.management.jfr/share/classes/jdk/management/jfr/RecordingInfo.java
src/jdk.management.jfr/share/classes/jdk/management/jfr/SettingDescriptorInfo.java
src/jdk.management.jfr/share/classes/jdk/management/jfr/Stream.java
src/jdk.management.jfr/share/classes/jdk/management/jfr/StreamCleanupTask.java
src/jdk.management.jfr/share/classes/jdk/management/jfr/StreamManager.java
src/jdk.management.jfr/share/classes/jdk/management/jfr/Stringifier.java
src/jdk.management.jfr/share/classes/jdk/management/jfr/internal/FlightRecorderMXBeanProvider.java
src/jdk.management.jfr/share/classes/jdk/management/jfr/package-info.java
src/jdk.management.jfr/share/classes/module-info.java
test/hotspot/gtest/gc/shared/test_oopStorage_parperf.cpp
test/hotspot/gtest/jfr/precompiled.hpp
test/hotspot/gtest/jfr/test_threadCpuLoad.cpp
test/hotspot/jtreg/runtime/appcds/CDSandJFR.java
test/hotspot/jtreg/runtime/appcds/TestWithProfiler.java
test/hotspot/jtreg/runtime/appcds/test-classes/GetFlightRecorder.java
test/hotspot/jtreg/runtime/appcds/test-classes/MyThread.java
test/hotspot/jtreg/runtime/appcds/test-classes/TestWithProfilerHelper.java
test/jdk/ProblemList.txt
test/jdk/TEST.ROOT
test/jdk/TEST.groups
test/jdk/jdk/jfr/TEST.properties
test/jdk/jdk/jfr/api/consumer/TEST.properties
test/jdk/jdk/jfr/api/consumer/TestFieldAccess.java
test/jdk/jdk/jfr/api/consumer/TestGetStackTrace.java
test/jdk/jdk/jfr/api/consumer/TestHiddenMethod.java
test/jdk/jdk/jfr/api/consumer/TestMethodGetModifiers.java
test/jdk/jdk/jfr/api/consumer/TestReadTwice.java
test/jdk/jdk/jfr/api/consumer/TestRecordedClassLoader.java
test/jdk/jdk/jfr/api/consumer/TestRecordedEvent.java
test/jdk/jdk/jfr/api/consumer/TestRecordedEventGetThread.java
test/jdk/jdk/jfr/api/consumer/TestRecordedEventGetThreadOther.java
test/jdk/jdk/jfr/api/consumer/TestRecordedFrame.java
test/jdk/jdk/jfr/api/consumer/TestRecordedFullStackTrace.java
test/jdk/jdk/jfr/api/consumer/TestRecordedInstantEventTimestamp.java
test/jdk/jdk/jfr/api/consumer/TestRecordedMethodDescriptor.java
test/jdk/jdk/jfr/api/consumer/TestRecordedObject.java
test/jdk/jdk/jfr/api/consumer/TestRecordedThreadGroupParent.java
test/jdk/jdk/jfr/api/consumer/TestRecordingFile.java
test/jdk/jdk/jfr/api/consumer/TestRecordingFileReadEventEof.java
test/jdk/jdk/jfr/api/consumer/TestRecordingInternals.java
test/jdk/jdk/jfr/api/consumer/TestSingleRecordedEvent.java
test/jdk/jdk/jfr/api/consumer/TestToString.java
test/jdk/jdk/jfr/api/consumer/TestValueDescriptorRecorded.java
test/jdk/jdk/jfr/api/event/TEST.properties
test/jdk/jdk/jfr/api/event/TestAbstractEvent.java
test/jdk/jdk/jfr/api/event/TestBeginEnd.java
test/jdk/jdk/jfr/api/event/TestClinitRegistration.java
test/jdk/jdk/jfr/api/event/TestClonedEvent.java
test/jdk/jdk/jfr/api/event/TestEnableDisable.java
test/jdk/jdk/jfr/api/event/TestEventFactory.java
test/jdk/jdk/jfr/api/event/TestEventFactoryRegisterTwice.java
test/jdk/jdk/jfr/api/event/TestEventFactoryRegistration.java
test/jdk/jdk/jfr/api/event/TestExtends.java
test/jdk/jdk/jfr/api/event/TestGetDuration.java
test/jdk/jdk/jfr/api/event/TestIsEnabled.java
test/jdk/jdk/jfr/api/event/TestIsEnabledMultiple.java
test/jdk/jdk/jfr/api/event/TestOwnCommit.java
test/jdk/jdk/jfr/api/event/TestShouldCommit.java
test/jdk/jdk/jfr/api/event/TestStaticEnable.java
test/jdk/jdk/jfr/api/event/dynamic/TestDynamicAnnotations.java
test/jdk/jdk/jfr/api/event/dynamic/TestEventFactory.java
test/jdk/jdk/jfr/api/flightrecorder/MyListener.java
test/jdk/jdk/jfr/api/flightrecorder/TestAddListenerTwice.java
test/jdk/jdk/jfr/api/flightrecorder/TestAddPeriodicEvent.java
test/jdk/jdk/jfr/api/flightrecorder/TestFlightRecorderListenerRecorderInitialized.java
test/jdk/jdk/jfr/api/flightrecorder/TestGetEventTypes.java
test/jdk/jdk/jfr/api/flightrecorder/TestGetPlatformRecorder.java
test/jdk/jdk/jfr/api/flightrecorder/TestGetRecordings.java
test/jdk/jdk/jfr/api/flightrecorder/TestGetSettings.java
test/jdk/jdk/jfr/api/flightrecorder/TestIsAvailable.java
test/jdk/jdk/jfr/api/flightrecorder/TestIsInitialized.java
test/jdk/jdk/jfr/api/flightrecorder/TestListener.java
test/jdk/jdk/jfr/api/flightrecorder/TestListenerNull.java
test/jdk/jdk/jfr/api/flightrecorder/TestPeriodicEventsSameHook.java
test/jdk/jdk/jfr/api/flightrecorder/TestRecorderInitializationCallback.java
test/jdk/jdk/jfr/api/flightrecorder/TestRegisterUnregisterEvent.java
test/jdk/jdk/jfr/api/flightrecorder/TestSettingsControl.java
test/jdk/jdk/jfr/api/flightrecorder/TestSnapshot.java
test/jdk/jdk/jfr/api/metadata/annotations/TestCategory.java
test/jdk/jdk/jfr/api/metadata/annotations/TestContentType.java
test/jdk/jdk/jfr/api/metadata/annotations/TestDescription.java
test/jdk/jdk/jfr/api/metadata/annotations/TestDynamicAnnotation.java
test/jdk/jdk/jfr/api/metadata/annotations/TestEnabled.java
test/jdk/jdk/jfr/api/metadata/annotations/TestExperimental.java
test/jdk/jdk/jfr/api/metadata/annotations/TestFieldAnnotations.java
test/jdk/jdk/jfr/api/metadata/annotations/TestHasValue.java
test/jdk/jdk/jfr/api/metadata/annotations/TestInheritedAnnotations.java
test/jdk/jdk/jfr/api/metadata/annotations/TestLabel.java
test/jdk/jdk/jfr/api/metadata/annotations/TestMetadata.java
test/jdk/jdk/jfr/api/metadata/annotations/TestName.java
test/jdk/jdk/jfr/api/metadata/annotations/TestPeriod.java
test/jdk/jdk/jfr/api/metadata/annotations/TestRegistered.java
test/jdk/jdk/jfr/api/metadata/annotations/TestRegisteredFalseAndRunning.java
test/jdk/jdk/jfr/api/metadata/annotations/TestRelational.java
test/jdk/jdk/jfr/api/metadata/annotations/TestSimpleMetadataEvent.java
test/jdk/jdk/jfr/api/metadata/annotations/TestStackTrace.java
test/jdk/jdk/jfr/api/metadata/annotations/TestThreshold.java
test/jdk/jdk/jfr/api/metadata/annotations/TestTypesIdentical.java
test/jdk/jdk/jfr/api/metadata/eventtype/EventWithCustomSettings.java
test/jdk/jdk/jfr/api/metadata/eventtype/TestGetAnnotation.java
test/jdk/jdk/jfr/api/metadata/eventtype/TestGetAnnotationElements.java
test/jdk/jdk/jfr/api/metadata/eventtype/TestGetAnnotations.java
test/jdk/jdk/jfr/api/metadata/eventtype/TestGetCategory.java
test/jdk/jdk/jfr/api/metadata/eventtype/TestGetDefaultValues.java
test/jdk/jdk/jfr/api/metadata/eventtype/TestGetDescription.java
test/jdk/jdk/jfr/api/metadata/eventtype/TestGetEventType.java
test/jdk/jdk/jfr/api/metadata/eventtype/TestGetField.java
test/jdk/jdk/jfr/api/metadata/eventtype/TestGetFields.java
test/jdk/jdk/jfr/api/metadata/eventtype/TestGetSettings.java
test/jdk/jdk/jfr/api/metadata/eventtype/TestUnloadingEventClass.java
test/jdk/jdk/jfr/api/metadata/settingdescriptor/AnnotatedSetting.java
test/jdk/jdk/jfr/api/metadata/settingdescriptor/BaseEvent.java
test/jdk/jdk/jfr/api/metadata/settingdescriptor/CustomEvent.java
test/jdk/jdk/jfr/api/metadata/settingdescriptor/PlainSetting.java
test/jdk/jdk/jfr/api/metadata/settingdescriptor/TestDefaultValue.java
test/jdk/jdk/jfr/api/metadata/settingdescriptor/TestGetAnnotation.java
test/jdk/jdk/jfr/api/metadata/settingdescriptor/TestGetAnnotationElement.java
test/jdk/jdk/jfr/api/metadata/settingdescriptor/TestGetContentType.java
test/jdk/jdk/jfr/api/metadata/settingdescriptor/TestGetDescription.java
test/jdk/jdk/jfr/api/metadata/settingdescriptor/TestGetLabel.java
test/jdk/jdk/jfr/api/metadata/settingdescriptor/TestGetName.java
test/jdk/jdk/jfr/api/metadata/settingdescriptor/TestGetTypeId.java
test/jdk/jdk/jfr/api/metadata/settingdescriptor/TestGetTypeName.java
test/jdk/jdk/jfr/api/metadata/valuedescriptor/TestClasses.java
test/jdk/jdk/jfr/api/metadata/valuedescriptor/TestConstructor.java
test/jdk/jdk/jfr/api/metadata/valuedescriptor/TestGetAnnotations.java
test/jdk/jdk/jfr/api/metadata/valuedescriptor/TestGetFields.java
test/jdk/jdk/jfr/api/metadata/valuedescriptor/TestIsArray.java
test/jdk/jdk/jfr/api/metadata/valuedescriptor/TestSimpleTypes.java
test/jdk/jdk/jfr/api/metadata/valuedescriptor/TestValueDescriptorContentType.java
test/jdk/jdk/jfr/api/modules/TestModularizedEvent.java
test/jdk/jdk/jfr/api/modules/src_mods/test.jfr.annotation/module-info.java
test/jdk/jdk/jfr/api/modules/src_mods/test.jfr.annotation/test/jfr/annotation/ModularizedAnnotation.java
test/jdk/jdk/jfr/api/modules/src_mods/test.jfr.event/module-info.java
test/jdk/jdk/jfr/api/modules/src_mods/test.jfr.event/test/jfr/event/ModularizedOrdinaryEvent.java
test/jdk/jdk/jfr/api/modules/src_mods/test.jfr.event/test/jfr/event/ModularizedPeriodicEvent.java
test/jdk/jdk/jfr/api/modules/src_mods/test.jfr.main/module-info.java
test/jdk/jdk/jfr/api/modules/src_mods/test.jfr.main/test/jfr/main/MainTest.java
test/jdk/jdk/jfr/api/modules/src_mods/test.jfr.setting/module-info.java
test/jdk/jdk/jfr/api/modules/src_mods/test.jfr.setting/test/jfr/setting/ModularizedSetting.java
test/jdk/jdk/jfr/api/recorder/TestRecorderInitialized.java
test/jdk/jdk/jfr/api/recorder/TestRecorderListener.java
test/jdk/jdk/jfr/api/recorder/TestStartStopRecording.java
test/jdk/jdk/jfr/api/recording/destination/TestDestFileExist.java
test/jdk/jdk/jfr/api/recording/destination/TestDestFileReadOnly.java
test/jdk/jdk/jfr/api/recording/destination/TestDestInvalid.java
test/jdk/jdk/jfr/api/recording/destination/TestDestLongPath.java
test/jdk/jdk/jfr/api/recording/destination/TestDestMultiple.java
test/jdk/jdk/jfr/api/recording/destination/TestDestReadOnly.java
test/jdk/jdk/jfr/api/recording/destination/TestDestState.java
test/jdk/jdk/jfr/api/recording/destination/TestDestToDiskFalse.java
test/jdk/jdk/jfr/api/recording/destination/TestDestToDiskTrue.java
test/jdk/jdk/jfr/api/recording/destination/TestDestWithDuration.java
test/jdk/jdk/jfr/api/recording/dump/TestDump.java
test/jdk/jdk/jfr/api/recording/dump/TestDumpInvalid.java
test/jdk/jdk/jfr/api/recording/dump/TestDumpLongPath.java
test/jdk/jdk/jfr/api/recording/dump/TestDumpMultiple.java
test/jdk/jdk/jfr/api/recording/dump/TestDumpReadOnly.java
test/jdk/jdk/jfr/api/recording/dump/TestDumpState.java
test/jdk/jdk/jfr/api/recording/event/TEST.properties
test/jdk/jdk/jfr/api/recording/event/TestChunkPeriod.java
test/jdk/jdk/jfr/api/recording/event/TestEnableClass.java
test/jdk/jdk/jfr/api/recording/event/TestEnableName.java
test/jdk/jdk/jfr/api/recording/event/TestEventTime.java
test/jdk/jdk/jfr/api/recording/event/TestLoadEventAfterStart.java
test/jdk/jdk/jfr/api/recording/event/TestPeriod.java
test/jdk/jdk/jfr/api/recording/event/TestReEnableClass.java
test/jdk/jdk/jfr/api/recording/event/TestReEnableMultiple.java
test/jdk/jdk/jfr/api/recording/event/TestReEnableName.java
test/jdk/jdk/jfr/api/recording/event/TestRecordingEnableDisable.java
test/jdk/jdk/jfr/api/recording/event/TestThreshold.java
test/jdk/jdk/jfr/api/recording/misc/TestGetId.java
test/jdk/jdk/jfr/api/recording/misc/TestGetSize.java
test/jdk/jdk/jfr/api/recording/misc/TestGetSizeToMem.java
test/jdk/jdk/jfr/api/recording/misc/TestGetStream.java
test/jdk/jdk/jfr/api/recording/misc/TestRecordingBase.java
test/jdk/jdk/jfr/api/recording/misc/TestRecordingCopy.java
test/jdk/jdk/jfr/api/recording/options/TestDuration.java
test/jdk/jdk/jfr/api/recording/options/TestName.java
test/jdk/jdk/jfr/api/recording/settings/TestConfigurationGetContents.java
test/jdk/jdk/jfr/api/recording/settings/TestCreateConfigFromPath.java
test/jdk/jdk/jfr/api/recording/settings/TestCreateConfigFromReader.java
test/jdk/jdk/jfr/api/recording/settings/TestGetConfigurations.java
test/jdk/jdk/jfr/api/recording/settings/TestSettingsAvailability.java
test/jdk/jdk/jfr/api/recording/settings/settings.jfc
test/jdk/jdk/jfr/api/recording/state/TestOptionState.java
test/jdk/jdk/jfr/api/recording/state/TestState.java
test/jdk/jdk/jfr/api/recording/state/TestStateDuration.java
test/jdk/jdk/jfr/api/recording/state/TestStateIdenticalListeners.java
test/jdk/jdk/jfr/api/recording/state/TestStateInvalid.java
test/jdk/jdk/jfr/api/recording/state/TestStateMultiple.java
test/jdk/jdk/jfr/api/recording/state/TestStateScheduleStart.java
test/jdk/jdk/jfr/api/recording/time/TestTime.java
test/jdk/jdk/jfr/api/recording/time/TestTimeDuration.java
test/jdk/jdk/jfr/api/recording/time/TestTimeMultiple.java
test/jdk/jdk/jfr/api/recording/time/TestTimeScheduleStart.java
test/jdk/jdk/jfr/api/settings/RegExpControl.java
test/jdk/jdk/jfr/api/settings/StringListSetting.java
test/jdk/jdk/jfr/api/settings/TestFilterEvents.java
test/jdk/jdk/jfr/cmd/ExecuteHelper.java
test/jdk/jdk/jfr/cmd/TestHelp.java
test/jdk/jdk/jfr/cmd/TestPrint.java
test/jdk/jdk/jfr/cmd/TestPrintDefault.java
test/jdk/jdk/jfr/cmd/TestPrintJSON.java
test/jdk/jdk/jfr/cmd/TestPrintXML.java
test/jdk/jdk/jfr/cmd/TestReconstruct.java
test/jdk/jdk/jfr/cmd/TestSplit.java
test/jdk/jdk/jfr/cmd/TestSummary.java
test/jdk/jdk/jfr/event/TEST.properties
test/jdk/jdk/jfr/event/compiler/TestAllocInNewTLAB.java
test/jdk/jdk/jfr/event/compiler/TestAllocOutsideTLAB.java
test/jdk/jdk/jfr/event/compiler/TestCodeCacheConfig.java
test/jdk/jdk/jfr/event/compiler/TestCodeCacheFull.java
test/jdk/jdk/jfr/event/compiler/TestCodeCacheStats.java
test/jdk/jdk/jfr/event/compiler/TestCodeSweeper.java
test/jdk/jdk/jfr/event/compiler/TestCodeSweeperConfig.java
test/jdk/jdk/jfr/event/compiler/TestCodeSweeperStats.java
test/jdk/jdk/jfr/event/compiler/TestCompilerCompile.java
test/jdk/jdk/jfr/event/compiler/TestCompilerConfig.java
test/jdk/jdk/jfr/event/compiler/TestCompilerInlining.java
test/jdk/jdk/jfr/event/compiler/TestCompilerPhase.java
test/jdk/jdk/jfr/event/compiler/TestCompilerStats.java
test/jdk/jdk/jfr/event/gc/collection/AppGCProvoker.java
test/jdk/jdk/jfr/event/gc/collection/GCEventAll.java
test/jdk/jdk/jfr/event/gc/collection/GCGarbageCollectionUtil.java
test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithCMSConcurrent.java
test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithCMSMarkSweep.java
test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithG1ConcurrentMark.java
test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithG1FullCollection.java
test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithPSMarkSweep.java
test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithParallelOld.java
test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithSerial.java
test/jdk/jdk/jfr/event/gc/collection/TestGCEventMixedWithCMSConcurrent.java
test/jdk/jdk/jfr/event/gc/collection/TestGCEventMixedWithCMSMarkSweep.java
test/jdk/jdk/jfr/event/gc/collection/TestGCEventMixedWithG1ConcurrentMark.java
test/jdk/jdk/jfr/event/gc/collection/TestGCEventMixedWithG1FullCollection.java
test/jdk/jdk/jfr/event/gc/collection/TestGCEventMixedWithPSMarkSweep.java
test/jdk/jdk/jfr/event/gc/collection/TestGCEventMixedWithParNew.java
test/jdk/jdk/jfr/event/gc/collection/TestGCEventMixedWithParallelOld.java
test/jdk/jdk/jfr/event/gc/collection/TestGCEventMixedWithSerial.java
test/jdk/jdk/jfr/event/gc/collection/TestGCGarbageCollectionEvent.java
test/jdk/jdk/jfr/event/gc/collection/TestGCWithFasttime.java
test/jdk/jdk/jfr/event/gc/collection/TestYoungGarbageCollectionEventWithDefNew.java
test/jdk/jdk/jfr/event/gc/collection/TestYoungGarbageCollectionEventWithG1New.java
test/jdk/jdk/jfr/event/gc/collection/TestYoungGarbageCollectionEventWithParNew.java
test/jdk/jdk/jfr/event/gc/collection/TestYoungGarbageCollectionEventWithParallelScavenge.java
test/jdk/jdk/jfr/event/gc/collection/YoungGarbageCollectionEvent.java
test/jdk/jdk/jfr/event/gc/collection/gc-testsettings.jfc
test/jdk/jdk/jfr/event/gc/configuration/GCHeapConfigurationEventTester.java
test/jdk/jdk/jfr/event/gc/configuration/GCHeapConfigurationEventVerifier.java
test/jdk/jdk/jfr/event/gc/configuration/GCYoungGenerationConfigurationEventTester.java
test/jdk/jdk/jfr/event/gc/configuration/TestGCConfigurationEvent.java
test/jdk/jdk/jfr/event/gc/configuration/TestGCConfigurationEventWithDefaultPauseTarget.java
test/jdk/jdk/jfr/event/gc/configuration/TestGCHeapConfigurationEventWith32BitOops.java
test/jdk/jdk/jfr/event/gc/configuration/TestGCHeapConfigurationEventWith32BitOops.sh
test/jdk/jdk/jfr/event/gc/configuration/TestGCHeapConfigurationEventWithHeapBasedOops.java
test/jdk/jdk/jfr/event/gc/configuration/TestGCHeapConfigurationEventWithHeapBasedOops.sh
test/jdk/jdk/jfr/event/gc/configuration/TestGCHeapConfigurationEventWithZeroBasedOops.java
test/jdk/jdk/jfr/event/gc/configuration/TestGCHeapConfigurationEventWithZeroBasedOops.sh
test/jdk/jdk/jfr/event/gc/configuration/TestGCSurvivorConfigurationEvent.java
test/jdk/jdk/jfr/event/gc/configuration/TestGCTLABConfigurationEvent.java
test/jdk/jdk/jfr/event/gc/configuration/TestGCYoungGenerationConfigurationEventWithMinAndMaxSize.java
test/jdk/jdk/jfr/event/gc/configuration/TestGCYoungGenerationConfigurationEventWithNewRatio.java
test/jdk/jdk/jfr/event/gc/detailed/ExecuteOOMApp.java
test/jdk/jdk/jfr/event/gc/detailed/OOMApp.java
test/jdk/jdk/jfr/event/gc/detailed/PromotionEvent.java
test/jdk/jdk/jfr/event/gc/detailed/PromotionFailedEvent.java
test/jdk/jdk/jfr/event/gc/detailed/StressAllocationGCEvents.java
test/jdk/jdk/jfr/event/gc/detailed/TestCMSConcurrentModeFailureEvent.java
test/jdk/jdk/jfr/event/gc/detailed/TestEvacuationFailedEvent.java
test/jdk/jdk/jfr/event/gc/detailed/TestEvacuationInfoEvent.java
test/jdk/jdk/jfr/event/gc/detailed/TestG1AIHOPEvent.java
test/jdk/jdk/jfr/event/gc/detailed/TestG1ConcurrentModeFailureEvent.java
test/jdk/jdk/jfr/event/gc/detailed/TestG1EvacMemoryStatsEvent.java
test/jdk/jdk/jfr/event/gc/detailed/TestG1HeapRegionInformationEvent.java
test/jdk/jdk/jfr/event/gc/detailed/TestG1HeapRegionTypeChangeEvent.java
test/jdk/jdk/jfr/event/gc/detailed/TestG1IHOPEvent.java
test/jdk/jdk/jfr/event/gc/detailed/TestG1MMUEvent.java
test/jdk/jdk/jfr/event/gc/detailed/TestPromotionEventWithG1.java
test/jdk/jdk/jfr/event/gc/detailed/TestPromotionEventWithParallelScavenge.java
test/jdk/jdk/jfr/event/gc/detailed/TestPromotionFailedEventWithDefNew.java
test/jdk/jdk/jfr/event/gc/detailed/TestPromotionFailedEventWithParNew.java
test/jdk/jdk/jfr/event/gc/detailed/TestPromotionFailedEventWithParallelScavenge.java
test/jdk/jdk/jfr/event/gc/detailed/TestStressAllocationGCEventsWithCMS.java
test/jdk/jdk/jfr/event/gc/detailed/TestStressAllocationGCEventsWithDefNew.java
test/jdk/jdk/jfr/event/gc/detailed/TestStressAllocationGCEventsWithG1.java
test/jdk/jdk/jfr/event/gc/detailed/TestStressAllocationGCEventsWithParNew.java
test/jdk/jdk/jfr/event/gc/detailed/TestStressAllocationGCEventsWithParallel.java
test/jdk/jdk/jfr/event/gc/detailed/TestStressBigAllocationGCEventsWithCMS.java
test/jdk/jdk/jfr/event/gc/detailed/TestStressBigAllocationGCEventsWithDefNew.java
test/jdk/jdk/jfr/event/gc/detailed/TestStressBigAllocationGCEventsWithG1.java
test/jdk/jdk/jfr/event/gc/detailed/TestStressBigAllocationGCEventsWithParNew.java
test/jdk/jdk/jfr/event/gc/detailed/TestStressBigAllocationGCEventsWithParallel.java
test/jdk/jdk/jfr/event/gc/detailed/TestTenuringDistributionEvent.java
test/jdk/jdk/jfr/event/gc/detailed/concurrentmodefailure-testsettings.jfc
test/jdk/jdk/jfr/event/gc/detailed/evacuationfailed-testsettings.jfc
test/jdk/jdk/jfr/event/gc/detailed/promotionfailed-testsettings.jfc
test/jdk/jdk/jfr/event/gc/heapsummary/HeapSummaryEventAllGcs.java
test/jdk/jdk/jfr/event/gc/heapsummary/TestHeapSummaryCommittedSize.java
test/jdk/jdk/jfr/event/gc/heapsummary/TestHeapSummaryEventConcurrentCMS.java
test/jdk/jdk/jfr/event/gc/heapsummary/TestHeapSummaryEventDefNewSerial.java
test/jdk/jdk/jfr/event/gc/heapsummary/TestHeapSummaryEventG1.java
test/jdk/jdk/jfr/event/gc/heapsummary/TestHeapSummaryEventPSParOld.java
test/jdk/jdk/jfr/event/gc/heapsummary/TestHeapSummaryEventPSSerial.java
test/jdk/jdk/jfr/event/gc/heapsummary/TestHeapSummaryEventParNewCMS.java
test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountAfterGCEvent.java
test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEventVerifier.java
test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithCMSConcurrent.java
test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithCMSMarkSweep.java
test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithG1ConcurrentMark.java
test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithG1FullCollection.java
test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithPSMarkSweep.java
test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithParallelOld.java
test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithSerial.java
test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEvent.java
test/jdk/jdk/jfr/event/gc/refstat/RefStatEvent.java
test/jdk/jdk/jfr/event/gc/refstat/TestRefStatEventWithCMSConcurrent.java
test/jdk/jdk/jfr/event/gc/refstat/TestRefStatEventWithCMSMarkSweep.java
test/jdk/jdk/jfr/event/gc/refstat/TestRefStatEventWithDefNew.java
test/jdk/jdk/jfr/event/gc/refstat/TestRefStatEventWithG1ConcurrentMark.java
test/jdk/jdk/jfr/event/gc/refstat/TestRefStatEventWithG1FullCollection.java
test/jdk/jdk/jfr/event/gc/refstat/TestRefStatEventWithG1New.java
test/jdk/jdk/jfr/event/gc/refstat/TestRefStatEventWithPSMarkSweep.java
test/jdk/jdk/jfr/event/gc/refstat/TestRefStatEventWithParallelOld.java
test/jdk/jdk/jfr/event/gc/refstat/TestRefStatEventWithParallelScavenge.java
test/jdk/jdk/jfr/event/gc/stacktrace/AllocationStackTrace.java
test/jdk/jdk/jfr/event/gc/stacktrace/TEST.properties
test/jdk/jdk/jfr/event/gc/stacktrace/TestConcMarkSweepAllocationPendingStackTrace.java
test/jdk/jdk/jfr/event/gc/stacktrace/TestDefNewAllocationPendingStackTrace.java
test/jdk/jdk/jfr/event/gc/stacktrace/TestG1HumongousAllocationPendingStackTrace.java
test/jdk/jdk/jfr/event/gc/stacktrace/TestG1OldAllocationPendingStackTrace.java
test/jdk/jdk/jfr/event/gc/stacktrace/TestG1YoungAllocationPendingStackTrace.java
test/jdk/jdk/jfr/event/gc/stacktrace/TestMarkSweepCompactAllocationPendingStackTrace.java
test/jdk/jdk/jfr/event/gc/stacktrace/TestMetaspaceConcMarkSweepGCAllocationPendingStackTrace.java
test/jdk/jdk/jfr/event/gc/stacktrace/TestMetaspaceG1GCAllocationPendingStackTrace.java
test/jdk/jdk/jfr/event/gc/stacktrace/TestMetaspaceParallelGCAllocationPendingStackTrace.java
test/jdk/jdk/jfr/event/gc/stacktrace/TestMetaspaceSerialGCAllocationPendingStackTrace.java
test/jdk/jdk/jfr/event/gc/stacktrace/TestParNewAllocationPendingStackTrace.java
test/jdk/jdk/jfr/event/gc/stacktrace/TestParallelMarkSweepAllocationPendingStackTrace.java
test/jdk/jdk/jfr/event/gc/stacktrace/TestParallelScavengeAllocationPendingStackTrace.java
test/jdk/jdk/jfr/event/io/EvilInstrument.java
test/jdk/jdk/jfr/event/io/IOEvent.java
test/jdk/jdk/jfr/event/io/IOHelper.java
test/jdk/jdk/jfr/event/io/InstrumentationCallback.java
test/jdk/jdk/jfr/event/io/MakeJAR.sh
test/jdk/jdk/jfr/event/io/TestDisabledEvents.java
test/jdk/jdk/jfr/event/io/TestFileChannelEvents.java
test/jdk/jdk/jfr/event/io/TestFileReadOnly.java
test/jdk/jdk/jfr/event/io/TestFileStreamEvents.java
test/jdk/jdk/jfr/event/io/TestInstrumentation.java
test/jdk/jdk/jfr/event/io/TestInstrumentation.mf
test/jdk/jdk/jfr/event/io/TestRandomAccessFileEvents.java
test/jdk/jdk/jfr/event/io/TestRandomAccessFileThread.java
test/jdk/jdk/jfr/event/io/TestSocketChannelEvents.java
test/jdk/jdk/jfr/event/io/TestSocketEvents.java
test/jdk/jdk/jfr/event/metadata/TestDefaultConfigurations.java
test/jdk/jdk/jfr/event/metadata/TestEventMetadata.java
test/jdk/jdk/jfr/event/oldobject/OldObjects.java
test/jdk/jdk/jfr/event/oldobject/TestAllocationTime.java
test/jdk/jdk/jfr/event/oldobject/TestArrayInformation.java
test/jdk/jdk/jfr/event/oldobject/TestCMS.java
test/jdk/jdk/jfr/event/oldobject/TestCircularReference.java
test/jdk/jdk/jfr/event/oldobject/TestClassLoader.java
test/jdk/jdk/jfr/event/oldobject/TestClassLoaderLeak.java
test/jdk/jdk/jfr/event/oldobject/TestFieldInformation.java
test/jdk/jdk/jfr/event/oldobject/TestG1.java
test/jdk/jdk/jfr/event/oldobject/TestHeapDeep.java
test/jdk/jdk/jfr/event/oldobject/TestHeapShallow.java
test/jdk/jdk/jfr/event/oldobject/TestLargeRootSet.java
test/jdk/jdk/jfr/event/oldobject/TestListenerLeak.java
test/jdk/jdk/jfr/event/oldobject/TestMetadataObject.java
test/jdk/jdk/jfr/event/oldobject/TestMetadataRetention.java
test/jdk/jdk/jfr/event/oldobject/TestObjectDescription.java
test/jdk/jdk/jfr/event/oldobject/TestParallel.java
test/jdk/jdk/jfr/event/oldobject/TestParallelOld.java
test/jdk/jdk/jfr/event/oldobject/TestReferenceChainLimit.java
test/jdk/jdk/jfr/event/oldobject/TestSanityDefault.java
test/jdk/jdk/jfr/event/oldobject/TestSerial.java
test/jdk/jdk/jfr/event/oldobject/TestThreadLocalLeak.java
test/jdk/jdk/jfr/event/os/TestCPUInformation.java
test/jdk/jdk/jfr/event/os/TestCPULoad.java
test/jdk/jdk/jfr/event/os/TestCPUTimeStampCounter.java
test/jdk/jdk/jfr/event/os/TestInitialEnvironmentVariable.java
test/jdk/jdk/jfr/event/os/TestInitialEnvironmentVariable.sh
test/jdk/jdk/jfr/event/os/TestOSInfo.java
test/jdk/jdk/jfr/event/os/TestPhysicalMemoryEvent.java
test/jdk/jdk/jfr/event/os/TestSystemProcess.java
test/jdk/jdk/jfr/event/os/TestThreadContextSwitches.java
test/jdk/jdk/jfr/event/profiling/TestFullStackTrace.java
test/jdk/jdk/jfr/event/runtime/TestActiveRecordingEvent.java
test/jdk/jdk/jfr/event/runtime/TestActiveSettingEvent.java
test/jdk/jdk/jfr/event/runtime/TestBiasedLockRevocationEvents.java
test/jdk/jdk/jfr/event/runtime/TestClassDefineEvent.java
test/jdk/jdk/jfr/event/runtime/TestClassLoadEvent.java
test/jdk/jdk/jfr/event/runtime/TestClassLoaderStatsEvent.java
test/jdk/jdk/jfr/event/runtime/TestClassLoadingStatisticsEvent.java
test/jdk/jdk/jfr/event/runtime/TestClassUnloadEvent.java
test/jdk/jdk/jfr/event/runtime/TestClasses.java
test/jdk/jdk/jfr/event/runtime/TestExceptionEvents.java
test/jdk/jdk/jfr/event/runtime/TestExceptionSubclass.java
test/jdk/jdk/jfr/event/runtime/TestJavaBlockedEvent.java
test/jdk/jdk/jfr/event/runtime/TestJavaMonitorInflateEvent.java
test/jdk/jdk/jfr/event/runtime/TestJavaMonitorWaitEvent.java
test/jdk/jdk/jfr/event/runtime/TestJavaMonitorWaitTimeOut.java
test/jdk/jdk/jfr/event/runtime/TestJavaThreadStatisticsEvent.java
test/jdk/jdk/jfr/event/runtime/TestJavaThreadStatisticsEventBean.java
test/jdk/jdk/jfr/event/runtime/TestModuleEvents.java
test/jdk/jdk/jfr/event/runtime/TestNativeLibrariesEvent.java
test/jdk/jdk/jfr/event/runtime/TestSafepointEvents.java
test/jdk/jdk/jfr/event/runtime/TestSizeTFlags.java
test/jdk/jdk/jfr/event/runtime/TestSystemPropertyEvent.java
test/jdk/jdk/jfr/event/runtime/TestThreadAllocationEvent.java
test/jdk/jdk/jfr/event/runtime/TestThreadCpuTimeEvent.java
test/jdk/jdk/jfr/event/runtime/TestThreadDumpEvent.java
test/jdk/jdk/jfr/event/runtime/TestThreadParkEvent.java
test/jdk/jdk/jfr/event/runtime/TestThreadSleepEvent.java
test/jdk/jdk/jfr/event/runtime/TestThreadStartEndEvents.java
test/jdk/jdk/jfr/event/runtime/TestThrowableInstrumentation.java
test/jdk/jdk/jfr/event/runtime/TestVMInfoEvent.flags
test/jdk/jdk/jfr/event/runtime/TestVMInfoEvent.java
test/jdk/jdk/jfr/event/runtime/TestVMInfoEvent.sh
test/jdk/jdk/jfr/event/runtime/TestVMOperation.java
test/jdk/jdk/jfr/event/runtime/TestVmFlagChangedEvent.java
test/jdk/jdk/jfr/event/runtime/exception.security.policy
test/jdk/jdk/jfr/event/sampling/TestNative.java
test/jdk/jdk/jfr/event/sampling/libTestNative.c
test/jdk/jdk/jfr/jcmd/JcmdAsserts.java
test/jdk/jdk/jfr/jcmd/JcmdHelper.java
test/jdk/jdk/jfr/jcmd/TEST.properties
test/jdk/jdk/jfr/jcmd/TestJcmdChangeLogLevel.java
test/jdk/jdk/jfr/jcmd/TestJcmdConfigure.java
test/jdk/jdk/jfr/jcmd/TestJcmdDump.java
test/jdk/jdk/jfr/jcmd/TestJcmdDumpPathToGCRoots.java
test/jdk/jdk/jfr/jcmd/TestJcmdLegacy.java
test/jdk/jdk/jfr/jcmd/TestJcmdSaveToFile.java
test/jdk/jdk/jfr/jcmd/TestJcmdStartDirNotExist.java
test/jdk/jdk/jfr/jcmd/TestJcmdStartInvaldFile.java
test/jdk/jdk/jfr/jcmd/TestJcmdStartPathToGCRoots.java
test/jdk/jdk/jfr/jcmd/TestJcmdStartReadOnlyFile.java
test/jdk/jdk/jfr/jcmd/TestJcmdStartStopDefault.java
test/jdk/jdk/jfr/jcmd/TestJcmdStartWithOptions.java
test/jdk/jdk/jfr/jcmd/TestJcmdStartWithSettings.java
test/jdk/jdk/jfr/jcmd/TestJcmdStopInvalidFile.java
test/jdk/jdk/jfr/jcmd/TestJcmdStopReadOnlyFile.java
test/jdk/jdk/jfr/jcmd/jcmd-testsettings.2.jfc
test/jdk/jdk/jfr/jcmd/jcmd-testsettings.jfc
test/jdk/jdk/jfr/jcmd/jcmd-testsettings3.jfc
test/jdk/jdk/jfr/jcmd/legacy.jfc
test/jdk/jdk/jfr/jmx/JmxHelper.java
test/jdk/jdk/jfr/jmx/TEST.properties
test/jdk/jdk/jfr/jmx/TestClone.java
test/jdk/jdk/jfr/jmx/TestCloneRepeat.java
test/jdk/jdk/jfr/jmx/TestConfigurationInfo.java
test/jdk/jdk/jfr/jmx/TestCopyTo.java
test/jdk/jdk/jfr/jmx/TestCopyToInvalidPath.java
test/jdk/jdk/jfr/jmx/TestCopyToReadOnlyDir.java
test/jdk/jdk/jfr/jmx/TestCopyToRunning.java
test/jdk/jdk/jfr/jmx/TestEventTypes.java
test/jdk/jdk/jfr/jmx/TestGetRecordings.java
test/jdk/jdk/jfr/jmx/TestGetRecordingsMultiple.java
test/jdk/jdk/jfr/jmx/TestMultipleRecordings.java
test/jdk/jdk/jfr/jmx/TestNotificationListener.java
test/jdk/jdk/jfr/jmx/TestPredefinedConfiguration.java
test/jdk/jdk/jfr/jmx/TestPredefinedConfigurationInvalid.java
test/jdk/jdk/jfr/jmx/TestRecordingOptions.java
test/jdk/jdk/jfr/jmx/TestRecordingSettings.java
test/jdk/jdk/jfr/jmx/TestRecordingSettingsInvalid.java
test/jdk/jdk/jfr/jmx/TestRecordingSettingsMultiple.java
test/jdk/jdk/jfr/jmx/TestRecordingState.java
test/jdk/jdk/jfr/jmx/TestRecordingStateInvalid.java
test/jdk/jdk/jfr/jmx/TestSetConfiguration.java
test/jdk/jdk/jfr/jmx/TestSetConfigurationInvalid.java
test/jdk/jdk/jfr/jmx/TestSnapshot.java
test/jdk/jdk/jfr/jmx/TestStartRecording.java
test/jdk/jdk/jfr/jmx/TestStream.java
test/jdk/jdk/jfr/jmx/TestStreamClosed.java
test/jdk/jdk/jfr/jmx/TestStreamMultiple.java
test/jdk/jdk/jfr/jmx/TestWrongId.java
test/jdk/jdk/jfr/jmx/info/TestConfigurationInfo.java
test/jdk/jdk/jfr/jmx/info/TestEventTypeInfo.java
test/jdk/jdk/jfr/jmx/info/TestRecordingInfo.java
test/jdk/jdk/jfr/jmx/info/TestSettingDescriptorInfo.java
test/jdk/jdk/jfr/jmx/security/TestEnoughPermission.java
test/jdk/jdk/jfr/jmx/security/TestNoControlPermission.java
test/jdk/jdk/jfr/jmx/security/TestNoMonitorPermission.java
test/jdk/jdk/jfr/jmx/security/TestNotificationListenerPermission.java
test/jdk/jdk/jfr/jmx/security/enough.policy
test/jdk/jdk/jfr/jmx/security/listener.policy
test/jdk/jdk/jfr/jmx/security/nocontrol.policy
test/jdk/jdk/jfr/jmx/security/nomonitor.policy
test/jdk/jdk/jfr/jvm/HelloWorldEvent1.java
test/jdk/jdk/jfr/jvm/HelloWorldEvent2.java
test/jdk/jdk/jfr/jvm/TestBeginAndEnd.java
test/jdk/jdk/jfr/jvm/TestClassId.java
test/jdk/jdk/jfr/jvm/TestCounterTime.java
test/jdk/jdk/jfr/jvm/TestCreateNative.java
test/jdk/jdk/jfr/jvm/TestDumpOnCrash.java
test/jdk/jdk/jfr/jvm/TestGetAllEventClasses.java
test/jdk/jdk/jfr/jvm/TestGetEventWriter.java
test/jdk/jdk/jfr/jvm/TestGetStackTraceId.java
test/jdk/jdk/jfr/jvm/TestJFRIntrinsic.java
test/jdk/jdk/jfr/jvm/TestJavaEvent.java
test/jdk/jdk/jfr/jvm/TestJfrJavaBase.java
test/jdk/jdk/jfr/jvm/TestLargeJavaEvent512k.java
test/jdk/jdk/jfr/jvm/TestLargeJavaEvent64k.java
test/jdk/jdk/jfr/jvm/TestLogImplementation.java
test/jdk/jdk/jfr/jvm/TestLogOutput.java
test/jdk/jdk/jfr/jvm/TestPid.java
test/jdk/jdk/jfr/jvm/TestUnloadEventClassCount.java
test/jdk/jdk/jfr/jvm/TestUnsupportedVM.java
test/jdk/jdk/jfr/startupargs/StartupHelper.java
test/jdk/jdk/jfr/startupargs/TestBadOptionValues.java
test/jdk/jdk/jfr/startupargs/TestDumpOnExit.java
test/jdk/jdk/jfr/startupargs/TestMemoryOptions.java
test/jdk/jdk/jfr/startupargs/TestOldObjectQueueSize.java
test/jdk/jdk/jfr/startupargs/TestRepositoryPath.java
test/jdk/jdk/jfr/startupargs/TestRepositoryPathLong.java
test/jdk/jdk/jfr/startupargs/TestRetransform.java
test/jdk/jdk/jfr/startupargs/TestRetransformUsingLog.java
test/jdk/jdk/jfr/startupargs/TestStartDelay.java
test/jdk/jdk/jfr/startupargs/TestStartDelayRunning.java
test/jdk/jdk/jfr/startupargs/TestStartDuration.java
test/jdk/jdk/jfr/startupargs/TestStartMaxAgeSize.java
test/jdk/jdk/jfr/startupargs/TestStartName.java
test/jdk/jdk/jfr/startupargs/TestStartRecording.java
test/lib/jdk/test/lib/jfr/AppExecutorHelper.java
test/lib/jdk/test/lib/jfr/CommonHelper.java
test/lib/jdk/test/lib/jfr/EventField.java
test/lib/jdk/test/lib/jfr/EventNames.java
test/lib/jdk/test/lib/jfr/EventTypePrototype.java
test/lib/jdk/test/lib/jfr/EventVerifier.java
test/lib/jdk/test/lib/jfr/Events.java
test/lib/jdk/test/lib/jfr/FileHelper.java
test/lib/jdk/test/lib/jfr/GCHelper.java
test/lib/jdk/test/lib/jfr/RecurseThread.java
test/lib/jdk/test/lib/jfr/SimpleEvent.java
test/lib/jdk/test/lib/jfr/SimpleEventHelper.java
test/lib/jdk/test/lib/jfr/SimpleSetting.java
test/lib/jdk/test/lib/jfr/Stressor.java
test/lib/jdk/test/lib/jfr/TestClassLoader.java
test/lib/jdk/test/lib/jfr/VoidFunction.java
test/lib/jdk/test/lib/thread/TestThread.java
test/lib/jdk/test/lib/thread/XRun.java
--- a/make/CompileJavaModules.gmk	Tue May 15 11:28:29 2018 -0700
+++ b/make/CompileJavaModules.gmk	Tue May 15 20:24:34 2018 +0200
@@ -509,6 +509,15 @@
 # Exclude BreakIterator classes that are just used in compile process to generate
 # data files and shouldn't go in the product
 jdk.localedata_EXCLUDE_FILES += sun/text/resources/ext/BreakIteratorRules_th.java
+################################################################################
+
+# There is an issue in sjavac that triggers a warning in jdk.jfr that isn't
+# triggered without sjavac.
+ifeq ($(ENABLE_SJAVAC), yes)
+  jdk.jfr_SETUP := GENERATE_JDKBYTECODE_NOWARNINGS
+endif
+jdk.jfr_COPY := .xsd .xml .dtd
+jdk.jfr_ADD_JAVAC_FLAGS := -XDstringConcat=inline -Xlint:-exports
 
 ################################################################################
 # If this is an imported module that has prebuilt classes, only compile
--- a/make/autoconf/hotspot.m4	Tue May 15 11:28:29 2018 -0700
+++ b/make/autoconf/hotspot.m4	Tue May 15 20:24:34 2018 +0200
@@ -26,7 +26,7 @@
 # All valid JVM features, regardless of platform
 VALID_JVM_FEATURES="compiler1 compiler2 zero minimal dtrace jvmti jvmci \
     graal vm-structs jni-check services management cmsgc g1gc parallelgc serialgc nmt cds \
-    static-build link-time-opt aot"
+    static-build link-time-opt aot jfr"
 
 # All valid JVM variants
 VALID_JVM_VARIANTS="server client minimal core zero custom"
@@ -309,6 +309,11 @@
     AC_MSG_ERROR([Specified JVM feature 'cmsgc' requires feature 'serialgc'])
   fi
 
+  # Enable JFR by default, except on linux-sparcv9 and on minimal.
+  if test "x$OPENJDK_TARGET_OS" != xlinux || test "x$OPENJDK_TARGET_CPU" != xsparcv9; then
+    NON_MINIMAL_FEATURES="$NON_MINIMAL_FEATURES jfr"
+  fi
+
   # Turn on additional features based on other parts of configure
   if test "x$INCLUDE_DTRACE" = "xtrue"; then
     JVM_FEATURES="$JVM_FEATURES dtrace"
@@ -396,7 +401,7 @@
     NON_MINIMAL_FEATURES="$NON_MINIMAL_FEATURES cds"
   fi
 
-  # Enable default features depending on variant.
+  # Enable features depending on variant.
   JVM_FEATURES_server="compiler1 compiler2 $NON_MINIMAL_FEATURES $JVM_FEATURES $JVM_FEATURES_jvmci $JVM_FEATURES_aot $JVM_FEATURES_graal"
   JVM_FEATURES_client="compiler1 $NON_MINIMAL_FEATURES $JVM_FEATURES $JVM_FEATURES_jvmci"
   JVM_FEATURES_core="$NON_MINIMAL_FEATURES $JVM_FEATURES"
--- a/make/autoconf/libraries.m4	Tue May 15 11:28:29 2018 -0700
+++ b/make/autoconf/libraries.m4	Tue May 15 20:24:34 2018 +0200
@@ -130,7 +130,7 @@
 
   if test "x$OPENJDK_TARGET_OS" = xsolaris; then
     BASIC_JVM_LIBS="$BASIC_JVM_LIBS -lsocket -lsched -ldoor -ldemangle -lnsl \
-        -lrt"
+        -lrt -lkstat"
     BASIC_JVM_LIBS="$BASIC_JVM_LIBS $LIBCXX_JVM"
   fi
 
--- a/make/common/Modules.gmk	Tue May 15 11:28:29 2018 -0700
+++ b/make/common/Modules.gmk	Tue May 15 20:24:34 2018 +0200
@@ -59,7 +59,9 @@
     java.security.sasl \
     java.xml \
     jdk.internal.vm.ci \
+    jdk.jfr \
     jdk.management \
+    jdk.management.jfr \
     jdk.management.agent \
     jdk.net \
     jdk.sctp \
@@ -152,6 +154,7 @@
     jdk.jdeps \
     jdk.jdi \
     jdk.jdwp.agent \
+    jdk.jfr \
     jdk.jlink \
     jdk.jsobject \
     jdk.jshell \
@@ -159,6 +162,7 @@
     jdk.localedata \
     jdk.management \
     jdk.management.agent \
+    jdk.management.jfr \
     jdk.naming.dns \
     jdk.naming.rmi \
     jdk.net \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/copy/Copy-jdk.jfr.gmk	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,46 @@
+#
+# Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+include CopyCommon.gmk
+
+################################################################################
+
+$(eval $(call SetupCopyFiles, COPY_JFR_METADATA, \
+    SRC := $(TOPDIR)/src/hotspot/share/jfr/metadata, \
+    DEST := $(JDK_OUTPUTDIR)/modules/jdk.jfr/jdk/jfr/internal/types, \
+    FILES := metadata.xml \
+))
+
+TARGETS += $(COPY_JFR_METADATA)
+
+JFR_CONF_DIR := $(TOPDIR)/src/jdk.jfr/share/conf/jfr
+$(eval $(call SetupCopyFiles, COPY_JFR_CONF, \
+    DEST := $(LIB_DST_DIR)/jfr, \
+    FILES := $(wildcard $(JFR_CONF_DIR)/*.jfc), \
+    FLATTEN := true, \
+))
+TARGETS += $(COPY_JFR_CONF)
+
+################################################################################
--- a/make/hotspot/gensrc/GenerateSources.gmk	Tue May 15 11:28:29 2018 -0700
+++ b/make/hotspot/gensrc/GenerateSources.gmk	Tue May 15 20:24:34 2018 +0200
@@ -38,6 +38,7 @@
 include gensrc/GensrcAdlc.gmk
 include gensrc/GensrcDtrace.gmk
 include gensrc/GensrcJvmti.gmk
+include gensrc/GensrcJfr.gmk
 
 $(eval $(call IncludeCustomExtension, hotspot/gensrc/GenerateSources.gmk))
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/hotspot/gensrc/GensrcJfr.gmk	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,94 @@
+#
+# Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+$(eval $(call IncludeCustomExtension, hotspot/gensrc/GensrcJfr.gmk))
+
+################################################################################
+# Build tools needed for the Jfr source code generation
+
+JFR_TOOLS_SRCDIR := $(TOPDIR)/src/hotspot/share/jfr/metadata
+JFR_TOOLS_OUTPUTDIR := $(JVM_VARIANT_OUTPUTDIR)/tools/jfr
+
+$(eval $(call SetupJavaCompiler, GENERATE_JFRBYTECODE, \
+    JAVAC := $(JAVAC), \
+    FLAGS := $(DISABLE_WARNINGS), \
+    SERVER_DIR := $(SJAVAC_SERVER_DIR), \
+    SERVER_JVM := $(SJAVAC_SERVER_JAVA), \
+    DISABLE_SJAVAC := true, \
+))
+
+$(eval $(call SetupJavaCompilation, BUILD_JFR_TOOLS, \
+    SETUP := GENERATE_JFRBYTECODE, \
+    SRC := $(JFR_TOOLS_SRCDIR), \
+    INCLUDE_FILES := GenerateJfrFiles.java, \
+    BIN := $(JFR_TOOLS_OUTPUTDIR), \
+))
+
+TOOL_JFR_GEN := $(JAVA_SMALL) -cp $(JFR_TOOLS_OUTPUTDIR) GenerateJfrFiles
+
+################################################################################
+# Setup make rules for Jfr file file generation.
+#
+# Parameter 1 is the name of the rule. This name is used as variable prefix,
+# and the targets generated are listed in a variable by that name. This name is
+# also used as the name of the output file.
+#
+# Remaining parameters are named arguments. These include:
+#   XML_FILE -- The input source file to use
+#   XSD_FILE -- The input schema for validation
+#   OUTPUT_DIR -- The directory to put the generated file in
+SetupJfrGeneration = $(NamedParamsMacroTemplate)
+define SetupJfrGenerationBody
+  $$($1_OUTPUT_DIR)/$1: $$($1_XML_FILE) $$($1_XSD_FILE) $$(BUILD_JFR_TOOLS)
+	$$(call LogInfo, Generating $$(@F))
+	$$(call MakeDir, $$(@D))
+	$$(call ExecuteWithLog, $$@, $$(TOOL_JFR_GEN) $$($1_XML_FILE) $$($1_XSD_FILE) $$($1_OUTPUT_DIR))
+	test -f $$@
+
+  TARGETS += $$($1_OUTPUT_DIR)/$1
+
+endef
+
+################################################################################
+# Create files in gensrc/jfrfiles
+
+JFR_OUTPUTDIR := $(JVM_VARIANT_OUTPUTDIR)/gensrc/jfrfiles
+JFR_SRCDIR := $(TOPDIR)/src/hotspot/share/jfr/metadata
+
+METADATA_XML ?= $(JFR_SRCDIR)/metadata.xml
+METADATA_XSD ?= $(JFR_SRCDIR)/metadata.xsd
+
+# Changing these will trigger a rebuild of generated jfr files.
+JFR_DEPS += \
+    $(METADATA_XML) \
+    $(METADATA_XSD) \
+    #
+
+# our generator will generate all files in one go, so only need to setup one target rule
+$(eval $(call SetupJfrGeneration, jfrEventClasses.hpp, \
+    XML_FILE := $(METADATA_XML), \
+    XSD_FILE := $(METADATA_XSD), \
+    OUTPUT_DIR := $(JFR_OUTPUTDIR), \
+))
\ No newline at end of file
--- a/make/hotspot/gensrc/GensrcJvmti.gmk	Tue May 15 11:28:29 2018 -0700
+++ b/make/hotspot/gensrc/GensrcJvmti.gmk	Tue May 15 20:24:34 2018 +0200
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -50,7 +50,7 @@
 TOOL_JVMTI_ENV_FILL := $(JAVA_SMALL) -cp $(JVMTI_TOOLS_OUTPUTDIR) jvmtiEnvFill
 
 ################################################################################
-# Setup make rules for an xml transform for jvmti/trace file generation.
+# Setup make rules for an xml transform for jvmti file generation.
 #
 # Parameter 1 is the name of the rule. This name is used as variable prefix,
 # and the targets generated are listed in a variable by that name. This name is
@@ -126,48 +126,3 @@
 
   TARGETS += $(COPY_JVMTI_H)
 endif
-
-################################################################################
-# Create trace files in gensrc/tracefiles
-
-TRACE_OUTPUTDIR := $(JVM_VARIANT_OUTPUTDIR)/gensrc/tracefiles
-TRACE_SRCDIR := $(TOPDIR)/src/hotspot/share/trace
-
-# Append list of XSL files to search (might have been set by custom extensions)
-TRACE_XSL_FILES += $(wildcard $(TRACE_SRCDIR)/*.xsl)
-
-TRACE_XML ?= $(TRACE_SRCDIR)/trace.xml
-
-# Changing these will trigger a rebuild of generated trace files.
-TRACE_DEPS += \
-    $(TRACE_XML) \
-    $(TRACE_SRCDIR)/tracetypes.xml \
-    $(TRACE_SRCDIR)/tracerelationdecls.xml \
-    $(TRACE_SRCDIR)/traceevents.xml \
-    $(TRACE_SRCDIR)/trace.dtd \
-    $(TRACE_SRCDIR)/xinclude.mod \
-    #
-
-# Setup rule for generating a trace file
-#
-# $1 is generated source file name in $(TRACE_OUTPUTDIR)
-define SetupTraceGeneration
-  $$(eval $$(call SetupXslTransform, $1, \
-      XML_FILE := $$(TRACE_XML), \
-      XSL_FILE := $$(firstword $$(filter %/$$(basename $1).xsl, $$(TRACE_XSL_FILES))), \
-      OUTPUT_DIR := $$(TRACE_OUTPUTDIR), \
-      DEPS := $$(TRACE_DEPS), \
-  ))
-endef
-
-# Append files to generated (might have been set by custom extensions)
-TRACE_GENSRC_FILES += \
-    traceEventClasses.hpp \
-    traceEventIds.hpp \
-    traceTypes.hpp \
-    #
-
-# Call SetupTraceGeneration for all trace gensrc files
-$(foreach tracefile, $(TRACE_GENSRC_FILES), \
-  $(eval $(call SetupTraceGeneration, $(tracefile))) \
-)
--- a/make/hotspot/lib/JvmFeatures.gmk	Tue May 15 11:28:29 2018 -0700
+++ b/make/hotspot/lib/JvmFeatures.gmk	Tue May 15 20:24:34 2018 +0200
@@ -154,6 +154,12 @@
   # If serial is disabled, we cannot use serial as OldGC in parallel
   JVM_EXCLUDE_FILES += psMarkSweep.cpp psMarkSweepDecorator.cpp
 endif
+
+ifneq ($(call check-jvm-feature, jfr), true)
+  JVM_CFLAGS_FEATURES += -DINCLUDE_JFR=0
+  JVM_EXCLUDE_PATTERNS += jfr
+endif
+
 ################################################################################
 
 ifeq ($(call check-jvm-feature, link-time-opt), true)
--- a/make/hotspot/src/classes/build/tools/projectcreator/BuildConfig.java	Tue May 15 11:28:29 2018 -0700
+++ b/make/hotspot/src/classes/build/tools/projectcreator/BuildConfig.java	Tue May 15 20:24:34 2018 +0200
@@ -223,7 +223,7 @@
         sysDefines.add("_WINDOWS");
         sysDefines.add("HOTSPOT_BUILD_USER=\\\""+System.getProperty("user.name")+"\\\"");
         sysDefines.add("HOTSPOT_BUILD_TARGET=\\\""+get("Build")+"\\\"");
-        sysDefines.add("INCLUDE_TRACE=1");
+        sysDefines.add("INCLUDE_JFR=1");
         sysDefines.add("_JNI_IMPLEMENTATION_");
         if (vars.get("PlatformName").equals("Win32")) {
             sysDefines.add("HOTSPOT_LIB_ARCH=\\\"i386\\\"");
--- a/make/jprt.properties	Tue May 15 11:28:29 2018 -0700
+++ b/make/jprt.properties	Tue May 15 20:24:34 2018 +0200
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -273,6 +273,7 @@
     ${my.test.target.set:TESTNAME=jdk_instrument},			\
     ${my.test.target.set:TESTNAME=jdk_jmx},				\
     ${my.test.target.set:TESTNAME=jdk_jdi},				\
+    ${my.test.target.set:TESTNAME=jdk_jfr},                             \
     ${my.test.target.set:TESTNAME=svc_tools},                           \
     ${my.make.rule.test.targets.svc.extra}
 
--- a/make/nashorn/project.properties	Tue May 15 11:28:29 2018 -0700
+++ b/make/nashorn/project.properties	Tue May 15 20:24:34 2018 +0200
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -98,8 +98,8 @@
 dist.nashornapi.javadoc.dir=${dist.javadoc.dir}/nashornapi
 dist.dynalinkapi.javadoc.dir=${dist.javadoc.dir}/dynalinkapi
 
-# configuration for java flight recorder
-run.test.jvmargs.jfr=-XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:FlightRecorderOptions=defaultrecording=true,disk=true,dumponexit=true,dumponexitpath=${build.dir},stackdepth=128
+# configuration for flight recorder
+run.test.jvmargs.jfr=XX:StartFlightRecording=disk=true,dumponexit=true,dumponexitpath=${build.dir},stackdepth=128
 
 # test library location
 test.lib=test/nashorn/lib
@@ -354,7 +354,7 @@
 # uncomment this jfr.args to enable light recordings. the stack needs to be cranked up to 1024 frames,
 # or everything will as of the now drown in lambda forms and be cut off.
 #
-#jfr.args=-XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:FlightRecorderOptions=defaultrecording=true,disk=true,dumponexit=true,dumponexitpath="test_suite.jfr",stackdepth=1024 \
+#jfr.args=-XX:StartFlightRecording=disk=true,dumponexit=true,dumponexitpath="test_suite.jfr",stackdepth=1024
 
 jfr.args=
 
--- a/make/nb_native/nbproject/configurations.xml	Tue May 15 11:28:29 2018 -0700
+++ b/make/nb_native/nbproject/configurations.xml	Tue May 15 20:24:34 2018 +0200
@@ -2891,7 +2891,6 @@
               <in>stringUtils.hpp</in>
               <in>ticks.cpp</in>
               <in>ticks.hpp</in>
-              <in>ticks.inline.hpp</in>
               <in>utf8.cpp</in>
               <in>utf8.hpp</in>
               <in>vmError.cpp</in>
@@ -6887,7 +6886,7 @@
             <pElem>../../hotspot/src/share/vm/ci</pElem>
             <pElem>../../hotspot/src/share/vm/oops</pElem>
             <pElem>../../hotspot/src/share/vm/trace</pElem>
-            <pElem>../../build/macosx-x86_64-normal-server-release/hotspot/variant-server/gensrc/tracefiles</pElem>
+            <pElem>../../build/macosx-x86_64-normal-server-release/hotspot/variant-server/gensrc/jfrfiles</pElem>
             <pElem>../../hotspot/src/share/vm/gc/parallel</pElem>
             <pElem>../../hotspot/src/share/vm/gc/shared</pElem>
             <pElem>../../hotspot/src/share/vm/classfile</pElem>
@@ -15408,11 +15407,6 @@
             tool="3"
             flavor2="0">
       </item>
-      <item path="../../src/hotspot/share/utilities/ticks.inline.hpp"
-            ex="false"
-            tool="3"
-            flavor2="0">
-      </item>
       <item path="../../src/hotspot/share/utilities/utf8.cpp"
             ex="false"
             tool="1"
@@ -29190,11 +29184,6 @@
             tool="3"
             flavor2="0">
       </item>
-      <item path="../../src/hotspot/share/utilities/ticks.inline.hpp"
-            ex="false"
-            tool="3"
-            flavor2="0">
-      </item>
       <item path="../../src/hotspot/share/utilities/utf8.cpp"
             ex="false"
             tool="1"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/cpu/aarch64/vm_version_ext_aarch64.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "memory/allocation.hpp"
+#include "memory/allocation.inline.hpp"
+#include "runtime/os.inline.hpp"
+#include "vm_version_ext_aarch64.hpp"
+
+// VM_Version_Ext statics
+int VM_Version_Ext::_no_of_threads = 0;
+int VM_Version_Ext::_no_of_cores = 0;
+int VM_Version_Ext::_no_of_sockets = 0;
+bool VM_Version_Ext::_initialized = false;
+char VM_Version_Ext::_cpu_name[CPU_TYPE_DESC_BUF_SIZE] = {0};
+char VM_Version_Ext::_cpu_desc[CPU_DETAILED_DESC_BUF_SIZE] = {0};
+
+void VM_Version_Ext::initialize_cpu_information(void) {
+  // do nothing if cpu info has been initialized
+  if (_initialized) {
+    return;
+  }
+
+  int core_id = -1;
+  int chip_id = -1;
+  int len = 0;
+  char* src_string = NULL;
+
+  _no_of_cores  = os::processor_count();
+  _no_of_threads = _no_of_cores;
+  _no_of_sockets = _no_of_cores;
+  snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "AArch64");
+  snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "%s", _features_string);
+  _initialized = true;
+}
+
+int VM_Version_Ext::number_of_threads(void) {
+  initialize_cpu_information();
+  return _no_of_threads;
+}
+
+int VM_Version_Ext::number_of_cores(void) {
+  initialize_cpu_information();
+  return _no_of_cores;
+}
+
+int VM_Version_Ext::number_of_sockets(void) {
+  initialize_cpu_information();
+  return _no_of_sockets;
+}
+
+const char* VM_Version_Ext::cpu_name(void) {
+  initialize_cpu_information();
+  char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_TYPE_DESC_BUF_SIZE, mtTracing);
+  if (NULL == tmp) {
+    return NULL;
+  }
+  strncpy(tmp, _cpu_name, CPU_TYPE_DESC_BUF_SIZE);
+  return tmp;
+}
+
+const char* VM_Version_Ext::cpu_description(void) {
+  initialize_cpu_information();
+  char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_DETAILED_DESC_BUF_SIZE, mtTracing);
+  if (NULL == tmp) {
+    return NULL;
+  }
+  strncpy(tmp, _cpu_desc, CPU_DETAILED_DESC_BUF_SIZE);
+  return tmp;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/cpu/aarch64/vm_version_ext_aarch64.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_AARCH64_VM_VM_VERSION_EXT_AARCH64_HPP
+#define CPU_AARCH64_VM_VM_VERSION_EXT_AARCH64_HPP
+
+#include "utilities/macros.hpp"
+#include "vm_version_aarch64.hpp"
+
+class VM_Version_Ext : public VM_Version {
+ private:
+  static const size_t      CPU_TYPE_DESC_BUF_SIZE = 256;
+  static const size_t      CPU_DETAILED_DESC_BUF_SIZE = 4096;
+
+  static int               _no_of_threads;
+  static int               _no_of_cores;
+  static int               _no_of_sockets;
+  static bool              _initialized;
+  static char              _cpu_name[CPU_TYPE_DESC_BUF_SIZE];
+  static char              _cpu_desc[CPU_DETAILED_DESC_BUF_SIZE];
+
+ public:
+  static int number_of_threads(void);
+  static int number_of_cores(void);
+  static int number_of_sockets(void);
+
+  static const char* cpu_name(void);
+  static const char* cpu_description(void);
+  static void initialize_cpu_information(void);
+
+};
+
+#endif // CPU_AARCH64_VM_VM_VERSION_EXT_AARCH64_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/cpu/arm/vm_version_ext_arm.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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 "memory/allocation.hpp"
+#include "memory/allocation.inline.hpp"
+#include "runtime/os.inline.hpp"
+#include "vm_version_ext_arm.hpp"
+
+// VM_Version_Ext statics
+int VM_Version_Ext::_no_of_threads = 0;
+int VM_Version_Ext::_no_of_cores = 0;
+int VM_Version_Ext::_no_of_sockets = 0;
+bool VM_Version_Ext::_initialized = false;
+char VM_Version_Ext::_cpu_name[CPU_TYPE_DESC_BUF_SIZE] = {0};
+char VM_Version_Ext::_cpu_desc[CPU_DETAILED_DESC_BUF_SIZE] = {0};
+
+void VM_Version_Ext::initialize_cpu_information(void) {
+  // do nothing if cpu info has been initialized
+  if (_initialized) {
+    return;
+  }
+
+  int core_id = -1;
+  int chip_id = -1;
+  int len = 0;
+  char* src_string = NULL;
+
+  _no_of_cores  = os::processor_count();
+  _no_of_threads = _no_of_cores;
+  _no_of_sockets = _no_of_cores;
+#ifdef AARCH64
+  snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "AArch64");
+#else
+  snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "ARM%d", _arm_arch);
+#endif
+  snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "%s", _features_string);
+  _initialized = true;
+}
+
+int VM_Version_Ext::number_of_threads(void) {
+  initialize_cpu_information();
+  return _no_of_threads;
+}
+
+int VM_Version_Ext::number_of_cores(void) {
+  initialize_cpu_information();
+  return _no_of_cores;
+}
+
+int VM_Version_Ext::number_of_sockets(void) {
+  initialize_cpu_information();
+  return _no_of_sockets;
+}
+
+const char* VM_Version_Ext::cpu_name(void) {
+  initialize_cpu_information();
+  char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_TYPE_DESC_BUF_SIZE, mtTracing);
+  if (NULL == tmp) {
+    return NULL;
+  }
+  strncpy(tmp, _cpu_name, CPU_TYPE_DESC_BUF_SIZE);
+  return tmp;
+}
+
+const char* VM_Version_Ext::cpu_description(void) {
+  initialize_cpu_information();
+  char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_DETAILED_DESC_BUF_SIZE, mtTracing);
+  if (NULL == tmp) {
+    return NULL;
+  }
+  strncpy(tmp, _cpu_desc, CPU_DETAILED_DESC_BUF_SIZE);
+  return tmp;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/cpu/arm/vm_version_ext_arm.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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 CPU_ARM_VM_VM_VERSION_EXT_ARM_HPP
+#define CPU_ARM_VM_VM_VERSION_EXT_ARM_HPP
+
+#include "utilities/macros.hpp"
+#include "vm_version_arm.hpp"
+
+class VM_Version_Ext : public VM_Version {
+ private:
+  static const size_t      CPU_TYPE_DESC_BUF_SIZE = 256;
+  static const size_t      CPU_DETAILED_DESC_BUF_SIZE = 4096;
+
+  static int               _no_of_threads;
+  static int               _no_of_cores;
+  static int               _no_of_sockets;
+  static bool              _initialized;
+  static char              _cpu_name[CPU_TYPE_DESC_BUF_SIZE];
+  static char              _cpu_desc[CPU_DETAILED_DESC_BUF_SIZE];
+
+ public:
+  static int number_of_threads(void);
+  static int number_of_cores(void);
+  static int number_of_sockets(void);
+
+  static const char* cpu_name(void);
+  static const char* cpu_description(void);
+  static void initialize_cpu_information(void);
+
+};
+
+#endif // CPU_ARM_VM_VM_VERSION_EXT_ARM_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/cpu/sparc/vm_version_ext_sparc.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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 "jvm.h"
+#include "memory/allocation.hpp"
+#include "memory/allocation.inline.hpp"
+#include "vm_version_ext_sparc.hpp"
+
+// VM_Version_Ext statics
+int   VM_Version_Ext::_no_of_threads = 0;
+int   VM_Version_Ext::_no_of_cores = 0;
+int   VM_Version_Ext::_no_of_sockets = 0;
+kid_t VM_Version_Ext::_kcid = -1;
+char  VM_Version_Ext::_cpu_name[CPU_TYPE_DESC_BUF_SIZE] = {0};
+char  VM_Version_Ext::_cpu_desc[CPU_DETAILED_DESC_BUF_SIZE] = {0};
+
+// get cpu information. It takes into account if the kstat chain id
+// has been changed and update the info if necessary.
+bool VM_Version_Ext::initialize_cpu_information(void) {
+
+  int core_id = -1;
+  int chip_id = -1;
+  int len = 0;
+  char* src_string = NULL;
+  kstat_ctl_t* kc = kstat_open();
+  if (!kc) {
+    return false;
+  }
+
+  // check if kstat chain has been updated
+  kid_t kcid = kstat_chain_update(kc);
+  if (kcid == -1) {
+    kstat_close(kc);
+    return false;
+  }
+
+  bool updated = ((kcid > 0) && (kcid != _kcid)) ||
+                 ((kcid == 0) && (_kcid == -1));
+  if (!updated) {
+    kstat_close(kc);
+    return true;
+  }
+
+  // update the cached _kcid
+  _kcid = kcid;
+
+  // find the number of online processors
+  // for modern processsors, it is also known as the
+  // hardware threads.
+  _no_of_threads  = sysconf(_SC_NPROCESSORS_ONLN);
+
+  if (_no_of_threads <= 0 ) {
+    kstat_close(kc);
+    return false;
+  }
+
+  _no_of_cores = 0;
+  _no_of_sockets = 0;
+
+  // loop through the kstat chain
+  kstat_t* ksp = NULL;
+  for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
+    // only interested in "cpu_info"
+    if (strcmp(ksp->ks_module, (char*)CPU_INFO) == 0) {
+      if (kstat_read(kc, ksp, NULL) == -1) {
+        kstat_close(kc);
+        return false;
+      }
+      if (ksp->ks_data != NULL) {
+        kstat_named_t* knm = (kstat_named_t *)ksp->ks_data;
+        // loop through the number of fields in each record
+        for (int i = 0; i < ksp->ks_ndata; i++) {
+          // set cpu type if it hasn't been already set
+          if ((strcmp((const char*)&(knm[i].name), CPU_TYPE) == 0) &&
+                     (_cpu_name[0] == '\0')) {
+            if (knm[i].data_type == KSTAT_DATA_STRING) {
+              src_string = (char*)KSTAT_NAMED_STR_PTR(&knm[i]);
+            } else {
+              src_string = (char*)&(knm[i].value.c[0]);
+            }
+            len = strlen(src_string);
+            if (len < CPU_TYPE_DESC_BUF_SIZE) {
+              jio_snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE,
+                                         "%s", src_string);
+            }
+          }
+
+          // set cpu description if it hasn't been already set
+          if ((strcmp((const char*)&(knm[i].name), CPU_DESCRIPTION) == 0) &&
+                      (_cpu_desc[0] == '\0')) {
+            if (knm[i].data_type == KSTAT_DATA_STRING) {
+              src_string = (char*)KSTAT_NAMED_STR_PTR(&knm[i]);
+            } else {
+              src_string = (char*)&(knm[i].value.c[0]);
+            }
+            len = strlen(src_string);
+            if (len < CPU_DETAILED_DESC_BUF_SIZE) {
+              jio_snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE,
+                                         "%s", src_string);
+            }
+          }
+
+          // count the number of sockets based on the chip id
+          if (strcmp((const char*)&(knm[i].name), CHIP_ID) == 0) {
+            if (chip_id != knm[i].value.l) {
+              chip_id = knm[i].value.l;
+              _no_of_sockets++;
+            }
+          }
+
+          // count the number of cores based on the core id
+          if (strcmp((const char*)&(knm[i].name), CORE_ID) == 0) {
+            if (core_id != knm[i].value.l) {
+              core_id = knm[i].value.l;
+              _no_of_cores++;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  kstat_close(kc);
+  return true;
+}
+
+int VM_Version_Ext::number_of_threads(void) {
+  initialize_cpu_information();
+  return _no_of_threads;
+}
+
+int VM_Version_Ext::number_of_cores(void) {
+  initialize_cpu_information();
+  return _no_of_cores;
+}
+
+int VM_Version_Ext::number_of_sockets(void) {
+  initialize_cpu_information();
+  return _no_of_sockets;
+}
+
+const char* VM_Version_Ext::cpu_name(void) {
+  if (!initialize_cpu_information()) {
+    return NULL;
+  }
+  char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_TYPE_DESC_BUF_SIZE, mtTracing);
+  if (NULL == tmp) {
+    return NULL;
+  }
+  strncpy(tmp, _cpu_name, CPU_TYPE_DESC_BUF_SIZE);
+  return tmp;
+}
+
+const char* VM_Version_Ext::cpu_description(void) {
+  if (!initialize_cpu_information()) {
+    return NULL;
+  }
+  char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_DETAILED_DESC_BUF_SIZE, mtTracing);
+  if (NULL == tmp) {
+    return NULL;
+  }
+  strncpy(tmp, _cpu_desc, CPU_DETAILED_DESC_BUF_SIZE);
+  return tmp;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/cpu/sparc/vm_version_ext_sparc.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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 CPU_SPARC_VM_VM_VERSION_EXT_SPARC_HPP
+#define CPU_SPARC_VM_VM_VERSION_EXT_SPARC_HPP
+
+#include "utilities/macros.hpp"
+#include "vm_version_sparc.hpp"
+#include <kstat.h>
+#include <sys/processor.h>
+
+#define CPU_INFO        "cpu_info"
+#define CPU_TYPE        "fpu_type"
+#define CPU_DESCRIPTION "implementation"
+#define CHIP_ID         "chip_id"
+#define CORE_ID         "core_id"
+
+class VM_Version_Ext : public VM_Version {
+ private:
+
+  static const size_t      CPU_TYPE_DESC_BUF_SIZE = 256;
+  static const size_t      CPU_DETAILED_DESC_BUF_SIZE = 4096;
+
+  static int               _no_of_threads;
+  static int               _no_of_cores;
+  static int               _no_of_sockets;
+  static kid_t             _kcid;
+  static char              _cpu_name[CPU_TYPE_DESC_BUF_SIZE];
+  static char              _cpu_desc[CPU_DETAILED_DESC_BUF_SIZE];
+
+  static bool initialize_cpu_information(void);
+
+ public:
+
+  static int number_of_threads(void);
+  static int number_of_cores(void);
+  static int number_of_sockets(void);
+
+  static const char* cpu_name(void);
+  static const char* cpu_description(void);
+};
+
+#endif // CPU_SPARC_VM_VM_VERSION_EXT_SPARC_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/cpu/x86/rdtsc_x86.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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 "rdtsc_x86.hpp"
+#include "runtime/thread.inline.hpp"
+#include "vm_version_ext_x86.hpp"
+
+// The following header contains the implementations of rdtsc()
+#include OS_CPU_HEADER_INLINE(os)
+
+static jlong _epoch = 0;
+static bool rdtsc_elapsed_counter_enabled = false;
+static jlong tsc_frequency = 0;
+
+static jlong set_epoch() {
+  assert(0 == _epoch, "invariant");
+  _epoch = os::rdtsc();
+  return _epoch;
+}
+
+// Base loop to estimate ticks frequency for tsc counter from user mode.
+// Volatiles and sleep() are used to prevent compiler from applying optimizations.
+static void do_time_measurements(volatile jlong& time_base,
+                                 volatile jlong& time_fast,
+                                 volatile jlong& time_base_elapsed,
+                                 volatile jlong& time_fast_elapsed) {
+  static const unsigned int FT_SLEEP_MILLISECS = 1;
+  const unsigned int loopcount = 3;
+
+  volatile jlong start = 0;
+  volatile jlong fstart = 0;
+  volatile jlong end = 0;
+  volatile jlong fend = 0;
+
+  // Figure out the difference between rdtsc and os provided timer.
+  // base algorithm adopted from JRockit.
+  for (unsigned int times = 0; times < loopcount; times++) {
+    start = os::elapsed_counter();
+    OrderAccess::fence();
+    fstart = os::rdtsc();
+
+    // use sleep to prevent compiler from optimizing
+    os::sleep(Thread::current(), FT_SLEEP_MILLISECS, true);
+
+    end = os::elapsed_counter();
+    OrderAccess::fence();
+    fend = os::rdtsc();
+
+    time_base += end - start;
+    time_fast += fend - fstart;
+
+    // basis for calculating the os tick start
+    // to fast time tick start offset
+    time_base_elapsed += end;
+    time_fast_elapsed += (fend - _epoch);
+  }
+
+  time_base /= loopcount;
+  time_fast /= loopcount;
+  time_base_elapsed /= loopcount;
+  time_fast_elapsed /= loopcount;
+}
+
+static jlong initialize_frequency() {
+  assert(0 == tsc_frequency, "invariant");
+  assert(0 == _epoch, "invariant");
+  const jlong initial_counter = set_epoch();
+  if (initial_counter == 0) {
+    return 0;
+  }
+  // os time frequency
+  static double os_freq = (double)os::elapsed_frequency();
+  assert(os_freq > 0, "os_elapsed frequency corruption!");
+
+  double tsc_freq = .0;
+  double os_to_tsc_conv_factor = 1.0;
+
+  // if platform supports invariant tsc,
+  // apply higher resolution and granularity for conversion calculations
+  if (VM_Version_Ext::supports_tscinv_ext()) {
+    // for invariant tsc platforms, take the maximum qualified cpu frequency
+    tsc_freq = (double)VM_Version_Ext::maximum_qualified_cpu_frequency();
+    os_to_tsc_conv_factor = tsc_freq / os_freq;
+  } else {
+    // use measurements to estimate
+    // a conversion factor and the tsc frequency
+
+    volatile jlong time_base = 0;
+    volatile jlong time_fast = 0;
+    volatile jlong time_base_elapsed = 0;
+    volatile jlong time_fast_elapsed = 0;
+
+    // do measurements to get base data
+    // on os timer and fast ticks tsc time relation.
+    do_time_measurements(time_base, time_fast, time_base_elapsed, time_fast_elapsed);
+
+    // if invalid measurements, cannot proceed
+    if (time_fast == 0 || time_base == 0) {
+      return 0;
+    }
+
+    os_to_tsc_conv_factor = (double)time_fast / (double)time_base;
+    if (os_to_tsc_conv_factor > 1) {
+      // estimate on tsc counter frequency
+      tsc_freq = os_to_tsc_conv_factor * os_freq;
+    }
+  }
+
+  if ((tsc_freq < 0) || (tsc_freq > 0 && tsc_freq <= os_freq) || (os_to_tsc_conv_factor <= 1)) {
+    // safer to run with normal os time
+    tsc_freq = .0;
+  }
+
+  // frequency of the tsc_counter
+  return (jlong)tsc_freq;
+}
+
+static bool initialize_elapsed_counter() {
+  tsc_frequency = initialize_frequency();
+  return tsc_frequency != 0 && _epoch != 0;
+}
+
+static bool ergonomics() {
+  const bool invtsc_support = Rdtsc::is_supported();
+  if (FLAG_IS_DEFAULT(UseFastUnorderedTimeStamps) && invtsc_support) {
+    FLAG_SET_ERGO(bool, UseFastUnorderedTimeStamps, true);
+  }
+
+  bool ft_enabled = UseFastUnorderedTimeStamps && invtsc_support;
+
+  if (!ft_enabled) {
+    if (UseFastUnorderedTimeStamps && VM_Version::supports_tsc()) {
+      warning("\nThe hardware does not support invariant tsc (INVTSC) register and/or cannot guarantee tsc synchronization between sockets at startup.\n"\
+        "Values returned via rdtsc() are not guaranteed to be accurate, esp. when comparing values from cross sockets reads. Enabling UseFastUnorderedTimeStamps on non-invariant tsc hardware should be considered experimental.\n");
+      ft_enabled = true;
+    }
+  }
+
+  if (!ft_enabled) {
+    // Warn if unable to support command-line flag
+    if (UseFastUnorderedTimeStamps && !VM_Version::supports_tsc()) {
+      warning("Ignoring UseFastUnorderedTimeStamps, hardware does not support normal tsc");
+    }
+  }
+
+  return ft_enabled;
+}
+
+bool Rdtsc::is_supported() {
+  return VM_Version_Ext::supports_tscinv_ext();
+}
+
+bool Rdtsc::is_elapsed_counter_enabled() {
+  return rdtsc_elapsed_counter_enabled;
+}
+
+jlong Rdtsc::frequency() {
+  return tsc_frequency;
+}
+
+jlong Rdtsc::elapsed_counter() {
+  return os::rdtsc() - _epoch;
+}
+
+jlong Rdtsc::epoch() {
+  return _epoch;
+}
+
+jlong Rdtsc::raw() {
+  return os::rdtsc();
+}
+
+bool Rdtsc::initialize() {
+  static bool initialized = false;
+  if (!initialized) {
+    assert(!rdtsc_elapsed_counter_enabled, "invariant");
+    VM_Version_Ext::initialize();
+    assert(0 == tsc_frequency, "invariant");
+    assert(0 == _epoch, "invariant");
+    bool result = initialize_elapsed_counter(); // init hw
+    if (result) {
+      result = ergonomics(); // check logical state
+    }
+    rdtsc_elapsed_counter_enabled = result;
+    initialized = true;
+  }
+  return rdtsc_elapsed_counter_enabled;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/cpu/x86/rdtsc_x86.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_X86_VM_RDTSC_X86_HPP
+#define CPU_X86_VM_RDTSC_X86_HPP
+
+#include "memory/allocation.hpp"
+#include "utilities/macros.hpp"
+
+// Interface to the x86 rdtsc() time counter, if available.
+// Not guaranteed to be synchronized across hardware threads and
+// therefore software threads, and can be updated asynchronously
+// by software. elapsed_counter() can jump backwards
+// as well as jump forward when threads query different cores/sockets.
+// Very much not recommended for general use.
+// INVTSC is a minimal requirement for auto-enablement.
+
+class Rdtsc : AllStatic {
+ public:
+  static jlong elapsed_counter(); // provides quick time stamps
+  static jlong frequency();       // tsc register
+  static bool  is_supported();    // InvariantTSC
+  static jlong raw();             // direct rdtsc() access
+  static bool  is_elapsed_counter_enabled(); // turn off with -XX:-UseFastUnorderedTimeStamps
+  static jlong epoch();
+  static bool  initialize();
+};
+
+#endif // CPU_X86_VM_RDTSC_X86_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/cpu/x86/vm_version_ext_x86.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,967 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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 "jvm.h"
+#include "utilities/macros.hpp"
+#include "asm/macroAssembler.hpp"
+#include "asm/macroAssembler.inline.hpp"
+#include "memory/allocation.inline.hpp"
+#include "memory/resourceArea.hpp"
+#include "runtime/java.hpp"
+#include "runtime/stubCodeGenerator.hpp"
+#include "vm_version_ext_x86.hpp"
+
+typedef enum {
+   CPU_FAMILY_8086_8088  = 0,
+   CPU_FAMILY_INTEL_286  = 2,
+   CPU_FAMILY_INTEL_386  = 3,
+   CPU_FAMILY_INTEL_486  = 4,
+   CPU_FAMILY_PENTIUM    = 5,
+   CPU_FAMILY_PENTIUMPRO = 6,    // Same family several models
+   CPU_FAMILY_PENTIUM_4  = 0xF
+} FamilyFlag;
+
+ typedef enum {
+    RDTSCP_FLAG  = 0x08000000, // bit 27
+    INTEL64_FLAG = 0x20000000  // bit 29
+  } _featureExtendedEdxFlag;
+
+#define CPUID_STANDARD_FN   0x0
+#define CPUID_STANDARD_FN_1 0x1
+#define CPUID_STANDARD_FN_4 0x4
+#define CPUID_STANDARD_FN_B 0xb
+
+#define CPUID_EXTENDED_FN   0x80000000
+#define CPUID_EXTENDED_FN_1 0x80000001
+#define CPUID_EXTENDED_FN_2 0x80000002
+#define CPUID_EXTENDED_FN_3 0x80000003
+#define CPUID_EXTENDED_FN_4 0x80000004
+#define CPUID_EXTENDED_FN_7 0x80000007
+#define CPUID_EXTENDED_FN_8 0x80000008
+
+typedef enum {
+   FPU_FLAG     = 0x00000001,
+   VME_FLAG     = 0x00000002,
+   DE_FLAG      = 0x00000004,
+   PSE_FLAG     = 0x00000008,
+   TSC_FLAG     = 0x00000010,
+   MSR_FLAG     = 0x00000020,
+   PAE_FLAG     = 0x00000040,
+   MCE_FLAG     = 0x00000080,
+   CX8_FLAG     = 0x00000100,
+   APIC_FLAG    = 0x00000200,
+   SEP_FLAG     = 0x00000800,
+   MTRR_FLAG    = 0x00001000,
+   PGE_FLAG     = 0x00002000,
+   MCA_FLAG     = 0x00004000,
+   CMOV_FLAG    = 0x00008000,
+   PAT_FLAG     = 0x00010000,
+   PSE36_FLAG   = 0x00020000,
+   PSNUM_FLAG   = 0x00040000,
+   CLFLUSH_FLAG = 0x00080000,
+   DTS_FLAG     = 0x00200000,
+   ACPI_FLAG    = 0x00400000,
+   MMX_FLAG     = 0x00800000,
+   FXSR_FLAG    = 0x01000000,
+   SSE_FLAG     = 0x02000000,
+   SSE2_FLAG    = 0x04000000,
+   SS_FLAG      = 0x08000000,
+   HTT_FLAG     = 0x10000000,
+   TM_FLAG      = 0x20000000
+} FeatureEdxFlag;
+
+static BufferBlob* cpuid_brand_string_stub_blob;
+static const int   cpuid_brand_string_stub_size = 550;
+
+extern "C" {
+  typedef void (*getCPUIDBrandString_stub_t)(void*);
+}
+
+static getCPUIDBrandString_stub_t getCPUIDBrandString_stub = NULL;
+
+class VM_Version_Ext_StubGenerator: public StubCodeGenerator {
+ public:
+
+  VM_Version_Ext_StubGenerator(CodeBuffer *c) : StubCodeGenerator(c) {}
+
+  address generate_getCPUIDBrandString(void) {
+    // Flags to test CPU type.
+    const uint32_t HS_EFL_AC           = 0x40000;
+    const uint32_t HS_EFL_ID           = 0x200000;
+    // Values for when we don't have a CPUID instruction.
+    const int      CPU_FAMILY_SHIFT = 8;
+    const uint32_t CPU_FAMILY_386   = (3 << CPU_FAMILY_SHIFT);
+    const uint32_t CPU_FAMILY_486   = (4 << CPU_FAMILY_SHIFT);
+
+    Label detect_486, cpu486, detect_586, done, ext_cpuid;
+
+    StubCodeMark mark(this, "VM_Version_Ext", "getCPUIDNameInfo_stub");
+#   define __ _masm->
+
+    address start = __ pc();
+
+    //
+    // void getCPUIDBrandString(VM_Version::CpuidInfo* cpuid_info);
+    //
+    // LP64: rcx and rdx are first and second argument registers on windows
+
+    __ push(rbp);
+#ifdef _LP64
+    __ mov(rbp, c_rarg0); // cpuid_info address
+#else
+    __ movptr(rbp, Address(rsp, 8)); // cpuid_info address
+#endif
+    __ push(rbx);
+    __ push(rsi);
+    __ pushf();          // preserve rbx, and flags
+    __ pop(rax);
+    __ push(rax);
+    __ mov(rcx, rax);
+    //
+    // if we are unable to change the AC flag, we have a 386
+    //
+    __ xorl(rax, HS_EFL_AC);
+    __ push(rax);
+    __ popf();
+    __ pushf();
+    __ pop(rax);
+    __ cmpptr(rax, rcx);
+    __ jccb(Assembler::notEqual, detect_486);
+
+    __ movl(rax, CPU_FAMILY_386);
+    __ jmp(done);
+
+    //
+    // If we are unable to change the ID flag, we have a 486 which does
+    // not support the "cpuid" instruction.
+    //
+    __ bind(detect_486);
+    __ mov(rax, rcx);
+    __ xorl(rax, HS_EFL_ID);
+    __ push(rax);
+    __ popf();
+    __ pushf();
+    __ pop(rax);
+    __ cmpptr(rcx, rax);
+    __ jccb(Assembler::notEqual, detect_586);
+
+    __ bind(cpu486);
+    __ movl(rax, CPU_FAMILY_486);
+    __ jmp(done);
+
+    //
+    // At this point, we have a chip which supports the "cpuid" instruction
+    //
+    __ bind(detect_586);
+    __ xorl(rax, rax);
+    __ cpuid();
+    __ orl(rax, rax);
+    __ jcc(Assembler::equal, cpu486);   // if cpuid doesn't support an input
+                                        // value of at least 1, we give up and
+                                        // assume a 486
+
+    //
+    // Extended cpuid(0x80000000) for processor brand string detection
+    //
+    __ bind(ext_cpuid);
+    __ movl(rax, CPUID_EXTENDED_FN);
+    __ cpuid();
+    __ cmpl(rax, CPUID_EXTENDED_FN_4);
+    __ jcc(Assembler::below, done);
+
+    //
+    // Extended cpuid(0x80000002)  // first 16 bytes in brand string
+    //
+    __ movl(rax, CPUID_EXTENDED_FN_2);
+    __ cpuid();
+    __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_0_offset())));
+    __ movl(Address(rsi, 0), rax);
+    __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_1_offset())));
+    __ movl(Address(rsi, 0), rbx);
+    __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_2_offset())));
+    __ movl(Address(rsi, 0), rcx);
+    __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_3_offset())));
+    __ movl(Address(rsi,0), rdx);
+
+    //
+    // Extended cpuid(0x80000003) // next 16 bytes in brand string
+    //
+    __ movl(rax, CPUID_EXTENDED_FN_3);
+    __ cpuid();
+    __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_4_offset())));
+    __ movl(Address(rsi, 0), rax);
+    __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_5_offset())));
+    __ movl(Address(rsi, 0), rbx);
+    __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_6_offset())));
+    __ movl(Address(rsi, 0), rcx);
+    __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_7_offset())));
+    __ movl(Address(rsi,0), rdx);
+
+    //
+    // Extended cpuid(0x80000004) // last 16 bytes in brand string
+    //
+    __ movl(rax, CPUID_EXTENDED_FN_4);
+    __ cpuid();
+    __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_8_offset())));
+    __ movl(Address(rsi, 0), rax);
+    __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_9_offset())));
+    __ movl(Address(rsi, 0), rbx);
+    __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_10_offset())));
+    __ movl(Address(rsi, 0), rcx);
+    __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_11_offset())));
+    __ movl(Address(rsi,0), rdx);
+
+    //
+    // return
+    //
+    __ bind(done);
+    __ popf();
+    __ pop(rsi);
+    __ pop(rbx);
+    __ pop(rbp);
+    __ ret(0);
+
+#   undef __
+
+    return start;
+  };
+};
+
+
+// VM_Version_Ext statics
+const size_t VM_Version_Ext::VENDOR_LENGTH = 13;
+const size_t VM_Version_Ext::CPU_EBS_MAX_LENGTH = (3 * 4 * 4 + 1);
+const size_t VM_Version_Ext::CPU_TYPE_DESC_BUF_SIZE = 256;
+const size_t VM_Version_Ext::CPU_DETAILED_DESC_BUF_SIZE = 4096;
+char* VM_Version_Ext::_cpu_brand_string = NULL;
+jlong VM_Version_Ext::_max_qualified_cpu_frequency = 0;
+
+int VM_Version_Ext::_no_of_threads = 0;
+int VM_Version_Ext::_no_of_cores = 0;
+int VM_Version_Ext::_no_of_packages = 0;
+
+void VM_Version_Ext::initialize(void) {
+  ResourceMark rm;
+
+  cpuid_brand_string_stub_blob = BufferBlob::create("getCPUIDBrandString_stub", cpuid_brand_string_stub_size);
+  if (cpuid_brand_string_stub_blob == NULL) {
+    vm_exit_during_initialization("Unable to allocate getCPUIDBrandString_stub");
+  }
+  CodeBuffer c(cpuid_brand_string_stub_blob);
+  VM_Version_Ext_StubGenerator g(&c);
+  getCPUIDBrandString_stub = CAST_TO_FN_PTR(getCPUIDBrandString_stub_t,
+                                   g.generate_getCPUIDBrandString());
+}
+
+const char* VM_Version_Ext::cpu_model_description(void) {
+  uint32_t cpu_family = extended_cpu_family();
+  uint32_t cpu_model = extended_cpu_model();
+  const char* model = NULL;
+
+  if (cpu_family == CPU_FAMILY_PENTIUMPRO) {
+    for (uint32_t i = 0; i <= cpu_model; i++) {
+      model = _model_id_pentium_pro[i];
+      if (model == NULL) {
+        break;
+      }
+    }
+  }
+  return model;
+}
+
+const char* VM_Version_Ext::cpu_brand_string(void) {
+  if (_cpu_brand_string == NULL) {
+    _cpu_brand_string = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_EBS_MAX_LENGTH, mtInternal);
+    if (NULL == _cpu_brand_string) {
+      return NULL;
+    }
+    int ret_val = cpu_extended_brand_string(_cpu_brand_string, CPU_EBS_MAX_LENGTH);
+    if (ret_val != OS_OK) {
+      FREE_C_HEAP_ARRAY(char, _cpu_brand_string);
+      _cpu_brand_string = NULL;
+    }
+  }
+  return _cpu_brand_string;
+}
+
+const char* VM_Version_Ext::cpu_brand(void) {
+  const char*  brand  = NULL;
+
+  if ((_cpuid_info.std_cpuid1_ebx.value & 0xFF) > 0) {
+    int brand_num = _cpuid_info.std_cpuid1_ebx.value & 0xFF;
+    brand = _brand_id[0];
+    for (int i = 0; brand != NULL && i <= brand_num; i += 1) {
+      brand = _brand_id[i];
+    }
+  }
+  return brand;
+}
+
+bool VM_Version_Ext::cpu_is_em64t(void) {
+  return ((_cpuid_info.ext_cpuid1_edx.value & INTEL64_FLAG) == INTEL64_FLAG);
+}
+
+bool VM_Version_Ext::is_netburst(void) {
+  return (is_intel() && (extended_cpu_family() == CPU_FAMILY_PENTIUM_4));
+}
+
+bool VM_Version_Ext::supports_tscinv_ext(void) {
+  if (!supports_tscinv_bit()) {
+    return false;
+  }
+
+  if (is_intel()) {
+    return true;
+  }
+
+  if (is_amd()) {
+    return !is_amd_Barcelona();
+  }
+
+  return false;
+}
+
+void VM_Version_Ext::resolve_cpu_information_details(void) {
+
+  // in future we want to base this information on proper cpu
+  // and cache topology enumeration such as:
+  // Intel 64 Architecture Processor Topology Enumeration
+  // which supports system cpu and cache topology enumeration
+  // either using 2xAPICIDs or initial APICIDs
+
+  // currently only rough cpu information estimates
+  // which will not necessarily reflect the exact configuration of the system
+
+  // this is the number of logical hardware threads
+  // visible to the operating system
+  _no_of_threads = os::processor_count();
+
+  // find out number of threads per cpu package
+  int threads_per_package = threads_per_core() * cores_per_cpu();
+
+  // use amount of threads visible to the process in order to guess number of sockets
+  _no_of_packages = _no_of_threads / threads_per_package;
+
+  // process might only see a subset of the total number of threads
+  // from a single processor package. Virtualization/resource management for example.
+  // If so then just write a hard 1 as num of pkgs.
+  if (0 == _no_of_packages) {
+    _no_of_packages = 1;
+  }
+
+  // estimate the number of cores
+  _no_of_cores = cores_per_cpu() * _no_of_packages;
+}
+
+int VM_Version_Ext::number_of_threads(void) {
+  if (_no_of_threads == 0) {
+   resolve_cpu_information_details();
+  }
+  return _no_of_threads;
+}
+
+int VM_Version_Ext::number_of_cores(void) {
+  if (_no_of_cores == 0) {
+    resolve_cpu_information_details();
+  }
+  return _no_of_cores;
+}
+
+int VM_Version_Ext::number_of_sockets(void) {
+  if (_no_of_packages == 0) {
+    resolve_cpu_information_details();
+  }
+  return _no_of_packages;
+}
+
+const char* VM_Version_Ext::cpu_family_description(void) {
+  int cpu_family_id = extended_cpu_family();
+  if (is_amd()) {
+    return _family_id_amd[cpu_family_id];
+  }
+  if (is_intel()) {
+    if (cpu_family_id == CPU_FAMILY_PENTIUMPRO) {
+      return cpu_model_description();
+    }
+    return _family_id_intel[cpu_family_id];
+  }
+  return "Unknown x86";
+}
+
+int VM_Version_Ext::cpu_type_description(char* const buf, size_t buf_len) {
+  assert(buf != NULL, "buffer is NULL!");
+  assert(buf_len >= CPU_TYPE_DESC_BUF_SIZE, "buffer len should at least be == CPU_TYPE_DESC_BUF_SIZE!");
+
+  const char* cpu_type = NULL;
+  const char* x64 = NULL;
+
+  if (is_intel()) {
+    cpu_type = "Intel";
+    x64 = cpu_is_em64t() ? " Intel64" : "";
+  } else if (is_amd()) {
+    cpu_type = "AMD";
+    x64 = cpu_is_em64t() ? " AMD64" : "";
+  } else {
+    cpu_type = "Unknown x86";
+    x64 = cpu_is_em64t() ? " x86_64" : "";
+  }
+
+  jio_snprintf(buf, buf_len, "%s %s%s SSE SSE2%s%s%s%s%s%s%s%s",
+    cpu_type,
+    cpu_family_description(),
+    supports_ht() ? " (HT)" : "",
+    supports_sse3() ? " SSE3" : "",
+    supports_ssse3() ? " SSSE3" : "",
+    supports_sse4_1() ? " SSE4.1" : "",
+    supports_sse4_2() ? " SSE4.2" : "",
+    supports_sse4a() ? " SSE4A" : "",
+    is_netburst() ? " Netburst" : "",
+    is_intel_family_core() ? " Core" : "",
+    x64);
+
+  return OS_OK;
+}
+
+int VM_Version_Ext::cpu_extended_brand_string(char* const buf, size_t buf_len) {
+  assert(buf != NULL, "buffer is NULL!");
+  assert(buf_len >= CPU_EBS_MAX_LENGTH, "buffer len should at least be == CPU_EBS_MAX_LENGTH!");
+  assert(getCPUIDBrandString_stub != NULL, "not initialized");
+
+  // invoke newly generated asm code to fetch CPU Brand String
+  getCPUIDBrandString_stub(&_cpuid_info);
+
+  // fetch results into buffer
+  *((uint32_t*) &buf[0])  = _cpuid_info.proc_name_0;
+  *((uint32_t*) &buf[4])  = _cpuid_info.proc_name_1;
+  *((uint32_t*) &buf[8])  = _cpuid_info.proc_name_2;
+  *((uint32_t*) &buf[12]) = _cpuid_info.proc_name_3;
+  *((uint32_t*) &buf[16]) = _cpuid_info.proc_name_4;
+  *((uint32_t*) &buf[20]) = _cpuid_info.proc_name_5;
+  *((uint32_t*) &buf[24]) = _cpuid_info.proc_name_6;
+  *((uint32_t*) &buf[28]) = _cpuid_info.proc_name_7;
+  *((uint32_t*) &buf[32]) = _cpuid_info.proc_name_8;
+  *((uint32_t*) &buf[36]) = _cpuid_info.proc_name_9;
+  *((uint32_t*) &buf[40]) = _cpuid_info.proc_name_10;
+  *((uint32_t*) &buf[44]) = _cpuid_info.proc_name_11;
+
+  return OS_OK;
+}
+
+size_t VM_Version_Ext::cpu_write_support_string(char* const buf, size_t buf_len) {
+  assert(buf != NULL, "buffer is NULL!");
+  assert(buf_len > 0, "buffer len not enough!");
+
+  unsigned int flag = 0;
+  unsigned int fi = 0;
+  size_t       written = 0;
+  const char*  prefix = "";
+
+#define WRITE_TO_BUF(string)                                                          \
+  {                                                                                   \
+    int res = jio_snprintf(&buf[written], buf_len - written, "%s%s", prefix, string); \
+    if (res < 0 || (size_t) res >= buf_len - 1) {                                     \
+      buf[buf_len-1] = '\0';                                                          \
+      return buf_len - 1;                                                             \
+    }                                                                                 \
+    written += res;                                                                   \
+    if (prefix[0] == '\0') {                                                          \
+      prefix = ", ";                                                                  \
+    }                                                                                 \
+  }
+
+  for (flag = 1, fi = 0; flag <= 0x20000000 ; flag <<= 1, fi++) {
+    if (flag == HTT_FLAG && (((_cpuid_info.std_cpuid1_ebx.value >> 16) & 0xff) <= 1)) {
+      continue; /* no hyperthreading */
+    } else if (flag == SEP_FLAG && (cpu_family() == CPU_FAMILY_PENTIUMPRO && ((_cpuid_info.std_cpuid1_eax.value & 0xff) < 0x33))) {
+      continue; /* no fast system call */
+    }
+    if ((_cpuid_info.std_cpuid1_edx.value & flag) && strlen(_feature_edx_id[fi]) > 0) {
+      WRITE_TO_BUF(_feature_edx_id[fi]);
+    }
+  }
+
+  for (flag = 1, fi = 0; flag <= 0x20000000; flag <<= 1, fi++) {
+    if ((_cpuid_info.std_cpuid1_ecx.value & flag) && strlen(_feature_ecx_id[fi]) > 0) {
+      WRITE_TO_BUF(_feature_ecx_id[fi]);
+    }
+  }
+
+  for (flag = 1, fi = 0; flag <= 0x20000000 ; flag <<= 1, fi++) {
+    if ((_cpuid_info.ext_cpuid1_ecx.value & flag) && strlen(_feature_extended_ecx_id[fi]) > 0) {
+      WRITE_TO_BUF(_feature_extended_ecx_id[fi]);
+    }
+  }
+
+  for (flag = 1, fi = 0; flag <= 0x20000000; flag <<= 1, fi++) {
+    if ((_cpuid_info.ext_cpuid1_edx.value & flag) && strlen(_feature_extended_edx_id[fi]) > 0) {
+      WRITE_TO_BUF(_feature_extended_edx_id[fi]);
+    }
+  }
+
+  if (supports_tscinv_bit()) {
+      WRITE_TO_BUF("Invariant TSC");
+  }
+
+  return written;
+}
+
+/**
+ * Write a detailed description of the cpu to a given buffer, including
+ * feature set.
+ */
+int VM_Version_Ext::cpu_detailed_description(char* const buf, size_t buf_len) {
+  assert(buf != NULL, "buffer is NULL!");
+  assert(buf_len >= CPU_DETAILED_DESC_BUF_SIZE, "buffer len should at least be == CPU_DETAILED_DESC_BUF_SIZE!");
+
+  static const char* unknown = "<unknown>";
+  char               vendor_id[VENDOR_LENGTH];
+  const char*        family = NULL;
+  const char*        model = NULL;
+  const char*        brand = NULL;
+  int                outputLen = 0;
+
+  family = cpu_family_description();
+  if (family == NULL) {
+    family = unknown;
+  }
+
+  model = cpu_model_description();
+  if (model == NULL) {
+    model = unknown;
+  }
+
+  brand = cpu_brand_string();
+
+  if (brand == NULL) {
+    brand = cpu_brand();
+    if (brand == NULL) {
+      brand = unknown;
+    }
+  }
+
+  *((uint32_t*) &vendor_id[0]) = _cpuid_info.std_vendor_name_0;
+  *((uint32_t*) &vendor_id[4]) = _cpuid_info.std_vendor_name_2;
+  *((uint32_t*) &vendor_id[8]) = _cpuid_info.std_vendor_name_1;
+  vendor_id[VENDOR_LENGTH-1] = '\0';
+
+  outputLen = jio_snprintf(buf, buf_len, "Brand: %s, Vendor: %s\n"
+    "Family: %s (0x%x), Model: %s (0x%x), Stepping: 0x%x\n"
+    "Ext. family: 0x%x, Ext. model: 0x%x, Type: 0x%x, Signature: 0x%8.8x\n"
+    "Features: ebx: 0x%8.8x, ecx: 0x%8.8x, edx: 0x%8.8x\n"
+    "Ext. features: eax: 0x%8.8x, ebx: 0x%8.8x, ecx: 0x%8.8x, edx: 0x%8.8x\n"
+    "Supports: ",
+    brand,
+    vendor_id,
+    family,
+    extended_cpu_family(),
+    model,
+    extended_cpu_model(),
+    cpu_stepping(),
+    _cpuid_info.std_cpuid1_eax.bits.ext_family,
+    _cpuid_info.std_cpuid1_eax.bits.ext_model,
+    _cpuid_info.std_cpuid1_eax.bits.proc_type,
+    _cpuid_info.std_cpuid1_eax.value,
+    _cpuid_info.std_cpuid1_ebx.value,
+    _cpuid_info.std_cpuid1_ecx.value,
+    _cpuid_info.std_cpuid1_edx.value,
+    _cpuid_info.ext_cpuid1_eax,
+    _cpuid_info.ext_cpuid1_ebx,
+    _cpuid_info.ext_cpuid1_ecx,
+    _cpuid_info.ext_cpuid1_edx);
+
+  if (outputLen < 0 || (size_t) outputLen >= buf_len - 1) {
+    buf[buf_len-1] = '\0';
+    return OS_ERR;
+  }
+
+  cpu_write_support_string(&buf[outputLen], buf_len - outputLen);
+
+  return OS_OK;
+}
+
+const char* VM_Version_Ext::cpu_name(void) {
+  char cpu_type_desc[CPU_TYPE_DESC_BUF_SIZE];
+  size_t cpu_desc_len = sizeof(cpu_type_desc);
+
+  cpu_type_description(cpu_type_desc, cpu_desc_len);
+  char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, cpu_desc_len, mtTracing);
+  if (NULL == tmp) {
+    return NULL;
+  }
+  strncpy(tmp, cpu_type_desc, cpu_desc_len);
+  return tmp;
+}
+
+const char* VM_Version_Ext::cpu_description(void) {
+  char cpu_detailed_desc_buffer[CPU_DETAILED_DESC_BUF_SIZE];
+  size_t cpu_detailed_desc_len = sizeof(cpu_detailed_desc_buffer);
+
+  cpu_detailed_description(cpu_detailed_desc_buffer, cpu_detailed_desc_len);
+
+  char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, cpu_detailed_desc_len, mtTracing);
+
+  if (NULL == tmp) {
+    return NULL;
+  }
+
+  strncpy(tmp, cpu_detailed_desc_buffer, cpu_detailed_desc_len);
+  return tmp;
+}
+
+/**
+ *  See Intel Application note 485 (chapter 10) for details
+ *  on frequency extraction from cpu brand string.
+ *  http://www.intel.com/content/dam/www/public/us/en/documents/application-notes/processor-identification-cpuid-instruction-note.pdf
+ *
+ */
+jlong VM_Version_Ext::max_qualified_cpu_freq_from_brand_string(void) {
+  // get brand string
+  const char* const brand_string = cpu_brand_string();
+  if (brand_string == NULL) {
+    return 0;
+  }
+
+  const u8 MEGA = 1000000;
+  u8 multiplier = 0;
+  jlong frequency = 0;
+
+  // the frequency information in the cpu brand string
+  // is given in either of two formats "x.xxyHz" or "xxxxyHz",
+  // where y=M,G,T and x is digits
+  const char* Hz_location = strchr(brand_string, 'H');
+
+  if (Hz_location != NULL) {
+    if (*(Hz_location + 1) == 'z') {
+      // switch on y in "yHz"
+      switch(*(Hz_location - 1)) {
+        case 'M' :
+          // Set multiplier to frequency is in Hz
+          multiplier = MEGA;
+          break;
+        case 'G' :
+          multiplier = MEGA * 1000;
+          break;
+        case 'T' :
+          multiplier = MEGA * 1000 * 1000;
+          break;
+      }
+    }
+  }
+
+  if (multiplier > 0) {
+    // compute frequency (in Hz) from brand string
+    if (*(Hz_location - 4) == '.') { // if format is "x.xx"
+      frequency =  (jlong)(*(Hz_location - 5) - '0') * (multiplier);
+      frequency += (jlong)(*(Hz_location - 3) - '0') * (multiplier / 10);
+      frequency += (jlong)(*(Hz_location - 2) - '0') * (multiplier / 100);
+    } else { // format is "xxxx"
+      frequency =  (jlong)(*(Hz_location - 5) - '0') * 1000;
+      frequency += (jlong)(*(Hz_location - 4) - '0') * 100;
+      frequency += (jlong)(*(Hz_location - 3) - '0') * 10;
+      frequency += (jlong)(*(Hz_location - 2) - '0');
+      frequency *= multiplier;
+    }
+  }
+  return frequency;
+}
+
+
+jlong VM_Version_Ext::maximum_qualified_cpu_frequency(void) {
+  if (_max_qualified_cpu_frequency == 0) {
+    _max_qualified_cpu_frequency = max_qualified_cpu_freq_from_brand_string();
+  }
+  return _max_qualified_cpu_frequency;
+}
+
+const char* const VM_Version_Ext::_family_id_intel[] = {
+  "8086/8088",
+  "",
+  "286",
+  "386",
+  "486",
+  "Pentium",
+  "Pentium Pro",   //or Pentium-M/Woodcrest depeding on model
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "Pentium 4"
+};
+
+const char* const VM_Version_Ext::_family_id_amd[] = {
+  "",
+  "",
+  "",
+  "",
+  "5x86",
+  "K5/K6",
+  "Athlon/AthlonXP",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "Opteron/Athlon64",
+  "Opteron QC/Phenom"  // Barcelona et.al.
+};
+// Partially from Intel 64 and IA-32 Architecture Software Developer's Manual,
+// September 2013, Vol 3C Table 35-1
+const char* const VM_Version_Ext::_model_id_pentium_pro[] = {
+  "",
+  "Pentium Pro",
+  "",
+  "Pentium II model 3",
+  "",
+  "Pentium II model 5/Xeon/Celeron",
+  "Celeron",
+  "Pentium III/Pentium III Xeon",
+  "Pentium III/Pentium III Xeon",
+  "Pentium M model 9",    // Yonah
+  "Pentium III, model A",
+  "Pentium III, model B",
+  "",
+  "Pentium M model D",    // Dothan
+  "",
+  "Core 2",               // 0xf Woodcrest/Conroe/Merom/Kentsfield/Clovertown
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "Celeron",              // 0x16 Celeron 65nm
+  "Core 2",               // 0x17 Penryn / Harpertown
+  "",
+  "",
+  "Core i7",              // 0x1A CPU_MODEL_NEHALEM_EP
+  "Atom",                 // 0x1B Z5xx series Silverthorn
+  "",
+  "Core 2",               // 0x1D Dunnington (6-core)
+  "Nehalem",              // 0x1E CPU_MODEL_NEHALEM
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "Westmere",             // 0x25 CPU_MODEL_WESTMERE
+  "",
+  "",
+  "",                     // 0x28
+  "",
+  "Sandy Bridge",         // 0x2a "2nd Generation Intel Core i7, i5, i3"
+  "",
+  "Westmere-EP",          // 0x2c CPU_MODEL_WESTMERE_EP
+  "Sandy Bridge-EP",      // 0x2d CPU_MODEL_SANDYBRIDGE_EP
+  "Nehalem-EX",           // 0x2e CPU_MODEL_NEHALEM_EX
+  "Westmere-EX",          // 0x2f CPU_MODEL_WESTMERE_EX
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "Ivy Bridge",           // 0x3a
+  "",
+  "Haswell",              // 0x3c "4th Generation Intel Core Processor"
+  "",                     // 0x3d "Next Generation Intel Core Processor"
+  "Ivy Bridge-EP",        // 0x3e "Next Generation Intel Xeon Processor E7 Family"
+  "",                     // 0x3f "Future Generation Intel Xeon Processor"
+  "",
+  "",
+  "",
+  "",
+  "",
+  "Haswell",              // 0x45 "4th Generation Intel Core Processor"
+  "Haswell",              // 0x46 "4th Generation Intel Core Processor"
+  NULL
+};
+
+/* Brand ID is for back compability
+ * Newer CPUs uses the extended brand string */
+const char* const VM_Version_Ext::_brand_id[] = {
+  "",
+  "Celeron processor",
+  "Pentium III processor",
+  "Intel Pentium III Xeon processor",
+  "",
+  "",
+  "",
+  "",
+  "Intel Pentium 4 processor",
+  NULL
+};
+
+
+const char* const VM_Version_Ext::_feature_edx_id[] = {
+  "On-Chip FPU",
+  "Virtual Mode Extensions",
+  "Debugging Extensions",
+  "Page Size Extensions",
+  "Time Stamp Counter",
+  "Model Specific Registers",
+  "Physical Address Extension",
+  "Machine Check Exceptions",
+  "CMPXCHG8B Instruction",
+  "On-Chip APIC",
+  "",
+  "Fast System Call",
+  "Memory Type Range Registers",
+  "Page Global Enable",
+  "Machine Check Architecture",
+  "Conditional Mov Instruction",
+  "Page Attribute Table",
+  "36-bit Page Size Extension",
+  "Processor Serial Number",
+  "CLFLUSH Instruction",
+  "",
+  "Debug Trace Store feature",
+  "ACPI registers in MSR space",
+  "Intel Architecture MMX Technology",
+  "Fast Float Point Save and Restore",
+  "Streaming SIMD extensions",
+  "Streaming SIMD extensions 2",
+  "Self-Snoop",
+  "Hyper Threading",
+  "Thermal Monitor",
+  "",
+  "Pending Break Enable"
+};
+
+const char* const VM_Version_Ext::_feature_extended_edx_id[] = {
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "SYSCALL/SYSRET",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "Execute Disable Bit",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "RDTSCP",
+  "",
+  "Intel 64 Architecture",
+  "",
+  ""
+};
+
+const char* const VM_Version_Ext::_feature_ecx_id[] = {
+  "Streaming SIMD Extensions 3",
+  "PCLMULQDQ",
+  "64-bit DS Area",
+  "MONITOR/MWAIT instructions",
+  "CPL Qualified Debug Store",
+  "Virtual Machine Extensions",
+  "Safer Mode Extensions",
+  "Enhanced Intel SpeedStep technology",
+  "Thermal Monitor 2",
+  "Supplemental Streaming SIMD Extensions 3",
+  "L1 Context ID",
+  "",
+  "Fused Multiply-Add",
+  "CMPXCHG16B",
+  "xTPR Update Control",
+  "Perfmon and Debug Capability",
+  "",
+  "Process-context identifiers",
+  "Direct Cache Access",
+  "Streaming SIMD extensions 4.1",
+  "Streaming SIMD extensions 4.2",
+  "x2APIC",
+  "MOVBE",
+  "Popcount instruction",
+  "TSC-Deadline",
+  "AESNI",
+  "XSAVE",
+  "OSXSAVE",
+  "AVX",
+  "F16C",
+  "RDRAND",
+  ""
+};
+
+const char* const VM_Version_Ext::_feature_extended_ecx_id[] = {
+  "LAHF/SAHF instruction support",
+  "Core multi-processor leagacy mode",
+  "",
+  "",
+  "",
+  "Advanced Bit Manipulations: LZCNT",
+  "SSE4A: MOVNTSS, MOVNTSD, EXTRQ, INSERTQ",
+  "Misaligned SSE mode",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+  ""
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/cpu/x86/vm_version_ext_x86.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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 CPU_X86_VM_VM_VERSION_EXT_X86_HPP
+#define CPU_X86_VM_VM_VERSION_EXT_X86_HPP
+
+#include "utilities/macros.hpp"
+#include "vm_version_x86.hpp"
+
+class VM_Version_Ext : public VM_Version {
+ private:
+  static const size_t      VENDOR_LENGTH;
+  static const size_t      CPU_EBS_MAX_LENGTH;
+  static const size_t      CPU_TYPE_DESC_BUF_SIZE;
+  static const size_t      CPU_DETAILED_DESC_BUF_SIZE;
+
+  static const char* const _family_id_intel[];
+  static const char* const _family_id_amd[];
+  static const char* const _brand_id[];
+  static const char* const _model_id_pentium_pro[];
+
+  static const char* const _feature_edx_id[];
+  static const char* const _feature_extended_edx_id[];
+  static const char* const _feature_ecx_id[];
+  static const char* const _feature_extended_ecx_id[];
+
+  static int               _no_of_threads;
+  static int               _no_of_cores;
+  static int               _no_of_packages;
+  static char*             _cpu_brand_string;
+  static jlong             _max_qualified_cpu_frequency;
+
+  static const char* cpu_family_description(void);
+  static const char* cpu_model_description(void);
+  static const char* cpu_brand(void);
+  static const char* cpu_brand_string(void);
+
+  static int cpu_type_description(char* const buf, size_t buf_len);
+  static int cpu_detailed_description(char* const buf, size_t buf_len);
+  static int cpu_extended_brand_string(char* const buf, size_t buf_len);
+
+  static bool cpu_is_em64t(void);
+  static bool is_netburst(void);
+
+  static size_t cpu_write_support_string(char* const buf, size_t buf_len);
+  static void resolve_cpu_information_details(void);
+  static jlong max_qualified_cpu_freq_from_brand_string(void);
+
+ public:
+  // Offsets for cpuid asm stub brand string
+  static ByteSize proc_name_0_offset() { return byte_offset_of(CpuidInfo, proc_name_0); }
+  static ByteSize proc_name_1_offset() { return byte_offset_of(CpuidInfo, proc_name_1); }
+  static ByteSize proc_name_2_offset() { return byte_offset_of(CpuidInfo, proc_name_2); }
+  static ByteSize proc_name_3_offset() { return byte_offset_of(CpuidInfo, proc_name_3); }
+  static ByteSize proc_name_4_offset() { return byte_offset_of(CpuidInfo, proc_name_4); }
+  static ByteSize proc_name_5_offset() { return byte_offset_of(CpuidInfo, proc_name_5); }
+  static ByteSize proc_name_6_offset() { return byte_offset_of(CpuidInfo, proc_name_6); }
+  static ByteSize proc_name_7_offset() { return byte_offset_of(CpuidInfo, proc_name_7); }
+  static ByteSize proc_name_8_offset() { return byte_offset_of(CpuidInfo, proc_name_8); }
+  static ByteSize proc_name_9_offset() { return byte_offset_of(CpuidInfo, proc_name_9); }
+  static ByteSize proc_name_10_offset() { return byte_offset_of(CpuidInfo, proc_name_10); }
+  static ByteSize proc_name_11_offset() { return byte_offset_of(CpuidInfo, proc_name_11); }
+
+  static int number_of_threads(void);
+  static int number_of_cores(void);
+  static int number_of_sockets(void);
+
+  static jlong maximum_qualified_cpu_frequency(void);
+
+  static bool supports_tscinv_ext(void);
+
+  static const char* cpu_name(void);
+  static const char* cpu_description(void);
+
+  static void initialize();
+};
+
+#endif // CPU_X86_VM_VM_VERSION_EXT_X86_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/os/bsd/os_perf_bsd.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,405 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+#include "precompiled.hpp"
+#include "memory/allocation.inline.hpp"
+#include "memory/resourceArea.hpp"
+#include "runtime/os.hpp"
+#include "runtime/os_perf.hpp"
+#include "vm_version_ext_x86.hpp"
+
+#ifdef __APPLE__
+  #import <libproc.h>
+  #include <sys/time.h>
+  #include <sys/sysctl.h>
+  #include <mach/mach.h>
+  #include <mach/task_info.h>
+#endif
+
+static const double NANOS_PER_SEC = 1000000000.0;
+
+class CPUPerformanceInterface::CPUPerformance : public CHeapObj<mtInternal> {
+   friend class CPUPerformanceInterface;
+ private:
+  long _total_cpu_nanos;
+  long _total_csr_nanos;
+  long _jvm_user_nanos;
+  long _jvm_system_nanos;
+  long _jvm_context_switches;
+  long _used_ticks;
+  long _total_ticks;
+  int  _active_processor_count;
+
+  bool now_in_nanos(long* resultp) {
+    timeval current_time;
+    if (gettimeofday(&current_time, NULL) != 0) {
+      // Error getting current time
+      return false;
+    }
+    *resultp = current_time.tv_sec * NANOS_PER_SEC + 1000L * current_time.tv_usec;
+    return true;
+  }
+
+  double normalize(double value) {
+    return MIN2<double>(MAX2<double>(value, 0.0), 1.0);
+  }
+  int cpu_load(int which_logical_cpu, double* cpu_load);
+  int context_switch_rate(double* rate);
+  int cpu_load_total_process(double* cpu_load);
+  int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad);
+
+  CPUPerformance(const CPUPerformance& rhs); // no impl
+  CPUPerformance& operator=(const CPUPerformance& rhs); // no impl
+ public:
+  CPUPerformance();
+  bool initialize();
+  ~CPUPerformance();
+};
+
+CPUPerformanceInterface::CPUPerformance::CPUPerformance() {
+  _total_cpu_nanos= 0;
+  _total_csr_nanos= 0;
+  _jvm_context_switches = 0;
+  _jvm_user_nanos = 0;
+  _jvm_system_nanos = 0;
+  _used_ticks = 0;
+  _total_ticks = 0;
+  _active_processor_count = 0;
+}
+
+bool CPUPerformanceInterface::CPUPerformance::initialize() {
+  return true;
+}
+
+CPUPerformanceInterface::CPUPerformance::~CPUPerformance() {
+}
+
+int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) {
+  return FUNCTIONALITY_NOT_IMPLEMENTED;
+}
+
+int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) {
+#ifdef __APPLE__
+  host_name_port_t host = mach_host_self();
+  host_flavor_t flavor = HOST_CPU_LOAD_INFO;
+  mach_msg_type_number_t host_info_count = HOST_CPU_LOAD_INFO_COUNT;
+  host_cpu_load_info_data_t cpu_load_info;
+
+  kern_return_t kr = host_statistics(host, flavor, (host_info_t)&cpu_load_info, &host_info_count);
+  if (kr != KERN_SUCCESS) {
+    return OS_ERR;
+  }
+
+  long used_ticks  = cpu_load_info.cpu_ticks[CPU_STATE_USER] + cpu_load_info.cpu_ticks[CPU_STATE_NICE] + cpu_load_info.cpu_ticks[CPU_STATE_SYSTEM];
+  long total_ticks = used_ticks + cpu_load_info.cpu_ticks[CPU_STATE_IDLE];
+
+  if (_used_ticks == 0 || _total_ticks == 0) {
+    // First call, just set the values
+    _used_ticks  = used_ticks;
+    _total_ticks = total_ticks;
+    return OS_ERR;
+  }
+
+  long used_delta  = used_ticks - _used_ticks;
+  long total_delta = total_ticks - _total_ticks;
+
+  _used_ticks  = used_ticks;
+  _total_ticks = total_ticks;
+
+  if (total_delta == 0) {
+    // Avoid division by zero
+    return OS_ERR;
+  }
+
+  *cpu_load = (double)used_delta / total_delta;
+
+  return OS_OK;
+#else
+  return FUNCTIONALITY_NOT_IMPLEMENTED;
+#endif
+}
+
+int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) {
+#ifdef __APPLE__
+  int result = cpu_load_total_process(psystemTotalLoad);
+  mach_port_t task = mach_task_self();
+  mach_msg_type_number_t task_info_count = TASK_INFO_MAX;
+  task_info_data_t task_info_data;
+  kern_return_t kr = task_info(task, TASK_ABSOLUTETIME_INFO, (task_info_t)task_info_data, &task_info_count);
+  if (kr != KERN_SUCCESS) {
+    return OS_ERR;
+  }
+  task_absolutetime_info_t absolutetime_info = (task_absolutetime_info_t)task_info_data;
+
+  int active_processor_count = os::active_processor_count();
+  long jvm_user_nanos = absolutetime_info->total_user;
+  long jvm_system_nanos = absolutetime_info->total_system;
+
+  long total_cpu_nanos;
+  if(!now_in_nanos(&total_cpu_nanos)) {
+    return OS_ERR;
+  }
+
+  if (_total_cpu_nanos == 0 || active_processor_count != _active_processor_count) {
+    // First call or change in active processor count
+    result = OS_ERR;
+  }
+
+  long delta_nanos = active_processor_count * (total_cpu_nanos - _total_cpu_nanos);
+  if (delta_nanos == 0) {
+    // Avoid division by zero
+    return OS_ERR;
+  }
+
+  *pjvmUserLoad = normalize((double)(jvm_user_nanos - _jvm_user_nanos)/delta_nanos);
+  *pjvmKernelLoad = normalize((double)(jvm_system_nanos - _jvm_system_nanos)/delta_nanos);
+
+  _active_processor_count = active_processor_count;
+  _total_cpu_nanos = total_cpu_nanos;
+  _jvm_user_nanos = jvm_user_nanos;
+  _jvm_system_nanos = jvm_system_nanos;
+
+  return result;
+#else
+  return FUNCTIONALITY_NOT_IMPLEMENTED;
+#endif
+}
+
+int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) {
+#ifdef __APPLE__
+  mach_port_t task = mach_task_self();
+  mach_msg_type_number_t task_info_count = TASK_INFO_MAX;
+  task_info_data_t task_info_data;
+  kern_return_t kr = task_info(task, TASK_EVENTS_INFO, (task_info_t)task_info_data, &task_info_count);
+  if (kr != KERN_SUCCESS) {
+    return OS_ERR;
+  }
+
+  int result = OS_OK;
+  if (_total_csr_nanos == 0 || _jvm_context_switches == 0) {
+    // First call just set initial values.
+    result = OS_ERR;
+  }
+
+  long jvm_context_switches = ((task_events_info_t)task_info_data)->csw;
+
+  long total_csr_nanos;
+  if(!now_in_nanos(&total_csr_nanos)) {
+    return OS_ERR;
+  }
+  double delta_in_sec = (double)(total_csr_nanos - _total_csr_nanos) / NANOS_PER_SEC;
+  if (delta_in_sec == 0.0) {
+    // Avoid division by zero
+    return OS_ERR;
+  }
+
+  *rate = (jvm_context_switches - _jvm_context_switches) / delta_in_sec;
+
+  _jvm_context_switches = jvm_context_switches;
+  _total_csr_nanos = total_csr_nanos;
+
+  return result;
+#else
+  return FUNCTIONALITY_NOT_IMPLEMENTED;
+#endif
+}
+
+CPUPerformanceInterface::CPUPerformanceInterface() {
+  _impl = NULL;
+}
+
+bool CPUPerformanceInterface::initialize() {
+  _impl = new CPUPerformanceInterface::CPUPerformance();
+  return _impl != NULL && _impl->initialize();
+}
+
+CPUPerformanceInterface::~CPUPerformanceInterface() {
+  if (_impl != NULL) {
+    delete _impl;
+  }
+}
+
+int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const {
+  return _impl->cpu_load(which_logical_cpu, cpu_load);
+}
+
+int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const {
+  return _impl->cpu_load_total_process(cpu_load);
+}
+
+int CPUPerformanceInterface::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) const {
+  return _impl->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotalLoad);
+}
+
+int CPUPerformanceInterface::context_switch_rate(double* rate) const {
+  return _impl->context_switch_rate(rate);
+}
+
+class SystemProcessInterface::SystemProcesses : public CHeapObj<mtInternal> {
+  friend class SystemProcessInterface;
+ private:
+  SystemProcesses();
+  bool initialize();
+  SystemProcesses(const SystemProcesses& rhs); // no impl
+  SystemProcesses& operator=(const SystemProcesses& rhs); // no impl
+  ~SystemProcesses();
+
+  //information about system processes
+  int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const;
+};
+
+SystemProcessInterface::SystemProcesses::SystemProcesses() {
+}
+
+bool SystemProcessInterface::SystemProcesses::initialize() {
+  return true;
+}
+
+SystemProcessInterface::SystemProcesses::~SystemProcesses() {
+}
+int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const {
+  assert(system_processes != NULL, "system_processes pointer is NULL!");
+  assert(no_of_sys_processes != NULL, "system_processes counter pointer is NULL!");
+#ifdef __APPLE__
+  pid_t* pids = NULL;
+  int pid_count = 0;
+  ResourceMark rm;
+
+  int try_count = 0;
+  while (pids == NULL) {
+    // Find out buffer size
+    size_t pids_bytes = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0);
+    if (pids_bytes <= 0) {
+      return OS_ERR;
+    }
+    pid_count = pids_bytes / sizeof(pid_t);
+    pids = NEW_RESOURCE_ARRAY(pid_t, pid_count);
+    memset(pids, 0, pids_bytes);
+
+    pids_bytes = proc_listpids(PROC_ALL_PIDS, 0, pids, pids_bytes);
+    if (pids_bytes <= 0) {
+       // couldn't fit buffer, retry.
+      FREE_RESOURCE_ARRAY(pid_t, pids, pid_count);
+      pids = NULL;
+      try_count++;
+      if (try_count > 3) {
+      return OS_ERR;
+      }
+    } else {
+      pid_count = pids_bytes / sizeof(pid_t);
+    }
+  }
+
+  int process_count = 0;
+  SystemProcess* next = NULL;
+  for (int i = 0; i < pid_count; i++) {
+    pid_t pid = pids[i];
+    if (pid != 0) {
+      char buffer[PROC_PIDPATHINFO_MAXSIZE];
+      memset(buffer, 0 , sizeof(buffer));
+      if (proc_pidpath(pid, buffer, sizeof(buffer)) != -1) {
+        int length = strlen(buffer);
+        if (length > 0) {
+          SystemProcess* current = new SystemProcess();
+          char * path = NEW_C_HEAP_ARRAY(char, length + 1, mtInternal);
+          strcpy(path, buffer);
+          current->set_path(path);
+          current->set_pid((int)pid);
+          current->set_next(next);
+          next = current;
+          process_count++;
+        }
+      }
+    }
+  }
+
+  *no_of_sys_processes = process_count;
+  *system_processes = next;
+
+  return OS_OK;
+#endif
+  return FUNCTIONALITY_NOT_IMPLEMENTED;
+}
+
+int SystemProcessInterface::system_processes(SystemProcess** system_procs, int* no_of_sys_processes) const {
+  return _impl->system_processes(system_procs, no_of_sys_processes);
+}
+
+SystemProcessInterface::SystemProcessInterface() {
+  _impl = NULL;
+}
+
+bool SystemProcessInterface::initialize() {
+  _impl = new SystemProcessInterface::SystemProcesses();
+  return _impl != NULL && _impl->initialize();
+}
+
+SystemProcessInterface::~SystemProcessInterface() {
+  if (_impl != NULL) {
+    delete _impl;
+ }
+}
+
+CPUInformationInterface::CPUInformationInterface() {
+  _cpu_info = NULL;
+}
+
+bool CPUInformationInterface::initialize() {
+  _cpu_info = new CPUInformation();
+
+  if (NULL == _cpu_info) {
+    return false;
+  }
+  _cpu_info->set_number_of_hardware_threads(VM_Version_Ext::number_of_threads());
+  _cpu_info->set_number_of_cores(VM_Version_Ext::number_of_cores());
+  _cpu_info->set_number_of_sockets(VM_Version_Ext::number_of_sockets());
+  _cpu_info->set_cpu_name(VM_Version_Ext::cpu_name());
+  _cpu_info->set_cpu_description(VM_Version_Ext::cpu_description());
+
+  return true;
+}
+
+CPUInformationInterface::~CPUInformationInterface() {
+  if (_cpu_info != NULL) {
+    if (_cpu_info->cpu_name() != NULL) {
+      const char* cpu_name = _cpu_info->cpu_name();
+      FREE_C_HEAP_ARRAY(char, cpu_name);
+      _cpu_info->set_cpu_name(NULL);
+    }
+    if (_cpu_info->cpu_description() != NULL) {
+      const char* cpu_desc = _cpu_info->cpu_description();
+      FREE_C_HEAP_ARRAY(char, cpu_desc);
+      _cpu_info->set_cpu_description(NULL);
+    }
+    delete _cpu_info;
+  }
+}
+
+int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {
+  if (NULL == _cpu_info) {
+    return OS_ERR;
+  }
+
+  cpu_info = *_cpu_info; // shallow copy assignment
+  return OS_OK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/os/linux/os_perf_linux.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,1060 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jvm.h"
+#include "memory/allocation.inline.hpp"
+#include "os_linux.inline.hpp"
+#include "runtime/os.hpp"
+#include "runtime/os_perf.hpp"
+
+#ifdef X86
+#include "vm_version_ext_x86.hpp"
+#endif
+#ifdef ARM
+#include "vm_version_ext_arm.hpp"
+#endif
+#ifndef ARM
+#ifdef AARCH64
+#include "vm_version_ext_aarch64.hpp"
+#endif
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <pthread.h>
+#include <limits.h>
+
+/**
+   /proc/[number]/stat
+              Status information about the process.  This is used by ps(1).  It is defined in /usr/src/linux/fs/proc/array.c.
+
+              The fields, in order, with their proper scanf(3) format specifiers, are:
+
+              1. pid %d The process id.
+
+              2. comm %s
+                     The filename of the executable, in parentheses.  This is visible whether or not the executable is swapped out.
+
+              3. state %c
+                     One  character  from  the  string "RSDZTW" where R is running, S is sleeping in an interruptible wait, D is waiting in uninterruptible disk
+                     sleep, Z is zombie, T is traced or stopped (on a signal), and W is paging.
+
+              4. ppid %d
+                     The PID of the parent.
+
+              5. pgrp %d
+                     The process group ID of the process.
+
+              6. session %d
+                     The session ID of the process.
+
+              7. tty_nr %d
+                     The tty the process uses.
+
+              8. tpgid %d
+                     The process group ID of the process which currently owns the tty that the process is connected to.
+
+              9. flags %lu
+                     The flags of the process.  The math bit is decimal 4, and the traced bit is decimal 10.
+
+              10. minflt %lu
+                     The number of minor faults the process has made which have not required loading a memory page from disk.
+
+              11. cminflt %lu
+                     The number of minor faults that the process's waited-for children have made.
+
+              12. majflt %lu
+                     The number of major faults the process has made which have required loading a memory page from disk.
+
+              13. cmajflt %lu
+                     The number of major faults that the process's waited-for children have made.
+
+              14. utime %lu
+                     The number of jiffies that this process has been scheduled in user mode.
+
+              15. stime %lu
+                     The number of jiffies that this process has been scheduled in kernel mode.
+
+              16. cutime %ld
+                     The number of jiffies that this process's waited-for children have been scheduled in user mode. (See also times(2).)
+
+              17. cstime %ld
+                     The number of jiffies that this process' waited-for children have been scheduled in kernel mode.
+
+              18. priority %ld
+                     The standard nice value, plus fifteen.  The value is never negative in the kernel.
+
+              19. nice %ld
+                     The nice value ranges from 19 (nicest) to -19 (not nice to others).
+
+              20. 0 %ld  This value is hard coded to 0 as a placeholder for a removed field.
+
+              21. itrealvalue %ld
+                     The time in jiffies before the next SIGALRM is sent to the process due to an interval timer.
+
+              22. starttime %lu
+                     The time in jiffies the process started after system boot.
+
+              23. vsize %lu
+                     Virtual memory size in bytes.
+
+              24. rss %ld
+                     Resident Set Size: number of pages the process has in real memory, minus 3 for administrative purposes. This is just the pages which  count
+                     towards text, data, or stack space.  This does not include pages which have not been demand-loaded in, or which are swapped out.
+
+              25. rlim %lu
+                     Current limit in bytes on the rss of the process (usually 4294967295 on i386).
+
+              26. startcode %lu
+                     The address above which program text can run.
+
+              27. endcode %lu
+                     The address below which program text can run.
+
+              28. startstack %lu
+                     The address of the start of the stack.
+
+              29. kstkesp %lu
+                     The current value of esp (stack pointer), as found in the kernel stack page for the process.
+
+              30. kstkeip %lu
+                     The current EIP (instruction pointer).
+
+              31. signal %lu
+                     The bitmap of pending signals (usually 0).
+
+              32. blocked %lu
+                     The bitmap of blocked signals (usually 0, 2 for shells).
+
+              33. sigignore %lu
+                     The bitmap of ignored signals.
+
+              34. sigcatch %lu
+                     The bitmap of catched signals.
+
+              35. wchan %lu
+                     This  is the "channel" in which the process is waiting.  It is the address of a system call, and can be looked up in a namelist if you need
+                     a textual name.  (If you have an up-to-date /etc/psdatabase, then try ps -l to see the WCHAN field in action.)
+
+              36. nswap %lu
+                     Number of pages swapped - not maintained.
+
+              37. cnswap %lu
+                     Cumulative nswap for child processes.
+
+              38. exit_signal %d
+                     Signal to be sent to parent when we die.
+
+              39. processor %d
+                     CPU number last executed on.
+
+
+
+ ///// SSCANF FORMAT STRING. Copy and use.
+
+field:        1  2  3  4  5  6  7  8  9   10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36  37  38 39
+format:       %d %s %c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %d %d
+
+
+*/
+
+/**
+ * For platforms that have them, when declaring
+ * a printf-style function,
+ *   formatSpec is the parameter number (starting at 1)
+ *       that is the format argument ("%d pid %s")
+ *   params is the parameter number where the actual args to
+ *       the format starts. If the args are in a va_list, this
+ *       should be 0.
+ */
+#ifndef PRINTF_ARGS
+#  define PRINTF_ARGS(formatSpec,  params) ATTRIBUTE_PRINTF(formatSpec, params)
+#endif
+
+#ifndef SCANF_ARGS
+#  define SCANF_ARGS(formatSpec,   params) ATTRIBUTE_SCANF(formatSpec, params)
+#endif
+
+#ifndef _PRINTFMT_
+#  define _PRINTFMT_
+#endif
+
+#ifndef _SCANFMT_
+#  define _SCANFMT_
+#endif
+
+
+struct CPUPerfTicks {
+  uint64_t  used;
+  uint64_t  usedKernel;
+  uint64_t  total;
+};
+
+typedef enum {
+  CPU_LOAD_VM_ONLY,
+  CPU_LOAD_GLOBAL,
+} CpuLoadTarget;
+
+enum {
+  UNDETECTED,
+  UNDETECTABLE,
+  LINUX26_NPTL,
+  BAREMETAL
+};
+
+struct CPUPerfCounters {
+  int   nProcs;
+  CPUPerfTicks jvmTicks;
+  CPUPerfTicks* cpus;
+};
+
+static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters, double* pkernelLoad, CpuLoadTarget target);
+
+/** reads /proc/<pid>/stat data, with some checks and some skips.
+ *  Ensure that 'fmt' does _NOT_ contain the first two "%d %s"
+ */
+static int SCANF_ARGS(2, 0) vread_statdata(const char* procfile, _SCANFMT_ const char* fmt, va_list args) {
+  FILE*f;
+  int n;
+  char buf[2048];
+
+  if ((f = fopen(procfile, "r")) == NULL) {
+    return -1;
+  }
+
+  if ((n = fread(buf, 1, sizeof(buf), f)) != -1) {
+    char *tmp;
+
+    buf[n-1] = '\0';
+    /** skip through pid and exec name. */
+    if ((tmp = strrchr(buf, ')')) != NULL) {
+      // skip the ')' and the following space
+      // but check that buffer is long enough
+      tmp += 2;
+      if (tmp < buf + n) {
+        n = vsscanf(tmp, fmt, args);
+      }
+    }
+  }
+
+  fclose(f);
+
+  return n;
+}
+
+static int SCANF_ARGS(2, 3) read_statdata(const char* procfile, _SCANFMT_ const char* fmt, ...) {
+  int   n;
+  va_list args;
+
+  va_start(args, fmt);
+  n = vread_statdata(procfile, fmt, args);
+  va_end(args);
+  return n;
+}
+
+static FILE* open_statfile(void) {
+  FILE *f;
+
+  if ((f = fopen("/proc/stat", "r")) == NULL) {
+    static int haveWarned = 0;
+    if (!haveWarned) {
+      haveWarned = 1;
+    }
+  }
+  return f;
+}
+
+static void
+next_line(FILE *f) {
+  int c;
+  do {
+    c = fgetc(f);
+  } while (c != '\n' && c != EOF);
+}
+
+/**
+ * Return the total number of ticks since the system was booted.
+ * If the usedTicks parameter is not NULL, it will be filled with
+ * the number of ticks spent on actual processes (user, system or
+ * nice processes) since system boot. Note that this is the total number
+ * of "executed" ticks on _all_ CPU:s, that is on a n-way system it is
+ * n times the number of ticks that has passed in clock time.
+ *
+ * Returns a negative value if the reading of the ticks failed.
+ */
+static OSReturn get_total_ticks(int which_logical_cpu, CPUPerfTicks* pticks) {
+  FILE*         fh;
+  uint64_t      userTicks, niceTicks, systemTicks, idleTicks;
+  uint64_t      iowTicks = 0, irqTicks = 0, sirqTicks= 0;
+  int           logical_cpu = -1;
+  const int     expected_assign_count = (-1 == which_logical_cpu) ? 4 : 5;
+  int           n;
+
+  if ((fh = open_statfile()) == NULL) {
+    return OS_ERR;
+  }
+  if (-1 == which_logical_cpu) {
+    n = fscanf(fh, "cpu " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " "
+            UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT,
+            &userTicks, &niceTicks, &systemTicks, &idleTicks,
+            &iowTicks, &irqTicks, &sirqTicks);
+  } else {
+    // Move to next line
+    next_line(fh);
+
+    // find the line for requested cpu faster to just iterate linefeeds?
+    for (int i = 0; i < which_logical_cpu; i++) {
+      next_line(fh);
+    }
+
+    n = fscanf(fh, "cpu%u " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " "
+               UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT,
+               &logical_cpu, &userTicks, &niceTicks,
+               &systemTicks, &idleTicks, &iowTicks, &irqTicks, &sirqTicks);
+  }
+
+  fclose(fh);
+  if (n < expected_assign_count || logical_cpu != which_logical_cpu) {
+#ifdef DEBUG_LINUX_PROC_STAT
+    vm_fprintf(stderr, "[stat] read failed");
+#endif
+    return OS_ERR;
+  }
+
+#ifdef DEBUG_LINUX_PROC_STAT
+  vm_fprintf(stderr, "[stat] read "
+          UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " "
+          UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " \n",
+          userTicks, niceTicks, systemTicks, idleTicks,
+          iowTicks, irqTicks, sirqTicks);
+#endif
+
+  pticks->used       = userTicks + niceTicks;
+  pticks->usedKernel = systemTicks + irqTicks + sirqTicks;
+  pticks->total      = userTicks + niceTicks + systemTicks + idleTicks +
+                       iowTicks + irqTicks + sirqTicks;
+
+  return OS_OK;
+}
+
+
+static int get_systemtype(void) {
+  static int procEntriesType = UNDETECTED;
+  DIR *taskDir;
+
+  if (procEntriesType != UNDETECTED) {
+    return procEntriesType;
+  }
+
+  // Check whether we have a task subdirectory
+  if ((taskDir = opendir("/proc/self/task")) == NULL) {
+    procEntriesType = UNDETECTABLE;
+  } else {
+    // The task subdirectory exists; we're on a Linux >= 2.6 system
+    closedir(taskDir);
+    procEntriesType = LINUX26_NPTL;
+  }
+
+  return procEntriesType;
+}
+
+/** read user and system ticks from a named procfile, assumed to be in 'stat' format then. */
+static int read_ticks(const char* procfile, uint64_t* userTicks, uint64_t* systemTicks) {
+  return read_statdata(procfile, "%*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u " UINT64_FORMAT " " UINT64_FORMAT,
+    userTicks, systemTicks);
+}
+
+/**
+ * Return the number of ticks spent in any of the processes belonging
+ * to the JVM on any CPU.
+ */
+static OSReturn get_jvm_ticks(CPUPerfTicks* pticks) {
+  uint64_t userTicks;
+  uint64_t systemTicks;
+
+  if (get_systemtype() != LINUX26_NPTL) {
+    return OS_ERR;
+  }
+
+  if (read_ticks("/proc/self/stat", &userTicks, &systemTicks) != 2) {
+    return OS_ERR;
+  }
+
+  // get the total
+  if (get_total_ticks(-1, pticks) != OS_OK) {
+    return OS_ERR;
+  }
+
+  pticks->used       = userTicks;
+  pticks->usedKernel = systemTicks;
+
+  return OS_OK;
+}
+
+/**
+ * Return the load of the CPU as a double. 1.0 means the CPU process uses all
+ * available time for user or system processes, 0.0 means the CPU uses all time
+ * being idle.
+ *
+ * Returns a negative value if there is a problem in determining the CPU load.
+ */
+static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters, double* pkernelLoad, CpuLoadTarget target) {
+  uint64_t udiff, kdiff, tdiff;
+  CPUPerfTicks* pticks;
+  CPUPerfTicks  tmp;
+  double user_load;
+
+  *pkernelLoad = 0.0;
+
+  if (target == CPU_LOAD_VM_ONLY) {
+    pticks = &counters->jvmTicks;
+  } else if (-1 == which_logical_cpu) {
+    pticks = &counters->cpus[counters->nProcs];
+  } else {
+    pticks = &counters->cpus[which_logical_cpu];
+  }
+
+  tmp = *pticks;
+
+  if (target == CPU_LOAD_VM_ONLY) {
+    if (get_jvm_ticks(pticks) != OS_OK) {
+      return -1.0;
+    }
+  } else if (get_total_ticks(which_logical_cpu, pticks) != OS_OK) {
+    return -1.0;
+  }
+
+  // seems like we sometimes end up with less kernel ticks when
+  // reading /proc/self/stat a second time, timing issue between cpus?
+  if (pticks->usedKernel < tmp.usedKernel) {
+    kdiff = 0;
+  } else {
+    kdiff = pticks->usedKernel - tmp.usedKernel;
+  }
+  tdiff = pticks->total - tmp.total;
+  udiff = pticks->used - tmp.used;
+
+  if (tdiff == 0) {
+    return 0.0;
+  } else if (tdiff < (udiff + kdiff)) {
+    tdiff = udiff + kdiff;
+  }
+  *pkernelLoad = (kdiff / (double)tdiff);
+  // BUG9044876, normalize return values to sane values
+  *pkernelLoad = MAX2<double>(*pkernelLoad, 0.0);
+  *pkernelLoad = MIN2<double>(*pkernelLoad, 1.0);
+
+  user_load = (udiff / (double)tdiff);
+  user_load = MAX2<double>(user_load, 0.0);
+  user_load = MIN2<double>(user_load, 1.0);
+
+  return user_load;
+}
+
+static int SCANF_ARGS(1, 2) parse_stat(_SCANFMT_ const char* fmt, ...) {
+  FILE *f;
+  va_list args;
+
+  va_start(args, fmt);
+
+  if ((f = open_statfile()) == NULL) {
+    va_end(args);
+    return OS_ERR;
+  }
+  for (;;) {
+    char line[80];
+    if (fgets(line, sizeof(line), f) != NULL) {
+      if (vsscanf(line, fmt, args) == 1) {
+        fclose(f);
+        va_end(args);
+        return OS_OK;
+      }
+    } else {
+        fclose(f);
+        va_end(args);
+        return OS_ERR;
+    }
+  }
+}
+
+static int get_noof_context_switches(uint64_t* switches) {
+  return parse_stat("ctxt " UINT64_FORMAT "\n", switches);
+}
+
+/** returns boot time in _seconds_ since epoch */
+static int get_boot_time(uint64_t* time) {
+  return parse_stat("btime " UINT64_FORMAT "\n", time);
+}
+
+static int perf_context_switch_rate(double* rate) {
+  static pthread_mutex_t contextSwitchLock = PTHREAD_MUTEX_INITIALIZER;
+  static uint64_t      lastTime;
+  static uint64_t      lastSwitches;
+  static double        lastRate;
+
+  uint64_t lt = 0;
+  int res = 0;
+
+  if (lastTime == 0) {
+    uint64_t tmp;
+    if (get_boot_time(&tmp) < 0) {
+      return OS_ERR;
+    }
+    lt = tmp * 1000;
+  }
+
+  res = OS_OK;
+
+  pthread_mutex_lock(&contextSwitchLock);
+  {
+
+    uint64_t sw;
+    s8 t, d;
+
+    if (lastTime == 0) {
+      lastTime = lt;
+    }
+
+    t = os::javaTimeMillis();
+    d = t - lastTime;
+
+    if (d == 0) {
+      *rate = lastRate;
+    } else if (!get_noof_context_switches(&sw)) {
+      *rate      = ( (double)(sw - lastSwitches) / d ) * 1000;
+      lastRate     = *rate;
+      lastSwitches = sw;
+      lastTime     = t;
+    } else {
+      *rate = 0;
+      res   = OS_ERR;
+    }
+    if (*rate <= 0) {
+      *rate = 0;
+      lastRate = 0;
+    }
+  }
+  pthread_mutex_unlock(&contextSwitchLock);
+
+  return res;
+}
+
+class CPUPerformanceInterface::CPUPerformance : public CHeapObj<mtInternal> {
+  friend class CPUPerformanceInterface;
+ private:
+  CPUPerfCounters _counters;
+
+  int cpu_load(int which_logical_cpu, double* cpu_load);
+  int context_switch_rate(double* rate);
+  int cpu_load_total_process(double* cpu_load);
+  int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad);
+
+ public:
+  CPUPerformance();
+  bool initialize();
+  ~CPUPerformance();
+};
+
+CPUPerformanceInterface::CPUPerformance::CPUPerformance() {
+  _counters.nProcs = os::active_processor_count();
+  _counters.cpus = NULL;
+}
+
+bool CPUPerformanceInterface::CPUPerformance::initialize() {
+  size_t tick_array_size = (_counters.nProcs +1) * sizeof(CPUPerfTicks);
+  _counters.cpus = (CPUPerfTicks*)NEW_C_HEAP_ARRAY(char, tick_array_size, mtInternal);
+  if (NULL == _counters.cpus) {
+    return false;
+  }
+  memset(_counters.cpus, 0, tick_array_size);
+
+  // For the CPU load total
+  get_total_ticks(-1, &_counters.cpus[_counters.nProcs]);
+
+  // For each CPU
+  for (int i = 0; i < _counters.nProcs; i++) {
+    get_total_ticks(i, &_counters.cpus[i]);
+  }
+  // For JVM load
+  get_jvm_ticks(&_counters.jvmTicks);
+
+  // initialize context switch system
+  // the double is only for init
+  double init_ctx_switch_rate;
+  perf_context_switch_rate(&init_ctx_switch_rate);
+
+  return true;
+}
+
+CPUPerformanceInterface::CPUPerformance::~CPUPerformance() {
+  if (_counters.cpus != NULL) {
+    FREE_C_HEAP_ARRAY(char, _counters.cpus);
+  }
+}
+
+int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) {
+  double u, s;
+  u = get_cpu_load(which_logical_cpu, &_counters, &s, CPU_LOAD_GLOBAL);
+  if (u < 0) {
+    *cpu_load = 0.0;
+    return OS_ERR;
+  }
+  // Cap total systemload to 1.0
+  *cpu_load = MIN2<double>((u + s), 1.0);
+  return OS_OK;
+}
+
+int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) {
+  double u, s;
+  u = get_cpu_load(-1, &_counters, &s, CPU_LOAD_VM_ONLY);
+  if (u < 0) {
+    *cpu_load = 0.0;
+    return OS_ERR;
+  }
+  *cpu_load = u + s;
+  return OS_OK;
+}
+
+int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) {
+  double u, s, t;
+
+  assert(pjvmUserLoad != NULL, "pjvmUserLoad not inited");
+  assert(pjvmKernelLoad != NULL, "pjvmKernelLoad not inited");
+  assert(psystemTotalLoad != NULL, "psystemTotalLoad not inited");
+
+  u = get_cpu_load(-1, &_counters, &s, CPU_LOAD_VM_ONLY);
+  if (u < 0) {
+    *pjvmUserLoad = 0.0;
+    *pjvmKernelLoad = 0.0;
+    *psystemTotalLoad = 0.0;
+    return OS_ERR;
+  }
+
+  cpu_load(-1, &t);
+  // clamp at user+system and 1.0
+  if (u + s > t) {
+    t = MIN2<double>(u + s, 1.0);
+  }
+
+  *pjvmUserLoad = u;
+  *pjvmKernelLoad = s;
+  *psystemTotalLoad = t;
+
+  return OS_OK;
+}
+
+int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) {
+  return perf_context_switch_rate(rate);
+}
+
+CPUPerformanceInterface::CPUPerformanceInterface() {
+  _impl = NULL;
+}
+
+bool CPUPerformanceInterface::initialize() {
+  _impl = new CPUPerformanceInterface::CPUPerformance();
+  return NULL == _impl ? false : _impl->initialize();
+}
+
+CPUPerformanceInterface::~CPUPerformanceInterface() {
+  if (_impl != NULL) {
+    delete _impl;
+  }
+}
+
+int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const {
+  return _impl->cpu_load(which_logical_cpu, cpu_load);
+}
+
+int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const {
+  return _impl->cpu_load_total_process(cpu_load);
+}
+
+int CPUPerformanceInterface::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) const {
+  return _impl->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotalLoad);
+}
+
+int CPUPerformanceInterface::context_switch_rate(double* rate) const {
+  return _impl->context_switch_rate(rate);
+}
+
+class SystemProcessInterface::SystemProcesses : public CHeapObj<mtInternal> {
+  friend class SystemProcessInterface;
+ private:
+  class ProcessIterator : public CHeapObj<mtInternal> {
+    friend class SystemProcessInterface::SystemProcesses;
+   private:
+    DIR*           _dir;
+    struct dirent* _entry;
+    bool           _valid;
+    char           _exeName[PATH_MAX];
+    char           _exePath[PATH_MAX];
+
+    ProcessIterator();
+    ~ProcessIterator();
+    bool initialize();
+
+    bool is_valid() const { return _valid; }
+    bool is_valid_entry(struct dirent* entry) const;
+    bool is_dir(const char* name) const;
+    int  fsize(const char* name, uint64_t& size) const;
+
+    char* allocate_string(const char* str) const;
+    void  get_exe_name();
+    char* get_exe_path();
+    char* get_cmdline();
+
+    int current(SystemProcess* process_info);
+    int next_process();
+  };
+
+  ProcessIterator* _iterator;
+  SystemProcesses();
+  bool initialize();
+  ~SystemProcesses();
+
+  //information about system processes
+  int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const;
+};
+
+bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_dir(const char* name) const {
+  struct stat mystat;
+  int ret_val = 0;
+
+  ret_val = stat(name, &mystat);
+  if (ret_val < 0) {
+    return false;
+  }
+  ret_val = S_ISDIR(mystat.st_mode);
+  return ret_val > 0;
+}
+
+int SystemProcessInterface::SystemProcesses::ProcessIterator::fsize(const char* name, uint64_t& size) const {
+  assert(name != NULL, "name pointer is NULL!");
+  size = 0;
+  struct stat fbuf;
+
+  if (stat(name, &fbuf) < 0) {
+    return OS_ERR;
+  }
+  size = fbuf.st_size;
+  return OS_OK;
+}
+
+// if it has a numeric name, is a directory and has a 'stat' file in it
+bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_valid_entry(struct dirent* entry) const {
+  char buffer[PATH_MAX];
+  uint64_t size = 0;
+
+  if (atoi(entry->d_name) != 0) {
+    jio_snprintf(buffer, PATH_MAX, "/proc/%s", entry->d_name);
+    buffer[PATH_MAX - 1] = '\0';
+
+    if (is_dir(buffer)) {
+      jio_snprintf(buffer, PATH_MAX, "/proc/%s/stat", entry->d_name);
+      buffer[PATH_MAX - 1] = '\0';
+      if (fsize(buffer, size) != OS_ERR) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+// get exe-name from /proc/<pid>/stat
+void SystemProcessInterface::SystemProcesses::ProcessIterator::get_exe_name() {
+  FILE* fp;
+  char  buffer[PATH_MAX];
+
+  jio_snprintf(buffer, PATH_MAX, "/proc/%s/stat", _entry->d_name);
+  buffer[PATH_MAX - 1] = '\0';
+  if ((fp = fopen(buffer, "r")) != NULL) {
+    if (fgets(buffer, PATH_MAX, fp) != NULL) {
+      char* start, *end;
+      // exe-name is between the first pair of ( and )
+      start = strchr(buffer, '(');
+      if (start != NULL && start[1] != '\0') {
+        start++;
+        end = strrchr(start, ')');
+        if (end != NULL) {
+          size_t len;
+          len = MIN2<size_t>(end - start, sizeof(_exeName) - 1);
+          memcpy(_exeName, start, len);
+          _exeName[len] = '\0';
+        }
+      }
+    }
+    fclose(fp);
+  }
+}
+
+// get command line from /proc/<pid>/cmdline
+char* SystemProcessInterface::SystemProcesses::ProcessIterator::get_cmdline() {
+  FILE* fp;
+  char  buffer[PATH_MAX];
+  char* cmdline = NULL;
+
+  jio_snprintf(buffer, PATH_MAX, "/proc/%s/cmdline", _entry->d_name);
+  buffer[PATH_MAX - 1] = '\0';
+  if ((fp = fopen(buffer, "r")) != NULL) {
+    size_t size = 0;
+    char   dummy;
+
+    // find out how long the file is (stat always returns 0)
+    while (fread(&dummy, 1, 1, fp) == 1) {
+      size++;
+    }
+    if (size > 0) {
+      cmdline = NEW_C_HEAP_ARRAY(char, size + 1, mtInternal);
+      if (cmdline != NULL) {
+        cmdline[0] = '\0';
+        if (fseek(fp, 0, SEEK_SET) == 0) {
+          if (fread(cmdline, 1, size, fp) == size) {
+            // the file has the arguments separated by '\0',
+            // so we translate '\0' to ' '
+            for (size_t i = 0; i < size; i++) {
+              if (cmdline[i] == '\0') {
+                cmdline[i] = ' ';
+              }
+            }
+            cmdline[size] = '\0';
+          }
+        }
+      }
+    }
+    fclose(fp);
+  }
+  return cmdline;
+}
+
+// get full path to exe from /proc/<pid>/exe symlink
+char* SystemProcessInterface::SystemProcesses::ProcessIterator::get_exe_path() {
+  char buffer[PATH_MAX];
+
+  jio_snprintf(buffer, PATH_MAX, "/proc/%s/exe", _entry->d_name);
+  buffer[PATH_MAX - 1] = '\0';
+  return realpath(buffer, _exePath);
+}
+
+char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const {
+  if (str != NULL) {
+    size_t len = strlen(str);
+    char* tmp = NEW_C_HEAP_ARRAY(char, len+1, mtInternal);
+    strncpy(tmp, str, len);
+    tmp[len] = '\0';
+    return tmp;
+  }
+  return NULL;
+}
+
+int SystemProcessInterface::SystemProcesses::ProcessIterator::current(SystemProcess* process_info) {
+  if (!is_valid()) {
+    return OS_ERR;
+  }
+
+  process_info->set_pid(atoi(_entry->d_name));
+
+  get_exe_name();
+  process_info->set_name(allocate_string(_exeName));
+
+  if (get_exe_path() != NULL) {
+     process_info->set_path(allocate_string(_exePath));
+  }
+
+  char* cmdline = NULL;
+  cmdline = get_cmdline();
+  if (cmdline != NULL) {
+    process_info->set_command_line(allocate_string(cmdline));
+    FREE_C_HEAP_ARRAY(char, cmdline);
+  }
+
+  return OS_OK;
+}
+
+int SystemProcessInterface::SystemProcesses::ProcessIterator::next_process() {
+  struct dirent* entry;
+
+  if (!is_valid()) {
+    return OS_ERR;
+  }
+
+  do {
+      entry = os::readdir(_dir, _entry);
+    if (entry == NULL) {
+      // error
+      _valid = false;
+      return OS_ERR;
+    }
+    if (_entry == NULL) {
+      // reached end
+      _valid = false;
+      return OS_ERR;
+    }
+  } while(!is_valid_entry(_entry));
+
+  _valid = true;
+  return OS_OK;
+}
+
+SystemProcessInterface::SystemProcesses::ProcessIterator::ProcessIterator() {
+  _dir = NULL;
+  _entry = NULL;
+  _valid = false;
+}
+
+bool SystemProcessInterface::SystemProcesses::ProcessIterator::initialize() {
+  _dir = opendir("/proc");
+  _entry = (struct dirent*)NEW_C_HEAP_ARRAY(char, sizeof(struct dirent) + NAME_MAX + 1, mtInternal);
+  if (NULL == _entry) {
+    return false;
+  }
+  _valid = true;
+  next_process();
+
+  return true;
+}
+
+SystemProcessInterface::SystemProcesses::ProcessIterator::~ProcessIterator() {
+  if (_entry != NULL) {
+    FREE_C_HEAP_ARRAY(char, _entry);
+  }
+  if (_dir != NULL) {
+    closedir(_dir);
+  }
+}
+
+SystemProcessInterface::SystemProcesses::SystemProcesses() {
+  _iterator = NULL;
+}
+
+bool SystemProcessInterface::SystemProcesses::initialize() {
+  _iterator = new SystemProcessInterface::SystemProcesses::ProcessIterator();
+  return NULL == _iterator ? false : _iterator->initialize();
+}
+
+SystemProcessInterface::SystemProcesses::~SystemProcesses() {
+  if (_iterator != NULL) {
+    delete _iterator;
+  }
+}
+
+int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const {
+  assert(system_processes != NULL, "system_processes pointer is NULL!");
+  assert(no_of_sys_processes != NULL, "system_processes counter pointers is NULL!");
+  assert(_iterator != NULL, "iterator is NULL!");
+
+  // initialize pointers
+  *no_of_sys_processes = 0;
+  *system_processes = NULL;
+
+  while (_iterator->is_valid()) {
+    SystemProcess* tmp = new SystemProcess();
+    _iterator->current(tmp);
+
+    //if already existing head
+    if (*system_processes != NULL) {
+      //move "first to second"
+      tmp->set_next(*system_processes);
+    }
+    // new head
+    *system_processes = tmp;
+    // increment
+    (*no_of_sys_processes)++;
+    // step forward
+    _iterator->next_process();
+  }
+  return OS_OK;
+}
+
+int SystemProcessInterface::system_processes(SystemProcess** system_procs, int* no_of_sys_processes) const {
+  return _impl->system_processes(system_procs, no_of_sys_processes);
+}
+
+SystemProcessInterface::SystemProcessInterface() {
+  _impl = NULL;
+}
+
+bool SystemProcessInterface::initialize() {
+  _impl = new SystemProcessInterface::SystemProcesses();
+  return NULL == _impl ? false : _impl->initialize();
+}
+
+SystemProcessInterface::~SystemProcessInterface() {
+  if (_impl != NULL) {
+    delete _impl;
+  }
+}
+
+CPUInformationInterface::CPUInformationInterface() {
+  _cpu_info = NULL;
+}
+
+bool CPUInformationInterface::initialize() {
+  _cpu_info = new CPUInformation();
+  if (NULL == _cpu_info) {
+    return false;
+  }
+  _cpu_info->set_number_of_hardware_threads(VM_Version_Ext::number_of_threads());
+  _cpu_info->set_number_of_cores(VM_Version_Ext::number_of_cores());
+  _cpu_info->set_number_of_sockets(VM_Version_Ext::number_of_sockets());
+  _cpu_info->set_cpu_name(VM_Version_Ext::cpu_name());
+  _cpu_info->set_cpu_description(VM_Version_Ext::cpu_description());
+
+  return true;
+}
+
+CPUInformationInterface::~CPUInformationInterface() {
+  if (_cpu_info != NULL) {
+    if (_cpu_info->cpu_name() != NULL) {
+      const char* cpu_name = _cpu_info->cpu_name();
+      FREE_C_HEAP_ARRAY(char, cpu_name);
+      _cpu_info->set_cpu_name(NULL);
+    }
+    if (_cpu_info->cpu_description() != NULL) {
+       const char* cpu_desc = _cpu_info->cpu_description();
+       FREE_C_HEAP_ARRAY(char, cpu_desc);
+      _cpu_info->set_cpu_description(NULL);
+    }
+    delete _cpu_info;
+  }
+}
+
+int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {
+  if (_cpu_info == NULL) {
+    return OS_ERR;
+  }
+
+  cpu_info = *_cpu_info; // shallow copy assignment
+  return OS_OK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/os/solaris/os_perf_solaris.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,756 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jvm.h"
+#include "memory/allocation.inline.hpp"
+#include "runtime/os.hpp"
+#include "runtime/os_perf.hpp"
+#include "os_solaris.inline.hpp"
+#include "utilities/macros.hpp"
+
+#include CPU_HEADER(vm_version_ext)
+
+#include <sys/types.h>
+#include <procfs.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <kstat.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/sysinfo.h>
+#include <sys/lwp.h>
+#include <pthread.h>
+#include <time.h>
+#include <utmpx.h>
+#include <dlfcn.h>
+#include <sys/loadavg.h>
+#include <limits.h>
+
+static const double NANOS_PER_SEC = 1000000000.0;
+
+struct CPUPerfTicks {
+  kstat_t* kstat;
+  uint64_t last_idle;
+  uint64_t last_total;
+  double   last_ratio;
+};
+
+struct CPUPerfCounters {
+  int           nProcs;
+  CPUPerfTicks* jvmTicks;
+  kstat_ctl_t*  kstat_ctrl;
+};
+
+static int get_info(const char* path, void* info, size_t s, off_t o) {
+  assert(path != NULL, "path is NULL!");
+  assert(info != NULL, "info is NULL!");
+
+  int fd = -1;
+
+  if ((fd = open(path, O_RDONLY)) < 0) {
+    return OS_ERR;
+  }
+  if (pread(fd, info, s, o) != s) {
+    close(fd);
+    return OS_ERR;
+  }
+  close(fd);
+  return OS_OK;
+}
+
+static int get_psinfo2(void* info, size_t s, off_t o) {
+  return get_info("/proc/self/psinfo", info, s, o);
+}
+
+static int get_psinfo(psinfo_t* info) {
+  return get_psinfo2(info, sizeof(*info), 0);
+}
+
+static int get_psinfo(char* file, psinfo_t* info) {
+  assert(file != NULL, "file is NULL!");
+  assert(info != NULL, "info is NULL!");
+  return get_info(file, info, sizeof(*info), 0);
+}
+
+
+static int get_usage(prusage_t* usage) {
+  assert(usage != NULL, "usage is NULL!");
+  return get_info("/proc/self/usage", usage, sizeof(*usage), 0);
+}
+
+static int read_cpustat(kstat_ctl_t* kstat_ctrl, CPUPerfTicks* load, cpu_stat_t* cpu_stat) {
+  assert(kstat_ctrl != NULL, "kstat_ctrl pointer is NULL!");
+  assert(load != NULL, "load pointer is NULL!");
+  assert(cpu_stat != NULL, "cpu_stat pointer is NULL!");
+
+  if (load->kstat == NULL) {
+    // no handle.
+    return OS_ERR;
+  }
+  if (kstat_read(kstat_ctrl, load->kstat, cpu_stat) == OS_ERR) {
+    // disable handle for this CPU
+     load->kstat = NULL;
+     return OS_ERR;
+  }
+  return OS_OK;
+}
+
+static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters) {
+  assert(counters != NULL, "counters pointer is NULL!");
+
+  cpu_stat_t  cpu_stat = {0};
+
+  if (which_logical_cpu >= counters->nProcs) {
+    return .0;
+  }
+
+  CPUPerfTicks load = counters->jvmTicks[which_logical_cpu];
+  if (read_cpustat(counters->kstat_ctrl, &load, &cpu_stat) != OS_OK) {
+    return .0;
+  }
+
+  uint_t* usage = cpu_stat.cpu_sysinfo.cpu;
+  if (usage == NULL) {
+    return .0;
+  }
+
+  uint64_t c_idle  = usage[CPU_IDLE];
+  uint64_t c_total = 0;
+
+  for (int i = 0; i < CPU_STATES; i++) {
+    c_total += usage[i];
+  }
+
+  // Calculate diff against previous snapshot
+  uint64_t d_idle  = c_idle - load.last_idle;
+  uint64_t d_total = c_total - load.last_total;
+
+  /** update if weve moved */
+  if (d_total > 0) {
+    // Save current values for next time around
+    load.last_idle  = c_idle;
+    load.last_total = c_total;
+    load.last_ratio = (double) (d_total - d_idle) / d_total;
+  }
+
+  return load.last_ratio;
+}
+
+static int get_boot_time(uint64_t* time) {
+  assert(time != NULL, "time pointer is NULL!");
+  setutxent();
+  for(;;) {
+    struct utmpx* u;
+    if ((u = getutxent()) == NULL) {
+      break;
+    }
+    if (u->ut_type == BOOT_TIME) {
+      *time = u->ut_xtime;
+      endutxent();
+      return OS_OK;
+    }
+  }
+  endutxent();
+  return OS_ERR;
+}
+
+static int get_noof_context_switches(CPUPerfCounters* counters, uint64_t* switches) {
+  assert(switches != NULL, "switches pointer is NULL!");
+  assert(counters != NULL, "counter pointer is NULL!");
+  *switches = 0;
+  uint64_t s = 0;
+
+  // Collect data from all CPUs
+  for (int i = 0; i < counters->nProcs; i++) {
+    cpu_stat_t cpu_stat = {0};
+    CPUPerfTicks load = counters->jvmTicks[i];
+
+    if (read_cpustat(counters->kstat_ctrl, &load, &cpu_stat) == OS_OK) {
+      s += cpu_stat.cpu_sysinfo.pswitch;
+    } else {
+      //fail fast...
+      return OS_ERR;
+    }
+  }
+  *switches = s;
+  return OS_OK;
+}
+
+static int perf_context_switch_rate(CPUPerfCounters* counters, double* rate) {
+  assert(counters != NULL, "counters is NULL!");
+  assert(rate != NULL, "rate pointer is NULL!");
+  static pthread_mutex_t contextSwitchLock = PTHREAD_MUTEX_INITIALIZER;
+  static uint64_t lastTime = 0;
+  static uint64_t lastSwitches = 0;
+  static double   lastRate = 0.0;
+
+  uint64_t lt = 0;
+  int res = 0;
+
+  if (lastTime == 0) {
+    uint64_t tmp;
+    if (get_boot_time(&tmp) < 0) {
+      return OS_ERR;
+    }
+    lt = tmp * 1000;
+  }
+
+  res = OS_OK;
+
+  pthread_mutex_lock(&contextSwitchLock);
+  {
+
+    uint64_t sw = 0;
+    clock_t t, d;
+
+    if (lastTime == 0) {
+      lastTime = lt;
+    }
+
+    t = clock();
+    d = t - lastTime;
+
+    if (d == 0) {
+      *rate = lastRate;
+    } else if (get_noof_context_switches(counters, &sw)== OS_OK) {
+      *rate      = ((double)(sw - lastSwitches) / d) * 1000;
+      lastRate     = *rate;
+      lastSwitches = sw;
+      lastTime     = t;
+    } else {
+      *rate = 0.0;
+      res   = OS_ERR;
+    }
+    if (*rate < 0.0) {
+      *rate = 0.0;
+      lastRate = 0.0;
+    }
+  }
+  pthread_mutex_unlock(&contextSwitchLock);
+  return res;
+ }
+
+
+
+class CPUPerformanceInterface::CPUPerformance : public CHeapObj<mtInternal> {
+   friend class CPUPerformanceInterface;
+ private:
+  CPUPerfCounters _counters;
+  int cpu_load(int which_logical_cpu, double* cpu_load);
+  int context_switch_rate(double* rate);
+  int cpu_load_total_process(double* cpu_load);
+  int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad);
+
+  CPUPerformance();
+  ~CPUPerformance();
+  bool initialize();
+};
+
+CPUPerformanceInterface::CPUPerformance::CPUPerformance() {
+  _counters.nProcs = 0;
+  _counters.jvmTicks = NULL;
+  _counters.kstat_ctrl = NULL;
+}
+
+bool CPUPerformanceInterface::CPUPerformance::initialize() {
+  // initialize kstat control structure,
+  _counters.kstat_ctrl = kstat_open();
+  assert(_counters.kstat_ctrl != NULL, "error initializing kstat control structure!");
+
+  if (NULL == _counters.kstat_ctrl) {
+    return false;
+  }
+
+  // Get number of CPU(s)
+  if ((_counters.nProcs = sysconf(_SC_NPROCESSORS_ONLN)) == OS_ERR) {
+    // ignore error?
+    _counters.nProcs = 1;
+  }
+
+  assert(_counters.nProcs > 0, "no CPUs detected in sysconf call!");
+  if (_counters.nProcs == 0) {
+    return false;
+  }
+
+  // Data structure(s) for saving CPU load (one per CPU)
+  size_t tick_array_size = _counters.nProcs * sizeof(CPUPerfTicks);
+  _counters.jvmTicks = (CPUPerfTicks*)NEW_C_HEAP_ARRAY(char, tick_array_size, mtInternal);
+  if (NULL == _counters.jvmTicks) {
+    return false;
+  }
+  memset(_counters.jvmTicks, 0, tick_array_size);
+
+  // Get kstat cpu_stat counters for every CPU
+  // loop over kstat to find our cpu_stat(s)
+  int i = 0;
+  for (kstat_t* kstat = _counters.kstat_ctrl->kc_chain; kstat != NULL; kstat = kstat->ks_next) {
+    if (strncmp(kstat->ks_module, "cpu_stat", 8) == 0) {
+      if (kstat_read(_counters.kstat_ctrl, kstat, NULL) == OS_ERR) {
+        continue;
+      }
+      if (i == _counters.nProcs) {
+        // more cpu_stats than reported CPUs
+        break;
+      }
+      _counters.jvmTicks[i++].kstat = kstat;
+    }
+  }
+  return true;
+}
+
+CPUPerformanceInterface::CPUPerformance::~CPUPerformance() {
+  if (_counters.jvmTicks != NULL) {
+    FREE_C_HEAP_ARRAY(char, _counters.jvmTicks);
+  }
+  if (_counters.kstat_ctrl != NULL) {
+    kstat_close(_counters.kstat_ctrl);
+  }
+}
+
+int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) {
+  assert(cpu_load != NULL, "cpu_load pointer is NULL!");
+  double t = .0;
+  if (-1 == which_logical_cpu) {
+    for (int i = 0; i < _counters.nProcs; i++) {
+      t += get_cpu_load(i, &_counters);
+    }
+    // Cap total systemload to 1.0
+    t = MIN2<double>((t / _counters.nProcs), 1.0);
+  } else {
+    t = MIN2<double>(get_cpu_load(which_logical_cpu, &_counters), 1.0);
+  }
+
+  *cpu_load = t;
+  return OS_OK;
+}
+
+int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) {
+  assert(cpu_load != NULL, "cpu_load pointer is NULL!");
+
+  psinfo_t info;
+
+  // Get the percentage of "recent cpu usage" from all the lwp:s in the JVM:s
+  // process. This is returned as a value between 0.0 and 1.0 multiplied by 0x8000.
+  if (get_psinfo2(&info.pr_pctcpu, sizeof(info.pr_pctcpu), offsetof(psinfo_t, pr_pctcpu)) != 0) {
+    *cpu_load = 0.0;
+    return OS_ERR;
+  }
+  *cpu_load = (double) info.pr_pctcpu / 0x8000;
+  return OS_OK;
+}
+
+int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) {
+  assert(pjvmUserLoad != NULL, "pjvmUserLoad not inited");
+  assert(pjvmKernelLoad != NULL, "pjvmKernelLoad not inited");
+  assert(psystemTotalLoad != NULL, "psystemTotalLoad not inited");
+
+  static uint64_t lastTime;
+  static uint64_t lastUser, lastKernel;
+  static double lastUserRes, lastKernelRes;
+
+  pstatus_t pss;
+  psinfo_t  info;
+
+  *pjvmKernelLoad = *pjvmUserLoad = *psystemTotalLoad = 0;
+  if (get_info("/proc/self/status", &pss.pr_utime, sizeof(timestruc_t)*2, offsetof(pstatus_t, pr_utime)) != 0) {
+    return OS_ERR;
+  }
+
+  if (get_psinfo(&info) != 0) {
+    return OS_ERR;
+  }
+
+  // get the total time in user, kernel and total time
+  // check ratios for 'lately' and multiply the 'recent load'.
+  uint64_t time   = (info.pr_time.tv_sec * NANOS_PER_SEC) + info.pr_time.tv_nsec;
+  uint64_t user   = (pss.pr_utime.tv_sec * NANOS_PER_SEC) + pss.pr_utime.tv_nsec;
+  uint64_t kernel = (pss.pr_stime.tv_sec * NANOS_PER_SEC) + pss.pr_stime.tv_nsec;
+  uint64_t diff   = time - lastTime;
+  double load     = (double) info.pr_pctcpu / 0x8000;
+
+  if (diff > 0) {
+    lastUserRes = (load * (user - lastUser)) / diff;
+    lastKernelRes = (load * (kernel - lastKernel)) / diff;
+
+    // BUG9182835 - patch for clamping these values to sane ones.
+    lastUserRes   = MIN2<double>(1, lastUserRes);
+    lastUserRes   = MAX2<double>(0, lastUserRes);
+    lastKernelRes = MIN2<double>(1, lastKernelRes);
+    lastKernelRes = MAX2<double>(0, lastKernelRes);
+  }
+
+  double t = .0;
+  cpu_load(-1, &t);
+  // clamp at user+system and 1.0
+  if (lastUserRes + lastKernelRes > t) {
+    t = MIN2<double>(lastUserRes + lastKernelRes, 1.0);
+  }
+
+  *pjvmUserLoad   = lastUserRes;
+  *pjvmKernelLoad = lastKernelRes;
+  *psystemTotalLoad = t;
+
+  lastTime   = time;
+  lastUser   = user;
+  lastKernel = kernel;
+
+  return OS_OK;
+}
+
+int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) {
+  return perf_context_switch_rate(&_counters, rate);
+}
+
+CPUPerformanceInterface::CPUPerformanceInterface() {
+  _impl = NULL;
+}
+
+bool CPUPerformanceInterface::initialize() {
+  _impl = new CPUPerformanceInterface::CPUPerformance();
+  return _impl != NULL && _impl->initialize();
+}
+
+CPUPerformanceInterface::~CPUPerformanceInterface(void) {
+  if (_impl != NULL) {
+    delete _impl;
+  }
+}
+
+int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const {
+  return _impl->cpu_load(which_logical_cpu, cpu_load);
+}
+
+int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const {
+  return _impl->cpu_load_total_process(cpu_load);
+}
+
+int CPUPerformanceInterface::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) const {
+  return _impl->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotalLoad);
+}
+
+int CPUPerformanceInterface::context_switch_rate(double* rate) const {
+  return _impl->context_switch_rate(rate);
+}
+
+class SystemProcessInterface::SystemProcesses : public CHeapObj<mtInternal> {
+  friend class SystemProcessInterface;
+ private:
+  class ProcessIterator : public CHeapObj<mtInternal> {
+    friend class SystemProcessInterface::SystemProcesses;
+   private:
+    DIR*           _dir;
+    struct dirent* _entry;
+    bool           _valid;
+
+    ProcessIterator();
+    ~ProcessIterator();
+    bool initialize();
+
+    bool is_valid() const { return _valid; }
+    bool is_valid_entry(struct dirent* const entry) const;
+    bool is_dir(const char* const name) const;
+    char* allocate_string(const char* const str) const;
+    int current(SystemProcess* const process_info);
+    int next_process();
+  };
+
+  ProcessIterator* _iterator;
+  SystemProcesses();
+  bool initialize();
+  ~SystemProcesses();
+
+  //information about system processes
+  int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const;
+};
+
+bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_dir(const char* name) const {
+  struct stat64 mystat;
+  int ret_val = 0;
+
+  ret_val = ::stat64(name, &mystat);
+
+  if (ret_val < 0) {
+    return false;
+  }
+  ret_val = S_ISDIR(mystat.st_mode);
+  return ret_val > 0;
+}
+
+// if it has a numeric name, is a directory and has a 'psinfo' file in it
+bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_valid_entry(struct dirent* entry) const {
+  // ignore the "." and ".." directories
+  if ((strcmp(entry->d_name, ".") == 0) ||
+      (strcmp(entry->d_name, "..") == 0)) {
+    return false;
+  }
+
+  char buffer[PATH_MAX] = {0};
+  uint64_t size = 0;
+  bool result = false;
+  FILE *fp = NULL;
+
+  if (atoi(entry->d_name) != 0) {
+    jio_snprintf(buffer, PATH_MAX, "/proc/%s", entry->d_name);
+
+    if (is_dir(buffer)) {
+      memset(buffer, 0, PATH_MAX);
+      jio_snprintf(buffer, PATH_MAX, "/proc/%s/psinfo", entry->d_name);
+      if ((fp = fopen(buffer, "r")) != NULL) {
+        int nread = 0;
+        psinfo_t psinfo_data;
+        if ((nread = fread(&psinfo_data, 1, sizeof(psinfo_t), fp)) != -1) {
+          // only considering system process owned by root
+          if (psinfo_data.pr_uid == 0) {
+            result = true;
+          }
+        }
+      }
+    }
+  }
+
+  if (fp != NULL) {
+    fclose(fp);
+  }
+
+  return result;
+}
+
+char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const {
+  if (str != NULL) {
+    size_t len = strlen(str);
+    char* tmp = NEW_C_HEAP_ARRAY(char, len+1, mtInternal);
+    strncpy(tmp, str, len);
+    tmp[len] = '\0';
+    return tmp;
+  }
+  return NULL;
+}
+
+int SystemProcessInterface::SystemProcesses::ProcessIterator::current(SystemProcess* process_info) {
+  if (!is_valid()) {
+    return OS_ERR;
+  }
+
+  char psinfo_path[PATH_MAX] = {0};
+  jio_snprintf(psinfo_path, PATH_MAX, "/proc/%s/psinfo", _entry->d_name);
+
+  FILE *fp = NULL;
+  if ((fp = fopen(psinfo_path, "r")) == NULL) {
+    return OS_ERR;
+  }
+
+  int nread = 0;
+  psinfo_t psinfo_data;
+  if ((nread = fread(&psinfo_data, 1, sizeof(psinfo_t), fp)) == -1) {
+    fclose(fp);
+    return OS_ERR;
+  }
+
+  char *exe_path = NULL;
+  if ((psinfo_data.pr_fname != NULL) &&
+      (psinfo_data.pr_psargs != NULL)) {
+    char *path_substring = strstr(psinfo_data.pr_psargs, psinfo_data.pr_fname);
+    if (path_substring != NULL) {
+      int len = path_substring - psinfo_data.pr_psargs;
+      exe_path = NEW_C_HEAP_ARRAY(char, len+1, mtInternal);
+      if (exe_path != NULL) {
+        jio_snprintf(exe_path, len, "%s", psinfo_data.pr_psargs);
+        exe_path[len] = '\0';
+      }
+    }
+  }
+
+  process_info->set_pid(atoi(_entry->d_name));
+  process_info->set_name(allocate_string(psinfo_data.pr_fname));
+  process_info->set_path(allocate_string(exe_path));
+  process_info->set_command_line(allocate_string(psinfo_data.pr_psargs));
+
+  if (exe_path != NULL) {
+    FREE_C_HEAP_ARRAY(char, exe_path);
+  }
+
+  if (fp != NULL) {
+    fclose(fp);
+  }
+
+  return OS_OK;
+}
+
+int SystemProcessInterface::SystemProcesses::ProcessIterator::next_process() {
+  struct dirent* entry;
+
+  if (!is_valid()) {
+    return OS_ERR;
+  }
+
+  do {
+    if ((entry = os::readdir(_dir, _entry)) == NULL) {
+      // error
+      _valid = false;
+      return OS_ERR;
+    }
+  } while(!is_valid_entry(_entry));
+
+  _valid = true;
+  return OS_OK;
+}
+
+SystemProcessInterface::SystemProcesses::ProcessIterator::ProcessIterator() {
+  _dir = NULL;
+  _entry = NULL;
+  _valid = false;
+}
+
+bool SystemProcessInterface::SystemProcesses::ProcessIterator::initialize() {
+  _dir = opendir("/proc");
+  _entry = (struct dirent*)NEW_C_HEAP_ARRAY(char, sizeof(struct dirent) + _PC_NAME_MAX + 1, mtInternal);
+  if (NULL == _entry) {
+    return false;
+  }
+  _valid = true;
+  next_process();
+
+  return true;
+}
+
+SystemProcessInterface::SystemProcesses::ProcessIterator::~ProcessIterator() {
+  if (_entry != NULL) {
+    FREE_C_HEAP_ARRAY(char, _entry);
+  }
+
+  if (_dir != NULL) {
+    closedir(_dir);
+  }
+}
+
+SystemProcessInterface::SystemProcesses::SystemProcesses() {
+  _iterator = NULL;
+}
+
+bool SystemProcessInterface::SystemProcesses::initialize() {
+  _iterator = new SystemProcessInterface::SystemProcesses::ProcessIterator();
+  return _iterator != NULL && _iterator->initialize();
+}
+
+SystemProcessInterface::SystemProcesses::~SystemProcesses() {
+  if (_iterator != NULL) {
+    delete _iterator;
+  }
+}
+
+int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const {
+  assert(system_processes != NULL, "system_processes pointer is NULL!");
+  assert(no_of_sys_processes != NULL, "system_processes counter pointer is NULL!");
+  assert(_iterator != NULL, "iterator is NULL!");
+
+  // initialize pointers
+  *no_of_sys_processes = 0;
+  *system_processes = NULL;
+
+  while (_iterator->is_valid()) {
+    SystemProcess* tmp = new SystemProcess();
+    _iterator->current(tmp);
+
+    //if already existing head
+    if (*system_processes != NULL) {
+      //move "first to second"
+      tmp->set_next(*system_processes);
+    }
+    // new head
+    *system_processes = tmp;
+    // increment
+    (*no_of_sys_processes)++;
+    // step forward
+    _iterator->next_process();
+  }
+  return OS_OK;
+}
+
+int SystemProcessInterface::system_processes(SystemProcess** system_procs, int* no_of_sys_processes) const {
+  return _impl->system_processes(system_procs, no_of_sys_processes);
+}
+
+SystemProcessInterface::SystemProcessInterface() {
+  _impl = NULL;
+}
+
+bool SystemProcessInterface::initialize() {
+  _impl = new SystemProcessInterface::SystemProcesses();
+  return _impl != NULL && _impl->initialize();
+
+}
+
+SystemProcessInterface::~SystemProcessInterface() {
+  if (_impl != NULL) {
+    delete _impl;
+  }
+}
+
+CPUInformationInterface::CPUInformationInterface() {
+  _cpu_info = NULL;
+}
+
+bool CPUInformationInterface::initialize() {
+  _cpu_info = new CPUInformation();
+  if (_cpu_info == NULL) {
+    return false;
+  }
+  _cpu_info->set_number_of_hardware_threads(VM_Version_Ext::number_of_threads());
+  _cpu_info->set_number_of_cores(VM_Version_Ext::number_of_cores());
+  _cpu_info->set_number_of_sockets(VM_Version_Ext::number_of_sockets());
+  _cpu_info->set_cpu_name(VM_Version_Ext::cpu_name());
+  _cpu_info->set_cpu_description(VM_Version_Ext::cpu_description());
+  return true;
+}
+
+CPUInformationInterface::~CPUInformationInterface() {
+  if (_cpu_info != NULL) {
+    if (_cpu_info->cpu_name() != NULL) {
+      const char* cpu_name = _cpu_info->cpu_name();
+      FREE_C_HEAP_ARRAY(char, cpu_name);
+      _cpu_info->set_cpu_name(NULL);
+    }
+    if (_cpu_info->cpu_description() != NULL) {
+      const char* cpu_desc = _cpu_info->cpu_description();
+      FREE_C_HEAP_ARRAY(char, cpu_desc);
+      _cpu_info->set_cpu_description(NULL);
+    }
+    delete _cpu_info;
+  }
+}
+
+int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {
+  if (_cpu_info == NULL) {
+    return OS_ERR;
+  }
+
+  cpu_info = *_cpu_info; // shallow copy assignment
+  return OS_OK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/os/windows/os_perf_windows.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,1332 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "logging/log.hpp"
+#include "memory/allocation.inline.hpp"
+#include "memory/resourceArea.hpp"
+#include "pdh_interface.hpp"
+#include "runtime/os_perf.hpp"
+#include "runtime/os.hpp"
+#include "vm_version_ext_x86.hpp"
+#include "utilities/macros.hpp"
+#include <math.h>
+#include <psapi.h>
+#include <TlHelp32.h>
+
+/*
+ * Windows provides a vast plethora of performance objects and counters,
+ * consumption of which is assisted using the Performance Data Helper (PDH) interface.
+ * We import a selected few api entry points from PDH, see pdh_interface.hpp.
+ *
+ * The code located in this file is to a large extent an abstraction over much of the
+ * plumbing needed to start consuming an object and/or counter of choice.
+ *
+ */
+
+ /*
+ * How to use:
+ * 1. Create query
+ * 2. Add counters to the query
+ * 3. Collect the performance data using the query
+ * 4. Display the performance data using the counters associated with the query
+ * 5. Destroy query (counter destruction implied)
+ */
+
+/*
+ * Every PDH artifact, like processor, process, thread, memory, and so forth are
+ * identified with an index that is always the same irrespective
+ * of the localized version of the operating system or service pack installed.
+ * INFO: Using PDH APIs Correctly in a Localized Language (Q287159)
+ *   http://support.microsoft.com/default.aspx?scid=kb;EN-US;q287159
+ *
+ * To find the correct index for an object or counter, inspect the registry key / value:
+ * [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009\Counter]
+ *
+ * some common PDH indexes
+ */
+static const DWORD PDH_PROCESSOR_IDX = 238;
+static const DWORD PDH_PROCESSOR_TIME_IDX = 6;
+static const DWORD PDH_PRIV_PROCESSOR_TIME_IDX = 144;
+static const DWORD PDH_PROCESS_IDX = 230;
+static const DWORD PDH_ID_PROCESS_IDX = 784;
+static const DWORD PDH_CONTEXT_SWITCH_RATE_IDX = 146;
+static const DWORD PDH_SYSTEM_IDX = 2;
+
+/* useful pdh fmt's */
+static const char* const OBJECT_COUNTER_FMT = "\\%s\\%s";
+static const size_t OBJECT_COUNTER_FMT_LEN = 2;
+static const char* const OBJECT_WITH_INSTANCES_COUNTER_FMT = "\\%s(%s)\\%s";
+static const size_t OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN = 4;
+static const char* const PROCESS_OBJECT_INSTANCE_COUNTER_FMT = "\\%s(%s#%s)\\%s";
+static const size_t PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN = 5;
+
+static const char* process_image_name = NULL; // for example, "java" but could have another image name
+static char* pdh_IDProcess_counter_fmt = NULL;   // "\Process(java#%d)\ID Process" */
+
+// Need to limit how often we update a query to minimize the heisenberg effect.
+// (PDH behaves erratically if the counters are queried too often, especially counters that
+// store and use values from two consecutive updates, like cpu load.)
+static const int min_update_interval_millis = 500;
+
+/*
+* Structs for PDH queries.
+*/
+typedef struct {
+  HQUERY query;
+  s8     lastUpdate; // Last time query was updated (current millis).
+} UpdateQueryS, *UpdateQueryP;
+
+
+typedef struct {
+  UpdateQueryS query;
+  HCOUNTER     counter;
+  bool         initialized;
+} CounterQueryS, *CounterQueryP;
+
+typedef struct {
+  UpdateQueryS query;
+  HCOUNTER*    counters;
+  int          noOfCounters;
+  bool         initialized;
+} MultiCounterQueryS, *MultiCounterQueryP;
+
+typedef struct {
+  MultiCounterQueryP queries;
+  int                size;
+  bool               initialized;
+} MultiCounterQuerySetS, *MultiCounterQuerySetP;
+
+static void pdh_cleanup(HQUERY* const query, HCOUNTER* const counter) {
+  if (counter != NULL && *counter != NULL) {
+    PdhDll::PdhRemoveCounter(*counter);
+    *counter = NULL;
+  }
+  if (query != NULL && *query != NULL) {
+    PdhDll::PdhCloseQuery(*query);
+    *query = NULL;
+  }
+}
+
+static CounterQueryP create_counter_query() {
+  CounterQueryP const query = NEW_C_HEAP_ARRAY(CounterQueryS, 1, mtInternal);
+  memset(query, 0, sizeof(CounterQueryS));
+  return query;
+}
+
+static void destroy_counter_query(CounterQueryP query) {
+  assert(query != NULL, "invariant");
+  pdh_cleanup(&query->query.query, &query->counter);
+  FREE_C_HEAP_ARRAY(CounterQueryS, query);
+}
+
+static MultiCounterQueryP create_multi_counter_query() {
+  MultiCounterQueryP const query = NEW_C_HEAP_ARRAY(MultiCounterQueryS, 1, mtInternal);
+  memset(query, 0, sizeof(MultiCounterQueryS));
+  return query;
+}
+
+static void destroy_counter_query(MultiCounterQueryP counter_query) {
+  if (counter_query != NULL) {
+    for (int i = 0; i < counter_query->noOfCounters; ++i) {
+      pdh_cleanup(NULL, &counter_query->counters[i]);
+    }
+    FREE_C_HEAP_ARRAY(char, counter_query->counters);
+    pdh_cleanup(&counter_query->query.query, NULL);
+    FREE_C_HEAP_ARRAY(MultiCounterQueryS, counter_query);
+  }
+}
+
+static void destroy_counter_query(MultiCounterQuerySetP counter_query_set) {
+  for (int i = 0; i < counter_query_set->size; i++) {
+    for (int j = 0; j < counter_query_set->queries[i].noOfCounters; ++j) {
+      pdh_cleanup(NULL, &counter_query_set->queries[i].counters[j]);
+    }
+    FREE_C_HEAP_ARRAY(char, counter_query_set->queries[i].counters);
+    pdh_cleanup(&counter_query_set->queries[i].query.query, NULL);
+  }
+  FREE_C_HEAP_ARRAY(MultiCounterQueryS, counter_query_set->queries);
+  FREE_C_HEAP_ARRAY(MultiCounterQuerySetS, counter_query_set);
+}
+
+static int open_query(HQUERY* query) {
+  return PdhDll::PdhOpenQuery(NULL, 0, query);
+}
+
+template <typename QueryP>
+static int open_query(QueryP query) {
+  return open_query(&query->query);
+}
+
+static int allocate_counters(MultiCounterQueryP query, size_t nofCounters) {
+  assert(query != NULL, "invariant");
+  assert(!query->initialized, "invariant");
+  assert(0 == query->noOfCounters, "invariant");
+  assert(query->counters == NULL, "invariant");
+  query->counters = (HCOUNTER*)NEW_C_HEAP_ARRAY(char, nofCounters * sizeof(HCOUNTER), mtInternal);
+  if (query->counters == NULL) {
+    return OS_ERR;
+  }
+  memset(query->counters, 0, nofCounters * sizeof(HCOUNTER));
+  query->noOfCounters = (int)nofCounters;
+  return OS_OK;
+}
+
+static int allocate_counters(MultiCounterQuerySetP query_set, size_t nofCounters) {
+  assert(query_set != NULL, "invariant");
+  assert(!query_set->initialized, "invariant");
+  for (int i = 0; i < query_set->size; ++i) {
+    if (allocate_counters(&query_set->queries[i], nofCounters) != OS_OK) {
+      return OS_ERR;
+    }
+  }
+  return OS_OK;
+}
+
+static void deallocate_counters(MultiCounterQueryP query) {
+  if (query->counters != NULL) {
+    FREE_C_HEAP_ARRAY(char, query->counters);
+    query->counters = NULL;
+    query->noOfCounters = 0;
+  }
+}
+
+static OSReturn add_counter(UpdateQueryP query, HCOUNTER* counter, const char* path, bool first_sample_on_init) {
+  assert(query != NULL, "invariant");
+  assert(counter != NULL, "invariant");
+  assert(path != NULL, "invariant");
+  if (query->query == NULL) {
+    if (open_query(query) != ERROR_SUCCESS) {
+      return OS_ERR;
+    }
+  }
+  assert(query->query != NULL, "invariant");
+  PDH_STATUS status = PdhDll::PdhAddCounter(query->query, path, 0, counter);
+  if (PDH_CSTATUS_NO_OBJECT == status || PDH_CSTATUS_NO_COUNTER == status) {
+    return OS_ERR;
+  }
+  /*
+  * According to the MSDN documentation, rate counters must be read twice:
+  *
+  * "Obtaining the value of rate counters such as Page faults/sec requires that
+  *  PdhCollectQueryData be called twice, with a specific time interval between
+  *  the two calls, before calling PdhGetFormattedCounterValue. Call Sleep to
+  *  implement the waiting period between the two calls to PdhCollectQueryData."
+  *
+  *  Take the first sample here already to allow for the next "real" sample
+  *  to succeed.
+  */
+  if (first_sample_on_init) {
+    PdhDll::PdhCollectQueryData(query->query);
+  }
+  return OS_OK;
+}
+
+template <typename QueryP>
+static OSReturn add_counter(QueryP counter_query, HCOUNTER* counter, const char* path, bool first_sample_on_init) {
+  assert(counter_query != NULL, "invariant");
+  assert(counter != NULL, "invariant");
+  assert(path != NULL, "invariant");
+  return add_counter(&counter_query->query, counter, path, first_sample_on_init);
+}
+
+static OSReturn add_counter(CounterQueryP counter_query, const char* path, bool first_sample_on_init) {
+  if (add_counter(counter_query, &counter_query->counter, path, first_sample_on_init) != OS_OK) {
+    // performance counter might be disabled in the registry
+    return OS_ERR;
+  }
+  counter_query->initialized = true;
+  return OS_OK;
+}
+
+static OSReturn add_process_counter(MultiCounterQueryP query, int slot_index, const char* path, bool first_sample_on_init) {
+  assert(query != NULL, "invariant");
+  assert(query != NULL, "invariant");
+  assert(slot_index < query->noOfCounters, "invariant");
+  assert(query->counters[slot_index] == NULL, "invariant");
+  const OSReturn ret = add_counter(query, &query->counters[slot_index], path, first_sample_on_init);
+  if (OS_OK == ret) {
+    if (slot_index + 1 == query->noOfCounters) {
+      query->initialized = true;
+    }
+  }
+  return ret;
+}
+
+static int collect_query_data(UpdateQueryP update_query) {
+  assert(update_query != NULL, "invariant");
+  const s8 now = os::javaTimeMillis();
+  if (now - update_query->lastUpdate > min_update_interval_millis) {
+    if (PdhDll::PdhCollectQueryData(update_query->query) != ERROR_SUCCESS) {
+      return OS_ERR;
+    }
+    update_query->lastUpdate = now;
+  }
+  return OS_OK;
+}
+
+template <typename Query>
+static int collect_query_data(Query* counter_query) {
+  assert(counter_query != NULL, "invariant");
+  return collect_query_data(&counter_query->query);
+}
+
+static int formatted_counter_value(HCOUNTER counter, DWORD format, PDH_FMT_COUNTERVALUE* const value) {
+  assert(value != NULL, "invariant");
+  if (PdhDll::PdhGetFormattedCounterValue(counter, format, NULL, value) != ERROR_SUCCESS) {
+    return OS_ERR;
+  }
+  return OS_OK;
+}
+
+/*
+* Working against the Process object and it's related counters is inherently problematic
+* when using the PDH API:
+*
+* Using PDH, a process is not primarily identified by the process id,
+* but with a sequential number, for example \Process(java#0), \Process(java#1), ...
+* The really bad part is that this list is reset as soon as a process exits:
+* If \Process(java#1) exits, \Process(java#3) now becomes \Process(java#2) etc.
+*
+* The PDH api requires a process identifier to be submitted when registering
+* a query, but as soon as the list resets, the query is invalidated (since the name changed).
+*
+* Solution:
+* The #number identifier for a Process query can only decrease after process creation.
+*
+* We therefore create an array of counter queries for all process object instances
+* up to and including ourselves:
+*
+* Ex. we come in as third process instance (java#2), we then create and register
+* queries for the following Process object instances:
+* java#0, java#1, java#2
+*
+* current_query_index_for_process() keeps track of the current "correct" query
+* (in order to keep this index valid when the list resets from underneath,
+* ensure to call current_query_index_for_process() before every query involving
+* Process object instance data).
+*/
+static int current_query_index_for_process() {
+  assert(process_image_name != NULL, "invariant");
+  assert(pdh_IDProcess_counter_fmt != NULL, "invariant");
+  HQUERY tmpQuery = NULL;
+  if (open_query(&tmpQuery) != ERROR_SUCCESS) {
+    return 0;
+  }
+  char counter[512];
+  HCOUNTER handle_counter = NULL;
+  // iterate over all instance indexes and try to find our own pid
+  for (int index = 0; index < max_intx; index++) {
+    jio_snprintf(counter, sizeof(counter) - 1, pdh_IDProcess_counter_fmt, index);
+    assert(strlen(counter) < sizeof(counter), "invariant");
+    if (PdhDll::PdhAddCounter(tmpQuery, counter, 0, &handle_counter) != ERROR_SUCCESS) {
+      pdh_cleanup(&tmpQuery, &handle_counter);
+      return 0;
+    }
+    const PDH_STATUS res = PdhDll::PdhCollectQueryData(tmpQuery);
+    if (res == PDH_INVALID_HANDLE || res == PDH_NO_DATA) {
+      pdh_cleanup(&tmpQuery, &handle_counter);
+      return 0;
+    } else {
+      PDH_FMT_COUNTERVALUE counter_value;
+      formatted_counter_value(handle_counter, PDH_FMT_LONG, &counter_value);
+      pdh_cleanup(NULL, &handle_counter);
+      if ((LONG)os::current_process_id() == counter_value.longValue) {
+        pdh_cleanup(&tmpQuery, NULL);
+        return index;
+      }
+    }
+  }
+  pdh_cleanup(&tmpQuery, NULL);
+  return 0;
+}
+
+static MultiCounterQuerySetP create_process_counter_query() {
+  MultiCounterQuerySetP const query = NEW_C_HEAP_ARRAY(MultiCounterQuerySetS, 1, mtInternal);
+  memset(query, 0, sizeof(MultiCounterQuerySetS));
+  const int current_process_idx = current_query_index_for_process();
+  query->queries = NEW_C_HEAP_ARRAY(MultiCounterQueryS, current_process_idx + 1, mtInternal);
+  memset(query->queries, 0, sizeof(MultiCounterQueryS) * (current_process_idx + 1));
+  query->size = current_process_idx + 1;
+  return query;
+}
+
+static MultiCounterQueryP current_process_counter_query(MultiCounterQuerySetP process_query_set) {
+  assert(process_query_set != NULL, "invariant");
+  const int current_query_index = current_query_index_for_process();
+  assert(current_query_index < process_query_set->size, "invariant");
+  return &process_query_set->queries[current_query_index];
+}
+
+static void clear_multi_counter(MultiCounterQueryP query) {
+  for (int i = 0; i < query->noOfCounters; ++i) {
+    pdh_cleanup(NULL, &query->counters[i]);
+  }
+  pdh_cleanup(&query->query.query, NULL);
+}
+
+static int collect_process_query_data(MultiCounterQuerySetP counter_query_set) {
+  const int current_process_idx = current_query_index_for_process();
+  while (current_process_idx < counter_query_set->size - 1) {
+    const int new_size = --counter_query_set->size;
+    clear_multi_counter(&counter_query_set->queries[new_size]);
+  }
+  return collect_query_data(&counter_query_set->queries[current_process_idx]);
+}
+
+static int query_process_counter(MultiCounterQuerySetP process_query_set, int slot_index, DWORD format, PDH_FMT_COUNTERVALUE* const value) {
+  MultiCounterQueryP const current_query = current_process_counter_query(process_query_set);
+  assert(current_query != NULL, "invariant");
+  assert(slot_index < current_query->noOfCounters, "invariant");
+  assert(current_query->counters[slot_index] != NULL, "invariant");
+  return formatted_counter_value(current_query->counters[slot_index], format, value);
+}
+
+/*
+ * Construct a fully qualified PDH path
+ *
+ * @param objectName   a PDH Object string representation(required)
+ * @param counterName  a PDH Counter string representation(required)
+ * @param imageName    a process image name string, ex. "java" (opt)
+ * @param instance     an instance string, ex. "0", "1", ... (opt)
+ * @return             the fully qualified PDH path.
+ *
+ * Caller will need a ResourceMark.
+ *
+ * (PdhMakeCounterPath() seems buggy on concatenating instances, hence this function instead)
+ */
+static const char* make_fully_qualified_counter_path(const char* object_name,
+                                                     const char* counter_name,
+                                                     const char* image_name = NULL,
+                                                     const char* instance = NULL) {
+  assert(object_name != NULL, "invariant");
+  assert(counter_name != NULL, "invariant");
+  size_t full_counter_path_len = strlen(object_name) + strlen(counter_name);
+
+  char* full_counter_path;
+  size_t jio_snprintf_result = 0;
+  if (image_name) {
+    /*
+    * For paths using the "Process" Object.
+    *
+    * Examples:
+    * form:   "\object_name(image_name#instance)\counter_name"
+    * actual: "\Process(java#2)\ID Process"
+    */
+    full_counter_path_len += PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN;
+    full_counter_path_len += strlen(image_name);
+    /*
+    * image_name must be passed together with an associated
+    * instance "number" ("0", "1", "2", ...).
+    * This is required in order to create valid "Process" Object paths.
+    *
+    * Examples: "\Process(java#0)", \Process(java#1"), ...
+    */
+    assert(instance != NULL, "invariant");
+    full_counter_path_len += strlen(instance);
+    full_counter_path = NEW_RESOURCE_ARRAY_RETURN_NULL(char, full_counter_path_len + 1);
+    if (full_counter_path == NULL) {
+      return NULL;
+    }
+    jio_snprintf_result = jio_snprintf(full_counter_path,
+                                       full_counter_path_len + 1,
+                                       PROCESS_OBJECT_INSTANCE_COUNTER_FMT,
+                                       object_name,
+                                       image_name,
+                                       instance,
+                                       counter_name);
+  } else {
+    if (instance) {
+      /*
+      * For paths where the Object has multiple instances.
+      *
+      * Examples:
+      * form:   "\object_name(instance)\counter_name"
+      * actual: "\Processor(0)\% Privileged Time"
+      */
+      full_counter_path_len += strlen(instance);
+      full_counter_path_len += OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN;
+    } else {
+      /*
+      * For "normal" paths.
+      *
+      * Examples:
+      * form:   "\object_name\counter_name"
+      * actual: "\Memory\Available Mbytes"
+      */
+      full_counter_path_len += OBJECT_COUNTER_FMT_LEN;
+    }
+    full_counter_path = NEW_RESOURCE_ARRAY_RETURN_NULL(char, full_counter_path_len + 1);
+    if (full_counter_path == NULL) {
+      return NULL;
+    }
+    if (instance) {
+      jio_snprintf_result = jio_snprintf(full_counter_path,
+                                         full_counter_path_len + 1,
+                                         OBJECT_WITH_INSTANCES_COUNTER_FMT,
+                                         object_name,
+                                         instance,
+                                         counter_name);
+    } else {
+      jio_snprintf_result = jio_snprintf(full_counter_path,
+                                         full_counter_path_len + 1,
+                                         OBJECT_COUNTER_FMT,
+                                         object_name,
+                                         counter_name);
+    }
+  }
+  assert(full_counter_path_len == jio_snprintf_result, "invariant");
+  return full_counter_path;
+}
+
+static void log_invalid_pdh_index(DWORD index) {
+  log_warning(os)("Unable to resolve PDH index: (%ld)", index);
+  log_warning(os)("Please check the registry if this performance object/counter is disabled");
+}
+
+static bool is_valid_pdh_index(DWORD index) {
+  DWORD dummy = 0;
+  if (PdhDll::PdhLookupPerfNameByIndex(NULL, index, NULL, &dummy) != PDH_MORE_DATA) {
+    log_invalid_pdh_index(index);
+    return false;
+  }
+  return true;
+}
+
+/*
+ * Maps an index to a resource area allocated string for the localized PDH artifact.
+ *
+ * Caller will need a ResourceMark.
+ *
+ * @param index    the counter index as specified in the registry
+ * @param ppBuffer pointer to a char*
+ * @return         OS_OK if successful, OS_ERR on failure.
+ */
+static OSReturn lookup_name_by_index(DWORD index, char** p_string) {
+  assert(p_string != NULL, "invariant");
+  if (!is_valid_pdh_index(index)) {
+    return OS_ERR;
+  }
+  // determine size needed
+  DWORD size = 0;
+  PDH_STATUS status = PdhDll::PdhLookupPerfNameByIndex(NULL, index, NULL, &size);
+  assert(status == PDH_MORE_DATA, "invariant");
+  *p_string = NEW_RESOURCE_ARRAY_RETURN_NULL(char, size);
+  if (*p_string== NULL) {
+    return OS_ERR;
+  }
+  if (PdhDll::PdhLookupPerfNameByIndex(NULL, index, *p_string, &size) != ERROR_SUCCESS) {
+    return OS_ERR;
+  }
+  if (0 == size || *p_string == NULL) {
+    return OS_ERR;
+  }
+  // windows vista does not null-terminate the string (although the docs says it will)
+  (*p_string)[size - 1] = '\0';
+  return OS_OK;
+}
+
+static const char* copy_string_to_c_heap(const char* string) {
+  assert(string != NULL, "invariant");
+  const size_t len = strlen(string);
+  char* const cheap_allocated_string = NEW_C_HEAP_ARRAY(char, len + 1, mtInternal);
+  if (NULL == cheap_allocated_string) {
+    return NULL;
+  }
+  strncpy(cheap_allocated_string, string, len + 1);
+  return cheap_allocated_string;
+}
+
+/*
+* Maps an index to a resource area allocated string for the localized PDH artifact.
+*
+* Caller will need a ResourceMark.
+*
+* @param index    the counter index as specified in the registry
+* @return         localized pdh artifact string if successful, NULL on failure.
+*/
+static const char* pdh_localized_artifact(DWORD pdh_artifact_index) {
+  char* pdh_localized_artifact_string = NULL;
+  // get localized name from pdh artifact index
+  if (lookup_name_by_index(pdh_artifact_index, &pdh_localized_artifact_string) != OS_OK) {
+    return NULL;
+  }
+  return pdh_localized_artifact_string;
+}
+
+/*
+ * Returns the PDH string identifying the current process image name.
+ * Use this prefix when getting counters from the PDH process object
+ * representing your process.
+ * Ex. "Process(java#0)\Virtual Bytes" - where "java" is the PDH process
+ * image description.
+ *
+ * Caller needs ResourceMark.
+ *
+ * @return the process image description. NULL if the call failed.
+*/
+static const char* pdh_process_image_name() {
+  char* module_name = NEW_RESOURCE_ARRAY_RETURN_NULL(char, MAX_PATH);
+  if (NULL == module_name) {
+    return NULL;
+  }
+  // Find our module name and use it to extract the image name used by PDH
+  DWORD getmfn_return = GetModuleFileName(NULL, module_name, MAX_PATH);
+  if (getmfn_return >= MAX_PATH || 0 == getmfn_return) {
+    return NULL;
+  }
+  if (os::get_last_error() == ERROR_INSUFFICIENT_BUFFER) {
+    return NULL;
+  }
+  char* process_image_name = strrchr(module_name, '\\'); //drop path
+  process_image_name++;                                  //skip slash
+  char* dot_pos = strrchr(process_image_name, '.');      //drop .exe
+  dot_pos[0] = '\0';
+  return process_image_name;
+}
+
+static void deallocate_pdh_constants() {
+  if (process_image_name != NULL) {
+    FREE_C_HEAP_ARRAY(char, process_image_name);
+    process_image_name = NULL;
+  }
+  if (pdh_IDProcess_counter_fmt != NULL) {
+    FREE_C_HEAP_ARRAY(char, pdh_IDProcess_counter_fmt);
+    pdh_IDProcess_counter_fmt = NULL;
+  }
+}
+
+static int allocate_pdh_constants() {
+  assert(process_image_name == NULL, "invariant");
+  const char* pdh_image_name = pdh_process_image_name();
+  if (pdh_image_name == NULL) {
+    return OS_ERR;
+  }
+  process_image_name = copy_string_to_c_heap(pdh_image_name);
+
+  const char* pdh_localized_process_object = pdh_localized_artifact(PDH_PROCESS_IDX);
+  if (pdh_localized_process_object == NULL) {
+    return OS_ERR;
+  }
+
+  const char* pdh_localized_IDProcess_counter = pdh_localized_artifact(PDH_ID_PROCESS_IDX);
+  if (pdh_localized_IDProcess_counter == NULL) {
+    return OS_ERR;
+  }
+
+  size_t pdh_IDProcess_counter_fmt_len = strlen(process_image_name);
+  pdh_IDProcess_counter_fmt_len += strlen(pdh_localized_process_object);
+  pdh_IDProcess_counter_fmt_len += strlen(pdh_localized_IDProcess_counter);
+  pdh_IDProcess_counter_fmt_len += PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN;
+  pdh_IDProcess_counter_fmt_len += 2; // "%d"
+
+  assert(pdh_IDProcess_counter_fmt == NULL, "invariant");
+  pdh_IDProcess_counter_fmt = NEW_C_HEAP_ARRAY_RETURN_NULL(char, pdh_IDProcess_counter_fmt_len + 1, mtInternal);
+  if (pdh_IDProcess_counter_fmt == NULL) {
+    return OS_ERR;
+  }
+
+  /* "\Process(java#%d)\ID Process" */
+  const size_t len = jio_snprintf(pdh_IDProcess_counter_fmt,
+                                  pdh_IDProcess_counter_fmt_len + 1,
+                                  PROCESS_OBJECT_INSTANCE_COUNTER_FMT,
+                                  pdh_localized_process_object,
+                                  process_image_name,
+                                  "%d",
+                                  pdh_localized_IDProcess_counter);
+
+  assert(pdh_IDProcess_counter_fmt != NULL, "invariant");
+  assert(len == pdh_IDProcess_counter_fmt_len, "invariant");
+  return OS_OK;
+}
+
+/*
+ * Enuerate the Processor PDH object and returns a buffer containing the enumerated instances.
+ * Caller needs ResourceMark;
+ *
+ * @return  buffer if successful, NULL on failure.
+*/
+static const char* enumerate_cpu_instances() {
+  char* processor; //'Processor' == PDH_PROCESSOR_IDX
+  if (lookup_name_by_index(PDH_PROCESSOR_IDX, &processor) != OS_OK) {
+    return NULL;
+  }
+  DWORD c_size = 0;
+  DWORD i_size = 0;
+  // enumerate all processors.
+  PDH_STATUS pdhStat = PdhDll::PdhEnumObjectItems(NULL, // reserved
+                                                  NULL, // local machine
+                                                  processor, // object to enumerate
+                                                  NULL,
+                                                  &c_size,
+                                                  NULL, // instance buffer is NULL and
+                                                  &i_size,  // pass 0 length in order to get the required size
+                                                  PERF_DETAIL_WIZARD, // counter detail level
+                                                  0);
+  if (PdhDll::PdhStatusFail((pdhStat))) {
+    return NULL;
+  }
+  char* const instances = NEW_RESOURCE_ARRAY_RETURN_NULL(char, i_size);
+  if (instances == NULL) {
+    return NULL;
+  }
+  c_size = 0;
+  pdhStat = PdhDll::PdhEnumObjectItems(NULL, // reserved
+                                       NULL, // local machine
+                                       processor, // object to enumerate
+                                       NULL,
+                                       &c_size,
+                                       instances, // now instance buffer is allocated to be filled in
+                                       &i_size, // and the required size is known
+                                       PERF_DETAIL_WIZARD, // counter detail level
+                                       0);
+  if (PdhDll::PdhStatusFail((pdhStat))) {
+    return NULL;
+  }
+  return instances;
+}
+
+static int count_logical_cpus(const char* instances) {
+  assert(instances != NULL, "invariant");
+  // count logical instances.
+  DWORD count;
+  char* tmp;
+  for (count = 0, tmp = const_cast<char*>(instances); *tmp != '\0'; tmp = &tmp[strlen(tmp) + 1], count++);
+  // PDH reports an instance for each logical processor plus an instance for the total (_Total)
+  assert(count == os::processor_count() + 1, "invalid enumeration!");
+  return count - 1;
+}
+
+static int number_of_logical_cpus() {
+  static int numberOfCPUS = 0;
+  if (numberOfCPUS == 0) {
+    const char* instances = enumerate_cpu_instances();
+    if (instances == NULL) {
+      return OS_ERR;
+    }
+    numberOfCPUS = count_logical_cpus(instances);
+  }
+  return numberOfCPUS;
+}
+
+static double cpu_factor() {
+  static DWORD  numCpus = 0;
+  static double cpuFactor = .0;
+  if (numCpus == 0) {
+    numCpus = number_of_logical_cpus();
+    assert(os::processor_count() <= (int)numCpus, "invariant");
+    cpuFactor = numCpus * 100;
+  }
+  return cpuFactor;
+}
+
+static void log_error_message_on_no_PDH_artifact(const char* full_counter_name) {
+  log_warning(os)("Unable to register PDH query for \"%s\"", full_counter_name);
+  log_warning(os)("Please check the registry if this performance object/counter is disabled");
+}
+
+static int initialize_cpu_query_counters(MultiCounterQueryP cpu_query, DWORD pdh_counter_idx) {
+  assert(cpu_query != NULL, "invariant");
+  assert(cpu_query->counters != NULL, "invariant");
+  char* processor; //'Processor' == PDH_PROCESSOR_IDX
+  if (lookup_name_by_index(PDH_PROCESSOR_IDX, &processor) != OS_OK) {
+    return OS_ERR;
+  }
+  char* counter_name = NULL;
+  if (lookup_name_by_index(pdh_counter_idx, &counter_name) != OS_OK) {
+    return OS_ERR;
+  }
+  if (cpu_query->query.query == NULL) {
+    if (open_query(cpu_query)) {
+      return OS_ERR;
+    }
+  }
+  assert(cpu_query->query.query != NULL, "invariant");
+  size_t counter_len = strlen(processor);
+  counter_len += strlen(counter_name);
+  counter_len += OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN; // "\\%s(%s)\\%s"
+
+  DWORD index;
+  char* tmp;
+  const char* instances = enumerate_cpu_instances();
+  for (index = 0, tmp = const_cast<char*>(instances); *tmp != '\0'; tmp = &tmp[strlen(tmp) + 1], index++) {
+    const size_t tmp_len = strlen(tmp);
+    char* counter_path = NEW_RESOURCE_ARRAY_RETURN_NULL(char, counter_len + tmp_len + 1);
+    if (counter_path == NULL) {
+      return OS_ERR;
+    }
+    const size_t jio_snprintf_result = jio_snprintf(counter_path,
+                                                    counter_len + tmp_len + 1,
+                                                    OBJECT_WITH_INSTANCES_COUNTER_FMT,
+                                                    processor,
+                                                    tmp, // instance "0", "1", .."_Total"
+                                                    counter_name);
+    assert(counter_len + tmp_len == jio_snprintf_result, "invariant");
+    if (add_counter(cpu_query, &cpu_query->counters[index], counter_path, false) != OS_OK) {
+      // performance counter is disabled in registry and not accessible via PerfLib
+      log_error_message_on_no_PDH_artifact(counter_path);
+      // return OS_OK to have the system continue to run without the missing counter
+      return OS_OK;
+    }
+  }
+  cpu_query->initialized = true;
+  // Query once to initialize the counters which require at least two samples
+  // (like the % CPU usage) to calculate correctly.
+  collect_query_data(cpu_query);
+  return OS_OK;
+}
+
+static int initialize_cpu_query(MultiCounterQueryP cpu_query, DWORD pdh_counter_idx) {
+  assert(cpu_query != NULL, "invariant");
+  assert(!cpu_query->initialized, "invariant");
+  const int logical_cpu_count = number_of_logical_cpus();
+  assert(logical_cpu_count >= os::processor_count(), "invariant");
+  // we also add another counter for instance "_Total"
+  if (allocate_counters(cpu_query, logical_cpu_count + 1) != OS_OK) {
+    return OS_ERR;
+  }
+  assert(cpu_query->noOfCounters == logical_cpu_count + 1, "invariant");
+  return initialize_cpu_query_counters(cpu_query, pdh_counter_idx);
+}
+
+static int initialize_process_counter(MultiCounterQuerySetP query_set, int slot_index, DWORD pdh_counter_index) {
+  char* localized_process_object;
+  if (lookup_name_by_index(PDH_PROCESS_IDX, &localized_process_object) != OS_OK) {
+    return OS_ERR;
+  }
+  assert(localized_process_object != NULL, "invariant");
+  char* localized_counter_name;
+  if (lookup_name_by_index(pdh_counter_index, &localized_counter_name) != OS_OK) {
+    return OS_ERR;
+  }
+  assert(localized_counter_name != NULL, "invariant");
+  for (int i = 0; i < query_set->size; ++i) {
+    char instanceIndexBuffer[32];
+    const char* counter_path = make_fully_qualified_counter_path(localized_process_object,
+                                                                 localized_counter_name,
+                                                                 process_image_name,
+                                                                 itoa(i, instanceIndexBuffer, 10));
+    if (counter_path == NULL) {
+      return OS_ERR;
+    }
+    MultiCounterQueryP const query = &query_set->queries[i];
+    if (add_process_counter(query, slot_index, counter_path, true)) {
+      return OS_ERR;
+    }
+  }
+  return OS_OK;
+}
+
+static CounterQueryP create_counter_query(DWORD pdh_object_idx, DWORD pdh_counter_idx) {
+  assert(is_valid_pdh_index(pdh_object_idx), "invariant");
+  assert(is_valid_pdh_index(pdh_counter_idx), "invariant");
+  CounterQueryP const query = create_counter_query();
+  const char* object = pdh_localized_artifact(pdh_object_idx);
+  assert(object != NULL, "invariant");
+  const char* counter = pdh_localized_artifact(pdh_counter_idx);
+  assert(counter != NULL, "invariant");
+  const char* full_counter_path = make_fully_qualified_counter_path(object, counter);
+  assert(full_counter_path != NULL, "invariant");
+  add_counter(query, full_counter_path, true);
+  return query;
+}
+
+static void deallocate() {
+  deallocate_pdh_constants();
+  PdhDll::PdhDetach();
+}
+
+static LONG critical_section = 0;
+static LONG reference_count = 0;
+static bool pdh_initialized = false;
+
+static void on_initialization_failure() {
+  // still holder of critical section
+  deallocate();
+  InterlockedExchangeAdd(&reference_count, -1);
+}
+
+static OSReturn initialize() {
+  ResourceMark rm;
+  if (!PdhDll::PdhAttach()) {
+    return OS_ERR;
+  }
+  if (allocate_pdh_constants() != OS_OK) {
+    on_initialization_failure();
+    return OS_ERR;
+  }
+  return OS_OK;
+}
+
+/*
+* Helper to initialize the PDH library, function pointers, constants and counters.
+*
+* Reference counting allows for unloading of pdh.dll granted all sessions use the pair:
+*
+*   pdh_acquire();
+*   pdh_release();
+*
+* @return  OS_OK if successful, OS_ERR on failure.
+*/
+static bool pdh_acquire() {
+  while (InterlockedCompareExchange(&critical_section, 1, 0) == 1);
+  InterlockedExchangeAdd(&reference_count, 1);
+  if (pdh_initialized) {
+    return true;
+  }
+  const OSReturn ret = initialize();
+  if (OS_OK == ret) {
+    pdh_initialized = true;
+  }
+  while (InterlockedCompareExchange(&critical_section, 0, 1) == 0);
+  return ret == OS_OK;
+}
+
+static void pdh_release() {
+  while (InterlockedCompareExchange(&critical_section, 1, 0) == 1);
+  const LONG prev_ref_count = InterlockedExchangeAdd(&reference_count, -1);
+  if (1 == prev_ref_count) {
+    deallocate();
+    pdh_initialized = false;
+  }
+  while (InterlockedCompareExchange(&critical_section, 0, 1) == 0);
+}
+
+class CPUPerformanceInterface::CPUPerformance : public CHeapObj<mtInternal> {
+  friend class CPUPerformanceInterface;
+ private:
+  CounterQueryP _context_switches;
+  MultiCounterQuerySetP _process_cpu_load;
+  MultiCounterQueryP _machine_cpu_load;
+
+  int cpu_load(int which_logical_cpu, double* cpu_load);
+  int context_switch_rate(double* rate);
+  int cpu_load_total_process(double* cpu_load);
+  int cpu_loads_process(double* jvm_user_load, double* jvm_kernel_load, double* psystemTotalLoad);
+  CPUPerformance();
+  ~CPUPerformance();
+  bool initialize();
+};
+
+class SystemProcessInterface::SystemProcesses : public CHeapObj<mtInternal> {
+  friend class SystemProcessInterface;
+ private:
+  class ProcessIterator : public CHeapObj<mtInternal> {
+    friend class SystemProcessInterface::SystemProcesses;
+   private:
+    HANDLE         _hProcessSnap;
+    PROCESSENTRY32 _pe32;
+    BOOL           _valid;
+    char           _exePath[MAX_PATH];
+    ProcessIterator();
+    ~ProcessIterator();
+    bool initialize();
+
+    int current(SystemProcess* const process_info);
+    int next_process();
+    bool is_valid() const { return _valid != FALSE; }
+    char* allocate_string(const char* str) const;
+    int snapshot();
+  };
+
+  ProcessIterator* _iterator;
+  SystemProcesses();
+  ~SystemProcesses();
+  bool initialize();
+
+  // information about system processes
+  int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const;
+};
+
+CPUPerformanceInterface::CPUPerformance::CPUPerformance() : _context_switches(NULL), _process_cpu_load(NULL), _machine_cpu_load(NULL) {}
+
+bool CPUPerformanceInterface::CPUPerformance::initialize() {
+  if (!pdh_acquire()) {
+    return false;
+  }
+  _context_switches = create_counter_query(PDH_SYSTEM_IDX, PDH_CONTEXT_SWITCH_RATE_IDX);
+  if (_context_switches == NULL) {
+    return false;
+  }
+  _process_cpu_load = create_process_counter_query();
+  if (_process_cpu_load == NULL) {
+    return false;
+  }
+  if (allocate_counters(_process_cpu_load, 2) != OS_OK) {
+    return false;
+  }
+  if (initialize_process_counter(_process_cpu_load, 0, PDH_PROCESSOR_TIME_IDX) != OS_OK) {
+    return false;
+  }
+  if (initialize_process_counter(_process_cpu_load, 1, PDH_PRIV_PROCESSOR_TIME_IDX) != OS_OK) {
+    return false;
+  }
+  _process_cpu_load->initialized = true;
+
+  _machine_cpu_load = create_multi_counter_query();
+  if (_machine_cpu_load == NULL) {
+    return false;
+  }
+  if (initialize_cpu_query(_machine_cpu_load, PDH_PROCESSOR_TIME_IDX) != OS_OK) {
+    return false;
+  }
+  return true;
+}
+
+CPUPerformanceInterface::CPUPerformance::~CPUPerformance() {
+  if (_context_switches != NULL) {
+    destroy_counter_query(_context_switches);
+    _context_switches = NULL;
+  }
+  if (_process_cpu_load != NULL) {
+    destroy_counter_query(_process_cpu_load);
+    _process_cpu_load = NULL;
+  }
+  if (_machine_cpu_load != NULL) {
+    destroy_counter_query(_machine_cpu_load);
+    _machine_cpu_load = NULL;
+  }
+  pdh_release();
+}
+
+CPUPerformanceInterface::CPUPerformanceInterface() {
+  _impl = NULL;
+}
+
+bool CPUPerformanceInterface::initialize() {
+  _impl = new CPUPerformanceInterface::CPUPerformance();
+  return _impl != NULL && _impl->initialize();
+}
+
+CPUPerformanceInterface::~CPUPerformanceInterface() {
+  if (_impl != NULL) {
+    delete _impl;
+  }
+}
+
+int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const {
+  return _impl->cpu_load(which_logical_cpu, cpu_load);
+}
+
+int CPUPerformanceInterface::context_switch_rate(double* rate) const {
+  return _impl->context_switch_rate(rate);
+}
+
+int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const {
+  return _impl->cpu_load_total_process(cpu_load);
+}
+
+int CPUPerformanceInterface::cpu_loads_process(double* pjvmUserLoad,
+                                               double* pjvmKernelLoad,
+                                               double* psystemTotalLoad) const {
+  return _impl->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotalLoad);
+}
+
+int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) {
+  assert(_machine_cpu_load != NULL, "invariant");
+  assert(which_logical_cpu < _machine_cpu_load->noOfCounters, "invariant");
+  *cpu_load = .0;
+  if (!_machine_cpu_load->initialized) {
+    return OS_ERR;
+  }
+  if (collect_query_data(_machine_cpu_load)) {
+    return OS_ERR;
+  }
+  // -1 is total (all cpus)
+  const int counter_idx = -1 == which_logical_cpu ? _machine_cpu_load->noOfCounters - 1 : which_logical_cpu;
+  PDH_FMT_COUNTERVALUE counter_value;
+  formatted_counter_value(_machine_cpu_load->counters[counter_idx], PDH_FMT_DOUBLE, &counter_value);
+  *cpu_load = counter_value.doubleValue / 100;
+  return OS_OK;
+}
+
+int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) {
+  assert(_process_cpu_load != NULL, "invariant");
+  *cpu_load = .0;
+  if (!_process_cpu_load->initialized) {
+    return OS_ERR;
+  }
+  if (collect_process_query_data(_process_cpu_load)) {
+    return OS_ERR;
+  }
+  PDH_FMT_COUNTERVALUE counter_value;
+  if (query_process_counter(_process_cpu_load, 0, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &counter_value) != OS_OK) {
+    return OS_ERR;
+  }
+  double process_load = counter_value.doubleValue / cpu_factor();
+  process_load = MIN2<double>(1, process_load);
+  process_load = MAX2<double>(0, process_load);
+  *cpu_load = process_load;
+  return OS_OK;
+}
+
+int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad,
+                                                               double* pjvmKernelLoad,
+                                                               double* psystemTotalLoad) {
+  assert(pjvmUserLoad != NULL, "pjvmUserLoad is NULL!");
+  assert(pjvmKernelLoad != NULL, "pjvmKernelLoad is NULL!");
+  assert(psystemTotalLoad != NULL, "psystemTotalLoad is NULL!");
+  *pjvmUserLoad = .0;
+  *pjvmKernelLoad = .0;
+  *psystemTotalLoad = .0;
+  if (!_process_cpu_load->initialized) {
+    return OS_ERR;
+  }
+  if (collect_process_query_data(_process_cpu_load)) {
+    return OS_ERR;
+  }
+  double process_load = .0;
+  PDH_FMT_COUNTERVALUE counter_value;
+  // Read  PDH_PROCESSOR_TIME_IDX
+  if (query_process_counter(_process_cpu_load, 0, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &counter_value) != OS_OK) {
+    return OS_ERR;
+  }
+  process_load = counter_value.doubleValue / cpu_factor();
+  process_load = MIN2<double>(1, process_load);
+  process_load = MAX2<double>(0, process_load);
+  // Read PDH_PRIV_PROCESSOR_TIME_IDX
+  if (query_process_counter(_process_cpu_load, 1, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &counter_value) != OS_OK) {
+    return OS_ERR;
+  }
+  double kernel_load = counter_value.doubleValue / cpu_factor();
+  kernel_load = MIN2<double>(1, kernel_load);
+  kernel_load = MAX2<double>(0, kernel_load);
+  *pjvmKernelLoad = kernel_load;
+
+  double user_load = process_load - kernel_load;
+  user_load = MIN2<double>(1, user_load);
+  user_load = MAX2<double>(0, user_load);
+  *pjvmUserLoad = user_load;
+
+  if (collect_query_data(_machine_cpu_load)) {
+    return OS_ERR;
+  }
+  if (formatted_counter_value(_machine_cpu_load->counters[_machine_cpu_load->noOfCounters - 1], PDH_FMT_DOUBLE, &counter_value) != OS_OK) {
+    return OS_ERR;
+  }
+  double machine_load = counter_value.doubleValue / 100;
+  assert(machine_load >= 0, "machine_load is negative!");
+  // clamp at user+system and 1.0
+  if (*pjvmKernelLoad + *pjvmUserLoad > machine_load) {
+    machine_load = MIN2(*pjvmKernelLoad + *pjvmUserLoad, 1.0);
+  }
+  *psystemTotalLoad = machine_load;
+  return OS_OK;
+}
+
+int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) {
+  assert(rate != NULL, "invariant");
+  *rate = .0;
+  if (!_context_switches->initialized) {
+    return OS_ERR;
+  }
+  if (collect_query_data(_context_switches) != OS_OK) {
+    return OS_ERR;
+  }
+  PDH_FMT_COUNTERVALUE counter_value;
+  if (formatted_counter_value(_context_switches->counter, PDH_FMT_DOUBLE, &counter_value) != OS_OK) {
+    return OS_ERR;
+  }
+  *rate = counter_value.doubleValue;
+  return OS_OK;
+}
+
+SystemProcessInterface::SystemProcesses::ProcessIterator::ProcessIterator() {
+  _hProcessSnap = INVALID_HANDLE_VALUE;
+  _valid = FALSE;
+  _pe32.dwSize = sizeof(PROCESSENTRY32);
+}
+
+bool SystemProcessInterface::SystemProcesses::ProcessIterator::initialize() {
+  return true;
+}
+
+int SystemProcessInterface::SystemProcesses::ProcessIterator::snapshot() {
+  // take snapshot of all process in the system
+  _hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+  if (_hProcessSnap == INVALID_HANDLE_VALUE) {
+    return OS_ERR;
+  }
+  // step to first process
+  _valid = Process32First(_hProcessSnap, &_pe32);
+  return is_valid() ? OS_OK : OS_ERR;
+}
+
+SystemProcessInterface::SystemProcesses::ProcessIterator::~ProcessIterator() {
+  if (_hProcessSnap != INVALID_HANDLE_VALUE) {
+    CloseHandle(_hProcessSnap);
+  }
+}
+
+int SystemProcessInterface::SystemProcesses::ProcessIterator::current(SystemProcess* process_info) {
+  assert(is_valid(), "no current process to be fetched!");
+  assert(process_info != NULL, "process_info is NULL!");
+  char* exePath = NULL;
+  HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, _pe32.th32ProcessID);
+  if (hProcess != NULL) {
+    HMODULE hMod;
+    DWORD cbNeeded;
+    if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded) != 0) {
+      if (GetModuleFileNameExA(hProcess, hMod, _exePath, sizeof(_exePath)) != 0) {
+        exePath = _exePath;
+      }
+    }
+    CloseHandle (hProcess);
+  }
+  process_info->set_pid((int)_pe32.th32ProcessID);
+  process_info->set_name(allocate_string(_pe32.szExeFile));
+  process_info->set_path(allocate_string(exePath));
+  return OS_OK;
+}
+
+char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const {
+  if (str != NULL) {
+    size_t len = strlen(str);
+    char* tmp = NEW_C_HEAP_ARRAY(char, len+1, mtInternal);
+    if (NULL == tmp) {
+      return NULL;
+    }
+    strncpy(tmp, str, len);
+    tmp[len] = '\0';
+    return tmp;
+  }
+  return NULL;
+}
+
+int SystemProcessInterface::SystemProcesses::ProcessIterator::next_process() {
+  _valid = Process32Next(_hProcessSnap, &_pe32);
+  return OS_OK;
+}
+
+SystemProcessInterface::SystemProcesses::SystemProcesses() {
+  _iterator = NULL;
+}
+
+bool SystemProcessInterface::SystemProcesses::initialize() {
+  _iterator = new SystemProcessInterface::SystemProcesses::ProcessIterator();
+  return _iterator != NULL && _iterator->initialize();
+}
+
+SystemProcessInterface::SystemProcesses::~SystemProcesses() {
+  if (_iterator != NULL) {
+    delete _iterator;
+    _iterator = NULL;
+  }
+}
+
+int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes,
+                                                              int* no_of_sys_processes) const {
+  assert(system_processes != NULL, "system_processes pointer is NULL!");
+  assert(no_of_sys_processes != NULL, "system_processes counter pointers is NULL!");
+  assert(_iterator != NULL, "iterator is NULL!");
+
+  // initialize pointers
+  *no_of_sys_processes = 0;
+  *system_processes = NULL;
+
+  // take process snapshot
+  if (_iterator->snapshot() != OS_OK) {
+    return OS_ERR;
+  }
+
+  while (_iterator->is_valid()) {
+    SystemProcess* tmp = new SystemProcess();
+    _iterator->current(tmp);
+
+    //if already existing head
+    if (*system_processes != NULL) {
+      //move "first to second"
+      tmp->set_next(*system_processes);
+    }
+    // new head
+    *system_processes = tmp;
+    // increment
+    (*no_of_sys_processes)++;
+    // step forward
+    _iterator->next_process();
+  }
+  return OS_OK;
+}
+
+int SystemProcessInterface::system_processes(SystemProcess** system_procs,
+                                             int* no_of_sys_processes) const {
+  return _impl->system_processes(system_procs, no_of_sys_processes);
+}
+
+SystemProcessInterface::SystemProcessInterface() {
+  _impl = NULL;
+}
+
+bool SystemProcessInterface::initialize() {
+  _impl = new SystemProcessInterface::SystemProcesses();
+  return _impl != NULL && _impl->initialize();
+}
+
+SystemProcessInterface::~SystemProcessInterface() {
+  if (_impl != NULL) {
+    delete _impl;
+  }
+}
+
+CPUInformationInterface::CPUInformationInterface() {
+  _cpu_info = NULL;
+}
+
+bool CPUInformationInterface::initialize() {
+  _cpu_info = new CPUInformation();
+  if (NULL == _cpu_info) {
+    return false;
+  }
+  _cpu_info->set_number_of_hardware_threads(VM_Version_Ext::number_of_threads());
+  _cpu_info->set_number_of_cores(VM_Version_Ext::number_of_cores());
+  _cpu_info->set_number_of_sockets(VM_Version_Ext::number_of_sockets());
+  _cpu_info->set_cpu_name(VM_Version_Ext::cpu_name());
+  _cpu_info->set_cpu_description(VM_Version_Ext::cpu_description());
+  return true;
+}
+
+CPUInformationInterface::~CPUInformationInterface() {
+  if (_cpu_info != NULL) {
+    const char* cpu_name = _cpu_info->cpu_name();
+    if (cpu_name != NULL) {
+      FREE_C_HEAP_ARRAY(char, cpu_name);
+      _cpu_info->set_cpu_name(NULL);
+    }
+    const char* cpu_desc = _cpu_info->cpu_description();
+    if (cpu_desc != NULL) {
+      FREE_C_HEAP_ARRAY(char, cpu_desc);
+      _cpu_info->set_cpu_description(NULL);
+    }
+    delete _cpu_info;
+    _cpu_info = NULL;
+  }
+}
+
+int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {
+  if (NULL == _cpu_info) {
+    return OS_ERR;
+  }
+  cpu_info = *_cpu_info; // shallow copy assignment
+  return OS_OK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/os/windows/pdh_interface.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "pdh_interface.hpp"
+#include "runtime/os.hpp"
+#include "utilities/macros.hpp"
+
+// PDH API
+typedef PDH_STATUS (WINAPI *PdhAddCounter_Fn)(HQUERY, LPCSTR, DWORD, HCOUNTER*);
+typedef PDH_STATUS (WINAPI *PdhOpenQuery_Fn)(LPCWSTR, DWORD, HQUERY*);
+typedef DWORD      (WINAPI *PdhCloseQuery_Fn)(HQUERY);
+typedef PDH_STATUS (WINAPI *PdhCollectQueryData_Fn)(HQUERY);
+typedef DWORD      (WINAPI *PdhGetFormattedCounterValue_Fn)(HCOUNTER, DWORD, LPDWORD, PPDH_FMT_COUNTERVALUE);
+typedef PDH_STATUS (WINAPI *PdhEnumObjectItems_Fn)(LPCTSTR, LPCTSTR, LPCTSTR, LPTSTR, LPDWORD, LPTSTR, LPDWORD, DWORD, DWORD);
+typedef PDH_STATUS (WINAPI *PdhRemoveCounter_Fn)(HCOUNTER);
+typedef PDH_STATUS (WINAPI *PdhLookupPerfNameByIndex_Fn)(LPCSTR, DWORD, LPSTR, LPDWORD);
+typedef PDH_STATUS (WINAPI *PdhMakeCounterPath_Fn)(PDH_COUNTER_PATH_ELEMENTS*, LPTSTR, LPDWORD, DWORD);
+
+PdhAddCounter_Fn PdhDll::_PdhAddCounter = NULL;
+PdhOpenQuery_Fn  PdhDll::_PdhOpenQuery = NULL;
+PdhCloseQuery_Fn PdhDll::_PdhCloseQuery = NULL;
+PdhCollectQueryData_Fn PdhDll::_PdhCollectQueryData = NULL;
+PdhGetFormattedCounterValue_Fn PdhDll::_PdhGetFormattedCounterValue = NULL;
+PdhEnumObjectItems_Fn PdhDll::_PdhEnumObjectItems = NULL;
+PdhRemoveCounter_Fn PdhDll::_PdhRemoveCounter = NULL;
+PdhLookupPerfNameByIndex_Fn PdhDll::_PdhLookupPerfNameByIndex = NULL;
+PdhMakeCounterPath_Fn PdhDll::_PdhMakeCounterPath = NULL;
+
+LONG PdhDll::_critical_section = 0;
+LONG PdhDll::_initialized = 0;
+LONG PdhDll::_pdh_reference_count = 0;
+HMODULE PdhDll::_hModule = NULL;
+
+void PdhDll::initialize(void) {
+  _hModule = os::win32::load_Windows_dll("pdh.dll", NULL, 0);
+  if (NULL == _hModule) {
+    return;
+  }
+  // The 'A' at the end means the ANSI (not the UNICODE) vesions of the methods
+  _PdhAddCounter               = (PdhAddCounter_Fn)::GetProcAddress(_hModule, "PdhAddCounterA");
+  _PdhOpenQuery                = (PdhOpenQuery_Fn)::GetProcAddress(_hModule, "PdhOpenQueryA");
+  _PdhCloseQuery               = (PdhCloseQuery_Fn)::GetProcAddress(_hModule, "PdhCloseQuery");
+  _PdhCollectQueryData         = (PdhCollectQueryData_Fn)::GetProcAddress(_hModule, "PdhCollectQueryData");
+  _PdhGetFormattedCounterValue = (PdhGetFormattedCounterValue_Fn)::GetProcAddress(_hModule, "PdhGetFormattedCounterValue");
+  _PdhEnumObjectItems          = (PdhEnumObjectItems_Fn)::GetProcAddress(_hModule, "PdhEnumObjectItemsA");
+  _PdhRemoveCounter            = (PdhRemoveCounter_Fn)::GetProcAddress(_hModule, "PdhRemoveCounter");
+  _PdhLookupPerfNameByIndex    = (PdhLookupPerfNameByIndex_Fn)::GetProcAddress(_hModule, "PdhLookupPerfNameByIndexA");
+  _PdhMakeCounterPath          = (PdhMakeCounterPath_Fn)::GetProcAddress(_hModule, "PdhMakeCounterPathA");
+  InterlockedExchange(&_initialized, 1);
+}
+
+bool PdhDll::PdhDetach(void) {
+  LONG prev_ref_count = InterlockedExchangeAdd(&_pdh_reference_count, -1);
+  BOOL ret = false;
+  if (1 == prev_ref_count) {
+    if (_initialized && _hModule != NULL) {
+      ret = FreeLibrary(_hModule);
+      if (ret) {
+        _hModule = NULL;
+        _PdhAddCounter = NULL;
+        _PdhOpenQuery = NULL;
+        _PdhCloseQuery = NULL;
+        _PdhCollectQueryData = NULL;
+        _PdhGetFormattedCounterValue = NULL;
+        _PdhEnumObjectItems = NULL;
+        _PdhRemoveCounter = NULL;
+        _PdhLookupPerfNameByIndex = NULL;
+        _PdhMakeCounterPath = NULL;
+        InterlockedExchange(&_initialized, 0);
+      }
+    }
+  }
+  return ret != 0;
+}
+
+bool PdhDll::PdhAttach(void) {
+  InterlockedExchangeAdd(&_pdh_reference_count, 1);
+  if (1 == _initialized) {
+    return true;
+  }
+  while (InterlockedCompareExchange(&_critical_section, 1, 0) == 1);
+  if (0 == _initialized) {
+    initialize();
+  }
+  while (InterlockedCompareExchange(&_critical_section, 0, 1) == 0);
+  return (_PdhAddCounter != NULL && _PdhOpenQuery != NULL
+         && _PdhCloseQuery != NULL && PdhCollectQueryData != NULL
+         && _PdhGetFormattedCounterValue != NULL && _PdhEnumObjectItems != NULL
+         && _PdhRemoveCounter != NULL && PdhLookupPerfNameByIndex != NULL
+         && _PdhMakeCounterPath != NULL);
+}
+
+PDH_STATUS PdhDll::PdhAddCounter(HQUERY hQuery, LPCSTR szFullCounterPath, DWORD dwUserData, HCOUNTER* phCounter) {
+  assert(_initialized && _PdhAddCounter != NULL, "PdhAvailable() not yet called");
+  return _PdhAddCounter(hQuery, szFullCounterPath, dwUserData, phCounter);
+}
+
+PDH_STATUS PdhDll::PdhOpenQuery(LPCWSTR szDataSource, DWORD dwUserData, HQUERY* phQuery) {
+  assert(_initialized && _PdhOpenQuery != NULL, "PdhAvailable() not yet called");
+  return _PdhOpenQuery(szDataSource, dwUserData, phQuery);
+}
+
+DWORD PdhDll::PdhCloseQuery(HQUERY hQuery) {
+  assert(_initialized && _PdhCloseQuery != NULL, "PdhAvailable() not yet called");
+  return _PdhCloseQuery(hQuery);
+}
+
+PDH_STATUS PdhDll::PdhCollectQueryData(HQUERY hQuery) {
+  assert(_initialized && _PdhCollectQueryData != NULL, "PdhAvailable() not yet called");
+  return _PdhCollectQueryData(hQuery);
+}
+
+DWORD PdhDll::PdhGetFormattedCounterValue(HCOUNTER hCounter, DWORD dwFormat, LPDWORD lpdwType, PPDH_FMT_COUNTERVALUE pValue) {
+  assert(_initialized && _PdhGetFormattedCounterValue != NULL, "PdhAvailable() not yet called");
+  return _PdhGetFormattedCounterValue(hCounter, dwFormat, lpdwType, pValue);
+}
+
+PDH_STATUS PdhDll::PdhEnumObjectItems(LPCTSTR szDataSource, LPCTSTR szMachineName, LPCTSTR szObjectName,
+    LPTSTR mszCounterList, LPDWORD pcchCounterListLength, LPTSTR mszInstanceList,
+    LPDWORD pcchInstanceListLength, DWORD dwDetailLevel, DWORD dwFlags) {
+  assert(_initialized && _PdhEnumObjectItems != NULL, "PdhAvailable() not yet called");
+  return _PdhEnumObjectItems(szDataSource, szMachineName, szObjectName, mszCounterList, pcchCounterListLength,
+    mszInstanceList, pcchInstanceListLength, dwDetailLevel, dwFlags);
+}
+
+PDH_STATUS PdhDll::PdhRemoveCounter(HCOUNTER hCounter) {
+  assert(_initialized && _PdhRemoveCounter != NULL, "PdhAvailable() not yet called");
+  return _PdhRemoveCounter(hCounter);
+}
+
+PDH_STATUS PdhDll::PdhLookupPerfNameByIndex(LPCSTR szMachineName, DWORD dwNameIndex, LPSTR szNameBuffer, LPDWORD pcchNameBufferSize) {
+  assert(_initialized && _PdhLookupPerfNameByIndex != NULL, "PdhAvailable() not yet called");
+  return _PdhLookupPerfNameByIndex(szMachineName, dwNameIndex, szNameBuffer, pcchNameBufferSize);
+}
+
+PDH_STATUS PdhDll::PdhMakeCounterPath(PDH_COUNTER_PATH_ELEMENTS* pCounterPathElements, LPTSTR szFullPathBuffer, LPDWORD pcchBufferSize, DWORD dwFlags) {
+  assert(_initialized && _PdhMakeCounterPath != NULL, "PdhAvailable() not yet called");
+  return _PdhMakeCounterPath(pCounterPathElements, szFullPathBuffer, pcchBufferSize, dwFlags);
+}
+
+bool PdhDll::PdhStatusFail(PDH_STATUS pdhStat) {
+  return pdhStat != ERROR_SUCCESS && pdhStat != PDH_MORE_DATA;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/os/windows/pdh_interface.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_WINDOWS_VM_PDH_INTERFACE_HPP
+#define OS_WINDOWS_VM_PDH_INTERFACE_HPP
+
+#include "memory/allocation.hpp"
+#include <pdh.h>
+#include <pdhmsg.h>
+
+class PdhDll: public AllStatic {
+ private:
+  static LONG       _pdh_reference_count;
+  static LONG       _critical_section;
+  static LONG       _initialized;
+  static HMODULE    _hModule;
+  static void       initialize();
+  static PDH_STATUS (WINAPI *_PdhAddCounter)(HQUERY, LPCSTR, DWORD, HCOUNTER*);
+  static PDH_STATUS (WINAPI *_PdhOpenQuery)(LPCWSTR, DWORD, HQUERY*);
+  static DWORD      (WINAPI *_PdhCloseQuery)(HQUERY);
+  static PDH_STATUS (WINAPI *_PdhCollectQueryData)(HQUERY);
+  static DWORD      (WINAPI *_PdhGetFormattedCounterValue)(HCOUNTER, DWORD, LPDWORD, PPDH_FMT_COUNTERVALUE);
+  static PDH_STATUS (WINAPI *_PdhEnumObjectItems)(LPCTSTR, LPCTSTR, LPCTSTR, LPTSTR, LPDWORD, LPTSTR, LPDWORD, DWORD, DWORD);
+  static PDH_STATUS (WINAPI *_PdhRemoveCounter)(HCOUNTER);
+  static PDH_STATUS (WINAPI *_PdhLookupPerfNameByIndex)(LPCSTR, DWORD, LPSTR, LPDWORD);
+  static PDH_STATUS (WINAPI *_PdhMakeCounterPath)(PPDH_COUNTER_PATH_ELEMENTS, LPTSTR, LPDWORD, DWORD);
+
+ public:
+  static PDH_STATUS PdhAddCounter(HQUERY, LPCSTR, DWORD, HCOUNTER*);
+  static PDH_STATUS PdhOpenQuery(LPCWSTR, DWORD, HQUERY*);
+  static DWORD      PdhCloseQuery(HQUERY);
+  static PDH_STATUS PdhCollectQueryData(HQUERY);
+  static DWORD      PdhGetFormattedCounterValue(HCOUNTER, DWORD, LPDWORD, PPDH_FMT_COUNTERVALUE);
+  static PDH_STATUS PdhEnumObjectItems(LPCTSTR, LPCTSTR, LPCTSTR, LPTSTR, LPDWORD, LPTSTR, LPDWORD, DWORD, DWORD);
+  static PDH_STATUS PdhRemoveCounter(HCOUNTER);
+  static PDH_STATUS PdhLookupPerfNameByIndex(LPCSTR, DWORD, LPSTR, LPDWORD);
+  static PDH_STATUS PdhMakeCounterPath(PPDH_COUNTER_PATH_ELEMENTS, LPTSTR, LPDWORD, DWORD);
+  static bool       PdhStatusFail(PDH_STATUS pdhStat);
+  static bool       PdhAttach();
+  static bool       PdhDetach();
+};
+
+#endif // OS_WINDOWS_VM_PDH_INTERFACE_HPP
--- a/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.inline.hpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.inline.hpp	Tue May 15 20:24:34 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,8 @@
 
 #include "runtime/os.hpp"
 
+extern "C" jlong _raw_rdtsc(); // In .il file
+
 inline jlong os::rdtsc() { return _raw_rdtsc(); }
 
 #endif // OS_CPU_SOLARIS_X86_VM_OS_SOLARIS_X86_INLINE_HPP
--- a/src/hotspot/share/c1/c1_Compiler.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/c1/c1_Compiler.cpp	Tue May 15 20:24:34 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,6 +33,7 @@
 #include "c1/c1_ValueType.hpp"
 #include "compiler/compileBroker.hpp"
 #include "interpreter/linkResolver.hpp"
+#include "jfr/support/jfrIntrinsics.hpp"
 #include "memory/allocation.hpp"
 #include "memory/allocation.inline.hpp"
 #include "memory/resourceArea.hpp"
@@ -41,6 +42,7 @@
 #include "runtime/interfaceSupport.inline.hpp"
 #include "runtime/sharedRuntime.hpp"
 #include "utilities/bitMap.inline.hpp"
+#include "utilities/macros.hpp"
 
 
 Compiler::Compiler() : AbstractCompiler(compiler_c1) {
@@ -222,10 +224,10 @@
   case vmIntrinsics::_compareAndSetObject:
   case vmIntrinsics::_getCharStringU:
   case vmIntrinsics::_putCharStringU:
-#ifdef TRACE_HAVE_INTRINSICS
+#ifdef JFR_HAVE_INTRINSICS
   case vmIntrinsics::_counterTime:
-  case vmIntrinsics::_getBufferWriter:
-#if defined(_LP64) || !defined(TRACE_ID_CLASS_SHIFT)
+  case vmIntrinsics::_getEventWriter:
+#if defined(_LP64) || !defined(TRACE_ID_SHIFT)
   case vmIntrinsics::_getClassId:
 #endif
 #endif
--- a/src/hotspot/share/c1/c1_GraphBuilder.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/c1/c1_GraphBuilder.cpp	Tue May 15 20:24:34 2018 +0200
@@ -35,6 +35,7 @@
 #include "ci/ciUtilities.inline.hpp"
 #include "compiler/compileBroker.hpp"
 #include "interpreter/bytecode.hpp"
+#include "jfr/jfrEvents.hpp"
 #include "memory/resourceArea.hpp"
 #include "oops/oop.inline.hpp"
 #include "runtime/sharedRuntime.hpp"
@@ -4300,6 +4301,30 @@
   }
 }
 
+static void post_inlining_event(EventCompilerInlining* event,
+                                int compile_id,
+                                const char* msg,
+                                bool success,
+                                int bci,
+                                ciMethod* caller,
+                                ciMethod* callee) {
+  assert(caller != NULL, "invariant");
+  assert(callee != NULL, "invariant");
+  assert(event != NULL, "invariant");
+  assert(event->should_commit(), "invariant");
+  JfrStructCalleeMethod callee_struct;
+  callee_struct.set_type(callee->holder()->name()->as_utf8());
+  callee_struct.set_name(callee->name()->as_utf8());
+  callee_struct.set_descriptor(callee->signature()->as_symbol()->as_utf8());
+  event->set_compileId(compile_id);
+  event->set_message(msg);
+  event->set_succeeded(success);
+  event->set_bci(bci);
+  event->set_caller(caller->get_Method());
+  event->set_callee(callee_struct);
+  event->commit();
+}
+
 void GraphBuilder::print_inlining(ciMethod* callee, const char* msg, bool success) {
   CompileLog* log = compilation()->log();
   if (log != NULL) {
@@ -4315,18 +4340,10 @@
         log->inline_fail("reason unknown");
     }
   }
-#if INCLUDE_TRACE
   EventCompilerInlining event;
   if (event.should_commit()) {
-    event.set_compileId(compilation()->env()->task()->compile_id());
-    event.set_message(msg);
-    event.set_succeeded(success);
-    event.set_bci(bci());
-    event.set_caller(method()->get_Method());
-    event.set_callee(callee->to_trace_struct());
-    event.commit();
+    post_inlining_event(&event, compilation()->env()->task()->compile_id(), msg, success, bci(), method(), callee);
   }
-#endif // INCLUDE_TRACE
 
   CompileTask::print_inlining_ul(callee, scope()->level(), bci(), msg);
 
--- a/src/hotspot/share/c1/c1_LIRGenerator.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp	Tue May 15 20:24:34 2018 +0200
@@ -42,9 +42,6 @@
 #include "runtime/vm_version.hpp"
 #include "utilities/bitMap.inline.hpp"
 #include "utilities/macros.hpp"
-#ifdef TRACE_HAVE_INTRINSICS
-#include "trace/traceMacros.hpp"
-#endif
 
 #ifdef ASSERT
 #define __ gen()->lir(__FILE__, __LINE__)->
@@ -2916,7 +2913,7 @@
   __ cmove(lir_cond(x->cond()), t_val.result(), f_val.result(), reg, as_BasicType(x->x()->type()));
 }
 
-#ifdef TRACE_HAVE_INTRINSICS
+#ifdef JFR_HAVE_INTRINSICS
 void LIRGenerator::do_ClassIDIntrinsic(Intrinsic* x) {
   CodeEmitInfo* info = state_for(x);
   CodeEmitInfo* info2 = new CodeEmitInfo(info); // Clone for the second null check
@@ -2928,7 +2925,7 @@
   LIR_Opr klass = new_register(T_METADATA);
   __ move(new LIR_Address(arg.result(), java_lang_Class::klass_offset_in_bytes(), T_ADDRESS), klass, info);
   LIR_Opr id = new_register(T_LONG);
-  ByteSize offset = TRACE_KLASS_TRACE_ID_OFFSET;
+  ByteSize offset = KLASS_TRACE_ID_OFFSET;
   LIR_Address* trace_id_addr = new LIR_Address(klass, in_bytes(offset), T_LONG);
 
   __ move(trace_id_addr, id);
@@ -2938,18 +2935,18 @@
 #ifdef TRACE_ID_META_BITS
   __ logical_and(id, LIR_OprFact::longConst(~TRACE_ID_META_BITS), id);
 #endif
-#ifdef TRACE_ID_CLASS_SHIFT
-  __ unsigned_shift_right(id, TRACE_ID_CLASS_SHIFT, id);
+#ifdef TRACE_ID_SHIFT
+  __ unsigned_shift_right(id, TRACE_ID_SHIFT, id);
 #endif
 
   __ move(id, rlock_result(x));
 }
 
-void LIRGenerator::do_getBufferWriter(Intrinsic* x) {
+void LIRGenerator::do_getEventWriter(Intrinsic* x) {
   LabelObj* L_end = new LabelObj();
 
   LIR_Address* jobj_addr = new LIR_Address(getThreadPointer(),
-                                           in_bytes(TRACE_THREAD_DATA_WRITER_OFFSET),
+                                           in_bytes(THREAD_LOCAL_WRITER_OFFSET_JFR),
                                            T_OBJECT);
   LIR_Opr result = rlock_result(x);
   __ move_wide(jobj_addr, result);
@@ -2987,15 +2984,15 @@
     break;
   }
 
-#ifdef TRACE_HAVE_INTRINSICS
+#ifdef JFR_HAVE_INTRINSICS
   case vmIntrinsics::_getClassId:
     do_ClassIDIntrinsic(x);
     break;
-  case vmIntrinsics::_getBufferWriter:
-    do_getBufferWriter(x);
+  case vmIntrinsics::_getEventWriter:
+    do_getEventWriter(x);
     break;
   case vmIntrinsics::_counterTime:
-    do_RuntimeCall(CAST_FROM_FN_PTR(address, TRACE_TIME_METHOD), x);
+    do_RuntimeCall(CAST_FROM_FN_PTR(address, JFR_TIME_FUNCTION), x);
     break;
 #endif
 
--- a/src/hotspot/share/c1/c1_LIRGenerator.hpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/c1/c1_LIRGenerator.hpp	Tue May 15 20:24:34 2018 +0200
@@ -30,6 +30,7 @@
 #include "c1/c1_LIR.hpp"
 #include "ci/ciMethodData.hpp"
 #include "gc/shared/barrierSet.hpp"
+#include "jfr/support/jfrIntrinsics.hpp"
 #include "utilities/macros.hpp"
 #include "utilities/sizes.hpp"
 
@@ -459,9 +460,9 @@
   SwitchRangeArray* create_lookup_ranges(LookupSwitch* x);
   void do_SwitchRanges(SwitchRangeArray* x, LIR_Opr value, BlockBegin* default_sux);
 
-#ifdef TRACE_HAVE_INTRINSICS
+#ifdef JFR_HAVE_INTRINSICS
   void do_ClassIDIntrinsic(Intrinsic* x);
-  void do_getBufferWriter(Intrinsic* x);
+  void do_getEventWriter(Intrinsic* x);
 #endif
 
   void do_RuntimeCall(address routine, Intrinsic* x);
--- a/src/hotspot/share/c1/c1_Runtime1.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/c1/c1_Runtime1.cpp	Tue May 15 20:24:34 2018 +0200
@@ -43,6 +43,7 @@
 #include "gc/shared/collectedHeap.hpp"
 #include "interpreter/bytecode.hpp"
 #include "interpreter/interpreter.hpp"
+#include "jfr/support/jfrIntrinsics.hpp"
 #include "logging/log.hpp"
 #include "memory/allocation.inline.hpp"
 #include "memory/oopFactory.hpp"
@@ -320,8 +321,8 @@
   FUNCTION_CASE(entry, SharedRuntime::dtrace_method_exit);
   FUNCTION_CASE(entry, is_instance_of);
   FUNCTION_CASE(entry, trace_block_entry);
-#ifdef TRACE_HAVE_INTRINSICS
-  FUNCTION_CASE(entry, TRACE_TIME_METHOD);
+#ifdef JFR_HAVE_INTRINSICS
+  FUNCTION_CASE(entry, JFR_TIME_FUNCTION);
 #endif
   FUNCTION_CASE(entry, StubRoutines::updateBytesCRC32());
   FUNCTION_CASE(entry, StubRoutines::updateBytesCRC32C());
--- a/src/hotspot/share/ci/ciEnv.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/ci/ciEnv.cpp	Tue May 15 20:24:34 2018 +0200
@@ -42,6 +42,7 @@
 #include "compiler/disassembler.hpp"
 #include "gc/shared/collectedHeap.inline.hpp"
 #include "interpreter/linkResolver.hpp"
+#include "jfr/jfrEvents.hpp"
 #include "memory/allocation.inline.hpp"
 #include "memory/oopFactory.hpp"
 #include "memory/resourceArea.hpp"
@@ -60,7 +61,6 @@
 #include "runtime/safepointVerifiers.hpp"
 #include "runtime/sharedRuntime.hpp"
 #include "runtime/thread.inline.hpp"
-#include "trace/tracing.hpp"
 #include "utilities/dtrace.hpp"
 #include "utilities/macros.hpp"
 #ifdef COMPILER1
@@ -1144,7 +1144,6 @@
 }
 
 void ciEnv::report_failure(const char* reason) {
-  // Create and fire JFR event
   EventCompilationFailure event;
   if (event.should_commit()) {
     event.set_compileId(compile_id());
--- a/src/hotspot/share/ci/ciMethod.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/ci/ciMethod.cpp	Tue May 15 20:24:34 2018 +0200
@@ -48,7 +48,6 @@
 #include "runtime/deoptimization.hpp"
 #include "utilities/bitMap.inline.hpp"
 #include "utilities/xmlstream.hpp"
-#include "trace/tracing.hpp"
 #ifdef COMPILER2
 #include "ci/bcEscapeAnalyzer.hpp"
 #include "ci/ciTypeFlow.hpp"
@@ -1495,13 +1494,3 @@
 }
 
 // ------------------------------------------------------------------
-
-#if INCLUDE_TRACE
-TraceStructCalleeMethod ciMethod::to_trace_struct() const {
-  TraceStructCalleeMethod result;
-  result.set_type(holder()->name()->as_utf8());
-  result.set_name(name()->as_utf8());
-  result.set_descriptor(signature()->as_symbol()->as_utf8());
-  return result;
-}
-#endif
--- a/src/hotspot/share/ci/ciMethod.hpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/ci/ciMethod.hpp	Tue May 15 20:24:34 2018 +0200
@@ -32,7 +32,6 @@
 #include "compiler/methodLiveness.hpp"
 #include "prims/methodHandles.hpp"
 #include "utilities/bitMap.hpp"
-#include "trace/tracing.hpp"
 
 class ciMethodBlocks;
 class MethodLiveness;
@@ -362,10 +361,6 @@
   void print_short_name(outputStream* st = tty);
 
   static bool is_consistent_info(ciMethod* declared_method, ciMethod* resolved_method);
-
-#if INCLUDE_TRACE
-  TraceStructCalleeMethod to_trace_struct() const;
-#endif
 };
 
 #endif // SHARE_VM_CI_CIMETHOD_HPP
--- a/src/hotspot/share/classfile/classFileParser.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/classfile/classFileParser.cpp	Tue May 15 20:24:34 2018 +0200
@@ -67,7 +67,6 @@
 #include "runtime/timer.hpp"
 #include "services/classLoadingService.hpp"
 #include "services/threadService.hpp"
-#include "trace/traceMacros.hpp"
 #include "utilities/align.hpp"
 #include "utilities/bitMap.inline.hpp"
 #include "utilities/copy.hpp"
@@ -80,6 +79,9 @@
 #if INCLUDE_CDS
 #include "classfile/systemDictionaryShared.hpp"
 #endif
+#if INCLUDE_JFR
+#include "jfr/support/jfrTraceIdExtension.hpp"
+#endif
 
 // We generally try to create the oops directly when parsing, rather than
 // allocating temporary data structures and copying the bytes twice. A
@@ -5639,7 +5641,7 @@
     }
   }
 
-  TRACE_INIT_ID(ik);
+  JFR_ONLY(INIT_ID(ik);)
 
   // If we reach here, all is well.
   // Now remove the InstanceKlass* from the _klass_to_deallocate field
--- a/src/hotspot/share/classfile/classLoaderData.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/classfile/classLoaderData.cpp	Tue May 15 20:24:34 2018 +0200
@@ -76,8 +76,10 @@
 #include "utilities/growableArray.hpp"
 #include "utilities/macros.hpp"
 #include "utilities/ostream.hpp"
-#if INCLUDE_TRACE
-#include "trace/tracing.hpp"
+#include "utilities/ticks.hpp"
+#if INCLUDE_JFR
+#include "jfr/jfr.hpp"
+#include "jfr/jfrEvents.hpp"
 #endif
 
 volatile size_t ClassLoaderDataGraph::_num_array_classes = 0;
@@ -161,7 +163,7 @@
 
   NOT_PRODUCT(_dependency_count = 0); // number of class loader dependencies
 
-  TRACE_INIT_ID(this);
+  JFR_ONLY(INIT_ID(this);)
 }
 
 ClassLoaderData::ChunkedHandleList::~ChunkedHandleList() {
@@ -1276,6 +1278,28 @@
 }
 #endif // PRODUCT
 
+#if INCLUDE_JFR
+static Ticks class_unload_time;
+static void post_class_unload_event(Klass* const k) {
+  assert(k != NULL, "invariant");
+  EventClassUnload event(UNTIMED);
+  event.set_endtime(class_unload_time);
+  event.set_unloadedClass(k);
+  event.set_definingClassLoader(k->class_loader_data());
+  event.commit();
+}
+
+static void post_class_unload_events() {
+  assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
+  if (Jfr::is_enabled()) {
+    if (EventClassUnload::is_enabled()) {
+      class_unload_time = Ticks::now();
+      ClassLoaderDataGraph::classes_unloading_do(&post_class_unload_event);
+    }
+    Jfr::on_unloading_classes();
+  }
+}
+#endif // INCLUDE_JFR
 
 // Move class loader data from main list to the unloaded list for unloading
 // and deallocation later.
@@ -1353,8 +1377,7 @@
       }
       data = data->next();
     }
-
-    post_class_unload_events();
+    JFR_ONLY(post_class_unload_events();)
   }
 
   log_debug(class, loader, data)("do_unloading: loaders processed %u, loaders removed %u", loaders_processed, loaders_removed);
@@ -1393,20 +1416,6 @@
   return resized;
 }
 
-void ClassLoaderDataGraph::post_class_unload_events() {
-#if INCLUDE_TRACE
-  assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
-  if (Tracing::enabled()) {
-    if (Tracing::is_event_enabled(TraceClassUnloadEvent)) {
-      assert(_unloading != NULL, "need class loader data unload list!");
-      _class_unload_time = Ticks::now();
-      classes_unloading_do(&class_unload_event);
-    }
-    Tracing::on_unloading_classes();
-  }
-#endif
-}
-
 ClassLoaderDataGraphKlassIteratorAtomic::ClassLoaderDataGraphKlassIteratorAtomic()
     : _next_klass(NULL) {
   ClassLoaderData* cld = ClassLoaderDataGraph::_head;
@@ -1490,20 +1499,3 @@
   }
 }
 #endif // PRODUCT
-
-#if INCLUDE_TRACE
-
-Ticks ClassLoaderDataGraph::_class_unload_time;
-
-void ClassLoaderDataGraph::class_unload_event(Klass* const k) {
-  assert(k != NULL, "invariant");
-
-  // post class unload event
-  EventClassUnload event(UNTIMED);
-  event.set_endtime(_class_unload_time);
-  event.set_unloadedClass(k);
-  event.set_definingClassLoader(k->class_loader_data());
-  event.commit();
-}
-
-#endif // INCLUDE_TRACE
--- a/src/hotspot/share/classfile/classLoaderData.hpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/classfile/classLoaderData.hpp	Tue May 15 20:24:34 2018 +0200
@@ -31,13 +31,13 @@
 #include "oops/oopHandle.hpp"
 #include "oops/weakHandle.hpp"
 #include "runtime/mutex.hpp"
-#include "trace/traceMacros.hpp"
 #include "utilities/growableArray.hpp"
 #include "utilities/macros.hpp"
-#if INCLUDE_TRACE
-#include "utilities/ticks.hpp"
+#if INCLUDE_JFR
+#include "jfr/support/jfrTraceIdExtension.hpp"
 #endif
 
+
 //
 // A class loader represents a linkset. Conceptually, a linkset identifies
 // the complete transitive closure of resolved links that a dynamic linker can
@@ -85,7 +85,6 @@
 
   static ClassLoaderData* add_to_graph(Handle class_loader, bool anonymous);
   static ClassLoaderData* add(Handle class_loader, bool anonymous);
-  static void post_class_unload_events();
  public:
   static ClassLoaderData* find_or_create(Handle class_loader);
   static void purge();
@@ -167,12 +166,6 @@
 #ifndef PRODUCT
   static bool contains_loader_data(ClassLoaderData* loader_data);
 #endif
-
-#if INCLUDE_TRACE
- private:
-  static Ticks _class_unload_time;
-  static void class_unload_event(Klass* const k);
-#endif
 };
 
 // ClassLoaderData class
@@ -268,7 +261,7 @@
   // JFR support
   Klass*  _class_loader_klass;
   Symbol* _class_loader_name;
-  TRACE_DEFINE_TRACE_ID_FIELD;
+  JFR_ONLY(DEFINE_TRACE_ID_FIELD;)
 
   void set_next(ClassLoaderData* next) { _next = next; }
   ClassLoaderData* next() const        { return _next; }
@@ -410,7 +403,7 @@
 
   Klass* class_loader_klass() const { return _class_loader_klass; }
   Symbol* class_loader_name() const { return _class_loader_name; }
-  TRACE_DEFINE_TRACE_ID_METHODS;
+  JFR_ONLY(DEFINE_TRACE_ID_METHODS;)
 };
 
 // An iterator that distributes Klasses to parallel worker threads.
--- a/src/hotspot/share/classfile/klassFactory.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/classfile/klassFactory.cpp	Tue May 15 20:24:34 2018 +0200
@@ -35,7 +35,11 @@
 #include "prims/jvmtiEnvBase.hpp"
 #include "prims/jvmtiRedefineClasses.hpp"
 #include "runtime/handles.inline.hpp"
-#include "trace/traceMacros.hpp"
+#include "utilities/macros.hpp"
+#if INCLUDE_JFR
+#include "jfr/support/jfrKlassExtension.hpp"
+#endif
+
 
 // called during initial loading of a shared class
 InstanceKlass* KlassFactory::check_shared_class_file_load_hook(
@@ -228,7 +232,7 @@
     result->store_fingerprint(stream->compute_fingerprint());
   }
 
-  TRACE_KLASS_CREATION(result, parser, THREAD);
+  JFR_ONLY(ON_KLASS_CREATION(result, parser, THREAD);)
 
 #if INCLUDE_CDS
   if (DumpSharedSpaces) {
--- a/src/hotspot/share/classfile/moduleEntry.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/classfile/moduleEntry.cpp	Tue May 15 20:24:34 2018 +0200
@@ -33,7 +33,6 @@
 #include "oops/symbol.hpp"
 #include "runtime/handles.inline.hpp"
 #include "runtime/safepoint.hpp"
-#include "trace/traceMacros.hpp"
 #include "utilities/events.hpp"
 #include "utilities/growableArray.hpp"
 #include "utilities/hashtable.inline.hpp"
@@ -215,7 +214,7 @@
   }
 }
 
-void ModuleEntry::module_reads_do(ModuleClosure* const f) {
+void ModuleEntry::module_reads_do(ModuleClosure* f) {
   assert_locked_or_safepoint(Module_lock);
   assert(f != NULL, "invariant");
 
@@ -279,7 +278,7 @@
   entry->set_loader_data(cld);
   entry->_is_open = true;
 
-  TRACE_INIT_ID(entry);
+  JFR_ONLY(INIT_ID(entry);)
 
   return entry;
 }
@@ -367,7 +366,7 @@
     }
   }
 
-  TRACE_INIT_ID(entry);
+  JFR_ONLY(INIT_ID(entry);)
 
   return entry;
 }
--- a/src/hotspot/share/classfile/moduleEntry.hpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/classfile/moduleEntry.hpp	Tue May 15 20:24:34 2018 +0200
@@ -32,10 +32,13 @@
 #include "oops/symbol.hpp"
 #include "runtime/jniHandles.hpp"
 #include "runtime/mutexLocker.hpp"
-#include "trace/traceMacros.hpp"
 #include "utilities/growableArray.hpp"
 #include "utilities/hashtable.hpp"
+#include "utilities/macros.hpp"
 #include "utilities/ostream.hpp"
+#if INCLUDE_JFR
+#include "jfr/support/jfrTraceIdExtension.hpp"
+#endif
 
 #define UNNAMED_MODULE "Unnamed Module"
 #define JAVAPKG "java"
@@ -69,7 +72,7 @@
   bool _must_walk_reads;               // walk module's reads list at GC safepoints to purge out dead modules
   bool _is_open;                       // whether the packages in the module are all unqualifiedly exported
   bool _is_patched;                    // whether the module is patched via --patch-module
-  TRACE_DEFINE_TRACE_ID_FIELD;
+  JFR_ONLY(DEFINE_TRACE_ID_FIELD;)
   enum {MODULE_READS_SIZE = 101};      // Initial size of list of modules that the module can read.
 
 public:
@@ -164,8 +167,6 @@
   // iteration support for readability
   void module_reads_do(ModuleClosure* const f);
 
-  TRACE_DEFINE_TRACE_ID_METHODS;
-
   // Purge dead weak references out of reads list when any given class loader is unloaded.
   void purge_reads();
   void delete_reads();
@@ -178,12 +179,14 @@
 
   void print(outputStream* st = tty);
   void verify();
+
+  JFR_ONLY(DEFINE_TRACE_ID_METHODS;)
 };
 
 // Iterator interface
 class ModuleClosure: public StackObj {
  public:
-  virtual void do_module(ModuleEntry* const module) = 0;
+  virtual void do_module(ModuleEntry* module) = 0;
 };
 
 
--- a/src/hotspot/share/classfile/packageEntry.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/classfile/packageEntry.cpp	Tue May 15 20:24:34 2018 +0200
@@ -29,7 +29,6 @@
 #include "memory/resourceArea.hpp"
 #include "oops/symbol.hpp"
 #include "runtime/handles.inline.hpp"
-#include "trace/traceMacros.hpp"
 #include "utilities/events.hpp"
 #include "utilities/growableArray.hpp"
 #include "utilities/hashtable.inline.hpp"
@@ -200,7 +199,7 @@
   assert(Module_lock->owned_by_self(), "should have the Module_lock");
   PackageEntry* entry = (PackageEntry*)Hashtable<Symbol*, mtModule>::allocate_new_entry(hash, name);
 
-  TRACE_INIT_ID(entry);
+  JFR_ONLY(INIT_ID(entry);)
 
   // Initialize fields specific to a PackageEntry
   entry->init();
@@ -283,7 +282,7 @@
 }
 
 // iteration of qualified exports
-void PackageEntry::package_exports_do(ModuleClosure* const f) {
+void PackageEntry::package_exports_do(ModuleClosure* f) {
   assert_locked_or_safepoint(Module_lock);
   assert(f != NULL, "invariant");
 
--- a/src/hotspot/share/classfile/packageEntry.hpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/classfile/packageEntry.hpp	Tue May 15 20:24:34 2018 +0200
@@ -29,7 +29,12 @@
 #include "oops/symbol.hpp"
 #include "utilities/growableArray.hpp"
 #include "utilities/hashtable.hpp"
+#include "utilities/macros.hpp"
 #include "utilities/ostream.hpp"
+#if INCLUDE_JFR
+#include "jfr/support/jfrTraceIdExtension.hpp"
+#endif
+
 
 // A PackageEntry basically represents a Java package.  It contains:
 //   - Symbol* containing the package's name.
@@ -104,7 +109,7 @@
   // Contains list of modules this package is qualifiedly exported to.  Access
   // to this list is protected by the Module_lock.
   GrowableArray<ModuleEntry*>* _qualified_exports;
-  TRACE_DEFINE_TRACE_ID_FIELD;
+  JFR_ONLY(DEFINE_TRACE_ID_FIELD;)
 
   // Initial size of a package entry's list of qualified exports.
   enum {QUAL_EXP_SIZE = 43};
@@ -197,9 +202,9 @@
   }
 
   // iteration of qualified exports
-  void package_exports_do(ModuleClosure* const f);
+  void package_exports_do(ModuleClosure* f);
 
-  TRACE_DEFINE_TRACE_ID_METHODS;
+  JFR_ONLY(DEFINE_TRACE_ID_METHODS;)
 
   // Purge dead weak references out of exported list when any given class loader is unloaded.
   void purge_qualified_exports();
--- a/src/hotspot/share/classfile/systemDictionary.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/classfile/systemDictionary.cpp	Tue May 15 20:24:34 2018 +0200
@@ -47,6 +47,7 @@
 #include "gc/shared/oopStorage.inline.hpp"
 #include "interpreter/bytecodeStream.hpp"
 #include "interpreter/interpreter.hpp"
+#include "jfr/jfrEvents.hpp"
 #include "logging/log.hpp"
 #include "logging/logStream.hpp"
 #include "memory/filemap.hpp"
@@ -81,7 +82,6 @@
 #include "services/classLoadingService.hpp"
 #include "services/diagnosticCommand.hpp"
 #include "services/threadService.hpp"
-#include "trace/tracing.hpp"
 #include "utilities/macros.hpp"
 #if INCLUDE_CDS
 #include "classfile/systemDictionaryShared.hpp"
@@ -623,32 +623,16 @@
   return NULL;
 }
 
-static void post_class_load_event(EventClassLoad* event,
-                                  const InstanceKlass* k,
-                                  const ClassLoaderData* init_cld) {
-#if INCLUDE_TRACE
+static void post_class_load_event(EventClassLoad* event, const InstanceKlass* k, const ClassLoaderData* init_cld) {
   assert(event != NULL, "invariant");
   assert(k != NULL, "invariant");
-  if (event->should_commit()) {
-    event->set_loadedClass(k);
-    event->set_definingClassLoader(k->class_loader_data());
-    event->set_initiatingClassLoader(init_cld);
-    event->commit();
-  }
-#endif // INCLUDE_TRACE
+  assert(event->should_commit(), "invariant");
+  event->set_loadedClass(k);
+  event->set_definingClassLoader(k->class_loader_data());
+  event->set_initiatingClassLoader(init_cld);
+  event->commit();
 }
 
-static void class_define_event(InstanceKlass* k,
-                               const ClassLoaderData* def_cld) {
-#if INCLUDE_TRACE
-  EventClassDefine event;
-  if (event.should_commit()) {
-    event.set_definedClass(k);
-    event.set_definingClassLoader(def_cld);
-    event.commit();
-  }
-#endif // INCLUDE_TRACE
-}
 
 // Be careful when modifying this code: once you have run
 // placeholders()->find_and_add(PlaceholderTable::LOAD_INSTANCE),
@@ -881,9 +865,9 @@
   if (HAS_PENDING_EXCEPTION || k == NULL) {
     return NULL;
   }
-
-  post_class_load_event(&class_load_start_event, k, loader_data);
-
+  if (class_load_start_event.should_commit()) {
+    post_class_load_event(&class_load_start_event, k, loader_data);
+  }
 #ifdef ASSERT
   {
     ClassLoaderData* loader_data = k->class_loader_data();
@@ -1045,8 +1029,9 @@
         assert(THREAD->is_Java_thread(), "thread->is_Java_thread()");
         JvmtiExport::post_class_load((JavaThread *) THREAD, k);
     }
-
-    post_class_load_event(&class_load_start_event, k, loader_data);
+    if (class_load_start_event.should_commit()) {
+      post_class_load_event(&class_load_start_event, k, loader_data);
+    }
   }
   assert(host_klass != NULL || NULL == cp_patches,
          "cp_patches only found with host_klass");
@@ -1558,6 +1543,15 @@
   }
 }
 
+static void post_class_define_event(InstanceKlass* k, const ClassLoaderData* def_cld) {
+  EventClassDefine event;
+  if (event.should_commit()) {
+    event.set_definedClass(k);
+    event.set_definingClassLoader(def_cld);
+    event.commit();
+  }
+}
+
 void SystemDictionary::define_instance_class(InstanceKlass* k, TRAPS) {
 
   HandleMark hm(THREAD);
@@ -1626,7 +1620,7 @@
       JvmtiExport::post_class_load((JavaThread *) THREAD, k);
 
   }
-  class_define_event(k, loader_data);
+  post_class_define_event(k, loader_data);
 }
 
 // Support parallel classloading
--- a/src/hotspot/share/classfile/vmSymbols.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/classfile/vmSymbols.cpp	Tue May 15 20:24:34 2018 +0200
@@ -350,7 +350,7 @@
 bool vmIntrinsics::preserves_state(vmIntrinsics::ID id) {
   assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
   switch(id) {
-#ifdef TRACE_HAVE_INTRINSICS
+#ifdef JFR_HAVE_INTRINSICS
   case vmIntrinsics::_counterTime:
 #endif
   case vmIntrinsics::_currentTimeMillis:
@@ -388,7 +388,7 @@
 bool vmIntrinsics::can_trap(vmIntrinsics::ID id) {
   assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
   switch(id) {
-#ifdef TRACE_HAVE_INTRINSICS
+#ifdef JFR_HAVE_INTRINSICS
   case vmIntrinsics::_counterTime:
   case vmIntrinsics::_getClassId:
 #endif
@@ -424,7 +424,7 @@
 bool vmIntrinsics::should_be_pinned(vmIntrinsics::ID id) {
   assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
   switch(id) {
-#ifdef TRACE_HAVE_INTRINSICS
+#ifdef JFR_HAVE_INTRINSICS
   case vmIntrinsics::_counterTime:
 #endif
   case vmIntrinsics::_currentTimeMillis:
--- a/src/hotspot/share/classfile/vmSymbols.hpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/classfile/vmSymbols.hpp	Tue May 15 20:24:34 2018 +0200
@@ -26,10 +26,12 @@
 #define SHARE_VM_CLASSFILE_VMSYMBOLS_HPP
 
 #include "classfile/moduleEntry.hpp"
-#include "oops/symbol.hpp"
+#include "jfr/support/jfrIntrinsics.hpp"
+#include "jvmci/vmSymbols_jvmci.hpp"
 #include "memory/iterator.hpp"
-#include "trace/traceMacros.hpp"
-#include "jvmci/vmSymbols_jvmci.hpp"
+#include "oops/symbol.hpp"
+#include "utilities/macros.hpp"
+
 
 // The class vmSymbols is a name space for fast lookup of
 // symbols commonly used in the VM.
@@ -640,8 +642,8 @@
   /* forEachRemaining support */                                                                                  \
   template(java_util_stream_StreamsRangeIntSpliterator,          "java/util/stream/Streams$RangeIntSpliterator")  \
                                                                                                                   \
-  /* trace signatures */                                                                                          \
-  TRACE_TEMPLATES(template)                                                                                       \
+  /* jfr signatures */                                                                                            \
+  JFR_TEMPLATES(template)                                                                                         \
                                                                                                                   \
   /* cds */                                                                                                       \
   template(jdk_internal_loader_ClassLoaders,       "jdk/internal/loader/ClassLoaders")                            \
@@ -827,7 +829,7 @@
   do_intrinsic(_nanoTime,                 java_lang_System,       nanoTime_name,          void_long_signature,   F_S)   \
    do_name(     nanoTime_name,                                   "nanoTime")                                            \
                                                                                                                         \
-  TRACE_INTRINSICS(do_intrinsic, do_class, do_name, do_signature, do_alias)                                             \
+  JFR_INTRINSICS(do_intrinsic, do_class, do_name, do_signature, do_alias)                                               \
                                                                                                                         \
   do_intrinsic(_arraycopy,                java_lang_System,       arraycopy_name, arraycopy_signature,           F_S)   \
    do_name(     arraycopy_name,                                  "arraycopy")                                           \
--- a/src/hotspot/share/code/codeCache.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/code/codeCache.cpp	Tue May 15 20:24:34 2018 +0200
@@ -33,6 +33,7 @@
 #include "code/nmethod.hpp"
 #include "code/pcDesc.hpp"
 #include "compiler/compileBroker.hpp"
+#include "jfr/jfrEvents.hpp"
 #include "logging/log.hpp"
 #include "logging/logStream.hpp"
 #include "memory/allocation.inline.hpp"
@@ -53,7 +54,6 @@
 #include "runtime/sweeper.hpp"
 #include "runtime/vmThread.hpp"
 #include "services/memoryService.hpp"
-#include "trace/tracing.hpp"
 #include "utilities/align.hpp"
 #include "utilities/vmError.hpp"
 #include "utilities/xmlstream.hpp"
--- a/src/hotspot/share/compiler/compileBroker.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/compiler/compileBroker.cpp	Tue May 15 20:24:34 2018 +0200
@@ -35,6 +35,7 @@
 #include "compiler/compilerOracle.hpp"
 #include "compiler/directivesParser.hpp"
 #include "interpreter/linkResolver.hpp"
+#include "jfr/jfrEvents.hpp"
 #include "logging/log.hpp"
 #include "logging/logStream.hpp"
 #include "memory/allocation.inline.hpp"
@@ -57,11 +58,11 @@
 #include "runtime/sweeper.hpp"
 #include "runtime/timerTrace.hpp"
 #include "runtime/vframe.inline.hpp"
-#include "trace/tracing.hpp"
 #include "utilities/debug.hpp"
 #include "utilities/dtrace.hpp"
 #include "utilities/events.hpp"
 #include "utilities/formatBuffer.hpp"
+#include "utilities/macros.hpp"
 #ifdef COMPILER1
 #include "c1/c1_Compiler.hpp"
 #endif
@@ -1945,8 +1946,7 @@
   }
 }
 
-void CompileBroker::post_compile(CompilerThread* thread, CompileTask* task, EventCompilation& event, bool success, ciEnv* ci_env) {
-
+void CompileBroker::post_compile(CompilerThread* thread, CompileTask* task, bool success, ciEnv* ci_env) {
   if (success) {
     task->mark_success();
     if (ci_env != NULL) {
@@ -1959,19 +1959,21 @@
       }
     }
   }
-
   // simulate crash during compilation
   assert(task->compile_id() != CICrashAt, "just as planned");
-  if (event.should_commit()) {
-    event.set_method(task->method());
-    event.set_compileId(task->compile_id());
-    event.set_compileLevel(task->comp_level());
-    event.set_succeded(task->is_success());
-    event.set_isOsr(task->osr_bci() != CompileBroker::standard_entry_bci);
-    event.set_codeSize((task->code() == NULL) ? 0 : task->code()->total_size());
-    event.set_inlinedBytes(task->num_inlined_bytecodes());
-    event.commit();
-  }
+}
+
+static void post_compilation_event(EventCompilation* event, CompileTask* task) {
+  assert(event != NULL, "invariant");
+  assert(event->should_commit(), "invariant");
+  event->set_method(task->method());
+  event->set_compileId(task->compile_id());
+  event->set_compileLevel(task->comp_level());
+  event->set_succeded(task->is_success());
+  event->set_isOsr(task->osr_bci() != CompileBroker::standard_entry_bci);
+  event->set_codeSize((task->code() == NULL) ? 0 : task->code()->total_size());
+  event->set_inlinedBytes(task->num_inlined_bytecodes());
+  event->commit();
 }
 
 int DirectivesStack::_depth = 0;
@@ -2066,7 +2068,10 @@
           compilable = ciEnv::MethodCompilable_not_at_tier;
         }
     }
-    post_compile(thread, task, event, task->code() != NULL, NULL);
+    post_compile(thread, task, task->code() != NULL, NULL);
+    if (event.should_commit()) {
+      post_compilation_event(&event, task);
+    }
 
   } else
 #endif // INCLUDE_JVMCI
@@ -2123,7 +2128,10 @@
       ci_env.report_failure(failure_reason);
     }
 
-    post_compile(thread, task, event, !ci_env.failing(), &ci_env);
+    post_compile(thread, task, !ci_env.failing(), &ci_env);
+    if (event.should_commit()) {
+      post_compilation_event(&event, task);
+    }
   }
   // Remove the JNI handle block after the ciEnv destructor has run in
   // the previous block.
--- a/src/hotspot/share/compiler/compileBroker.hpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/compiler/compileBroker.hpp	Tue May 15 20:24:34 2018 +0200
@@ -30,7 +30,6 @@
 #include "compiler/compileTask.hpp"
 #include "compiler/compilerDirectives.hpp"
 #include "runtime/perfData.hpp"
-#include "trace/tracing.hpp"
 #include "utilities/stack.hpp"
 #if INCLUDE_JVMCI
 #include "jvmci/jvmciCompiler.hpp"
@@ -252,7 +251,7 @@
 #endif
 
   static void invoke_compiler_on_method(CompileTask* task);
-  static void post_compile(CompilerThread* thread, CompileTask* task, EventCompilation& event, bool success, ciEnv* ci_env);
+  static void post_compile(CompilerThread* thread, CompileTask* task, bool success, ciEnv* ci_env);
   static void set_last_compile(CompilerThread *thread, const methodHandle& method, bool is_osr, int comp_level);
   static void push_jni_handle_block();
   static void pop_jni_handle_block();
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp	Tue May 15 20:24:34 2018 +0200
@@ -86,7 +86,6 @@
 class G1NewTracer;
 class EvacuationFailedInfo;
 class nmethod;
-class Ticks;
 class WorkGang;
 class G1Allocator;
 class G1ArchiveAllocator;
--- a/src/hotspot/share/gc/g1/g1EvacStats.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1EvacStats.cpp	Tue May 15 20:24:34 2018 +0200
@@ -23,12 +23,11 @@
  */
 
 #include "precompiled.hpp"
-#include "memory/allocation.inline.hpp"
 #include "gc/g1/g1_globals.hpp"
 #include "gc/g1/g1EvacStats.hpp"
 #include "gc/shared/gcId.hpp"
 #include "logging/log.hpp"
-#include "trace/tracing.hpp"
+#include "memory/allocation.inline.hpp"
 
 void G1EvacStats::log_plab_allocation() {
   PLABStats::log_plab_allocation();
--- a/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp	Tue May 15 20:24:34 2018 +0200
@@ -34,7 +34,6 @@
 #include "gc/shared/gcTraceTime.inline.hpp"
 #include "gc/shared/referenceProcessor.hpp"
 #include "logging/log.hpp"
-#include "utilities/ticks.inline.hpp"
 
 class G1AdjustLiveClosure : public StackObj {
   G1AdjustClosure* _adjust_closure;
--- a/src/hotspot/share/gc/g1/g1FullGCCompactTask.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1FullGCCompactTask.cpp	Tue May 15 20:24:34 2018 +0200
@@ -32,7 +32,7 @@
 #include "gc/shared/gcTraceTime.inline.hpp"
 #include "logging/log.hpp"
 #include "oops/oop.inline.hpp"
-#include "utilities/ticks.inline.hpp"
+#include "utilities/ticks.hpp"
 
 class G1ResetHumongousClosure : public HeapRegionClosure {
   G1CMBitMap* _bitmap;
--- a/src/hotspot/share/gc/g1/g1FullGCCompactTask.hpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1FullGCCompactTask.hpp	Tue May 15 20:24:34 2018 +0200
@@ -31,7 +31,6 @@
 #include "gc/g1/g1StringDedup.hpp"
 #include "gc/g1/heapRegionManager.hpp"
 #include "gc/shared/referenceProcessor.hpp"
-#include "utilities/ticks.hpp"
 
 class G1CollectedHeap;
 class G1CMBitMap;
--- a/src/hotspot/share/gc/g1/g1FullGCPrepareTask.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1FullGCPrepareTask.cpp	Tue May 15 20:24:34 2018 +0200
@@ -36,7 +36,7 @@
 #include "gc/shared/referenceProcessor.hpp"
 #include "logging/log.hpp"
 #include "oops/oop.inline.hpp"
-#include "utilities/ticks.inline.hpp"
+#include "utilities/ticks.hpp"
 
 bool G1FullGCPrepareTask::G1CalculatePointersClosure::do_heap_region(HeapRegion* hr) {
   if (hr->is_humongous()) {
--- a/src/hotspot/share/gc/g1/g1FullGCPrepareTask.hpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1FullGCPrepareTask.hpp	Tue May 15 20:24:34 2018 +0200
@@ -32,7 +32,6 @@
 #include "gc/g1/g1StringDedup.hpp"
 #include "gc/g1/heapRegionManager.hpp"
 #include "gc/shared/referenceProcessor.hpp"
-#include "utilities/ticks.hpp"
 
 class G1CMBitMap;
 
--- a/src/hotspot/share/gc/g1/g1FullGCTask.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1FullGCTask.cpp	Tue May 15 20:24:34 2018 +0200
@@ -25,7 +25,7 @@
 #include "precompiled.hpp"
 #include "gc/g1/g1FullGCTask.hpp"
 #include "logging/log.hpp"
-#include "utilities/ticks.inline.hpp"
+#include "utilities/ticks.hpp"
 
 void G1FullGCTask::log_task(const char* name, uint worker_id, const Ticks& start, const Ticks& stop) {
   Tickspan duration = stop - start;
--- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp	Tue May 15 20:24:34 2018 +0200
@@ -488,7 +488,7 @@
 
 G1GCParPhaseTimesTracker::~G1GCParPhaseTimesTracker() {
   if (_phase_times != NULL) {
-    _phase_times->record_time_secs(_phase, _worker_id, TicksToTimeHelper::seconds(Ticks::now() - _start_time));
+    _phase_times->record_time_secs(_phase, _worker_id, (Ticks::now() - _start_time).seconds());
   }
 }
 
@@ -506,7 +506,7 @@
   if (_phase_times != NULL) {
     // Exclude trim time by increasing the start time.
     _start_time += _trim_time;
-    _phase_times->record_or_add_objcopy_time_secs(_worker_id, TicksToTimeHelper::seconds(_trim_time));
+    _phase_times->record_or_add_objcopy_time_secs(_worker_id, _trim_time.seconds());
   }
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/g1/g1HeapRegionEventSender.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "gc/g1/g1CollectedHeap.hpp"
+#include "gc/g1/heapRegion.hpp"
+#include "g1HeapRegionEventSender.hpp"
+#include "jfr/jfrEvents.hpp"
+
+class DumpEventInfoClosure : public HeapRegionClosure {
+public:
+  bool do_heap_region(HeapRegion* r) {
+    EventG1HeapRegionInformation evt;
+    evt.set_index(r->hrm_index());
+    evt.set_type(r->get_trace_type());
+    evt.set_start((uintptr_t)r->bottom());
+    evt.set_used(r->used());
+    evt.commit();
+    return false;
+  }
+};
+
+
+void G1HeapRegionEventSender::send_events() {
+  DumpEventInfoClosure c;
+
+  G1CollectedHeap::heap()->heap_region_iterate(&c);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/g1/g1HeapRegionEventSender.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_G1_G1HEAPREGIONEVENTSENDER_HPP
+#define SHARE_VM_GC_G1_G1HEAPREGIONEVENTSENDER_HPP
+
+#include "memory/allocation.hpp"
+
+class G1HeapRegionEventSender : public AllStatic {
+public:
+  static void send_events();
+};
+
+#endif // SHARE_VM_GC_G1_G1HEAPREGIONEVENTSENDER_HPP
--- a/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp	Tue May 15 20:24:34 2018 +0200
@@ -29,7 +29,6 @@
 #include "gc/g1/g1RemSet.hpp"
 #include "oops/access.inline.hpp"
 #include "oops/oop.inline.hpp"
-#include "utilities/ticks.inline.hpp"
 
 template <class T> void G1ParScanThreadState::do_oop_evac(T* p) {
   // Reference should not be NULL here as such are never pushed to the task queue.
--- a/src/hotspot/share/gc/g1/g1RemSet.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1RemSet.cpp	Tue May 15 20:24:34 2018 +0200
@@ -44,11 +44,12 @@
 #include "memory/resourceArea.hpp"
 #include "oops/access.inline.hpp"
 #include "oops/oop.inline.hpp"
+#include "runtime/os.hpp"
 #include "utilities/align.hpp"
 #include "utilities/globalDefinitions.hpp"
 #include "utilities/intHisto.hpp"
 #include "utilities/stack.inline.hpp"
-#include "utilities/ticks.inline.hpp"
+#include "utilities/ticks.hpp"
 
 // Collects information about the overall remembered set scan progress during an evacuation.
 class G1RemSetScanState : public CHeapObj<mtGC> {
@@ -428,15 +429,15 @@
 
   G1GCPhaseTimes* p = _g1p->phase_times();
 
-  p->record_time_secs(G1GCPhaseTimes::ScanRS, worker_i, TicksToTimeHelper::seconds(cl.rem_set_root_scan_time()));
-  p->add_time_secs(G1GCPhaseTimes::ObjCopy, worker_i, TicksToTimeHelper::seconds(cl.rem_set_trim_partially_time()));
+  p->record_time_secs(G1GCPhaseTimes::ScanRS, worker_i, cl.rem_set_root_scan_time().seconds());
+  p->add_time_secs(G1GCPhaseTimes::ObjCopy, worker_i, cl.rem_set_trim_partially_time().seconds());
 
   p->record_thread_work_item(G1GCPhaseTimes::ScanRS, worker_i, cl.cards_scanned(), G1GCPhaseTimes::ScanRSScannedCards);
   p->record_thread_work_item(G1GCPhaseTimes::ScanRS, worker_i, cl.cards_claimed(), G1GCPhaseTimes::ScanRSClaimedCards);
   p->record_thread_work_item(G1GCPhaseTimes::ScanRS, worker_i, cl.cards_skipped(), G1GCPhaseTimes::ScanRSSkippedCards);
 
-  p->record_time_secs(G1GCPhaseTimes::CodeRoots, worker_i, TicksToTimeHelper::seconds(cl.strong_code_root_scan_time()));
-  p->add_time_secs(G1GCPhaseTimes::ObjCopy, worker_i, TicksToTimeHelper::seconds(cl.strong_code_root_trim_partially_time()));
+  p->record_time_secs(G1GCPhaseTimes::CodeRoots, worker_i, cl.strong_code_root_scan_time().seconds());
+  p->add_time_secs(G1GCPhaseTimes::ObjCopy, worker_i, cl.strong_code_root_trim_partially_time().seconds());
 }
 
 // Closure used for updating rem sets. Only called during an evacuation pause.
@@ -935,7 +936,7 @@
                                         "TARS " PTR_FORMAT,
                                         region_idx,
                                         _cm->liveness(region_idx) * HeapWordSize,
-                                        TicksToTimeHelper::seconds(time) * 1000.0,
+                                        time.seconds() * 1000.0,
                                         marked_bytes,
                                         p2i(hr->bottom()),
                                         p2i(top_at_mark_start),
--- a/src/hotspot/share/gc/g1/heapRegionTracer.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/gc/g1/heapRegionTracer.cpp	Tue May 15 20:24:34 2018 +0200
@@ -24,7 +24,7 @@
 
 #include "precompiled.hpp"
 #include "gc/g1/heapRegionTracer.hpp"
-#include "trace/tracing.hpp"
+#include "jfr/jfrEvents.hpp"
 
 void HeapRegionTracer::send_region_type_change(uint index,
                                                G1HeapRegionTraceType::Type from,
--- a/src/hotspot/share/gc/shared/ageTableTracer.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/gc/shared/ageTableTracer.cpp	Tue May 15 20:24:34 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,7 +25,7 @@
 #include "precompiled.hpp"
 #include "gc/shared/ageTableTracer.hpp"
 #include "gc/shared/gcId.hpp"
-#include "trace/tracing.hpp"
+#include "jfr/jfrEvents.hpp"
 
 void AgeTableTracer::send_tenuring_distribution_event(uint age, size_t size) {
   EventTenuringDistribution e;
--- a/src/hotspot/share/gc/shared/allocTracer.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/gc/shared/allocTracer.cpp	Tue May 15 20:24:34 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,13 +24,16 @@
 
 #include "precompiled.hpp"
 #include "gc/shared/allocTracer.hpp"
+#include "jfr/jfrEvents.hpp"
 #include "runtime/handles.hpp"
-#include "trace/tracing.hpp"
-#include "trace/traceMacros.hpp"
 #include "utilities/globalDefinitions.hpp"
+#include "utilities/macros.hpp"
+#if INCLUDE_JFR
+#include "jfr/support/jfrAllocationTracer.hpp"
+#endif
 
 void AllocTracer::send_allocation_outside_tlab(Klass* klass, HeapWord* obj, size_t alloc_size, Thread* thread) {
-  TRACE_ALLOCATION(obj, alloc_size, thread);
+  JFR_ONLY(JfrAllocationTracer tracer(obj, alloc_size, thread);)
   EventObjectAllocationOutsideTLAB event;
   if (event.should_commit()) {
     event.set_objectClass(klass);
@@ -40,7 +43,7 @@
 }
 
 void AllocTracer::send_allocation_in_new_tlab(Klass* klass, HeapWord* obj, size_t tlab_size, size_t alloc_size, Thread* thread) {
-  TRACE_ALLOCATION(obj, tlab_size, thread);
+  JFR_ONLY(JfrAllocationTracer tracer(obj, alloc_size, thread);)
   EventObjectAllocationInNewTLAB event;
   if (event.should_commit()) {
     event.set_objectClass(klass);
--- a/src/hotspot/share/gc/shared/copyFailedInfo.hpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/gc/shared/copyFailedInfo.hpp	Tue May 15 20:24:34 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,8 +25,8 @@
 #ifndef SHARE_VM_GC_SHARED_COPYFAILEDINFO_HPP
 #define SHARE_VM_GC_SHARED_COPYFAILEDINFO_HPP
 
+#include "jfr/support/jfrThreadId.hpp"
 #include "runtime/thread.hpp"
-#include "trace/traceMacros.hpp"
 #include "utilities/globalDefinitions.hpp"
 
 class CopyFailedInfo : public CHeapObj<mtGC> {
@@ -72,9 +72,9 @@
   void register_copy_failure(size_t size) {
     CopyFailedInfo::register_copy_failure(size);
     if (_thread_trace_id == 0) {
-      _thread_trace_id = THREAD_TRACE_ID(Thread::current());
+      _thread_trace_id = JFR_THREAD_ID(Thread::current());
     } else {
-      assert(THREAD_TRACE_ID(Thread::current()) == _thread_trace_id,
+      assert(JFR_THREAD_ID(Thread::current()) == _thread_trace_id,
         "The PromotionFailedInfo should be thread local.");
     }
   }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/gcConfiguration.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+#include "precompiled.hpp"
+
+#include "gc/shared/collectedHeap.hpp"
+#include "gc/shared/gcConfiguration.hpp"
+#include "memory/universe.hpp"
+#include "runtime/arguments.hpp"
+#include "runtime/globals.hpp"
+#include "utilities/debug.hpp"
+
+GCName GCConfiguration::young_collector() const {
+  if (UseG1GC) {
+    return G1New;
+  }
+
+  if (UseParallelGC) {
+    return ParallelScavenge;
+  }
+
+  if (UseConcMarkSweepGC) {
+    return ParNew;
+  }
+
+  return DefNew;
+}
+
+GCName GCConfiguration::old_collector() const {
+  if (UseG1GC) {
+    return G1Old;
+  }
+
+  if (UseConcMarkSweepGC) {
+    return ConcurrentMarkSweep;
+  }
+
+  if (UseParallelOldGC) {
+    return ParallelOld;
+  }
+
+  return SerialOld;
+}
+
+uint GCConfiguration::num_parallel_gc_threads() const {
+  return ParallelGCThreads;
+}
+
+uint GCConfiguration::num_concurrent_gc_threads() const {
+  return ConcGCThreads;
+}
+
+bool GCConfiguration::uses_dynamic_gc_threads() const {
+  return UseDynamicNumberOfGCThreads;
+}
+
+bool GCConfiguration::is_explicit_gc_concurrent() const {
+  return ExplicitGCInvokesConcurrent;
+}
+
+bool GCConfiguration::is_explicit_gc_disabled() const {
+  return DisableExplicitGC;
+}
+
+bool GCConfiguration::has_pause_target_default_value() const {
+  return FLAG_IS_DEFAULT(MaxGCPauseMillis);
+}
+
+uintx GCConfiguration::pause_target() const {
+  return MaxGCPauseMillis;
+}
+
+uintx GCConfiguration::gc_time_ratio() const {
+  return GCTimeRatio;
+}
+
+bool GCTLABConfiguration::uses_tlabs() const {
+  return UseTLAB;
+}
+
+size_t GCTLABConfiguration::min_tlab_size() const {
+  return MinTLABSize;
+}
+
+uint GCTLABConfiguration::tlab_refill_waste_limit() const {
+  return TLABRefillWasteFraction;
+}
+
+intx GCSurvivorConfiguration::max_tenuring_threshold() const {
+  return MaxTenuringThreshold;
+}
+
+intx GCSurvivorConfiguration::initial_tenuring_threshold() const {
+  return InitialTenuringThreshold;
+}
+
+size_t GCHeapConfiguration::max_size() const {
+  return MaxHeapSize;
+}
+
+size_t GCHeapConfiguration::min_size() const {
+  return Arguments::min_heap_size();
+}
+
+size_t GCHeapConfiguration::initial_size() const {
+  return InitialHeapSize;
+}
+
+bool GCHeapConfiguration::uses_compressed_oops() const {
+  return UseCompressedOops;
+}
+
+Universe::NARROW_OOP_MODE GCHeapConfiguration::narrow_oop_mode() const {
+  return Universe::narrow_oop_mode();
+}
+
+uint GCHeapConfiguration::object_alignment_in_bytes() const {
+  return ObjectAlignmentInBytes;
+}
+
+int GCHeapConfiguration::heap_address_size_in_bits() const {
+  return BitsPerHeapOop;
+}
+
+bool GCYoungGenerationConfiguration::has_max_size_default_value() const {
+  return FLAG_IS_DEFAULT(MaxNewSize);
+}
+
+uintx GCYoungGenerationConfiguration::max_size() const {
+  return MaxNewSize;
+}
+
+uintx GCYoungGenerationConfiguration::min_size() const {
+  return NewSize;
+}
+
+intx GCYoungGenerationConfiguration::new_ratio() const {
+  return NewRatio;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/gcConfiguration.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_SHARED_GCCONFIGURATION_HPP
+#define SHARE_VM_GC_SHARED_GCCONFIGURATION_HPP
+
+#include "gc/shared/gcName.hpp"
+#include "memory/universe.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+class GCConfiguration {
+ public:
+  GCName young_collector() const;
+  GCName old_collector() const;
+  uint num_parallel_gc_threads() const;
+  uint num_concurrent_gc_threads() const;
+  bool uses_dynamic_gc_threads() const;
+  bool is_explicit_gc_concurrent() const;
+  bool is_explicit_gc_disabled() const;
+  uintx gc_time_ratio() const;
+
+  bool has_pause_target_default_value() const;
+  uintx pause_target() const;
+};
+
+class GCTLABConfiguration {
+ public:
+  bool uses_tlabs() const;
+  size_t min_tlab_size() const;
+  uint tlab_refill_waste_limit() const;
+};
+
+class GCSurvivorConfiguration {
+ public:
+  intx initial_tenuring_threshold() const;
+  intx max_tenuring_threshold() const;
+};
+
+class GCHeapConfiguration {
+ public:
+  size_t max_size() const;
+  size_t min_size() const;
+  size_t initial_size() const;
+  bool uses_compressed_oops() const;
+  Universe::NARROW_OOP_MODE narrow_oop_mode() const;
+  uint object_alignment_in_bytes() const;
+  int heap_address_size_in_bits() const;
+};
+
+class GCYoungGenerationConfiguration {
+ public:
+  bool has_max_size_default_value() const;
+  uintx max_size() const;
+
+  uintx min_size() const;
+  intx new_ratio() const;
+};
+
+#endif // SHARE_VM_GC_SHARED_GCCONFIGURATION_HPP
--- a/src/hotspot/share/gc/shared/gcTimer.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/gc/shared/gcTimer.cpp	Tue May 15 20:24:34 2018 +0200
@@ -25,7 +25,6 @@
 #include "precompiled.hpp"
 #include "gc/shared/gcTimer.hpp"
 #include "utilities/growableArray.hpp"
-#include "utilities/ticks.inline.hpp"
 
 // the "time" parameter for most functions
 // has a default value set by Ticks::now()
@@ -376,7 +375,7 @@
     GCTimer gc_timer;
     gc_timer.register_gc_start(1);
 
-    assert(gc_timer.gc_start() == 1, "Incorrect");
+    assert(gc_timer.gc_start() == Ticks(1), "Incorrect");
   }
 
   static void gc_end() {
@@ -384,7 +383,7 @@
     gc_timer.register_gc_start(1);
     gc_timer.register_gc_end(2);
 
-    assert(gc_timer.gc_end() == 2, "Incorrect");
+    assert(gc_timer.gc_end() == Ticks(2), "Incorrect");
   }
 };
 
--- a/src/hotspot/share/gc/shared/gcTrace.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/gc/shared/gcTrace.cpp	Tue May 15 20:24:34 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,7 +35,7 @@
 #include "runtime/os.hpp"
 #include "utilities/globalDefinitions.hpp"
 #include "utilities/macros.hpp"
-#include "utilities/ticks.inline.hpp"
+#include "utilities/ticks.hpp"
 #if INCLUDE_G1GC
 #include "gc/g1/evacuationInfo.hpp"
 #endif
--- a/src/hotspot/share/gc/shared/gcTraceSend.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/gc/shared/gcTraceSend.cpp	Tue May 15 20:24:34 2018 +0200
@@ -28,10 +28,8 @@
 #include "gc/shared/gcTimer.hpp"
 #include "gc/shared/gcTrace.hpp"
 #include "gc/shared/gcWhen.hpp"
+#include "jfr/jfrEvents.hpp"
 #include "runtime/os.hpp"
-#include "trace/traceBackend.hpp"
-#include "trace/tracing.hpp"
-#include "tracefiles/traceEventClasses.hpp"
 #include "utilities/macros.hpp"
 #if INCLUDE_G1GC
 #include "gc/g1/evacuationInfo.hpp"
@@ -160,8 +158,8 @@
   }
 }
 
-static TraceStructCopyFailed to_trace_struct(const CopyFailedInfo& cf_info) {
-  TraceStructCopyFailed failed_info;
+static JfrStructCopyFailed to_struct(const CopyFailedInfo& cf_info) {
+  JfrStructCopyFailed failed_info;
   failed_info.set_objectCount(cf_info.failed_count());
   failed_info.set_firstSize(cf_info.first_size());
   failed_info.set_smallestSize(cf_info.smallest_size());
@@ -173,7 +171,7 @@
   EventPromotionFailed e;
   if (e.should_commit()) {
     e.set_gcId(GCId::current());
-    e.set_promotionFailed(to_trace_struct(pf_info));
+    e.set_promotionFailed(to_struct(pf_info));
     e.set_thread(pf_info.thread_trace_id());
     e.commit();
   }
@@ -231,14 +229,14 @@
   EventEvacuationFailed e;
   if (e.should_commit()) {
     e.set_gcId(GCId::current());
-    e.set_evacuationFailed(to_trace_struct(ef_info));
+    e.set_evacuationFailed(to_struct(ef_info));
     e.commit();
   }
 }
 
-static TraceStructG1EvacuationStatistics
+static JfrStructG1EvacuationStatistics
 create_g1_evacstats(unsigned gcid, const G1EvacSummary& summary) {
-  TraceStructG1EvacuationStatistics s;
+  JfrStructG1EvacuationStatistics s;
   s.set_gcId(gcid);
   s.set_allocated(summary.allocated() * HeapWordSize);
   s.set_wasted(summary.wasted() * HeapWordSize);
@@ -313,8 +311,8 @@
 
 #endif // INCLUDE_G1GC
 
-static TraceStructVirtualSpace to_trace_struct(const VirtualSpaceSummary& summary) {
-  TraceStructVirtualSpace space;
+static JfrStructVirtualSpace to_struct(const VirtualSpaceSummary& summary) {
+  JfrStructVirtualSpace space;
   space.set_start((TraceAddress)summary.start());
   space.set_committedEnd((TraceAddress)summary.committed_end());
   space.set_committedSize(summary.committed_size());
@@ -323,8 +321,8 @@
   return space;
 }
 
-static TraceStructObjectSpace to_trace_struct(const SpaceSummary& summary) {
-  TraceStructObjectSpace space;
+static JfrStructObjectSpace to_struct(const SpaceSummary& summary) {
+  JfrStructObjectSpace space;
   space.set_start((TraceAddress)summary.start());
   space.set_end((TraceAddress)summary.end());
   space.set_used(summary.used());
@@ -344,7 +342,7 @@
     if (e.should_commit()) {
       e.set_gcId(GCId::current());
       e.set_when((u1)_when);
-      e.set_heapSpace(to_trace_struct(heap_space));
+      e.set_heapSpace(to_struct(heap_space));
       e.set_heapUsed(heap_summary->used());
       e.commit();
     }
@@ -380,12 +378,12 @@
       e.set_gcId(GCId::current());
       e.set_when((u1)_when);
 
-      e.set_oldSpace(to_trace_struct(ps_heap_summary->old()));
-      e.set_oldObjectSpace(to_trace_struct(ps_heap_summary->old_space()));
-      e.set_youngSpace(to_trace_struct(ps_heap_summary->young()));
-      e.set_edenSpace(to_trace_struct(ps_heap_summary->eden()));
-      e.set_fromSpace(to_trace_struct(ps_heap_summary->from()));
-      e.set_toSpace(to_trace_struct(ps_heap_summary->to()));
+      e.set_oldSpace(to_struct(ps_heap_summary->old()));
+      e.set_oldObjectSpace(to_struct(ps_heap_summary->old_space()));
+      e.set_youngSpace(to_struct(ps_heap_summary->young()));
+      e.set_edenSpace(to_struct(ps_heap_summary->eden()));
+      e.set_fromSpace(to_struct(ps_heap_summary->from()));
+      e.set_toSpace(to_struct(ps_heap_summary->to()));
       e.commit();
     }
   }
@@ -396,8 +394,8 @@
   heap_summary.accept(&visitor);
 }
 
-static TraceStructMetaspaceSizes to_trace_struct(const MetaspaceSizes& sizes) {
-  TraceStructMetaspaceSizes meta_sizes;
+static JfrStructMetaspaceSizes to_struct(const MetaspaceSizes& sizes) {
+  JfrStructMetaspaceSizes meta_sizes;
 
   meta_sizes.set_committed(sizes.committed());
   meta_sizes.set_used(sizes.used());
@@ -412,9 +410,9 @@
     e.set_gcId(GCId::current());
     e.set_when((u1) when);
     e.set_gcThreshold(meta_space_summary.capacity_until_GC());
-    e.set_metaspace(to_trace_struct(meta_space_summary.meta_space()));
-    e.set_dataSpace(to_trace_struct(meta_space_summary.data_space()));
-    e.set_classSpace(to_trace_struct(meta_space_summary.class_space()));
+    e.set_metaspace(to_struct(meta_space_summary.meta_space()));
+    e.set_dataSpace(to_struct(meta_space_summary.data_space()));
+    e.set_classSpace(to_struct(meta_space_summary.class_space()));
     e.commit();
   }
 }
--- a/src/hotspot/share/gc/shared/objectCountEventSender.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/gc/shared/objectCountEventSender.cpp	Tue May 15 20:24:34 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,34 +26,50 @@
 #include "precompiled.hpp"
 #include "gc/shared/gcId.hpp"
 #include "gc/shared/objectCountEventSender.hpp"
+#include "jfr/jfrEvents.hpp"
 #include "memory/heapInspection.hpp"
-#include "trace/tracing.hpp"
-#include "utilities/globalDefinitions.hpp"
 #include "utilities/macros.hpp"
 #include "utilities/ticks.hpp"
 #if INCLUDE_SERVICES
 
-void ObjectCountEventSender::send(const KlassInfoEntry* entry, const Ticks& timestamp) {
-#if INCLUDE_TRACE
-  assert(Tracing::is_event_enabled(EventObjectCountAfterGC::eventId),
-         "Only call this method if the event is enabled");
+bool ObjectCountEventSender::should_send_event() {
+#if INCLUDE_JFR
+  return _should_send_requestable_event || EventObjectCountAfterGC::is_enabled();
+#else
+  return false;
+#endif // INCLUDE_JFR
+}
 
-  EventObjectCountAfterGC event(UNTIMED);
-  event.set_gcId(GCId::current());
-  event.set_objectClass(entry->klass());
-  event.set_count(entry->count());
-  event.set_totalSize(entry->words() * BytesPerWord);
-  event.set_endtime(timestamp);
-  event.commit();
-#endif // INCLUDE_TRACE
+bool ObjectCountEventSender::_should_send_requestable_event = false;
+
+void ObjectCountEventSender::enable_requestable_event() {
+  _should_send_requestable_event = true;
+}
+
+void ObjectCountEventSender::disable_requestable_event() {
+  _should_send_requestable_event = false;
 }
 
-bool ObjectCountEventSender::should_send_event() {
-#if INCLUDE_TRACE
-  return Tracing::is_event_enabled(EventObjectCountAfterGC::eventId);
-#else
-  return false;
-#endif // INCLUDE_TRACE
+template <typename T>
+void ObjectCountEventSender::send_event_if_enabled(Klass* klass, jlong count, julong size, const Ticks& timestamp) {
+  T event(UNTIMED);
+  if (event.should_commit()) {
+    event.set_gcId(GCId::current());
+    event.set_objectClass(klass);
+    event.set_count(count);
+    event.set_totalSize(size);
+    event.set_endtime(timestamp);
+    event.commit();
+  }
+}
+
+void ObjectCountEventSender::send(const KlassInfoEntry* entry, const Ticks& timestamp) {
+  Klass* klass = entry->klass();
+  jlong count = entry->count();
+  julong total_size = entry->words() * BytesPerWord;
+
+  send_event_if_enabled<EventObjectCount>(klass, count, total_size, timestamp);
+  send_event_if_enabled<EventObjectCountAfterGC>(klass, count, total_size, timestamp);
 }
 
 #endif // INCLUDE_SERVICES
--- a/src/hotspot/share/gc/shared/objectCountEventSender.hpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/gc/shared/objectCountEventSender.hpp	Tue May 15 20:24:34 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,15 +27,25 @@
 
 #include "gc/shared/gcTrace.hpp"
 #include "memory/allocation.hpp"
+#include "utilities/globalDefinitions.hpp"
 #include "utilities/macros.hpp"
+#include "utilities/ticks.hpp"
 
 #if INCLUDE_SERVICES
 
 class KlassInfoEntry;
-class Ticks;
+class Klass;
 
 class ObjectCountEventSender : public AllStatic {
+  static bool _should_send_requestable_event;
+
+  template <typename T>
+  static void send_event_if_enabled(Klass* klass, jlong count, julong size, const Ticks& timestamp);
+
  public:
+  static void enable_requestable_event();
+  static void disable_requestable_event();
+
   static void send(const KlassInfoEntry* entry, const Ticks& timestamp);
   static bool should_send_event();
 };
--- a/src/hotspot/share/gc/shared/weakProcessor.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/gc/shared/weakProcessor.cpp	Tue May 15 20:24:34 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,13 +26,15 @@
 #include "gc/shared/weakProcessor.hpp"
 #include "prims/jvmtiExport.hpp"
 #include "runtime/jniHandles.hpp"
-#include "trace/tracing.hpp"
-#include "trace/traceMacros.hpp"
+#include "utilities/macros.hpp"
+#if INCLUDE_JFR
+#include "jfr/jfr.hpp"
+#endif
 
 void WeakProcessor::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive) {
   JNIHandles::weak_oops_do(is_alive, keep_alive);
   JvmtiExport::weak_oops_do(is_alive, keep_alive);
-  TRACE_WEAK_OOPS_DO(is_alive, keep_alive);
+  JFR_ONLY(Jfr::weak_oops_do(is_alive, keep_alive);)
 }
 
 void WeakProcessor::oops_do(OopClosure* closure) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,633 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/javaClasses.hpp"
+#include "classfile/vmSymbols.hpp"
+#include "jfr/jfr.hpp"
+#include "jfr/dcmd/jfrDcmds.hpp"
+#include "jfr/jni/jfrJavaSupport.hpp"
+#include "jfr/recorder/jfrRecorder.hpp"
+#include "jfr/recorder/service/jfrOptionSet.hpp"
+#include "memory/resourceArea.hpp"
+#include "oops/oop.inline.hpp"
+#include "oops/symbol.hpp"
+#include "runtime/handles.inline.hpp"
+#include "services/diagnosticArgument.hpp"
+#include "services/diagnosticFramework.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+#ifdef _WINDOWS
+#define JFR_FILENAME_EXAMPLE "C:\\Users\\user\\My Recording.jfr"
+#endif
+
+#ifdef __APPLE__
+#define JFR_FILENAME_EXAMPLE  "/Users/user/My Recording.jfr"
+#endif
+
+#ifndef JFR_FILENAME_EXAMPLE
+#define JFR_FILENAME_EXAMPLE "/home/user/My Recording.jfr"
+#endif
+
+// JNIHandle management
+
+// ------------------------------------------------------------------
+// push_jni_handle_block
+//
+// Push on a new block of JNI handles.
+static void push_jni_handle_block(Thread* const thread) {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(thread));
+
+  // Allocate a new block for JNI handles.
+  // Inlined code from jni_PushLocalFrame()
+  JNIHandleBlock* prev_handles = thread->active_handles();
+  JNIHandleBlock* entry_handles = JNIHandleBlock::allocate_block(thread);
+  assert(entry_handles != NULL && prev_handles != NULL, "should not be NULL");
+  entry_handles->set_pop_frame_link(prev_handles);  // make sure prev handles get gc'd.
+  thread->set_active_handles(entry_handles);
+}
+
+// ------------------------------------------------------------------
+// pop_jni_handle_block
+//
+// Pop off the current block of JNI handles.
+static void pop_jni_handle_block(Thread* const thread) {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(thread));
+
+  // Release our JNI handle block
+  JNIHandleBlock* entry_handles = thread->active_handles();
+  JNIHandleBlock* prev_handles = entry_handles->pop_frame_link();
+  // restore
+  thread->set_active_handles(prev_handles);
+  entry_handles->set_pop_frame_link(NULL);
+  JNIHandleBlock::release_block(entry_handles, thread); // may block
+}
+
+class JNIHandleBlockManager : public StackObj {
+ private:
+  Thread* const _thread;
+ public:
+  JNIHandleBlockManager(Thread* thread) : _thread(thread) {
+    push_jni_handle_block(_thread);
+  }
+
+  ~JNIHandleBlockManager() {
+    pop_jni_handle_block(_thread);
+  }
+};
+
+static bool is_module_available(outputStream* output, TRAPS) {
+  return JfrJavaSupport::is_jdk_jfr_module_available(output, THREAD);
+}
+
+static bool is_disabled(outputStream* output) {
+  if (Jfr::is_disabled()) {
+    if (output != NULL) {
+      output->print_cr("Flight Recorder is disabled.\n");
+    }
+    return true;
+  }
+  return false;
+}
+
+static bool is_recorder_instance_created(outputStream* output) {
+  if (!JfrRecorder::is_created()) {
+    if (output != NULL) {
+      output->print_cr("No available recordings.\n");
+      output->print_cr("Use JFR.start to start a recording.\n");
+    }
+    return false;
+  }
+  return true;
+}
+
+static bool invalid_state(outputStream* out, TRAPS) {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
+  return is_disabled(out) || !is_module_available(out, THREAD);
+}
+
+static void print_pending_exception(outputStream* output, oop throwable) {
+  assert(throwable != NULL, "invariant");
+
+  oop msg = java_lang_Throwable::message(throwable);
+
+  if (msg != NULL) {
+    char* text = java_lang_String::as_utf8_string(msg);
+    output->print_raw_cr(text);
+  }
+}
+
+static void print_message(outputStream* output, const char* message) {
+  if (message != NULL) {
+    output->print_raw(message);
+  }
+}
+
+static void handle_dcmd_result(outputStream* output,
+                               const oop result,
+                               const DCmdSource source,
+                               TRAPS) {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
+  assert(output != NULL, "invariant");
+  if (HAS_PENDING_EXCEPTION) {
+    print_pending_exception(output, PENDING_EXCEPTION);
+    // Don't clear excption on startup, JVM should fail initialization.
+    if (DCmd_Source_Internal != source) {
+      CLEAR_PENDING_EXCEPTION;
+    }
+    return;
+  }
+
+  assert(!HAS_PENDING_EXCEPTION, "invariant");
+
+  if (result != NULL) {
+    const char* result_chars = java_lang_String::as_utf8_string(result);
+    print_message(output, result_chars);
+  }
+}
+
+static oop construct_dcmd_instance(JfrJavaArguments* args, TRAPS) {
+  assert(args != NULL, "invariant");
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
+  assert(args->klass() != NULL, "invariant");
+  args->set_name("<init>", CHECK_NULL);
+  args->set_signature("()V", CHECK_NULL);
+  JfrJavaSupport::new_object(args, CHECK_NULL);
+  return (oop)args->result()->get_jobject();
+}
+
+JfrDumpFlightRecordingDCmd::JfrDumpFlightRecordingDCmd(outputStream* output,
+                                                       bool heap) : DCmdWithParser(output, heap),
+  _name("name", "Recording name, e.g. \\\"My Recording\\\"", "STRING", true, NULL),
+  _filename("filename", "Copy recording data to file, i.e \\\"" JFR_FILENAME_EXAMPLE "\\\"", "STRING", true),
+  _path_to_gc_roots("path-to-gc-roots", "Collect path to GC roots", "BOOLEAN", false, "false") {
+  _dcmdparser.add_dcmd_option(&_name);
+  _dcmdparser.add_dcmd_option(&_filename);
+  _dcmdparser.add_dcmd_option(&_path_to_gc_roots);
+};
+
+int JfrDumpFlightRecordingDCmd::num_arguments() {
+  ResourceMark rm;
+  JfrDumpFlightRecordingDCmd* dcmd = new JfrDumpFlightRecordingDCmd(NULL, false);
+  if (dcmd != NULL) {
+    DCmdMark mark(dcmd);
+    return dcmd->_dcmdparser.num_arguments();
+  }
+  return 0;
+}
+
+void JfrDumpFlightRecordingDCmd::execute(DCmdSource source, TRAPS) {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
+
+  if (invalid_state(output(), THREAD) || !is_recorder_instance_created(output())) {
+    return;
+  }
+
+  ResourceMark rm(THREAD);
+  HandleMark hm(THREAD);
+  JNIHandleBlockManager jni_handle_management(THREAD);
+
+  JavaValue result(T_OBJECT);
+  JfrJavaArguments constructor_args(&result);
+  constructor_args.set_klass("jdk/jfr/internal/dcmd/DCmdDump", CHECK);
+  const oop dcmd = construct_dcmd_instance(&constructor_args, CHECK);
+  Handle h_dcmd_instance(THREAD, dcmd);
+  assert(h_dcmd_instance.not_null(), "invariant");
+
+  jstring name = NULL;
+  if (_name.is_set() && _name.value()  != NULL) {
+    name = JfrJavaSupport::new_string(_name.value(), CHECK);
+  }
+
+  jstring filepath = NULL;
+  if (_filename.is_set() && _filename.value() != NULL) {
+    filepath = JfrJavaSupport::new_string(_filename.value(), CHECK);
+  }
+
+  jobject path_to_gc_roots = NULL;
+  if (_path_to_gc_roots.is_set()) {
+    path_to_gc_roots = JfrJavaSupport::new_java_lang_Boolean(_path_to_gc_roots.value(), CHECK);
+  }
+
+  static const char klass[] = "jdk/jfr/internal/dcmd/DCmdDump";
+  static const char method[] = "execute";
+  static const char signature[] = "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;)Ljava/lang/String;";
+
+  JfrJavaArguments execute_args(&result, klass, method, signature, CHECK);
+  execute_args.set_receiver(h_dcmd_instance);
+
+  // arguments
+  execute_args.push_jobject(name);
+  execute_args.push_jobject(filepath);
+  execute_args.push_jobject(path_to_gc_roots);
+
+  JfrJavaSupport::call_virtual(&execute_args, THREAD);
+  handle_dcmd_result(output(), (oop)result.get_jobject(), source, THREAD);
+}
+
+JfrCheckFlightRecordingDCmd::JfrCheckFlightRecordingDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap),
+  _name("name","Recording text, e.g. \\\"My Recording\\\" or omit to see all recordings","STRING",false, NULL),
+  _verbose("verbose","Print event settings for the recording(s)","BOOLEAN",
+           false, "false") {
+  _dcmdparser.add_dcmd_option(&_name);
+  _dcmdparser.add_dcmd_option(&_verbose);
+};
+
+int JfrCheckFlightRecordingDCmd::num_arguments() {
+  ResourceMark rm;
+  JfrCheckFlightRecordingDCmd* dcmd = new JfrCheckFlightRecordingDCmd(NULL, false);
+  if (dcmd != NULL) {
+    DCmdMark mark(dcmd);
+    return dcmd->_dcmdparser.num_arguments();
+  }
+  return 0;
+}
+
+void JfrCheckFlightRecordingDCmd::execute(DCmdSource source, TRAPS) {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
+
+  if (invalid_state(output(), THREAD) || !is_recorder_instance_created(output())) {
+    return;
+  }
+
+  ResourceMark rm(THREAD);
+  HandleMark hm(THREAD);
+  JNIHandleBlockManager jni_handle_management(THREAD);
+
+  JavaValue result(T_OBJECT);
+  JfrJavaArguments constructor_args(&result);
+  constructor_args.set_klass("jdk/jfr/internal/dcmd/DCmdCheck", CHECK);
+  const oop dcmd = construct_dcmd_instance(&constructor_args, CHECK);
+  Handle h_dcmd_instance(THREAD, dcmd);
+  assert(h_dcmd_instance.not_null(), "invariant");
+
+  jstring name = NULL;
+  if (_name.is_set() && _name.value() != NULL) {
+    name = JfrJavaSupport::new_string(_name.value(), CHECK);
+  }
+
+  jobject verbose = NULL;
+  if (_verbose.is_set()) {
+    verbose = JfrJavaSupport::new_java_lang_Boolean(_verbose.value(), CHECK);
+  }
+
+  static const char klass[] = "jdk/jfr/internal/dcmd/DCmdCheck";
+  static const char method[] = "execute";
+  static const char signature[] = "(Ljava/lang/String;Ljava/lang/Boolean;)Ljava/lang/String;";
+
+  JfrJavaArguments execute_args(&result, klass, method, signature, CHECK);
+  execute_args.set_receiver(h_dcmd_instance);
+
+  // arguments
+  execute_args.push_jobject(name);
+  execute_args.push_jobject(verbose);
+
+  JfrJavaSupport::call_virtual(&execute_args, THREAD);
+  handle_dcmd_result(output(), (oop)result.get_jobject(), source, THREAD);
+}
+
+JfrStartFlightRecordingDCmd::JfrStartFlightRecordingDCmd(outputStream* output,
+                                                         bool heap) : DCmdWithParser(output, heap),
+  _name("name", "Name that can be used to identify recording, e.g. \\\"My Recording\\\"", "STRING", false, NULL),
+  _settings("settings", "Settings file(s), e.g. profile or default. See JRE_HOME/lib/jfr", "STRING SET", false),
+  _delay("delay", "Delay recording start with (s)econds, (m)inutes), (h)ours), or (d)ays, e.g. 5h.", "NANOTIME", false, "0"),
+  _duration("duration", "Duration of recording in (s)econds, (m)inutes, (h)ours, or (d)ays, e.g. 300s.", "NANOTIME", false, "0"),
+  _filename("filename", "Resulting recording filename, e.g. \\\"" JFR_FILENAME_EXAMPLE "\\\"", "STRING", false),
+  _disk("disk", "Recording should be persisted to disk", "BOOLEAN", false),
+  _maxage("maxage", "Maximum time to keep recorded data (on disk) in (s)econds, (m)inutes, (h)ours, or (d)ays, e.g. 60m, or 0 for no limit", "NANOTIME", false, "0"),
+  _maxsize("maxsize", "Maximum amount of bytes to keep (on disk) in (k)B, (M)B or (G)B, e.g. 500M, or 0 for no limit", "MEMORY SIZE", false, "0"),
+  _dump_on_exit("dumponexit", "Dump running recording when JVM shuts down", "BOOLEAN", false),
+  _path_to_gc_roots("path-to-gc-roots", "Collect path to GC roots", "BOOLEAN", false, "false") {
+  _dcmdparser.add_dcmd_option(&_name);
+  _dcmdparser.add_dcmd_option(&_settings);
+  _dcmdparser.add_dcmd_option(&_delay);
+  _dcmdparser.add_dcmd_option(&_duration);
+  _dcmdparser.add_dcmd_option(&_disk);
+  _dcmdparser.add_dcmd_option(&_filename);
+  _dcmdparser.add_dcmd_option(&_maxage);
+  _dcmdparser.add_dcmd_option(&_maxsize);
+  _dcmdparser.add_dcmd_option(&_dump_on_exit);
+  _dcmdparser.add_dcmd_option(&_path_to_gc_roots);
+};
+
+int JfrStartFlightRecordingDCmd::num_arguments() {
+  ResourceMark rm;
+  JfrStartFlightRecordingDCmd* dcmd = new JfrStartFlightRecordingDCmd(NULL, false);
+  if (dcmd != NULL) {
+    DCmdMark mark(dcmd);
+    return dcmd->_dcmdparser.num_arguments();
+  }
+  return 0;
+}
+
+void JfrStartFlightRecordingDCmd::execute(DCmdSource source, TRAPS) {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
+
+  if (invalid_state(output(), THREAD)) {
+    return;
+  }
+
+  ResourceMark rm(THREAD);
+  HandleMark hm(THREAD);
+  JNIHandleBlockManager jni_handle_management(THREAD);
+
+  JavaValue result(T_OBJECT);
+  JfrJavaArguments constructor_args(&result);
+  constructor_args.set_klass("jdk/jfr/internal/dcmd/DCmdStart", THREAD);
+  const oop dcmd = construct_dcmd_instance(&constructor_args, CHECK);
+  Handle h_dcmd_instance(THREAD, dcmd);
+  assert(h_dcmd_instance.not_null(), "invariant");
+
+  jstring name = NULL;
+  if (_name.is_set() && _name.value() != NULL) {
+    name = JfrJavaSupport::new_string(_name.value(), CHECK);
+  }
+
+  jstring filename = NULL;
+  if (_filename.is_set() && _filename.value() != NULL) {
+    filename = JfrJavaSupport::new_string(_filename.value(), CHECK);
+  }
+
+  jobject maxage = NULL;
+  if (_maxage.is_set()) {
+    maxage = JfrJavaSupport::new_java_lang_Long(_maxage.value()._nanotime, CHECK);
+  }
+
+  jobject maxsize = NULL;
+  if (_maxsize.is_set()) {
+    maxsize = JfrJavaSupport::new_java_lang_Long(_maxsize.value()._size, CHECK);
+  }
+
+  jobject duration = NULL;
+  if (_duration.is_set()) {
+    duration = JfrJavaSupport::new_java_lang_Long(_duration.value()._nanotime, CHECK);
+  }
+
+  jobject delay = NULL;
+  if (_delay.is_set()) {
+    delay = JfrJavaSupport::new_java_lang_Long(_delay.value()._nanotime, CHECK);
+  }
+
+  jobject disk = NULL;
+  if (_disk.is_set()) {
+    disk = JfrJavaSupport::new_java_lang_Boolean(_disk.value(), CHECK);
+  }
+
+  jobject dump_on_exit = NULL;
+  if (_dump_on_exit.is_set()) {
+    dump_on_exit = JfrJavaSupport::new_java_lang_Boolean(_dump_on_exit.value(), CHECK);
+  }
+
+  jobject path_to_gc_roots = NULL;
+  if (_path_to_gc_roots.is_set()) {
+    path_to_gc_roots = JfrJavaSupport::new_java_lang_Boolean(_path_to_gc_roots.value(), CHECK);
+  }
+
+  jobjectArray settings = NULL;
+  if (_settings.is_set()) {
+    const int length = _settings.value()->array()->length();
+    settings = JfrJavaSupport::new_string_array(length, CHECK);
+    assert(settings != NULL, "invariant");
+    for (int i = 0; i < length; ++i) {
+      jobject element = JfrJavaSupport::new_string(_settings.value()->array()->at(i), CHECK);
+      assert(element != NULL, "invariant");
+      JfrJavaSupport::set_array_element(settings, element, i, CHECK);
+    }
+  }
+
+  static const char klass[] = "jdk/jfr/internal/dcmd/DCmdStart";
+  static const char method[] = "execute";
+  static const char signature[] = "(Ljava/lang/String;[Ljava/lang/String;Ljava/lang/Long;"
+    "Ljava/lang/Long;Ljava/lang/Boolean;Ljava/lang/String;"
+    "Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Boolean;Ljava/lang/Boolean;)Ljava/lang/String;";
+
+  JfrJavaArguments execute_args(&result, klass, method, signature, CHECK);
+  execute_args.set_receiver(h_dcmd_instance);
+
+  // arguments
+  execute_args.push_jobject(name);
+  execute_args.push_jobject(settings);
+  execute_args.push_jobject(delay);
+  execute_args.push_jobject(duration);
+  execute_args.push_jobject(disk);
+  execute_args.push_jobject(filename);
+  execute_args.push_jobject(maxage);
+  execute_args.push_jobject(maxsize);
+  execute_args.push_jobject(dump_on_exit);
+  execute_args.push_jobject(path_to_gc_roots);
+
+  JfrJavaSupport::call_virtual(&execute_args, THREAD);
+  handle_dcmd_result(output(), (oop)result.get_jobject(), source, THREAD);
+}
+
+JfrStopFlightRecordingDCmd::JfrStopFlightRecordingDCmd(outputStream* output,
+                                                       bool heap) : DCmdWithParser(output, heap),
+  _name("name", "Recording text,.e.g \\\"My Recording\\\"", "STRING", false, NULL),
+  _filename("filename", "Copy recording data to file, e.g. \\\"" JFR_FILENAME_EXAMPLE "\\\"", "STRING", false, NULL) {
+  _dcmdparser.add_dcmd_option(&_name);
+  _dcmdparser.add_dcmd_option(&_filename);
+};
+
+int JfrStopFlightRecordingDCmd::num_arguments() {
+  ResourceMark rm;
+  JfrStopFlightRecordingDCmd* dcmd = new JfrStopFlightRecordingDCmd(NULL, false);
+  if (dcmd != NULL) {
+    DCmdMark mark(dcmd);
+    return dcmd->_dcmdparser.num_arguments();
+  }
+  return 0;
+}
+
+void JfrStopFlightRecordingDCmd::execute(DCmdSource source, TRAPS) {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
+
+  if (invalid_state(output(), THREAD) || !is_recorder_instance_created(output())) {
+    return;
+  }
+
+  ResourceMark rm(THREAD);
+  HandleMark hm(THREAD);
+  JNIHandleBlockManager jni_handle_management(THREAD);
+
+  JavaValue result(T_OBJECT);
+  JfrJavaArguments constructor_args(&result);
+  constructor_args.set_klass("jdk/jfr/internal/dcmd/DCmdStop", CHECK);
+  const oop dcmd = construct_dcmd_instance(&constructor_args, CHECK);
+  Handle h_dcmd_instance(THREAD, dcmd);
+  assert(h_dcmd_instance.not_null(), "invariant");
+
+  jstring name = NULL;
+  if (_name.is_set() && _name.value()  != NULL) {
+    name = JfrJavaSupport::new_string(_name.value(), CHECK);
+  }
+
+  jstring filepath = NULL;
+  if (_filename.is_set() && _filename.value() != NULL) {
+    filepath = JfrJavaSupport::new_string(_filename.value(), CHECK);
+  }
+
+  static const char klass[] = "jdk/jfr/internal/dcmd/DCmdStop";
+  static const char method[] = "execute";
+  static const char signature[] = "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;";
+
+  JfrJavaArguments execute_args(&result, klass, method, signature, CHECK);
+  execute_args.set_receiver(h_dcmd_instance);
+
+  // arguments
+  execute_args.push_jobject(name);
+  execute_args.push_jobject(filepath);
+
+  JfrJavaSupport::call_virtual(&execute_args, THREAD);
+  handle_dcmd_result(output(), (oop)result.get_jobject(), source, THREAD);
+}
+
+JfrConfigureFlightRecorderDCmd::JfrConfigureFlightRecorderDCmd(outputStream* output,
+                                                               bool heap) : DCmdWithParser(output, heap),
+  _repository_path("repositorypath", "Path to repository,.e.g \\\"My Repository\\\"", "STRING", false, NULL),
+  _dump_path("dumppath", "Path to dump,.e.g \\\"My Dump path\\\"", "STRING", false, NULL),
+  _stack_depth("stackdepth", "Stack Depth", "JLONG", false, "64"),
+  _global_buffer_count("globalbuffercount", "Number of global buffers,", "JLONG", false, "32"),
+  _global_buffer_size("globalbuffersize", "Size of a global buffers,", "JLONG", false, "524288"),
+  _thread_buffer_size("thread_buffer_size", "Size of a thread buffer", "JLONG", false, "8192"),
+  _memory_size("memorysize", "Overall memory size, ", "JLONG", false, "16777216"),
+  _max_chunk_size("maxchunksize", "Size of an individual disk chunk", "JLONG", false, "12582912"),
+  _sample_threads("samplethreads", "Activate Thread sampling", "BOOLEAN", false, "true") {
+  _dcmdparser.add_dcmd_option(&_repository_path);
+  _dcmdparser.add_dcmd_option(&_dump_path);
+  _dcmdparser.add_dcmd_option(&_stack_depth);
+  _dcmdparser.add_dcmd_option(&_global_buffer_count);
+  _dcmdparser.add_dcmd_option(&_global_buffer_size);
+  _dcmdparser.add_dcmd_option(&_thread_buffer_size);
+  _dcmdparser.add_dcmd_option(&_memory_size);
+  _dcmdparser.add_dcmd_option(&_max_chunk_size);
+  _dcmdparser.add_dcmd_option(&_sample_threads);
+};
+
+int JfrConfigureFlightRecorderDCmd::num_arguments() {
+  ResourceMark rm;
+  JfrConfigureFlightRecorderDCmd* dcmd = new JfrConfigureFlightRecorderDCmd(NULL, false);
+  if (dcmd != NULL) {
+    DCmdMark mark(dcmd);
+    return dcmd->_dcmdparser.num_arguments();
+  }
+  return 0;
+}
+
+void JfrConfigureFlightRecorderDCmd::execute(DCmdSource source, TRAPS) {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
+
+  if (invalid_state(output(), THREAD)) {
+    return;
+  }
+
+  ResourceMark rm(THREAD);
+  HandleMark hm(THREAD);
+  JNIHandleBlockManager jni_handle_management(THREAD);
+
+  JavaValue result(T_OBJECT);
+  JfrJavaArguments constructor_args(&result);
+  constructor_args.set_klass("jdk/jfr/internal/dcmd/DCmdConfigure", CHECK);
+  const oop dcmd = construct_dcmd_instance(&constructor_args, CHECK);
+  Handle h_dcmd_instance(THREAD, dcmd);
+  assert(h_dcmd_instance.not_null(), "invariant");
+
+  jstring repository_path = NULL;
+  if (_repository_path.is_set() && _repository_path.value() != NULL) {
+    repository_path = JfrJavaSupport::new_string(_repository_path.value(), CHECK);
+  }
+
+  jstring dump_path = NULL;
+  if (_dump_path.is_set() && _dump_path.value() != NULL) {
+    dump_path = JfrJavaSupport::new_string(_dump_path.value(), CHECK);
+  }
+
+  jobject stack_depth = NULL;
+  if (_stack_depth.is_set()) {
+    stack_depth = JfrJavaSupport::new_java_lang_Integer((jint)_stack_depth.value(), CHECK);
+  }
+
+  jobject global_buffer_count = NULL;
+  if (_global_buffer_count.is_set()) {
+    global_buffer_count = JfrJavaSupport::new_java_lang_Long(_global_buffer_count.value(), CHECK);
+  }
+
+  jobject global_buffer_size = NULL;
+  if (_global_buffer_size.is_set()) {
+    global_buffer_size = JfrJavaSupport::new_java_lang_Long(_global_buffer_size.value(), CHECK);
+  }
+
+  jobject thread_buffer_size = NULL;
+  if (_thread_buffer_size.is_set()) {
+    thread_buffer_size = JfrJavaSupport::new_java_lang_Long(_thread_buffer_size.value(), CHECK);
+  }
+
+  jobject max_chunk_size = NULL;
+  if (_max_chunk_size.is_set()) {
+    max_chunk_size = JfrJavaSupport::new_java_lang_Long(_max_chunk_size.value(), CHECK);
+  }
+
+  jobject memory_size = NULL;
+  if (_memory_size.is_set()) {
+    memory_size = JfrJavaSupport::new_java_lang_Long(_memory_size.value(), CHECK);
+  }
+
+  jobject sample_threads = NULL;
+  if (_sample_threads.is_set()) {
+    sample_threads = JfrJavaSupport::new_java_lang_Boolean(_sample_threads.value(), CHECK);
+  }
+
+  static const char klass[] = "jdk/jfr/internal/dcmd/DCmdConfigure";
+  static const char method[] = "execute";
+  static const char signature[] = "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;"
+    "Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;"
+    "Ljava/lang/Long;Ljava/lang/Boolean;)Ljava/lang/String;";
+
+  JfrJavaArguments execute_args(&result, klass, method, signature, CHECK);
+  execute_args.set_receiver(h_dcmd_instance);
+
+  // params
+  execute_args.push_jobject(repository_path);
+  execute_args.push_jobject(dump_path);
+  execute_args.push_jobject(stack_depth);
+  execute_args.push_jobject(global_buffer_count);
+  execute_args.push_jobject(global_buffer_size);
+  execute_args.push_jobject(thread_buffer_size);
+  execute_args.push_jobject(memory_size);
+  execute_args.push_jobject(max_chunk_size);
+  execute_args.push_jobject(sample_threads);
+
+  JfrJavaSupport::call_virtual(&execute_args, THREAD);
+  handle_dcmd_result(output(), (oop)result.get_jobject(), source, THREAD);
+}
+
+bool register_jfr_dcmds() {
+  uint32_t full_export = DCmd_Source_Internal | DCmd_Source_AttachAPI | DCmd_Source_MBean;
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JfrCheckFlightRecordingDCmd>(full_export, true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JfrDumpFlightRecordingDCmd>(full_export, true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JfrStartFlightRecordingDCmd>(full_export, true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JfrStopFlightRecordingDCmd>(full_export, true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JfrConfigureFlightRecorderDCmd>(full_export, true, false));
+  return true;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/dcmd/jfrDcmds.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_JFRDCMDS_HPP
+#define SHARE_VM_JFR_JFRDCMDS_HPP
+
+#include "services/diagnosticCommand.hpp"
+
+class JfrDumpFlightRecordingDCmd : public DCmdWithParser {
+ protected:
+  DCmdArgument<char*> _name;
+  DCmdArgument<char*> _filename;
+  DCmdArgument<bool>  _path_to_gc_roots;
+
+ public:
+  JfrDumpFlightRecordingDCmd(outputStream* output, bool heap);
+  static const char* name() {
+    return "JFR.dump";
+  }
+  static const char* description() {
+    return "Copies contents of a JFR recording to file. Either the name or the recording id must be specified.";
+  }
+  static const char* impact() {
+    return "Low";
+  }
+  static const JavaPermission permission() {
+    JavaPermission p = {"java.lang.management.ManagementPermission", "monitor", NULL};
+    return p;
+  }
+  static int num_arguments();
+  virtual void execute(DCmdSource source, TRAPS);
+};
+
+class JfrCheckFlightRecordingDCmd : public DCmdWithParser {
+ protected:
+  DCmdArgument<char*> _name;
+  DCmdArgument<bool>  _verbose;
+
+ public:
+  JfrCheckFlightRecordingDCmd(outputStream* output, bool heap);
+  static const char* name() {
+    return "JFR.check";
+  }
+  static const char* description() {
+    return "Checks running JFR recording(s)";
+  }
+  static const char* impact() {
+    return "Low";
+  }
+  static const JavaPermission permission() {
+    JavaPermission p = {"java.lang.management.ManagementPermission", "monitor", NULL};
+    return p;
+  }
+  static int num_arguments();
+  virtual void execute(DCmdSource source, TRAPS);
+};
+
+class JfrStartFlightRecordingDCmd : public DCmdWithParser {
+ protected:
+  DCmdArgument<char*> _name;
+  DCmdArgument<StringArrayArgument*> _settings;
+  DCmdArgument<NanoTimeArgument> _delay;
+  DCmdArgument<NanoTimeArgument> _duration;
+  DCmdArgument<bool> _disk;
+  DCmdArgument<char*> _filename;
+  DCmdArgument<NanoTimeArgument> _maxage;
+  DCmdArgument<MemorySizeArgument> _maxsize;
+  DCmdArgument<bool> _dump_on_exit;
+  DCmdArgument<bool> _path_to_gc_roots;
+
+ public:
+  JfrStartFlightRecordingDCmd(outputStream* output, bool heap);
+  static const char* name() {
+    return "JFR.start";
+  }
+  static const char* description() {
+    return "Starts a new JFR recording";
+  }
+  static const char* impact() {
+    return "Medium: Depending on the settings for a recording, the impact can range from low to high.";
+  }
+  static const JavaPermission permission() {
+    JavaPermission p = {"java.lang.management.ManagementPermission", "monitor", NULL};
+    return p;
+  }
+  static int num_arguments();
+  virtual void execute(DCmdSource source, TRAPS);
+};
+
+class JfrStopFlightRecordingDCmd : public DCmdWithParser {
+ protected:
+  DCmdArgument<char*> _name;
+  DCmdArgument<char*> _filename;
+
+ public:
+  JfrStopFlightRecordingDCmd(outputStream* output, bool heap);
+  static const char* name() {
+    return "JFR.stop";
+  }
+  static const char* description() {
+    return "Stops a JFR recording";
+  }
+  static const char* impact() {
+    return "Low";
+  }
+  static const JavaPermission permission() {
+    JavaPermission p = {"java.lang.management.ManagementPermission", "monitor", NULL};
+    return p;
+  }
+  static int num_arguments();
+  virtual void execute(DCmdSource source, TRAPS);
+};
+
+class JfrRuntimeOptions;
+
+class JfrConfigureFlightRecorderDCmd : public DCmdWithParser {
+  friend class JfrOptionSet;
+ protected:
+  DCmdArgument<char*> _repository_path;
+  DCmdArgument<char*> _dump_path;
+  DCmdArgument<jlong> _stack_depth;
+  DCmdArgument<jlong> _global_buffer_count;
+  DCmdArgument<jlong> _global_buffer_size;
+  DCmdArgument<jlong> _thread_buffer_size;
+  DCmdArgument<jlong> _memory_size;
+  DCmdArgument<jlong> _max_chunk_size;
+  DCmdArgument<bool>  _sample_threads;
+
+ public:
+  JfrConfigureFlightRecorderDCmd(outputStream* output, bool heap);
+  static const char* name() {
+    return "JFR.configure";
+  }
+  static const char* description() {
+    return "Configure JFR";
+  }
+  static const char* impact() {
+    return "Low";
+  }
+  static const JavaPermission permission() {
+    JavaPermission p = {"java.lang.management.ManagementPermission", "monitor", NULL};
+    return p;
+  }
+  static int num_arguments();
+  virtual void execute(DCmdSource source, TRAPS);
+};
+
+bool register_jfr_dcmds();
+
+#endif // SHARE_VM_JFR_JFRDCMDS_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,1556 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jvm.h"
+#include "classfile/classFileParser.hpp"
+#include "classfile/classFileStream.hpp"
+#include "classfile/javaClasses.inline.hpp"
+#include "classfile/stackMapTable.hpp"
+#include "classfile/verificationType.hpp"
+#include "interpreter/bytecodes.hpp"
+#include "jfr/instrumentation/jfrEventClassTransformer.hpp"
+#include "jfr/jfr.hpp"
+#include "jfr/jni/jfrJavaSupport.hpp"
+#include "jfr/jni/jfrUpcalls.hpp"
+#include "jfr/support/jfrEventClass.hpp"
+#include "jfr/utilities/jfrBigEndian.hpp"
+#include "jfr/writers/jfrBigEndianWriter.hpp"
+#include "logging/log.hpp"
+#include "memory/allocation.inline.hpp"
+#include "memory/resourceArea.hpp"
+#include "oops/array.hpp"
+#include "oops/instanceKlass.hpp"
+#include "oops/method.hpp"
+#include "prims/jvmtiRedefineClasses.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/os.hpp"
+#include "runtime/thread.inline.hpp"
+#include "utilities/exceptions.hpp"
+#include "utilities/globalDefinitions.hpp"
+#include "utilities/macros.hpp"
+
+static const u2 number_of_new_methods = 5;
+static const u2 number_of_new_fields = 3;
+static const int extra_stream_bytes = 0x280;
+static const u2 invalid_cp_index = 0;
+
+static const char* utf8_constants[] = {
+  "Code",         // 0
+  "J",            // 1
+  "commit",       // 2
+  "eventHandler", // 3
+  "Ljdk/jfr/internal/handlers/EventHandler;", // 4
+  "duration",     // 5
+  "begin",        // 6
+  "()V",          // 7
+  "isEnabled",    // 8
+  "()Z",          // 9
+  "end",          // 10
+  "shouldCommit", // 11
+  "startTime",    // 12
+  "<clinit>",     // 13
+  "jdk/jfr/FlightRecorder", // 14
+  "register", // 15
+  "(Ljava/lang/Class;)V", // 16 // LAST_REQUIRED_UTF8
+  "StackMapTable", // 17
+  "Exceptions", // 18
+  "LineNumberTable", // 20
+  "LocalVariableTable", // 21
+  "LocalVariableTypeTable", // 22
+  "RuntimeVisibleAnnotation" // 23
+};
+
+enum utf8_req_symbols {
+  UTF8_REQ_Code,
+  UTF8_REQ_J_FIELD_DESC,
+  UTF8_REQ_commit,
+  UTF8_REQ_eventHandler,
+  UTF8_REQ_eventHandler_FIELD_DESC,
+  UTF8_REQ_duration,
+  UTF8_REQ_begin,
+  UTF8_REQ_EMPTY_VOID_METHOD_DESC,
+  UTF8_REQ_isEnabled,
+  UTF8_REQ_EMPTY_BOOLEAN_METHOD_DESC,
+  UTF8_REQ_end,
+  UTF8_REQ_shouldCommit,
+  UTF8_REQ_startTime,
+  UTF8_REQ_clinit,
+  UTF8_REQ_FlightRecorder,
+  UTF8_REQ_register,
+  UTF8_REQ_CLASS_VOID_METHOD_DESC,
+  NOF_UTF8_REQ_SYMBOLS
+};
+
+enum utf8_opt_symbols {
+  UTF8_OPT_StackMapTable = NOF_UTF8_REQ_SYMBOLS,
+  UTF8_OPT_Exceptions,
+  UTF8_OPT_LineNumberTable,
+  UTF8_OPT_LocalVariableTable,
+  UTF8_OPT_LocalVariableTypeTable,
+  UTF8_OPT_RuntimeVisibleAnnotation,
+  NOF_UTF8_SYMBOLS
+};
+
+static u1 empty_void_method_code_attribute[] = {
+  0x0,
+  0x0,
+  0x0,
+  0xd, // attribute len
+  0x0,
+  0x0, // max stack
+  0x0,
+  0x1, // max locals
+  0x0,
+  0x0,
+  0x0,
+  0x1, // code length
+  Bytecodes::_return,
+  0x0,
+  0x0, // ex table len
+  0x0,
+  0x0  // attributes_count
+};
+
+static u1 boolean_method_code_attribute[] = {
+  0x0,
+  0x0,
+  0x0,
+  0xe,
+  0x0,
+  0x1, // max stack
+  0x0,
+  0x1, // max locals
+  0x0,
+  0x0,
+  0x0,
+  0x2,
+  Bytecodes::_iconst_0,
+  Bytecodes::_ireturn,
+  0x0,
+  0x0, // ex table len
+  0x0,
+  0x0, // attributes_count
+};
+
+// annotation processing support
+
+enum {  // initial annotation layout
+  atype_off = 0,      // utf8 such as 'Ljava/lang/annotation/Retention;'
+  count_off = 2,      // u2   such as 1 (one value)
+  member_off = 4,     // utf8 such as 'value'
+  tag_off = 6,        // u1   such as 'c' (type) or 'e' (enum)
+  e_tag_val = 'e',
+  e_type_off = 7,   // utf8 such as 'Ljava/lang/annotation/RetentionPolicy;'
+  e_con_off = 9,    // utf8 payload, such as 'SOURCE', 'CLASS', 'RUNTIME'
+  e_size = 11,     // end of 'e' annotation
+  c_tag_val = 'c',    // payload is type
+  c_con_off = 7,    // utf8 payload, such as 'I'
+  c_size = 9,       // end of 'c' annotation
+  s_tag_val = 's',    // payload is String
+  s_con_off = 7,    // utf8 payload, such as 'Ljava/lang/String;'
+  s_size = 9,
+  min_size = 6        // smallest possible size (zero members)
+};
+
+static int skip_annotation_value(const address, int, int); // fwd decl
+
+// Skip an annotation.  Return >=limit if there is any problem.
+static int next_annotation_index(const address buffer, int limit, int index) {
+  assert(buffer != NULL, "invariant");
+  index += 2;  // skip atype
+  if ((index += 2) >= limit) {
+    return limit;
+  }
+  int nof_members = JfrBigEndian::read<u2>(buffer + index - 2);
+  while (--nof_members >= 0 && index < limit) {
+    index += 2; // skip member
+    index = skip_annotation_value(buffer, limit, index);
+  }
+  return index;
+}
+
+// Skip an annotation value.  Return >=limit if there is any problem.
+static int skip_annotation_value(const address buffer, int limit, int index) {
+  assert(buffer != NULL, "invariant");
+  // value := switch (tag:u1) {
+  //   case B, C, I, S, Z, D, F, J, c: con:u2;
+  //   case e: e_class:u2 e_name:u2;
+  //   case s: s_con:u2;
+  //   case [: do(nval:u2) {value};
+  //   case @: annotation;
+  //   case s: s_con:u2;
+  // }
+  if ((index += 1) >= limit) {
+    return limit;
+  }
+  const u1 tag = buffer[index - 1];
+  switch (tag) {
+    case 'B':
+    case 'C':
+    case 'I':
+    case 'S':
+    case 'Z':
+    case 'D':
+    case 'F':
+    case 'J':
+    case 'c':
+    case 's':
+      index += 2;  // skip con or s_con
+      break;
+    case 'e':
+      index += 4;  // skip e_class, e_name
+      break;
+    case '[':
+      {
+        if ((index += 2) >= limit) {
+          return limit;
+        }
+        int nof_values = JfrBigEndian::read<u2>(buffer + index - 2);
+        while (--nof_values >= 0 && index < limit) {
+          index = skip_annotation_value(buffer, limit, index);
+        }
+      }
+      break;
+    case '@':
+      index = next_annotation_index(buffer, limit, index);
+      break;
+    default:
+      return limit;  //  bad tag byte
+  }
+  return index;
+}
+
+static const u2 number_of_elements_offset = (u2)2;
+static const u2 element_name_offset = (u2)(number_of_elements_offset + 2);
+static const u2 element_name_size = (u2)2;
+static const u2 value_type_relative_offset = (u2)2;
+static const u2 value_relative_offset = (u2)(value_type_relative_offset + 1);
+
+// see JVMS - 4.7.16. The RuntimeVisibleAnnotations Attribute
+
+class AnnotationElementIterator : public StackObj {
+ private:
+  const InstanceKlass* _ik;
+  const address _buffer;
+  const u2 _limit; // length of annotation
+  mutable u2 _current; // element
+  mutable u2 _next; // element
+  u2 value_index() const {
+    return JfrBigEndian::read<u2>(_buffer + _current + value_relative_offset);
+  }
+
+ public:
+  AnnotationElementIterator(const InstanceKlass* ik, address buffer, u2 limit) : _ik(ik),
+                                                                                 _buffer(buffer),
+                                                                                 _limit(limit),
+                                                                                 _next(element_name_offset),
+                                                                                 _current(element_name_offset) {
+    assert(_buffer != NULL, "invariant");
+    assert(_next == element_name_offset, "invariant");
+    assert(_current == element_name_offset, "invariant");
+  }
+
+  bool has_next() const {
+    return _next < _limit;
+  }
+
+  void move_to_next() const {
+    assert(has_next(), "invariant");
+    _current = _next;
+    if (_next < _limit) {
+      _next = skip_annotation_value(_buffer, _limit, _next + element_name_size);
+    }
+    assert(_next <= _limit, "invariant");
+    assert(_current <= _limit, "invariant");
+  }
+
+  u2 number_of_elements() const {
+    return JfrBigEndian::read<u2>(_buffer + number_of_elements_offset);
+  }
+
+  const Symbol* name() const {
+    assert(_current < _next, "invariant");
+    return _ik->constants()->symbol_at(JfrBigEndian::read<u2>(_buffer + _current));
+  }
+
+  char value_type() const {
+    return JfrBigEndian::read<u1>(_buffer + _current + value_type_relative_offset);
+  }
+
+  jint read_int() const {
+    return _ik->constants()->int_at(value_index());
+  }
+
+  bool read_bool() const {
+    return read_int() != 0;
+  }
+};
+
+class AnnotationIterator : public StackObj {
+ private:
+  const InstanceKlass* _ik;
+  // ensure _limit field is declared before _buffer
+  u2 _limit; // length of annotations array
+  const address _buffer;
+  mutable u2 _current; // annotation
+  mutable u2 _next; // annotation
+
+ public:
+  AnnotationIterator(const InstanceKlass* ik, AnnotationArray* ar) : _ik(ik),
+                                                                     _current(0),
+                                                                     _next(0),
+                                                                     _limit(ar != NULL ? ar->length() : 0),
+                                                                     _buffer(_limit > 2 ? ar->adr_at(2) : NULL) {
+    if (_buffer != NULL) {
+      _limit -= 2; // subtract sizeof(u2) number of annotations field
+    }
+  }
+  bool has_next() const {
+    return _next < _limit;
+  }
+
+  void move_to_next() const {
+    assert(has_next(), "invariant");
+    _current = _next;
+    if (_next < _limit) {
+      _next = next_annotation_index(_buffer, _limit, _next);
+    }
+    assert(_next <= _limit, "invariant");
+    assert(_current <= _limit, "invariant");
+  }
+  const AnnotationElementIterator elements() const {
+    assert(_current < _next, "invariant");
+    return AnnotationElementIterator(_ik, _buffer + _current, _next - _current);
+  }
+  const Symbol* type() const {
+    assert(_buffer != NULL, "invariant");
+    assert(_current < _limit, "invariant");
+    return _ik->constants()->symbol_at(JfrBigEndian::read<u2>(_buffer + _current));
+  }
+};
+
+static unsigned int unused_hash = 0;
+static const char value_name[] = "value";
+static bool has_registered_annotation(const InstanceKlass* ik, const Symbol* annotation_type, bool& value) {
+  assert(annotation_type != NULL, "invariant");
+  AnnotationArray* class_annotations = ik->class_annotations();
+  if (class_annotations == NULL) {
+    return false;
+  }
+
+  const AnnotationIterator annotation_iterator(ik, class_annotations);
+  while (annotation_iterator.has_next()) {
+    annotation_iterator.move_to_next();
+    if (annotation_iterator.type() == annotation_type) {
+      // target annotation found
+      static const Symbol* value_symbol =
+        SymbolTable::lookup_only(value_name, sizeof value_name - 1, unused_hash);
+      assert(value_symbol != NULL, "invariant");
+      const AnnotationElementIterator element_iterator = annotation_iterator.elements();
+      while (element_iterator.has_next()) {
+        element_iterator.move_to_next();
+        if (value_symbol == element_iterator.name()) {
+          // "value" element
+          assert('Z' == element_iterator.value_type(), "invariant");
+          value = element_iterator.read_bool();
+          return true;
+        }
+      }
+    }
+  }
+  return false;
+}
+
+static bool registered_annotation_value(const InstanceKlass* ik, const Symbol* const registered_symbol) {
+  assert(registered_symbol != NULL, "invariant");
+  assert(ik != NULL, "invariant");
+  assert(JdkJfrEvent::is_a(ik), "invariant");
+  bool registered_value = false;
+  if (has_registered_annotation(ik, registered_symbol, registered_value)) {
+    return registered_value;
+  }
+  InstanceKlass* super = InstanceKlass::cast(ik->super());
+  return registered_annotation_value(super, registered_symbol);
+}
+
+static const char registered_constant[] = "Ljdk/jfr/Registered;";
+
+// Evaluate to the value of the first found "Ljdk/jfr/Registered;" annotation.
+// Searching moves upwards in the klass hierarchy in order to support
+// inherited annotations in addition to the ability to override.
+static bool should_register_klass(const InstanceKlass* ik) {
+  static const Symbol* const registered_symbol = SymbolTable::lookup_only(registered_constant,
+                                                                          sizeof registered_constant - 1,
+                                                                          unused_hash);
+  assert(registered_symbol != NULL, "invariant");
+  return registered_annotation_value(ik, registered_symbol);
+}
+/*
+ * Map an utf8 constant back to its CONSTANT_UTF8_INFO
+ */
+static u2 utf8_info_index(const InstanceKlass* ik, const Symbol* const target, TRAPS) {
+  assert(target != NULL, "invariant");
+  const ConstantPool* cp = ik->constants();
+  const int cp_len = cp->length();
+  for (u2 index = 1; index < cp_len; ++index) {
+    const constantTag tag = cp->tag_at(index);
+    if (tag.is_utf8()) {
+      const Symbol* const utf8_sym = cp->symbol_at(index);
+      assert(utf8_sym != NULL, "invariant");
+      if (utf8_sym == target) {
+        return index;
+      }
+    }
+  }
+  // not in constant pool
+  return invalid_cp_index;
+}
+
+#ifdef ASSERT
+static bool is_index_within_range(u2 index, u2 orig_cp_len, u2 new_cp_entries_len) {
+  return index > 0 && index < orig_cp_len + new_cp_entries_len;
+}
+#endif
+
+static u2 add_utf8_info(JfrBigEndianWriter& writer, const char* utf8_constant, u2 orig_cp_len, u2& new_cp_entries_len) {
+  assert(utf8_constant != NULL, "invariant");
+  writer.write<u1>(JVM_CONSTANT_Utf8);
+  writer.write_utf8_u2_len(utf8_constant);
+  assert(writer.is_valid(), "invariant");
+  // return index for the added utf8 info
+  return orig_cp_len + new_cp_entries_len++;
+}
+
+static u2 add_method_ref_info(JfrBigEndianWriter& writer,
+                              u2 cls_name_index,
+                              u2 method_index,
+                              u2 desc_index,
+                              u2 orig_cp_len,
+                              u2& number_of_new_constants,
+                              TRAPS) {
+  assert(is_index_within_range(cls_name_index, orig_cp_len, number_of_new_constants), "invariant");
+  assert(is_index_within_range(method_index, orig_cp_len, number_of_new_constants), "invariant");
+  assert(is_index_within_range(desc_index, orig_cp_len, number_of_new_constants), "invariant");
+  writer.write<u1>(JVM_CONSTANT_Class);
+  writer.write<u2>(cls_name_index);
+  const u2 cls_entry_index = orig_cp_len + number_of_new_constants;
+  ++number_of_new_constants;
+  writer.write<u1>(JVM_CONSTANT_NameAndType);
+  writer.write<u2>(method_index);
+  writer.write<u2>(desc_index);
+  const u2 nat_entry_index = orig_cp_len + number_of_new_constants;
+  ++number_of_new_constants;
+  writer.write<u1>(JVM_CONSTANT_Methodref);
+  writer.write<u2>(cls_entry_index);
+  writer.write<u2>(nat_entry_index);
+  // post-increment number_of_new_constants
+  // value returned is the index to the added method_ref
+  return orig_cp_len + number_of_new_constants++;
+}
+
+static u2 add_flr_register_method_constants(JfrBigEndianWriter& writer,
+                                            const u2* utf8_indexes,
+                                            u2 orig_cp_len,
+                                            u2& number_of_new_constants,
+                                            TRAPS) {
+  assert(utf8_indexes != NULL, "invariant");
+  return add_method_ref_info(writer,
+                             utf8_indexes[UTF8_REQ_FlightRecorder],
+                             utf8_indexes[UTF8_REQ_register],
+                             utf8_indexes[UTF8_REQ_CLASS_VOID_METHOD_DESC],
+                             orig_cp_len,
+                             number_of_new_constants,
+                             THREAD);
+}
+
+/*
+ * field_info {
+ *   u2             access_flags;
+ *   u2             name_index;
+ *   u2             descriptor_index;
+ *   u2             attributes_count;
+ *   attribute_info attributes[attributes_count];
+ * }
+ */
+static jlong add_field_info(JfrBigEndianWriter& writer, u2 name_index, u2 desc_index, bool is_static = false) {
+  assert(name_index > 0, "invariant");
+  assert(desc_index > 0, "invariant");
+  DEBUG_ONLY(const jlong start_offset = writer.current_offset();)
+  writer.write<u2>(JVM_ACC_SYNTHETIC | JVM_ACC_PRIVATE | (is_static ? JVM_ACC_STATIC : JVM_ACC_TRANSIENT)); // flags
+  writer.write(name_index);
+  writer.write(desc_index);
+  writer.write((u2)0x0); // attributes_count
+  assert(writer.is_valid(), "invariant");
+  DEBUG_ONLY(assert(start_offset + 8 == writer.current_offset(), "invariant");)
+  return writer.current_offset();
+}
+
+static u2 add_field_infos(JfrBigEndianWriter& writer, const u2* utf8_indexes) {
+  assert(utf8_indexes != NULL, "invariant");
+  add_field_info(writer,
+                 utf8_indexes[UTF8_REQ_eventHandler],
+                 utf8_indexes[UTF8_REQ_eventHandler_FIELD_DESC],
+                 true); // static
+
+  add_field_info(writer,
+                 utf8_indexes[UTF8_REQ_startTime],
+                 utf8_indexes[UTF8_REQ_J_FIELD_DESC]);
+
+  add_field_info(writer,
+                 utf8_indexes[UTF8_REQ_duration],
+                 utf8_indexes[UTF8_REQ_J_FIELD_DESC]);
+
+  return number_of_new_fields;
+}
+
+/*
+ * method_info {
+ *  u2             access_flags;
+ *  u2             name_index;
+ *  u2             descriptor_index;
+ *  u2             attributes_count;
+ *  attribute_info attributes[attributes_count];
+ * }
+ *
+ * Code_attribute {
+ *   u2 attribute_name_index;
+ *   u4 attribute_length;
+ *   u2 max_stack;
+ *   u2 max_locals;
+ *   u4 code_length;
+ *   u1 code[code_length];
+ *   u2 exception_table_length;
+ *   {   u2 start_pc;
+ *       u2 end_pc;
+ *       u2 handler_pc;
+ *       u2 catch_type;
+ *   } exception_table[exception_table_length];
+ *   u2 attributes_count;
+ *   attribute_info attributes[attributes_count];
+ * }
+ */
+
+static jlong add_method_info(JfrBigEndianWriter& writer,
+                             u2 name_index,
+                             u2 desc_index,
+                             u2 code_index,
+                             const u1* const code,
+                             const size_t code_len) {
+  assert(name_index > 0, "invariant");
+  assert(desc_index > 0, "invariant");
+  assert(code_index > 0, "invariant");
+  DEBUG_ONLY(const jlong start_offset = writer.current_offset();)
+  writer.write<u2>(JVM_ACC_SYNTHETIC | JVM_ACC_PUBLIC); // flags
+  writer.write(name_index);
+  writer.write(desc_index);
+  writer.write<u2>(0x1); // attributes_count ; 1 for "Code" attribute
+  assert(writer.is_valid(), "invariant");
+  DEBUG_ONLY(assert(start_offset + 8 == writer.current_offset(), "invariant");)
+  // Code attribute
+  writer.write(code_index); // "Code"
+  writer.bytes(code, code_len);
+  DEBUG_ONLY(assert((start_offset + 8 + 2 + (jlong)code_len) == writer.current_offset(), "invariant");)
+  return writer.current_offset();
+}
+
+/*
+ * On return, the passed stream will be positioned
+ * just after the constant pool section in the classfile
+ * and the cp length is returned.
+ *
+ * Stream should come in at the start position.
+ */
+static u2 position_stream_after_cp(const ClassFileStream* stream) {
+  assert(stream != NULL, "invariant");
+  assert(stream->current_offset() == 0, "invariant");
+  stream->skip_u4_fast(2);  // 8 bytes skipped
+  const u2 cp_len = stream->get_u2_fast();
+  assert(cp_len > 0, "invariant");
+  // now spin the stream position to just after the constant pool
+  for (u2 index = 1; index < cp_len; ++index) {
+    const u1 tag = stream->get_u1_fast(); // cp tag
+    switch (tag) {
+      case JVM_CONSTANT_Class:
+      case JVM_CONSTANT_String: {
+        stream->skip_u2_fast(1); // skip 2 bytes
+        continue;
+      }
+      case JVM_CONSTANT_Fieldref:
+      case JVM_CONSTANT_Methodref:
+      case JVM_CONSTANT_InterfaceMethodref:
+      case JVM_CONSTANT_Integer:
+      case JVM_CONSTANT_Float:
+      case JVM_CONSTANT_NameAndType:
+      case JVM_CONSTANT_InvokeDynamic: {
+        stream->skip_u4_fast(1); // skip 4 bytes
+        continue;
+      }
+      case JVM_CONSTANT_Long:
+      case JVM_CONSTANT_Double: {
+        stream->skip_u4_fast(2); // skip 8 bytes
+        // Skip entry following eigth-byte constant, see JVM book p. 98
+        ++index;
+        continue;
+      }
+      case JVM_CONSTANT_Utf8: {
+        u2 utf8_length = stream->get_u2_fast();
+        stream->skip_u1_fast(utf8_length); // skip 2 + len bytes
+        continue;
+      }
+      case JVM_CONSTANT_MethodHandle:
+      case JVM_CONSTANT_MethodType: {
+        if (tag == JVM_CONSTANT_MethodHandle) {
+          stream->skip_u1_fast(1);
+          stream->skip_u2_fast(1); // skip 3 bytes
+        }
+        else if (tag == JVM_CONSTANT_MethodType) {
+          stream->skip_u2_fast(1); // skip 3 bytes
+        }
+      }
+      continue;
+      default:
+        assert(false, "error in skip logic!");
+        break;
+    } // end switch(tag)
+  }
+  return cp_len;
+}
+
+/*
+* On return, the passed stream will be positioned
+* just after the fields section in the classfile
+* and the number of fields will be returned.
+*
+* Stream should come in positioned just before fields_count
+*/
+static u2 position_stream_after_fields(const ClassFileStream* stream) {
+  assert(stream != NULL, "invariant");
+  assert(stream->current_offset() > 0, "invariant");
+  // fields len
+  const u2 orig_fields_len = stream->get_u2_fast();
+  // fields
+  for (u2 i = 0; i < orig_fields_len; ++i) {
+    stream->skip_u2_fast(3);
+    const u2 attrib_info_len = stream->get_u2_fast();
+    for (u2 j = 0; j < attrib_info_len; ++j) {
+      stream->skip_u2_fast(1);
+      const u4 attrib_len = stream->get_u4_fast();
+      stream->skip_u1_fast(attrib_len);
+    }
+  }
+  return orig_fields_len;
+}
+
+/*
+* On return, the passed stream will be positioned
+* just after the methods section in the classfile
+* and the number of methods will be returned.
+*
+* Stream should come in positioned just before methods_count
+*/
+static u2 position_stream_after_methods(JfrBigEndianWriter& writer,
+                                        const ClassFileStream* stream,
+                                        const u2* utf8_indexes,
+                                        bool register_klass,
+                                        const Method* clinit_method,
+                                        u4& orig_method_len_offset) {
+  assert(stream != NULL, "invariant");
+  assert(stream->current_offset() > 0, "invariant");
+  assert(utf8_indexes != NULL, "invariant");
+  // We will come back to this location when we
+  // know how many methods there will be.
+  writer.reserve(sizeof(u2));
+  const u2 orig_methods_len = stream->get_u2_fast();
+  // Move copy position past original method_count
+  // in order to not copy the original count
+  orig_method_len_offset += sizeof(u2);
+  for (u2 i = 0; i < orig_methods_len; ++i) {
+    const u4 method_offset = stream->current_offset();
+    stream->skip_u2_fast(1); // Access Flags
+    const u2 name_index = stream->get_u2_fast(); // Name index
+    stream->skip_u2_fast(1); // Descriptor index
+    const u2 attributes_count = stream->get_u2_fast();
+    for (u2 j = 0; j < attributes_count; ++j) {
+      stream->skip_u2_fast(1);
+      const u4 attrib_len = stream->get_u4_fast();
+      stream->skip_u1_fast(attrib_len);
+    }
+    if (clinit_method != NULL && name_index == clinit_method->name_index()) {
+      // The method just parsed is an existing <clinit> method.
+      // If the class has the @Registered(false) annotation, i.e. marking a class
+      // for opting out from automatic registration, then we do not need to do anything.
+      if (!register_klass) {
+        continue;
+      }
+      // Automatic registration with the jfr system is acccomplished
+      // by pre-pending code to the <clinit> method of the class.
+      // We will need to re-create a new <clinit> in a later step.
+      // For now, ensure that this method is excluded from the methods
+      // being copied.
+      writer.bytes(stream->buffer() + orig_method_len_offset,
+                   method_offset - orig_method_len_offset);
+      assert(writer.is_valid(), "invariant");
+
+      // Update copy position to skip copy of <clinit> method
+      orig_method_len_offset = stream->current_offset();
+    }
+  }
+  return orig_methods_len;
+}
+
+static u2 add_method_infos(JfrBigEndianWriter& writer, const u2* utf8_indexes) {
+  assert(utf8_indexes != NULL, "invariant");
+  add_method_info(writer,
+                  utf8_indexes[UTF8_REQ_begin],
+                  utf8_indexes[UTF8_REQ_EMPTY_VOID_METHOD_DESC],
+                  utf8_indexes[UTF8_REQ_Code],
+                  empty_void_method_code_attribute,
+                  sizeof(empty_void_method_code_attribute));
+
+  assert(writer.is_valid(), "invariant");
+
+  add_method_info(writer,
+                  utf8_indexes[UTF8_REQ_end],
+                  utf8_indexes[UTF8_REQ_EMPTY_VOID_METHOD_DESC],
+                  utf8_indexes[UTF8_REQ_Code],
+                  empty_void_method_code_attribute,
+                  sizeof(empty_void_method_code_attribute));
+
+  assert(writer.is_valid(), "invariant");
+
+  add_method_info(writer,
+                  utf8_indexes[UTF8_REQ_commit],
+                  utf8_indexes[UTF8_REQ_EMPTY_VOID_METHOD_DESC],
+                  utf8_indexes[UTF8_REQ_Code],
+                  empty_void_method_code_attribute,
+                  sizeof(empty_void_method_code_attribute));
+
+  assert(writer.is_valid(), "invariant");
+
+  add_method_info(writer,
+                  utf8_indexes[UTF8_REQ_isEnabled],
+                  utf8_indexes[UTF8_REQ_EMPTY_BOOLEAN_METHOD_DESC],
+                  utf8_indexes[UTF8_REQ_Code],
+                  boolean_method_code_attribute,
+                  sizeof(boolean_method_code_attribute));
+
+  assert(writer.is_valid(), "invariant");
+
+  add_method_info(writer,
+                  utf8_indexes[UTF8_REQ_shouldCommit],
+                  utf8_indexes[UTF8_REQ_EMPTY_BOOLEAN_METHOD_DESC],
+                  utf8_indexes[UTF8_REQ_Code],
+                  boolean_method_code_attribute,
+                  sizeof(boolean_method_code_attribute));
+  assert(writer.is_valid(), "invariant");
+  return number_of_new_methods;
+}
+
+static void adjust_exception_table(JfrBigEndianWriter& writer, u2 bci_adjustment_offset, const Method* method, TRAPS) {
+  const u2 ex_table_length = method != NULL ? (u2)method->exception_table_length() : 0;
+  writer.write<u2>(ex_table_length); // Exception table length
+  if (ex_table_length > 0) {
+    assert(method != NULL, "invariant");
+    const ExceptionTableElement* const ex_elements = method->exception_table_start();
+    for (int i = 0; i < ex_table_length; ++i) {
+      assert(ex_elements != NULL, "invariant");
+      writer.write<u2>(ex_elements[i].start_pc + bci_adjustment_offset);
+      writer.write<u2>(ex_elements[i].end_pc + bci_adjustment_offset);
+      writer.write<u2>(ex_elements[i].handler_pc + bci_adjustment_offset);
+      writer.write<u2>(ex_elements[i].catch_type_index); // no adjustment
+    }
+  }
+}
+
+enum StackMapFrameTypes {
+  SAME_FRAME_BEGIN = 0,
+  SAME_FRAME_END = 63,
+  SAME_LOCALS_1_STACK_ITEM_FRAME_BEGIN = 64,
+  SAME_LOCALS_1_STACK_ITEM_FRAME_END = 127,
+  SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247,
+  CHOP_FRAME_BEGIN = 248,
+  CHOP_FRAME_END = 250,
+  SAME_FRAME_EXTENDED = 251,
+  APPEND_FRAME_BEGIN = 252,
+  APPEND_FRAME_END = 254,
+  FULL_FRAME = 255
+};
+
+static void adjust_stack_map(JfrBigEndianWriter& writer,
+                             Array<u1>* stack_map,
+                             const u2* utf8_indexes,
+                             u2 bci_adjustment_offset,
+                             TRAPS) {
+  assert(stack_map != NULL, "invariant");
+  assert(utf8_indexes != NULL, "invariant");
+  writer.write<u2>(utf8_indexes[UTF8_OPT_StackMapTable]);
+  const jlong stack_map_attrib_len_offset = writer.current_offset();
+  writer.reserve(sizeof(u4));
+  StackMapStream stream(stack_map);
+  const u2 stack_map_entries = stream.get_u2(THREAD);
+  // number of entries
+  writer.write<u2>(stack_map_entries); // new stack map entry added
+  const u1 frame_type = stream.get_u1(THREAD);
+  // SAME_FRAME and SAME_LOCALS_1_STACK_ITEM_FRAME encode
+  // their offset_delta into the actual frame type itself.
+  // If such a frame type is the first frame, then we transform
+  // it to a SAME_FRAME_EXTENDED or a SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED frame.
+  // This is done in order to not overflow frame types accidentally
+  // when adjusting the offset_delta. In changing the frame types,
+  // we can work with an explicit u2 offset_delta field (like the other frame types)
+  if (frame_type <= SAME_FRAME_END) {
+    writer.write<u1>(SAME_FRAME_EXTENDED);
+    writer.write<u2>(frame_type + bci_adjustment_offset);
+  } else if (frame_type >= SAME_LOCALS_1_STACK_ITEM_FRAME_BEGIN &&
+             frame_type <= SAME_LOCALS_1_STACK_ITEM_FRAME_END) {
+    writer.write<u1>(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED);
+    writer.write<u2>((frame_type - SAME_LOCALS_1_STACK_ITEM_FRAME_BEGIN) + bci_adjustment_offset);
+  } else if (frame_type >= SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
+      // SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED to FULL_FRAME
+      // has a u2 offset_delta field
+      writer.write<u1>(frame_type);
+      writer.write<u2>(stream.get_u2(THREAD) + bci_adjustment_offset);
+  } else {
+    assert(false, "stackMapFrame type is invalid");
+  }
+
+  while (!stream.at_end()) {
+    writer.write<u1>(stream.get_u1(THREAD));
+  }
+
+  u4 stack_map_attrib_len = writer.current_offset() - stack_map_attrib_len_offset;
+  // the stack_map_table_attributes_length value is exclusive
+  stack_map_attrib_len -= sizeof(u4);
+  writer.write_at_offset(stack_map_attrib_len, stack_map_attrib_len_offset);
+}
+
+static void adjust_line_number_table(JfrBigEndianWriter& writer,
+                                     const u2* utf8_indexes,
+                                     u4 bci_adjustement_offset,
+                                     const Method* method,
+                                     TRAPS) {
+  assert(utf8_indexes != NULL, "invariant");
+  assert(method != NULL, "invariant");
+  assert(method->has_linenumber_table(), "invariant");
+  writer.write(utf8_indexes[UTF8_OPT_LineNumberTable]);
+  const jlong lnt_attributes_length_offset = writer.current_offset();
+  writer.reserve(sizeof(u4));
+  const jlong lnt_attributes_entries_offset = writer.current_offset();
+  writer.reserve(sizeof(u2));
+  u1* lnt = method->compressed_linenumber_table();
+  CompressedLineNumberReadStream lnt_stream(lnt);
+  u2 line_number_table_entries = 0;
+  while (lnt_stream.read_pair()) {
+    ++line_number_table_entries;
+    const u2 bci = (u2)lnt_stream.bci();
+    writer.write<u2>(bci + (u2)bci_adjustement_offset);
+    writer.write<u2>((u2)lnt_stream.line());
+  }
+  writer.write_at_offset(line_number_table_entries, lnt_attributes_entries_offset);
+  u4 lnt_table_attributes_len = writer.current_offset() - lnt_attributes_length_offset;
+  // the line_number_table_attributes_length value is exclusive
+  lnt_table_attributes_len -= sizeof(u4);
+  writer.write_at_offset(lnt_table_attributes_len, lnt_attributes_length_offset);
+}
+
+// returns the number of lvtt entries
+static u2 adjust_local_variable_table(JfrBigEndianWriter& writer,
+                                      const u2* utf8_indexes,
+                                      u2 bci_adjustment_offset,
+                                      const Method* method,
+                                      TRAPS) {
+  assert(utf8_indexes != NULL, "invariant");
+  assert(method != NULL, "invariant");
+  assert(method->has_localvariable_table(), "invariant");
+  writer.write<u2>(utf8_indexes[UTF8_OPT_LocalVariableTable]);
+  const jlong lvt_attributes_length_offset = writer.current_offset();
+  writer.reserve(sizeof(u4));
+  const int lvt_len = method->localvariable_table_length();
+  writer.write<u2>((u2)lvt_len);
+  const LocalVariableTableElement* table = method->localvariable_table_start();
+  assert(table != NULL, "invariant");
+  u2 num_lvtt_entries = 0;
+  for (int i = 0; i < lvt_len; ++i) {
+    writer.write<u2>(table[i].start_bci + bci_adjustment_offset);
+    writer.write<u2>(table[i].length);
+    writer.write<u2>(table[i].name_cp_index);
+    writer.write<u2>(table[i].descriptor_cp_index);
+    writer.write<u2>(table[i].slot);
+    if (table[i].signature_cp_index > 0) {
+      ++num_lvtt_entries;
+    }
+  }
+  u4 lvt_table_attributes_len = writer.current_offset() - lvt_attributes_length_offset;
+  // the lvt_table_attributes_length value is exclusive
+  lvt_table_attributes_len -= sizeof(u4);
+  writer.write_at_offset(lvt_table_attributes_len, lvt_attributes_length_offset);
+  return num_lvtt_entries;
+}
+
+static void adjust_local_variable_type_table(JfrBigEndianWriter& writer,
+                                            const u2* utf8_indexes,
+                                            u2 bci_adjustment_offset,
+                                            u2 num_lvtt_entries,
+                                            const Method* method,
+                                            TRAPS) {
+  assert(num_lvtt_entries > 0, "invariant");
+  writer.write<u2>(utf8_indexes[UTF8_OPT_LocalVariableTypeTable]);
+  const jlong lvtt_attributes_length_offset = writer.current_offset();
+  writer.reserve(sizeof(u4));
+  writer.write<u2>(num_lvtt_entries);
+  const LocalVariableTableElement* table = method->localvariable_table_start();
+  assert(table != NULL, "invariant");
+  const int lvt_len = method->localvariable_table_length();
+  for (int i = 0; i < lvt_len; ++i) {
+    if (table[i].signature_cp_index > 0) {
+      writer.write<u2>(table[i].start_bci + bci_adjustment_offset);
+      writer.write<u2>(table[i].length);
+      writer.write<u2>(table[i].name_cp_index);
+      writer.write<u2>(table[i].signature_cp_index);
+      writer.write<u2>(table[i].slot);
+    }
+  }
+  u4 lvtt_table_attributes_len = writer.current_offset() - lvtt_attributes_length_offset;
+  // the lvtt_table_attributes_length value is exclusive
+  lvtt_table_attributes_len -= sizeof(u4);
+  writer.write_at_offset(lvtt_table_attributes_len, lvtt_attributes_length_offset);
+}
+
+static void adjust_code_attributes(JfrBigEndianWriter& writer,
+                                   const u2* utf8_indexes,
+                                   u2 bci_adjustment_offset,
+                                   const Method* clinit_method,
+                                   TRAPS) {
+  // "Code" attributes
+  assert(utf8_indexes != NULL, "invariant");
+  const jlong code_attributes_offset = writer.current_offset();
+  writer.reserve(sizeof(u2));
+  u2 number_of_code_attributes = 0;
+  if (clinit_method != NULL) {
+    Array<u1>* stack_map = clinit_method->stackmap_data();
+    if (stack_map != NULL) {
+      ++number_of_code_attributes;
+      adjust_stack_map(writer, stack_map, utf8_indexes, bci_adjustment_offset, THREAD);
+      assert(writer.is_valid(), "invariant");
+    }
+    if (clinit_method != NULL && clinit_method->has_linenumber_table()) {
+      ++number_of_code_attributes;
+      adjust_line_number_table(writer, utf8_indexes, bci_adjustment_offset, clinit_method, THREAD);
+      assert(writer.is_valid(), "invariant");
+    }
+    if (clinit_method != NULL && clinit_method->has_localvariable_table()) {
+      ++number_of_code_attributes;
+      const u2 num_of_lvtt_entries = adjust_local_variable_table(writer, utf8_indexes, bci_adjustment_offset, clinit_method, THREAD);
+      assert(writer.is_valid(), "invariant");
+      if (num_of_lvtt_entries > 0) {
+        ++number_of_code_attributes;
+        adjust_local_variable_type_table(writer, utf8_indexes, bci_adjustment_offset, num_of_lvtt_entries, clinit_method, THREAD);
+        assert(writer.is_valid(), "invariant");
+      }
+    }
+  }
+
+  // Store the number of code_attributes
+  writer.write_at_offset(number_of_code_attributes, code_attributes_offset);
+}
+
+static jlong insert_clinit_method(const InstanceKlass* ik,
+                                  const ClassFileParser& parser,
+                                  JfrBigEndianWriter& writer,
+                                  u2 orig_constant_pool_len,
+                                  const u2* utf8_indexes,
+                                  const u2 register_method_ref_index,
+                                  const Method* clinit_method,
+                                  TRAPS) {
+  assert(utf8_indexes != NULL, "invariant");
+  // The injected code length is always this value.
+  // This is to ensure that padding can be done
+  // where needed and to simplify size calculations.
+  static const u2 injected_code_length = 8;
+  const u2 name_index = utf8_indexes[UTF8_REQ_clinit];
+  const u2 desc_index = utf8_indexes[UTF8_REQ_EMPTY_VOID_METHOD_DESC];
+  const u2 max_stack = MAX2(clinit_method != NULL ? clinit_method->verifier_max_stack() : 1, 1);
+  const u2 max_locals = MAX2(clinit_method != NULL ? clinit_method->max_locals() : 0, 0);
+  const u2 orig_bytecodes_length = clinit_method != NULL ? (u2)clinit_method->code_size() : 0;
+  const address orig_bytecodes = clinit_method != NULL ? clinit_method->code_base() : NULL;
+  const u2 new_code_length = injected_code_length + orig_bytecodes_length;
+  DEBUG_ONLY(const jlong start_offset = writer.current_offset();)
+  writer.write<u2>(JVM_ACC_STATIC); // flags
+  writer.write<u2>(name_index);
+  writer.write<u2>(desc_index);
+  writer.write<u2>((u2)0x1); // attributes_count // "Code"
+  assert(writer.is_valid(), "invariant");
+  DEBUG_ONLY(assert(start_offset + 8 == writer.current_offset(), "invariant");)
+  // "Code" attribute
+  writer.write<u2>(utf8_indexes[UTF8_REQ_Code]); // "Code"
+  const jlong code_attribute_length_offset = writer.current_offset();
+  writer.reserve(sizeof(u4));
+  writer.write<u2>(max_stack); // max stack
+  writer.write<u2>(max_locals); // max locals
+  writer.write<u4>((u4)new_code_length); // code length
+
+  /* BEGIN CLINIT CODE */
+
+  // Note the use of ldc_w here instead of ldc.
+  // This is to handle all values of "this_class_index"
+  writer.write<u1>((u1)Bytecodes::_ldc_w);
+  writer.write<u2>((u2)parser.this_class_index()); // load constant "this class"
+  writer.write<u1>((u1)Bytecodes::_invokestatic);
+  // invoke "FlightRecorder.register(Ljava/lang/Class;")
+  writer.write<u2>(register_method_ref_index);
+  if (clinit_method == NULL) {
+    writer.write<u1>((u1)Bytecodes::_nop);
+    writer.write<u1>((u1)Bytecodes::_return);
+  } else {
+    // If we are pre-pending to original code,
+    // do padding to minimize disruption to the original.
+    // It might have dependencies on 4-byte boundaries
+    // i.e. lookupswitch and tableswitch instructions
+    writer.write<u1>((u1)Bytecodes::_nop);
+    writer.write<u1>((u1)Bytecodes::_nop);
+    // insert original clinit code
+    writer.bytes(orig_bytecodes, orig_bytecodes_length);
+  }
+
+  /* END CLINIT CODE */
+
+  assert(writer.is_valid(), "invariant");
+  adjust_exception_table(writer, injected_code_length, clinit_method, THREAD);
+  assert(writer.is_valid(), "invariant");
+  adjust_code_attributes(writer, utf8_indexes, injected_code_length, clinit_method, THREAD);
+  assert(writer.is_valid(), "invariant");
+  u4 code_attribute_len = writer.current_offset() - code_attribute_length_offset;
+  // the code_attribute_length value is exclusive
+  code_attribute_len -= sizeof(u4);
+  writer.write_at_offset(code_attribute_len, code_attribute_length_offset);
+  return writer.current_offset();
+}
+
+// Caller needs ResourceMark
+static ClassFileStream* create_new_bytes_for_event_klass(const InstanceKlass* ik, const ClassFileParser& parser, TRAPS) {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
+  static const u2 public_final_flag_mask = JVM_ACC_PUBLIC | JVM_ACC_FINAL;
+  const ClassFileStream* const orig_stream = parser.clone_stream();
+  const int orig_stream_length = orig_stream->length();
+  // allocate an identically sized buffer
+  u1* const new_buffer = NEW_RESOURCE_ARRAY_IN_THREAD_RETURN_NULL(THREAD, u1, orig_stream_length);
+  if (new_buffer == NULL) {
+    return NULL;
+  }
+  assert(new_buffer != NULL, "invariant");
+  // memcpy the entire [B
+  memcpy(new_buffer, orig_stream->buffer(), orig_stream_length);
+  const u2 orig_cp_len = position_stream_after_cp(orig_stream);
+  assert(orig_cp_len > 0, "invariant");
+  assert(orig_stream->current_offset() > 0, "invariant");
+  orig_stream->skip_u2_fast(3); // access_flags, this_class_index, super_class_index
+  const u2 iface_len = orig_stream->get_u2_fast();
+  orig_stream->skip_u2_fast(iface_len);
+  // fields len
+  const u2 orig_fields_len = orig_stream->get_u2_fast();
+  // fields
+  for (u2 i = 0; i < orig_fields_len; ++i) {
+    orig_stream->skip_u2_fast(3);
+    const u2 attrib_info_len = orig_stream->get_u2_fast();
+    for (u2 j = 0; j < attrib_info_len; ++j) {
+      orig_stream->skip_u2_fast(1);
+      const u4 attrib_len = orig_stream->get_u4_fast();
+      orig_stream->skip_u1_fast(attrib_len);
+    }
+  }
+  // methods
+  const u2 orig_methods_len = orig_stream->get_u2_fast();
+  for (u2 i = 0; i < orig_methods_len; ++i) {
+    const u4 access_flag_offset = orig_stream->current_offset();
+    const u2 flags = orig_stream->get_u2_fast();
+    // Rewrite JVM_ACC_FINAL -> JVM_ACC_PUBLIC
+    if (public_final_flag_mask == flags) {
+      JfrBigEndianWriter accessflagsrewriter(new_buffer + access_flag_offset, sizeof(u2));
+      accessflagsrewriter.write<u2>(JVM_ACC_PUBLIC);
+      assert(accessflagsrewriter.is_valid(), "invariant");
+    }
+    orig_stream->skip_u2_fast(2);
+    const u2 attributes_count = orig_stream->get_u2_fast();
+    for (u2 j = 0; j < attributes_count; ++j) {
+      orig_stream->skip_u2_fast(1);
+      const u4 attrib_len = orig_stream->get_u4_fast();
+      orig_stream->skip_u1_fast(attrib_len);
+    }
+  }
+  return new ClassFileStream(new_buffer, orig_stream_length, NULL, ClassFileStream::verify);
+}
+
+// Attempt to locate an existing UTF8_INFO mapping the utf8_constant.
+// If no UTF8_INFO exists, add (append) a new one to the constant pool.
+static u2 find_or_add_utf8_info(JfrBigEndianWriter& writer,
+                                const InstanceKlass* ik,
+                                const char* const utf8_constant,
+                                u2 orig_cp_len,
+                                u2& added_cp_entries,
+                                TRAPS) {
+  assert(utf8_constant != NULL, "invariant");
+  TempNewSymbol utf8_sym = SymbolTable::new_symbol(utf8_constant, THREAD);
+  // lookup existing
+  const int utf8_orig_idx = utf8_info_index(ik, utf8_sym, THREAD);
+  if (utf8_orig_idx != invalid_cp_index) {
+    // existing constant pool entry found
+    return utf8_orig_idx;
+  }
+  // no existing match, need to add a new utf8 cp entry
+  assert(invalid_cp_index == utf8_orig_idx, "invariant");
+  // add / append new
+  return add_utf8_info(writer, utf8_constant, orig_cp_len, added_cp_entries);
+}
+
+/*
+ * This routine will resolve the required utf8_constants array
+ * to their constant pool indexes (mapping to their UTF8_INFO's)
+ * Only if a constant is actually needed and does not already exist
+ * will it be added.
+ *
+ * The passed in indexes array will be populated with the resolved indexes.
+ * The number of newly added constant pool entries is returned.
+ */
+static u2 resolve_utf8_indexes(JfrBigEndianWriter& writer,
+                               const InstanceKlass* ik,
+                               u2* const utf8_indexes,
+                               u2 orig_cp_len,
+                               const Method* clinit_method,
+                               TRAPS) {
+  assert(utf8_indexes != NULL, "invariant");
+  u2 added_cp_entries = 0;
+  // resolve all required symbols
+  for (u2 index = 0; index < NOF_UTF8_REQ_SYMBOLS; ++index) {
+    utf8_indexes[index] = find_or_add_utf8_info(writer,
+                                                ik,
+                                                utf8_constants[index],
+                                                orig_cp_len,
+                                                added_cp_entries,
+                                                THREAD);
+  }
+  // Now determine optional constants (mainly "Code" attributes)
+  if (clinit_method != NULL && clinit_method->has_stackmap_table()) {
+    utf8_indexes[UTF8_OPT_StackMapTable] =
+      find_or_add_utf8_info(writer,
+                            ik,
+                            utf8_constants[UTF8_OPT_StackMapTable],
+                            orig_cp_len,
+                            added_cp_entries,
+                            THREAD);
+  } else {
+    utf8_indexes[UTF8_OPT_StackMapTable] = invalid_cp_index;
+  }
+
+  if (clinit_method != NULL && clinit_method->has_linenumber_table()) {
+    utf8_indexes[UTF8_OPT_LineNumberTable] =
+      find_or_add_utf8_info(writer,
+                            ik,
+                            utf8_constants[UTF8_OPT_LineNumberTable],
+                            orig_cp_len,
+                            added_cp_entries,
+                            THREAD);
+  } else {
+    utf8_indexes[UTF8_OPT_LineNumberTable] = invalid_cp_index;
+  }
+
+  if (clinit_method != NULL && clinit_method->has_localvariable_table()) {
+    utf8_indexes[UTF8_OPT_LocalVariableTable] =
+      find_or_add_utf8_info(writer,
+                            ik,
+                            utf8_constants[UTF8_OPT_LocalVariableTable],
+                            orig_cp_len,
+                            added_cp_entries,
+                            THREAD);
+
+    utf8_indexes[UTF8_OPT_LocalVariableTypeTable] =
+      find_or_add_utf8_info(writer,
+                            ik,
+                            utf8_constants[UTF8_OPT_LocalVariableTypeTable],
+                            orig_cp_len,
+                            added_cp_entries,
+                            THREAD);
+  } else {
+    utf8_indexes[UTF8_OPT_LocalVariableTable] = invalid_cp_index;
+    utf8_indexes[UTF8_OPT_LocalVariableTypeTable] = invalid_cp_index;
+  }
+
+  return added_cp_entries;
+}
+
+static u1* new_bytes_for_lazy_instrumentation(const InstanceKlass* ik,
+                                              const ClassFileParser& parser,
+                                              jint& size_of_new_bytes,
+                                              TRAPS) {
+  assert(ik != NULL, "invariant");
+  // If the class already has a clinit method
+  // we need to take that into account
+  const Method* clinit_method = ik->class_initializer();
+  const bool register_klass = should_register_klass(ik);
+  const ClassFileStream* const orig_stream = parser.clone_stream();
+  const int orig_stream_size = orig_stream->length();
+  assert(orig_stream->current_offset() == 0, "invariant");
+  const u2 orig_cp_len = position_stream_after_cp(orig_stream);
+  assert(orig_cp_len > 0, "invariant");
+  assert(orig_stream->current_offset() > 0, "invariant");
+  // Dimension and allocate a working byte buffer
+  // to be used in building up a modified class [B.
+  const jint new_buffer_size = extra_stream_bytes + orig_stream_size;
+  u1* const new_buffer = NEW_RESOURCE_ARRAY_IN_THREAD_RETURN_NULL(THREAD, u1, new_buffer_size);
+  if (new_buffer == NULL) {
+    log_error(jfr, system) ("Thread local allocation (native) for " SIZE_FORMAT
+      " bytes failed in JfrClassAdapter::on_klass_creation", (size_t)new_buffer_size);
+    return NULL;
+  }
+  assert(new_buffer != NULL, "invariant");
+  // [B wrapped in a big endian writer
+  JfrBigEndianWriter writer(new_buffer, new_buffer_size);
+  assert(writer.current_offset() == 0, "invariant");
+  const u4 orig_access_flag_offset = orig_stream->current_offset();
+  // Copy original stream from the beginning up to AccessFlags
+  // This means the original constant pool contents are copied unmodified
+  writer.bytes(orig_stream->buffer(), orig_access_flag_offset);
+  assert(writer.is_valid(), "invariant");
+  assert(writer.current_offset() == orig_access_flag_offset, "invariant"); // same positions
+  // Our writer now sits just after the last original constant pool entry.
+  // I.e. we are in a good position to append new constant pool entries
+  // This array will contain the resolved indexes
+  // in order to reference UTF8_INFO's needed
+  u2 utf8_indexes[NOF_UTF8_SYMBOLS];
+  // Resolve_utf8_indexes will be conservative in attempting to
+  // locate an existing UTF8_INFO; it will only append constants
+  // that is absolutely required
+  u2 number_of_new_constants = resolve_utf8_indexes(writer, ik, utf8_indexes, orig_cp_len, clinit_method, THREAD);
+  // UTF8_INFO entries now added to the constant pool
+  // In order to invoke a method we would need additional
+  // constants, JVM_CONSTANT_Class, JVM_CONSTANT_NameAndType
+  // and JVM_CONSTANT_Methodref.
+  const u2 flr_register_method_ref_index =
+    register_klass ?
+      add_flr_register_method_constants(writer,
+                                        utf8_indexes,
+                                        orig_cp_len,
+                                        number_of_new_constants,
+                                        THREAD) :  invalid_cp_index;
+
+  // New constant pool entries added and all UTF8_INFO indexes resolved
+  // Now update the class file constant_pool_count with an updated count
+  writer.write_at_offset<u2>(orig_cp_len + number_of_new_constants, 8);
+  assert(writer.is_valid(), "invariant");
+  orig_stream->skip_u2_fast(3); // access_flags, this_class_index, super_class_index
+  const u2 iface_len = orig_stream->get_u2_fast(); // interfaces
+  orig_stream->skip_u2_fast(iface_len);
+  const u4 orig_fields_len_offset = orig_stream->current_offset();
+  // Copy from AccessFlags up to and including interfaces
+  writer.bytes(orig_stream->buffer() + orig_access_flag_offset,
+               orig_fields_len_offset - orig_access_flag_offset);
+  assert(writer.is_valid(), "invariant");
+  const jlong new_fields_len_offset = writer.current_offset();
+  const u2 orig_fields_len = position_stream_after_fields(orig_stream);
+  u4 orig_method_len_offset = orig_stream->current_offset();
+  // Copy up to and including fields
+  writer.bytes(orig_stream->buffer() + orig_fields_len_offset, orig_method_len_offset - orig_fields_len_offset);
+  assert(writer.is_valid(), "invariant");
+  // We are sitting just after the original number of field_infos
+  // so this is a position where we can add (append) new field_infos
+  const u2 number_of_new_fields = add_field_infos(writer, utf8_indexes);
+  assert(writer.is_valid(), "invariant");
+  const jlong new_method_len_offset = writer.current_offset();
+  // Additional field_infos added, update classfile fields_count
+  writer.write_at_offset<u2>(orig_fields_len + number_of_new_fields, new_fields_len_offset);
+  assert(writer.is_valid(), "invariant");
+  // Our current location is now at classfile methods_count
+  const u2 orig_methods_len = position_stream_after_methods(writer,
+                                                            orig_stream,
+                                                            utf8_indexes,
+                                                            register_klass,
+                                                            clinit_method,
+                                                            orig_method_len_offset);
+  const u4 orig_attributes_count_offset = orig_stream->current_offset();
+  // Copy existing methods
+  writer.bytes(orig_stream->buffer() + orig_method_len_offset, orig_attributes_count_offset - orig_method_len_offset);
+  assert(writer.is_valid(), "invariant");
+  // We are sitting just after the original number of method_infos
+  // so this is a position where we can add (append) new method_infos
+  u2 number_of_new_methods = add_method_infos(writer, utf8_indexes);
+
+  // We have just added the new methods.
+  //
+  // What about the state of <clinit>?
+  // We would need to do:
+  // 1. Nothing (@Registered(false) annotation)
+  // 2. Build up a new <clinit> - and if the original class already contains a <clinit>,
+  //                              merging will be neccessary.
+  //
+  if (register_klass) {
+    insert_clinit_method(ik, parser, writer, orig_cp_len, utf8_indexes, flr_register_method_ref_index, clinit_method, THREAD);
+  }
+  number_of_new_methods += clinit_method != NULL ? 0 : register_klass ? 1 : 0;
+  // Update classfile methods_count
+  writer.write_at_offset<u2>(orig_methods_len + number_of_new_methods, new_method_len_offset);
+  assert(writer.is_valid(), "invariant");
+  // Copy last remaining bytes
+  writer.bytes(orig_stream->buffer() + orig_attributes_count_offset, orig_stream_size - orig_attributes_count_offset);
+  assert(writer.is_valid(), "invariant");
+  assert(writer.current_offset() > orig_stream->length(), "invariant");
+  size_of_new_bytes = (jint)writer.current_offset();
+  return new_buffer;
+}
+
+static void log_pending_exception(oop throwable) {
+  assert(throwable != NULL, "invariant");
+  oop msg = java_lang_Throwable::message(throwable);
+  if (msg != NULL) {
+    char* text = java_lang_String::as_utf8_string(msg);
+    if (text != NULL) {
+      log_error(jfr, system) ("%s", text);
+    }
+  }
+}
+
+static bool should_force_instrumentation() {
+  return !JfrOptionSet::allow_event_retransforms() || JfrEventClassTransformer::is_force_instrumentation();
+}
+
+static ClassFileStream* create_new_bytes_for_subklass(const InstanceKlass* ik, const ClassFileParser& parser, Thread* t) {
+  assert(JdkJfrEvent::is_a(ik), "invariant");
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(t));
+  jint size_of_new_bytes = 0;
+  const u1* new_bytes = new_bytes_for_lazy_instrumentation(ik, parser, size_of_new_bytes, t);
+  if (new_bytes == NULL) {
+    return NULL;
+  }
+  assert(new_bytes != NULL, "invariant");
+  assert(size_of_new_bytes > 0, "invariant");
+
+  bool force_instrumentation = should_force_instrumentation();
+  if (Jfr::is_recording() || force_instrumentation) {
+    jint size_instrumented_data = 0;
+    unsigned char* instrumented_data = NULL;
+    const jclass super = (jclass)JNIHandles::make_local(ik->super()->java_mirror());
+    JfrUpcalls::new_bytes_eager_instrumentation(TRACE_ID(ik),
+                                                force_instrumentation,
+                                                super,
+                                                size_of_new_bytes,
+                                                new_bytes,
+                                                &size_instrumented_data,
+                                                &instrumented_data,
+                                                t);
+    if (t->has_pending_exception()) {
+      log_pending_exception(t->pending_exception());
+      t->clear_pending_exception();
+      return NULL;
+    }
+    assert(instrumented_data != NULL, "invariant");
+    assert(size_instrumented_data > 0, "invariant");
+    return new ClassFileStream(instrumented_data, size_instrumented_data, NULL, ClassFileStream::verify);
+  }
+  return new ClassFileStream(new_bytes, size_of_new_bytes, NULL, ClassFileStream::verify);
+}
+
+static bool cache_bytes(InstanceKlass* ik, ClassFileStream* new_stream, InstanceKlass* new_ik, TRAPS) {
+  assert(ik != NULL, "invariant");
+  assert(new_ik != NULL, "invariant");
+  assert(new_ik->name() != NULL, "invariant");
+  assert(new_stream != NULL, "invariant");
+  assert(!HAS_PENDING_EXCEPTION, "invariant");
+  static const bool can_retransform = JfrOptionSet::allow_retransforms();
+  if (!can_retransform) {
+    return true;
+  }
+  const jint stream_len = new_stream->length();
+  JvmtiCachedClassFileData* p =
+    (JvmtiCachedClassFileData*)NEW_C_HEAP_ARRAY_RETURN_NULL(u1, offset_of(JvmtiCachedClassFileData, data) + stream_len, mtInternal);
+  if (p == NULL) {
+    log_error(jfr, system)("Allocation using C_HEAP_ARRAY for " SIZE_FORMAT
+      " bytes failed in JfrClassAdapter::on_klass_creation", (size_t)offset_of(JvmtiCachedClassFileData, data) + stream_len);
+    return false;
+  }
+  p->length = stream_len;
+  memcpy(p->data, new_stream->buffer(), stream_len);
+  new_ik->set_cached_class_file(p);
+  JvmtiCachedClassFileData* const cached_class_data = ik->get_cached_class_file();
+  if (cached_class_data != NULL) {
+    os::free(cached_class_data);
+    ik->set_cached_class_file(NULL);
+  }
+  return true;
+}
+
+static InstanceKlass* create_new_instance_klass(InstanceKlass* ik, ClassFileStream* stream, TRAPS) {
+  assert(stream != NULL, "invariant");
+  ResourceMark rm(THREAD);
+  ClassLoaderData* const cld = ik->class_loader_data();
+  Handle pd(THREAD, ik->protection_domain());
+  Symbol* const class_name = ik->name();
+  const char* const klass_name = class_name != NULL ? class_name->as_C_string() : "";
+  ClassFileParser new_parser(stream,
+                             class_name,
+                             cld,
+                             pd,
+                             NULL, // host klass
+                             NULL, // cp_patches
+                             ClassFileParser::INTERNAL, // internal visibility
+                             THREAD);
+  if (HAS_PENDING_EXCEPTION) {
+    log_pending_exception(PENDING_EXCEPTION);
+    CLEAR_PENDING_EXCEPTION;
+    return NULL;
+  }
+  InstanceKlass* const new_ik = new_parser.create_instance_klass(false, THREAD);
+  if (HAS_PENDING_EXCEPTION) {
+    log_pending_exception(PENDING_EXCEPTION);
+    CLEAR_PENDING_EXCEPTION;
+    return NULL;
+  }
+  assert(new_ik != NULL, "invariant");
+  assert(new_ik->name() != NULL, "invariant");
+  assert(strncmp(ik->name()->as_C_string(), new_ik->name()->as_C_string(), strlen(ik->name()->as_C_string())) == 0, "invariant");
+  return cache_bytes(ik, stream, new_ik, THREAD) ? new_ik : NULL;
+}
+
+static void rewrite_klass_pointer(InstanceKlass*& ik, InstanceKlass* new_ik, ClassFileParser& parser, TRAPS) {
+  assert(ik != NULL, "invariant");
+  assert(new_ik != NULL, "invariant");
+  assert(new_ik->name() != NULL, "invariant");
+  assert(JdkJfrEvent::is(new_ik) || JdkJfrEvent::is_subklass(new_ik), "invariant");
+  assert(!HAS_PENDING_EXCEPTION, "invariant");
+  // assign original InstanceKlass* back onto "its" parser object for proper destruction
+  parser.set_klass_to_deallocate(ik);
+  // now rewrite original pointer to newly created InstanceKlass
+  ik = new_ik;
+}
+
+// During retransform/redefine, copy the Method specific trace flags
+// from the previous ik ("the original klass") to the new ik ("the scratch_klass").
+// The open code for retransform/redefine does not know about these.
+// In doing this migration here, we ensure the new Methods (defined in scratch klass)
+// will carry over trace tags from the old Methods being replaced,
+// ensuring flag/tag continuity while being transparent to open code.
+static void copy_method_trace_flags(const InstanceKlass* the_original_klass, const InstanceKlass* the_scratch_klass) {
+  assert(the_original_klass != NULL, "invariant");
+  assert(the_scratch_klass != NULL, "invariant");
+  assert(the_original_klass->name() == the_scratch_klass->name(), "invariant");
+  const Array<Method*>* old_methods = the_original_klass->methods();
+  const Array<Method*>* new_methods = the_scratch_klass->methods();
+  const bool equal_array_length = old_methods->length() == new_methods->length();
+  // The Method array has the property of being sorted.
+  // If they are the same length, there is a one-to-one mapping.
+  // If they are unequal, there was a method added (currently only
+  // private static methods allowed to be added), use lookup.
+  for (int i = 0; i < old_methods->length(); ++i) {
+    const Method* const old_method = old_methods->at(i);
+    Method* const new_method = equal_array_length ? new_methods->at(i) :
+      the_scratch_klass->find_method(old_method->name(), old_method->signature());
+    assert(new_method != NULL, "invariant");
+    assert(new_method->name() == old_method->name(), "invariant");
+    assert(new_method->signature() == old_method->signature(), "invariant");
+    *new_method->trace_flags_addr() = old_method->trace_flags();
+    assert(new_method->trace_flags() == old_method->trace_flags(), "invariant");
+  }
+}
+
+static bool is_retransforming(const InstanceKlass* ik, TRAPS) {
+  assert(ik != NULL, "invariant");
+  assert(JdkJfrEvent::is_a(ik), "invariant");
+  Symbol* const name = ik->name();
+  assert(name != NULL, "invariant");
+  Handle class_loader(THREAD, ik->class_loader());
+  Handle protection_domain(THREAD, ik->protection_domain());
+  // nota bene: use lock-free dictionary lookup
+  const InstanceKlass* prev_ik = (const InstanceKlass*)SystemDictionary::find(name, class_loader, protection_domain, THREAD);
+  if (prev_ik == NULL) {
+    return false;
+  }
+  // an existing ik implies a retransform/redefine
+  assert(prev_ik != NULL, "invariant");
+  assert(JdkJfrEvent::is_a(prev_ik), "invariant");
+  copy_method_trace_flags(prev_ik, ik);
+  return true;
+}
+
+// target for JFR_ON_KLASS_CREATION hook
+void JfrEventClassTransformer::on_klass_creation(InstanceKlass*& ik, ClassFileParser& parser, TRAPS) {
+  assert(ik != NULL, "invariant");
+  if (JdkJfrEvent::is(ik)) {
+    ResourceMark rm(THREAD);
+    HandleMark hm(THREAD);
+    ClassFileStream* new_stream = create_new_bytes_for_event_klass(ik, parser, THREAD);
+    if (new_stream == NULL) {
+      log_error(jfr, system)("JfrClassAdapter: unable to create ClassFileStream");
+      return;
+    }
+    assert(new_stream != NULL, "invariant");
+    InstanceKlass* new_ik = create_new_instance_klass(ik, new_stream, THREAD);
+    if (new_ik == NULL) {
+      log_error(jfr, system)("JfrClassAdapter: unable to create InstanceKlass");
+      return;
+    }
+    assert(new_ik != NULL, "invariant");
+    // We now need to explicitly tag the replaced klass as the jdk.jfr.Event klass
+    assert(!JdkJfrEvent::is(new_ik), "invariant");
+    JdkJfrEvent::tag_as(new_ik);
+    assert(JdkJfrEvent::is(new_ik), "invariant");
+    rewrite_klass_pointer(ik, new_ik, parser, THREAD);
+    return;
+  }
+  assert(JdkJfrEvent::is_subklass(ik), "invariant");
+  if (is_retransforming(ik, THREAD)) {
+    // not the initial klass load
+    return;
+  }
+  if (ik->is_abstract()) {
+    // abstract classes are not instrumented
+    return;
+  }
+  ResourceMark rm(THREAD);
+  HandleMark hm(THREAD);
+  ClassFileStream* const new_stream = create_new_bytes_for_subklass(ik, parser, THREAD);
+  if (NULL == new_stream) {
+    log_error(jfr, system)("JfrClassAdapter: unable to create ClassFileStream");
+    return;
+  }
+  assert(new_stream != NULL, "invariant");
+  InstanceKlass* new_ik = create_new_instance_klass(ik, new_stream, THREAD);
+  if (new_ik == NULL) {
+    log_error(jfr, system)("JfrClassAdapter: unable to create InstanceKlass");
+    return;
+  }
+  assert(new_ik != NULL, "invariant");
+  // would have been tagged already as a subklass during the normal process of traceid assignment
+  assert(JdkJfrEvent::is_subklass(new_ik), "invariant");
+  traceid id = ik->trace_id();
+  ik->set_trace_id(0);
+  new_ik->set_trace_id(id);
+  rewrite_klass_pointer(ik, new_ik, parser, THREAD);
+}
+
+static bool _force_instrumentation = false;
+void JfrEventClassTransformer::set_force_instrumentation(bool force_instrumentation) {
+  _force_instrumentation = force_instrumentation;
+}
+
+bool JfrEventClassTransformer::is_force_instrumentation() {
+  return _force_instrumentation;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_INSTRUMENTATION_JFREVENTCLASSTRANSFORMER_HPP
+#define SHARE_VM_JFR_INSTRUMENTATION_JFREVENTCLASSTRANSFORMER_HPP
+
+#include "memory/allocation.hpp"
+#include "utilities/exceptions.hpp"
+
+class ClassFileParser;
+class InstanceKlass;
+
+//
+// Intercepts the initial class load of jdk.jfr.Event and subclasses.
+// Will replace the sent in InstanceKlass* with a class file schema extended InstanceKlass*.
+//
+class JfrEventClassTransformer : AllStatic {
+ public:
+  static void on_klass_creation(InstanceKlass*& ik, ClassFileParser& parser, TRAPS);
+  static void set_force_instrumentation(bool force_instrumentation);
+  static bool is_force_instrumentation();
+};
+
+#endif // SHARE_VM_JFR_INSTRUMENTATION_JFREVENTCLASSTRANSFORMER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/instrumentation/jfrJvmtiAgent.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jvm.h"
+#include "jfr/instrumentation/jfrJvmtiAgent.hpp"
+#include "jfr/jni/jfrJavaSupport.hpp"
+#include "jfr/jni/jfrUpcalls.hpp"
+#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
+#include "jfr/recorder/service/jfrOptionSet.hpp"
+#include "jfr/support/jfrEventClass.hpp"
+#include "logging/log.hpp"
+#include "memory/resourceArea.hpp"
+#include "prims/jvmtiExport.hpp"
+#include "runtime/interfaceSupport.inline.hpp"
+#include "runtime/thread.inline.hpp"
+#include "utilities/exceptions.hpp"
+
+static const size_t ERROR_MSG_BUFFER_SIZE = 256;
+static JfrJvmtiAgent* agent = NULL;
+static jvmtiEnv* jfr_jvmti_env = NULL;
+
+static void check_jvmti_error(jvmtiEnv* jvmti, jvmtiError errnum, const char* str) {
+  if (errnum != JVMTI_ERROR_NONE) {
+    char* errnum_str = NULL;
+    jvmti->GetErrorName(errnum, &errnum_str);
+    log_error(jfr, system)("ERROR: JfrJvmtiAgent: " INT32_FORMAT " (%s): %s\n",
+                           errnum,
+                           NULL == errnum_str ? "Unknown" : errnum_str,
+                           NULL == str ? "" : str);
+  }
+}
+
+static jvmtiError set_event_notification_mode(jvmtiEventMode mode,
+                                              jvmtiEvent event,
+                                              jthread event_thread,
+                                              ...) {
+  if (jfr_jvmti_env == NULL) {
+    return JVMTI_ERROR_NONE;
+  }
+  const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventNotificationMode(mode, event, event_thread);
+  check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventNotificationMode");
+  return jvmti_ret_code;
+}
+
+static jvmtiError update_class_file_load_hook_event(jvmtiEventMode mode) {
+  return set_event_notification_mode(mode, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL);
+}
+
+static JavaThread* current_java_thread() {
+  Thread* this_thread = Thread::current();
+  assert(this_thread != NULL && this_thread->is_Java_thread(), "invariant");
+  return static_cast<JavaThread*>(this_thread);
+}
+
+// jvmti event callbacks require C linkage
+extern "C" void JNICALL jfr_on_class_file_load_hook(jvmtiEnv *jvmti_env,
+                                                    JNIEnv* jni_env,
+                                                    jclass class_being_redefined,
+                                                    jobject loader,
+                                                    const char* name,
+                                                    jobject protection_domain,
+                                                    jint class_data_len,
+                                                    const unsigned char* class_data,
+                                                    jint* new_class_data_len,
+                                                    unsigned char** new_class_data) {
+  if (class_being_redefined == NULL) {
+    return;
+  }
+  JavaThread* jt = JavaThread::thread_from_jni_environment(jni_env);
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt));;
+  ThreadInVMfromNative tvmfn(jt);
+  JfrUpcalls::on_retransform(JfrTraceId::get(class_being_redefined),
+                             class_being_redefined,
+                             class_data_len,
+                             class_data,
+                             new_class_data_len,
+                             new_class_data,
+                             jt);
+}
+
+// caller needs ResourceMark
+static jclass* create_classes_array(jint classes_count, TRAPS) {
+  assert(classes_count > 0, "invariant");
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD));
+  ThreadInVMfromNative tvmfn((JavaThread*)THREAD);
+  jclass* const classes = NEW_RESOURCE_ARRAY_IN_THREAD_RETURN_NULL(THREAD, jclass, classes_count);
+  if (NULL == classes) {
+    char error_buffer[ERROR_MSG_BUFFER_SIZE];
+    jio_snprintf(error_buffer, ERROR_MSG_BUFFER_SIZE,
+      "Thread local allocation (native) of " SIZE_FORMAT " bytes failed "
+      "in retransform classes", sizeof(jclass) * classes_count);
+    log_error(jfr, system)("%s", error_buffer);
+    JfrJavaSupport::throw_out_of_memory_error(error_buffer, CHECK_NULL);
+  }
+  return classes;
+}
+
+static void log_and_throw(TRAPS) {
+  if (!HAS_PENDING_EXCEPTION) {
+    DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD));
+    ThreadInVMfromNative tvmfn((JavaThread*)THREAD);
+    log_error(jfr, system)("JfrJvmtiAgent::retransformClasses failed");
+    JfrJavaSupport::throw_class_format_error("JfrJvmtiAgent::retransformClasses failed", THREAD);
+  }
+}
+
+static void check_exception_and_log(JNIEnv* env, TRAPS) {
+  assert(env != NULL, "invariant");
+  if (env->ExceptionOccurred()) {
+    // array index out of bound
+    DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD));
+    ThreadInVMfromNative tvmfn((JavaThread*)THREAD);
+    log_error(jfr, system)("GetObjectArrayElement threw an exception");
+    return;
+  }
+}
+
+void JfrJvmtiAgent::retransform_classes(JNIEnv* env, jobjectArray classes_array, TRAPS) {
+  assert(env != NULL, "invariant");
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD));
+  if (classes_array == NULL) {
+    return;
+  }
+  const jint classes_count = env->GetArrayLength(classes_array);
+  if (classes_count <= 0) {
+    return;
+  }
+  ResourceMark rm(THREAD);
+  jclass* const classes = create_classes_array(classes_count, CHECK);
+  assert(classes != NULL, "invariant");
+  for (jint i = 0; i < classes_count; i++) {
+    jclass clz = (jclass)env->GetObjectArrayElement(classes_array, i);
+    check_exception_and_log(env, THREAD);
+
+    // inspecting the oop/klass requires a thread transition
+    {
+      ThreadInVMfromNative transition((JavaThread*)THREAD);
+      if (JdkJfrEvent::is_a(clz)) {
+        // should have been tagged already
+        assert(JdkJfrEvent::is_subklass(clz), "invariant");
+      } else {
+        // outside the event hierarchy
+        JdkJfrEvent::tag_as_host(clz);
+      }
+    }
+
+    classes[i] = clz;
+  }
+  if (jfr_jvmti_env->RetransformClasses(classes_count, classes) != JVMTI_ERROR_NONE) {
+    log_and_throw(THREAD);
+  }
+}
+
+static jvmtiError register_callbacks(JavaThread* jt) {
+  assert(jfr_jvmti_env != NULL, "invariant");
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt));
+  jvmtiEventCallbacks callbacks;
+  /* Set callbacks */
+  memset(&callbacks, 0, sizeof(callbacks));
+  callbacks.ClassFileLoadHook = jfr_on_class_file_load_hook;
+  const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
+  check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventCallbacks");
+  return jvmti_ret_code;
+}
+
+static jvmtiError register_capabilities(JavaThread* jt) {
+  assert(jfr_jvmti_env != NULL, "invariant");
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt));
+  jvmtiCapabilities capabilities;
+  /* Add JVMTI capabilities */
+  (void)memset(&capabilities, 0, sizeof(capabilities));
+  capabilities.can_retransform_classes = 1;
+  capabilities.can_retransform_any_class = 1;
+  const jvmtiError jvmti_ret_code = jfr_jvmti_env->AddCapabilities(&capabilities);
+  check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "Add Capabilities");
+  return jvmti_ret_code;
+}
+
+static jint create_jvmti_env(JavaThread* jt) {
+  assert(jfr_jvmti_env == NULL, "invariant");
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt));
+  extern struct JavaVM_ main_vm;
+  JavaVM* vm = &main_vm;
+  return vm->GetEnv((void **)&jfr_jvmti_env, JVMTI_VERSION);
+}
+
+static jvmtiError unregister_callbacks(JavaThread* jt) {
+  if (jfr_jvmti_env == NULL) {
+    return JVMTI_ERROR_NONE;
+  }
+  jvmtiEventCallbacks callbacks;
+  /* Set empty callbacks */
+  memset(&callbacks, 0, sizeof(callbacks));
+  const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
+  check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventCallbacks");
+  return jvmti_ret_code;
+}
+
+JfrJvmtiAgent::JfrJvmtiAgent() {}
+
+JfrJvmtiAgent::~JfrJvmtiAgent() {
+  JavaThread* jt = current_java_thread();
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt));
+  ThreadToNativeFromVM transition(jt);
+  update_class_file_load_hook_event(JVMTI_DISABLE);
+  unregister_callbacks(jt);
+  if (jfr_jvmti_env != NULL) {
+    jfr_jvmti_env->DisposeEnvironment();
+    jfr_jvmti_env = NULL;
+  }
+  agent = NULL;
+}
+
+static bool initialize() {
+  JavaThread* const jt = current_java_thread();
+  assert(jt != NULL, "invariant");
+  assert(jt->thread_state() == _thread_in_vm, "invariant");
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt));
+  ThreadToNativeFromVM transition(jt);
+  if (create_jvmti_env(jt) != JNI_OK) {
+    assert(jfr_jvmti_env == NULL, "invariant");
+    return false;
+  }
+  assert(jfr_jvmti_env != NULL, "invariant");
+  if (register_capabilities(jt) != JVMTI_ERROR_NONE) {
+    return false;
+  }
+  if (register_callbacks(jt) != JVMTI_ERROR_NONE) {
+    return false;
+  }
+  if (update_class_file_load_hook_event(JVMTI_ENABLE) != JVMTI_ERROR_NONE) {
+    return false;
+  }
+  return true;
+}
+
+bool JfrJvmtiAgent::create() {
+  assert(jfr_jvmti_env == NULL, "invariant");
+  agent = new JfrJvmtiAgent();
+  if (agent == NULL) {
+    return false;
+  }
+  if (!initialize()) {
+    delete agent;
+    agent = NULL;
+    return false;
+  }
+  return true;
+}
+
+void JfrJvmtiAgent::destroy() {
+  if (agent != NULL) {
+    delete agent;
+    agent = NULL;
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/instrumentation/jfrJvmtiAgent.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_INSTRUMENTATION_JFRJVMTIAGENT_HPP
+#define SHARE_VM_JFR_INSTRUMENTATION_JFRJVMTIAGENT_HPP
+
+#include "jfr/utilities/jfrAllocation.hpp"
+
+class JfrJvmtiAgent : public JfrCHeapObj {
+  friend class JfrRecorder;
+ private:
+  JfrJvmtiAgent();
+  ~JfrJvmtiAgent();
+  static bool create();
+  static void destroy();
+ public:
+  static void retransform_classes(JNIEnv* env, jobjectArray classes, TRAPS);
+};
+
+#endif // SHARE_VM_JFR_INSTRUMENTATION_JFRJVMTIAGENT_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/jfr.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/jfr.hpp"
+#include "jfr/leakprofiler/leakProfiler.hpp"
+#include "jfr/periodic/sampling/jfrThreadSampler.hpp"
+#include "jfr/recorder/service/jfrOptionSet.hpp"
+#include "jfr/recorder/jfrRecorder.hpp"
+#include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
+#include "jfr/recorder/repository/jfrEmergencyDump.hpp"
+#include "jfr/support/jfrThreadLocal.hpp"
+#include "runtime/java.hpp"
+
+bool Jfr::is_enabled() {
+  return JfrRecorder::is_enabled();
+}
+
+bool Jfr::is_disabled() {
+  return JfrRecorder::is_disabled();
+}
+
+bool Jfr::is_recording() {
+  return JfrRecorder::is_recording();
+}
+
+void Jfr::on_vm_init() {
+  if (!JfrRecorder::on_vm_init()) {
+    vm_exit_during_initialization("Failure when starting JFR on_vm_init");
+  }
+}
+
+void Jfr::on_vm_start() {
+  if (!JfrRecorder::on_vm_start()) {
+    vm_exit_during_initialization("Failure when starting JFR on_vm_start");
+  }
+}
+
+void Jfr::on_unloading_classes() {
+  if (JfrRecorder::is_created()) {
+    JfrCheckpointManager::write_type_set_for_unloaded_classes();
+  }
+}
+
+void Jfr::on_thread_exit(JavaThread* thread) {
+  if (JfrRecorder::is_recording()) {
+    JfrThreadLocal::on_exit(thread);
+  }
+}
+
+void Jfr::on_thread_destruct(Thread* thread) {
+  if (JfrRecorder::is_created()) {
+    JfrThreadLocal::on_destruct(thread);
+  }
+}
+
+void Jfr::on_vm_shutdown(bool exception_handler) {
+  if (JfrRecorder::is_recording()) {
+    JfrEmergencyDump::on_vm_shutdown(exception_handler);
+  }
+}
+
+void Jfr::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f) {
+  LeakProfiler::oops_do(is_alive, f);
+}
+
+bool Jfr::on_start_flight_recording_option(const JavaVMOption** option, char* tail) {
+  return JfrOptionSet::parse_start_flight_recording_option(option, tail);
+}
+
+bool Jfr::on_flight_recorder_option(const JavaVMOption** option, char* tail) {
+  return JfrOptionSet::parse_flight_recorder_option(option, tail);
+}
+
+Thread* Jfr::sampler_thread() {
+  return JfrThreadSampling::sampler_thread();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/jfr.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_JFR_HPP
+#define SHARE_VM_JFR_JFR_HPP
+
+#include "jni.h"
+#include "memory/allocation.hpp"
+
+class BoolObjectClosure;
+class JavaThread;
+class OopClosure;
+class Thread;
+
+extern "C" void JNICALL jfr_register_natives(JNIEnv*, jclass);
+
+//
+// The VM interface to Flight Recorder.
+//
+class Jfr : AllStatic {
+ public:
+  static bool is_enabled();
+  static bool is_disabled();
+  static bool is_recording();
+  static void on_vm_init();
+  static void on_vm_start();
+  static void on_unloading_classes();
+  static void on_thread_exit(JavaThread* thread);
+  static void on_thread_destruct(Thread* thread);
+  static void on_vm_shutdown(bool exception_handler = false);
+  static bool on_start_flight_recording_option(const JavaVMOption** option, char* tail);
+  static bool on_flight_recorder_option(const JavaVMOption** option, char* tail);
+  static void weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f);
+  static Thread* sampler_thread();
+};
+
+#endif // SHARE_VM_JFR_JFR_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/jfrEvents.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_JFREVENTS_HPP
+#define SHARE_VM_JFR_JFREVENTS_HPP
+/*
+ * Declare your event in jfr/metadata/metadata.xml.
+ *
+ * Include this header to access the machine generated event class.
+ */
+#include "jfrfiles/jfrEventClasses.hpp"
+#include "jfrfiles/jfrEventIds.hpp"
+
+#endif // SHARE_VM_JFR_JFREVENTS_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/jni/jfrGetAllEventClasses.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/javaClasses.inline.hpp"
+#include "classfile/symbolTable.hpp"
+#include "jfr/jni/jfrGetAllEventClasses.hpp"
+#include "jfr/jni/jfrJavaSupport.hpp"
+#include "jfr/support/jfrEventClass.hpp"
+#include "oops/instanceKlass.hpp"
+#include "memory/allocation.inline.hpp"
+#include "memory/resourceArea.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/safepoint.hpp"
+#include "runtime/thread.inline.hpp"
+#include "utilities/growableArray.hpp"
+#include "utilities/stack.inline.hpp"
+
+ // incremented during class unloading (safepoint) for each unloaded event class
+static jlong unloaded_event_classes = 0;
+
+jlong JfrEventClasses::unloaded_event_classes_count() {
+  return unloaded_event_classes;
+}
+
+void JfrEventClasses::increment_unloaded_event_class() {
+  // incremented during class unloading (safepoint) for each unloaded event class
+  assert(SafepointSynchronize::is_at_safepoint(), "invariant");
+  ++unloaded_event_classes;
+}
+
+static jobject empty_java_util_arraylist = NULL;
+
+static oop new_java_util_arraylist(TRAPS) {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
+  JavaValue result(T_OBJECT);
+  JfrJavaArguments args(&result, "java/util/ArrayList", "<init>", "()V", CHECK_NULL);
+  JfrJavaSupport::new_object(&args, CHECK_NULL);
+  return (oop)result.get_jobject();
+}
+
+static bool initialize(TRAPS) {
+  static bool initialized = false;
+  if (!initialized) {
+    unloaded_event_classes = 0;
+    assert(NULL == empty_java_util_arraylist, "invariant");
+    const oop array_list = new_java_util_arraylist(CHECK_false);
+    empty_java_util_arraylist = JfrJavaSupport::global_jni_handle(array_list, THREAD);
+    initialized = empty_java_util_arraylist != NULL;
+  }
+  return initialized;
+}
+
+/*
+ * Abstract klasses are filtered out unconditionally.
+ * If a klass is not yet initialized, i.e yet to run its <clinit>
+ * it is also filtered out so we don't accidentally
+ * trigger initialization.
+ */
+static bool is_whitelisted(const Klass* k) {
+  assert(k != NULL, "invariant");
+  return !(k->is_abstract() || k->should_be_initialized());
+}
+
+static void fill_klasses(GrowableArray<const void*>& event_subklasses, const Klass* event_klass, Thread* thread) {
+  assert(event_subklasses.length() == 0, "invariant");
+  assert(event_klass != NULL, "invariant");
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(thread));
+
+  Stack<const Klass*, mtTracing> mark_stack;
+  MutexLocker ml(Compile_lock, thread);
+  mark_stack.push(event_klass->subklass());
+
+  while (!mark_stack.is_empty()) {
+    const Klass* const current = mark_stack.pop();
+    assert(current != NULL, "null element in stack!");
+
+    if (is_whitelisted(current)) {
+      event_subklasses.append(current);
+    }
+
+    // subclass (depth)
+    const Klass* next_klass = current->subklass();
+    if (next_klass != NULL) {
+      mark_stack.push(next_klass);
+    }
+
+    // siblings (breadth)
+    next_klass = current->next_sibling();
+    if (next_klass != NULL) {
+      mark_stack.push(next_klass);
+    }
+  }
+  assert(mark_stack.is_empty(), "invariant");
+}
+
+ static void transform_klasses_to_local_jni_handles(GrowableArray<const void*>& event_subklasses, Thread* thread) {
+  assert(event_subklasses.is_nonempty(), "invariant");
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(thread));
+
+  for (int i = 0; i < event_subklasses.length(); ++i) {
+    const InstanceKlass* k = static_cast<const InstanceKlass*>(event_subklasses.at(i));
+    assert(is_whitelisted(k), "invariant");
+    event_subklasses.at_put(i, JfrJavaSupport::local_jni_handle(k->java_mirror(), thread));
+  }
+}
+
+static const int initial_size_growable_array = 64;
+
+jobject JfrEventClasses::get_all_event_classes(TRAPS) {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
+  initialize(THREAD);
+  assert(empty_java_util_arraylist != NULL, "should have been setup already!");
+  static const char jdk_jfr_event_name[] = "jdk/jfr/Event";
+  unsigned int unused_hash = 0;
+  Symbol* const event_klass_name = SymbolTable::lookup_only(jdk_jfr_event_name, sizeof jdk_jfr_event_name - 1, unused_hash);
+
+  if (NULL == event_klass_name) {
+    // not loaded yet
+    return empty_java_util_arraylist;
+  }
+
+  const Klass* const klass = SystemDictionary::resolve_or_null(event_klass_name, THREAD);
+  assert(klass != NULL, "invariant");
+  assert(JdkJfrEvent::is(klass), "invariant");
+
+  if (klass->subklass() == NULL) {
+    return empty_java_util_arraylist;
+  }
+
+  ResourceMark rm(THREAD);
+  GrowableArray<const void*> event_subklasses(THREAD, initial_size_growable_array);
+  fill_klasses(event_subklasses, klass, THREAD);
+
+  if (event_subklasses.is_empty()) {
+    return empty_java_util_arraylist;
+  }
+
+  transform_klasses_to_local_jni_handles(event_subklasses, THREAD);
+
+  Handle h_array_list(THREAD, new_java_util_arraylist(THREAD));
+  assert(h_array_list.not_null(), "invariant");
+
+  static const char add_method_name[] = "add";
+  static const char add_method_signature[] = "(Ljava/lang/Object;)Z";
+  const Klass* const array_list_klass = JfrJavaSupport::klass(empty_java_util_arraylist);
+  assert(array_list_klass != NULL, "invariant");
+
+  const Symbol* const add_method_sym = SymbolTable::lookup(add_method_name, sizeof add_method_name - 1, THREAD);
+  assert(add_method_sym != NULL, "invariant");
+
+  const Symbol* const add_method_sig_sym = SymbolTable::lookup(add_method_signature, sizeof add_method_signature - 1, THREAD);
+  assert(add_method_signature != NULL, "invariant");
+
+  JavaValue result(T_BOOLEAN);
+  for (int i = 0; i < event_subklasses.length(); ++i) {
+    const jclass clazz = (const jclass)event_subklasses.at(i);
+    assert(JdkJfrEvent::is_subklass(clazz), "invariant");
+    JfrJavaArguments args(&result, array_list_klass, add_method_sym, add_method_sig_sym);
+    args.set_receiver(h_array_list());
+    args.push_jobject(clazz);
+    JfrJavaSupport::call_virtual(&args, THREAD);
+    if (HAS_PENDING_EXCEPTION || JNI_FALSE == result.get_jboolean()) {
+      return empty_java_util_arraylist;
+    }
+  }
+  return JfrJavaSupport::local_jni_handle(h_array_list(), THREAD);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/jni/jfrGetAllEventClasses.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+#ifndef SHARE_VM_JFR_JNI_JFRGETALLEVENTCLASSES_HPP
+#define SHARE_VM_JFR_JNI_JFRGETALLEVENTCLASSES_HPP
+
+#include "jni.h"
+#include "memory/allocation.hpp"
+#include "utilities/exceptions.hpp"
+
+//
+// Responsible for the delivery of currently loaded jdk.jfr.Event subklasses to Java.
+//
+class JfrEventClasses : AllStatic {
+ public:
+  static void increment_unloaded_event_class();
+  static jlong unloaded_event_classes_count();
+  static jobject get_all_event_classes(TRAPS);
+};
+
+#endif // SHARE_VM_JFR_JNI_JFRGETALLEVENTCLASSES_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/jni/jfrJavaCall.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,380 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/symbolTable.hpp"
+#include "classfile/systemDictionary.hpp"
+#include "jfr/jni/jfrJavaCall.hpp"
+#include "jfr/jni/jfrJavaSupport.hpp"
+#include "memory/resourceArea.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/javaCalls.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+#ifdef ASSERT
+static bool is_large_value(const JavaValue& value) {
+  return value.get_type() == T_LONG || value.get_type() == T_DOUBLE;
+}
+#endif // ASSERT
+
+static Symbol* resolve(const char* str, TRAPS) {
+  assert(str != NULL, "invariant");
+  return SymbolTable::lookup(str, (int)strlen(str), THREAD);
+}
+
+static Klass* resolve(Symbol* k_sym, TRAPS) {
+  assert(k_sym != NULL, "invariant");
+  return SystemDictionary::resolve_or_fail(k_sym, true, THREAD);
+}
+
+JfrJavaArguments::Parameters::Parameters() : _storage_index(0), _java_stack_slots(0) {
+  JavaValue value(T_VOID);
+  push(value);
+}
+
+void JfrJavaArguments::Parameters::push(const JavaValue& value) {
+  assert(_storage != NULL, "invariant");
+  assert(!is_large_value(value), "invariant");
+  assert(_storage_index < SIZE, "invariant");
+  _storage[_storage_index++] = value;
+  _java_stack_slots++;
+}
+
+void JfrJavaArguments::Parameters::push_large(const JavaValue& value) {
+  assert(_storage != NULL, "invariant");
+  assert(is_large_value(value), "invariant");
+  assert(_storage_index < SIZE, "invariant");
+  _storage[_storage_index++] = value;
+  _java_stack_slots += 2;
+}
+
+void JfrJavaArguments::Parameters::set_receiver(const oop receiver) {
+  assert(_storage != NULL, "invariant");
+  assert(receiver != NULL, "invariant");
+  JavaValue value(T_OBJECT);
+  value.set_jobject((jobject)receiver);
+  _storage[0] = value;
+}
+
+void JfrJavaArguments::Parameters::set_receiver(Handle receiver) {
+  set_receiver(receiver());
+}
+
+oop JfrJavaArguments::Parameters::receiver() const {
+  assert(has_receiver(), "invariant");
+  assert(_storage[0].get_type() == T_OBJECT, "invariant");
+  return (oop)_storage[0].get_jobject();
+}
+
+bool JfrJavaArguments::Parameters::has_receiver() const {
+  assert(_storage != NULL, "invariant");
+  assert(_storage_index >= 1, "invariant");
+  assert(_java_stack_slots >= 1, "invariant");
+  return _storage[0].get_type() == T_OBJECT;
+}
+
+void JfrJavaArguments::Parameters::push_oop(const oop obj) {
+  JavaValue value(T_OBJECT);
+  value.set_jobject((jobject)obj);
+  push(value);
+}
+
+void JfrJavaArguments::Parameters::push_oop(Handle h_obj) {
+  push_oop(h_obj());
+}
+
+void JfrJavaArguments::Parameters::push_jobject(jobject h) {
+  JavaValue value(T_ADDRESS);
+  value.set_jobject(h);
+  push(value);
+}
+
+void JfrJavaArguments::Parameters::push_jint(jint i) {
+  JavaValue value(T_INT);
+  value.set_jint(i);
+  push(value);
+}
+
+void JfrJavaArguments::Parameters::push_jfloat(jfloat f) {
+  JavaValue value(T_FLOAT);
+  value.set_jfloat(f);
+  push(value);
+}
+
+void JfrJavaArguments::Parameters::push_jdouble(jdouble d) {
+  JavaValue value(T_DOUBLE);
+  value.set_jdouble(d);
+  push_large(value);
+}
+
+void JfrJavaArguments::Parameters::push_jlong(jlong l) {
+  JavaValue value(T_LONG);
+  value.set_jlong(l);
+  push_large(value);
+}
+
+// including receiver (even if there is none)
+inline int JfrJavaArguments::Parameters::length() const {
+  assert(_storage_index >= 1, "invariant");
+  return _storage_index;
+}
+
+inline int JfrJavaArguments::Parameters::java_stack_slots() const {
+  return _java_stack_slots;
+}
+
+const JavaValue& JfrJavaArguments::Parameters::values(int idx) const {
+  assert(idx >= 0, "invariant");
+  assert(idx < SIZE, "invariant");
+  return _storage[idx];
+}
+
+void JfrJavaArguments::Parameters::copy(JavaCallArguments& args, TRAPS) const {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
+  if (has_receiver()) {
+    args.set_receiver(Handle(THREAD, receiver()));
+  }
+  for (int i = 1; i < length(); ++i) {
+    switch(values(i).get_type()) {
+      case T_BOOLEAN:
+      case T_CHAR:
+      case T_SHORT:
+      case T_INT:
+        args.push_int(values(i).get_jint());
+        break;
+      case T_LONG:
+        args.push_long(values(i).get_jlong());
+        break;
+      case T_FLOAT:
+        args.push_float(values(i).get_jfloat());
+        break;
+      case T_DOUBLE:
+        args.push_double(values(i).get_jdouble());
+        break;
+      case T_OBJECT:
+        args.push_oop(Handle(THREAD, (oop)values(i).get_jobject()));
+        break;
+      case T_ADDRESS:
+        args.push_jobject(values(i).get_jobject());
+        break;
+      default:
+        ShouldNotReachHere();
+    }
+  }
+}
+
+JfrJavaArguments::JfrJavaArguments(JavaValue* result) : _result(result), _klass(NULL), _name(NULL), _signature(NULL), _array_length(0) {
+  assert(result != NULL, "invariant");
+}
+
+JfrJavaArguments::JfrJavaArguments(JavaValue* result, const char* klass_name, const char* name, const char* signature, TRAPS) :
+  _result(result),
+  _klass(NULL),
+  _name(NULL),
+  _signature(NULL),
+  _array_length(0) {
+  assert(result != NULL, "invariant");
+  if (klass_name != NULL) {
+    set_klass(klass_name, CHECK);
+  }
+  if (name != NULL) {
+    set_name(name, CHECK);
+  }
+  if (signature != NULL) {
+    set_signature(signature, THREAD);
+  }
+}
+
+JfrJavaArguments::JfrJavaArguments(JavaValue* result, const Klass* klass, const Symbol* name, const Symbol* signature) : _result(result),
+  _klass(NULL),
+  _name(NULL),
+  _signature(NULL),
+  _array_length(0) {
+  assert(result != NULL, "invariant");
+  if (klass != NULL) {
+    set_klass(klass);
+  }
+  if (name != NULL) {
+    set_name(name);
+  }
+  if (signature != NULL) {
+    set_signature(signature);
+  }
+}
+
+Klass* JfrJavaArguments::klass() const {
+  assert(_klass != NULL, "invariant");
+  return const_cast<Klass*>(_klass);
+}
+
+void JfrJavaArguments::set_klass(const char* klass_name, TRAPS) {
+  assert(klass_name != NULL, "invariant");
+  Symbol* const k_sym = resolve(klass_name, CHECK);
+  assert(k_sym != NULL, "invariant");
+  const Klass* const klass = resolve(k_sym, CHECK);
+  set_klass(klass);
+}
+
+void JfrJavaArguments::set_klass(const Klass* klass) {
+  assert(klass != NULL, "invariant");
+  _klass = klass;
+}
+
+Symbol* JfrJavaArguments::name() const {
+  assert(_name != NULL, "invariant");
+  return const_cast<Symbol*>(_name);
+}
+
+void JfrJavaArguments::set_name(const char* name, TRAPS) {
+  assert(name != NULL, "invariant");
+  const Symbol* const sym = resolve(name, CHECK);
+  set_name(sym);
+}
+
+void JfrJavaArguments::set_name(const Symbol* name) {
+  assert(name != NULL, "invariant");
+  _name = name;
+}
+
+Symbol* JfrJavaArguments::signature() const {
+  assert(_signature != NULL, "invariant");
+  return const_cast<Symbol*>(_signature);
+}
+
+void JfrJavaArguments::set_signature(const char* signature, TRAPS) {
+  assert(signature != NULL, "invariant");
+  const Symbol* const sym = resolve(signature, CHECK);
+  set_signature(sym);
+}
+
+void JfrJavaArguments::set_signature(const Symbol* signature) {
+  assert(signature != NULL, "invariant");
+  _signature = signature;
+}
+
+int JfrJavaArguments::array_length() const {
+  return _array_length;
+}
+
+void JfrJavaArguments::set_array_length(int length) {
+  assert(length >= 0, "invariant");
+  _array_length = length;
+}
+
+JavaValue* JfrJavaArguments::result() const {
+  assert(_result != NULL, "invariant");
+  return const_cast<JavaValue*>(_result);
+}
+
+int JfrJavaArguments::length() const {
+  return _params.length();
+}
+
+bool JfrJavaArguments::has_receiver() const {
+  return _params.has_receiver();
+}
+
+oop JfrJavaArguments::receiver() const {
+  return _params.receiver();
+}
+
+void JfrJavaArguments::set_receiver(const oop receiver) {
+  _params.set_receiver(receiver);
+}
+
+void JfrJavaArguments::set_receiver(Handle receiver) {
+  _params.set_receiver(receiver);
+}
+
+void JfrJavaArguments::push_oop(const oop obj) {
+  _params.push_oop(obj);
+}
+
+void JfrJavaArguments::push_oop(Handle h_obj) {
+  _params.push_oop(h_obj);
+}
+
+void JfrJavaArguments::push_jobject(jobject h) {
+  _params.push_jobject(h);
+}
+
+void JfrJavaArguments::push_int(jint i) {
+  _params.push_jint(i);
+}
+
+void JfrJavaArguments::push_float(jfloat f) {
+  _params.push_jfloat(f);
+}
+
+void JfrJavaArguments::push_double(jdouble d) {
+  _params.push_jdouble(d);
+}
+
+void JfrJavaArguments::push_long(jlong l) {
+  _params.push_jlong(l);
+}
+
+const JavaValue& JfrJavaArguments::param(int idx) const {
+  return _params.values(idx);
+}
+
+int JfrJavaArguments::java_call_arg_slots() const {
+  return _params.java_stack_slots();
+}
+
+void JfrJavaArguments::copy(JavaCallArguments& args, TRAPS) {
+  _params.copy(args, THREAD);
+}
+
+void JfrJavaCall::call_static(JfrJavaArguments* args, TRAPS) {
+  assert(args != NULL, "invariant");
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
+  ResourceMark rm(THREAD);
+  HandleMark hm(THREAD);
+  JavaCallArguments jcas(args->java_call_arg_slots());
+  args->copy(jcas, CHECK);
+  JavaCalls::call_static(args->result(), args->klass(), args->name(), args->signature(), &jcas, THREAD);
+}
+
+void JfrJavaCall::call_special(JfrJavaArguments* args, TRAPS) {
+  assert(args != NULL, "invariant");
+  assert(args->has_receiver(), "invariant");
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
+  ResourceMark rm(THREAD);
+  HandleMark hm(THREAD);
+  JavaCallArguments jcas(args->java_call_arg_slots());
+  args->copy(jcas, CHECK);
+  JavaCalls::call_special(args->result(), args->klass(), args->name(), args->signature(), &jcas, THREAD);
+}
+
+void JfrJavaCall::call_virtual(JfrJavaArguments* args, TRAPS) {
+  assert(args != NULL, "invariant");
+  assert(args->has_receiver(), "invariant");
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
+  ResourceMark rm(THREAD);
+  HandleMark hm(THREAD);
+  JavaCallArguments jcas(args->java_call_arg_slots());
+  args->copy(jcas, CHECK);
+  JavaCalls::call_virtual(args->result(), args->klass(), args->name(), args->signature(), &jcas, THREAD);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/jni/jfrJavaCall.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_JNI_JFRJAVACALL_HPP
+#define SHARE_VM_JFR_JNI_JFRJAVACALL_HPP
+
+#include "jni.h"
+#include "jfr/utilities/jfrAllocation.hpp"
+#include "utilities/exceptions.hpp"
+
+class JavaCallArguments;
+class JavaThread;
+class JavaValue;
+class Klass;
+class Symbol;
+
+class JfrJavaArguments : public StackObj {
+  friend class JfrJavaCall;
+ public:
+  JfrJavaArguments(JavaValue* result);
+  JfrJavaArguments(JavaValue* result, const char* klass_name, const char* name, const char* signature, TRAPS);
+  JfrJavaArguments(JavaValue* result, const Klass* klass, const Symbol* name, const Symbol* signature);
+
+  Klass* klass() const;
+  void set_klass(const char* klass_name, TRAPS);
+  void set_klass(const Klass* klass);
+
+  Symbol* name() const;
+  void set_name(const char* name, TRAPS);
+  void set_name(const Symbol* name);
+
+  Symbol* signature() const;
+  void set_signature(const char* signature, TRAPS);
+  void set_signature(const Symbol* signature);
+
+  int array_length() const;
+  void set_array_length(int length);
+
+  JavaValue* result() const;
+
+  bool has_receiver() const;
+  void set_receiver(const oop receiver);
+  void set_receiver(Handle receiver);
+  oop receiver() const;
+
+  // parameters
+  void push_oop(const oop obj);
+  void push_oop(Handle h_obj);
+  void push_jobject(jobject h);
+  void push_int(jint i);
+  void push_double(jdouble d);
+  void push_long(jlong l);
+  void push_float(jfloat f);
+
+  int length() const;
+  const JavaValue& param(int idx) const;
+
+ private:
+  class Parameters {
+    friend class JfrJavaArguments;
+   private:
+    enum { SIZE = 16};
+    JavaValue _storage[SIZE];
+    int _storage_index;
+    int _java_stack_slots;
+
+    Parameters();
+    Parameters(const Parameters&); // no impl
+    Parameters& operator=(const Parameters&); // no impl
+
+    void push(const JavaValue& value);
+    void push_large(const JavaValue& value);
+
+    void push_oop(const oop obj);
+    void push_oop(Handle h_obj);
+    void push_jobject(jobject h);
+    void push_jint(jint i);
+    void push_jdouble(jdouble d);
+    void push_jlong(jlong l);
+    void push_jfloat(jfloat f);
+
+    bool has_receiver() const;
+    void set_receiver(const oop receiver);
+    void set_receiver(Handle receiver);
+    oop receiver() const;
+
+    int length() const;
+    int java_stack_slots() const;
+
+    void copy(JavaCallArguments& args, TRAPS) const;
+    const JavaValue& values(int idx) const;
+  };
+
+  Parameters _params;
+  const JavaValue* const _result;
+  const Klass* _klass;
+  const Symbol* _name;
+  const Symbol* _signature;
+  int _array_length;
+
+  int java_call_arg_slots() const;
+  void copy(JavaCallArguments& args, TRAPS);
+};
+
+class JfrJavaCall : public AllStatic {
+  friend class JfrJavaSupport;
+ private:
+  static void call_static(JfrJavaArguments* args, TRAPS);
+  static void call_special(JfrJavaArguments* args, TRAPS);
+  static void call_virtual(JfrJavaArguments* args, TRAPS);
+};
+
+#endif // SHARE_VM_JFR_JNI_JFRJAVACALL_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,612 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jni.h"
+#include "classfile/javaClasses.inline.hpp"
+#include "classfile/modules.hpp"
+#include "classfile/symbolTable.hpp"
+#include "classfile/systemDictionary.hpp"
+#include "classfile/vmSymbols.hpp"
+#include "jfr/jni/jfrJavaCall.hpp"
+#include "jfr/jni/jfrJavaSupport.hpp"
+#include "jfr/support/jfrThreadId.hpp"
+#include "logging/log.hpp"
+#include "memory/resourceArea.hpp"
+#include "oops/instanceOop.hpp"
+#include "oops/oop.inline.hpp"
+#include "oops/objArrayKlass.hpp"
+#include "oops/objArrayOop.inline.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/fieldDescriptor.hpp"
+#include "runtime/java.hpp"
+#include "runtime/jniHandles.inline.hpp"
+#include "runtime/synchronizer.hpp"
+#include "runtime/thread.inline.hpp"
+#include "runtime/threadSMR.hpp"
+
+#ifdef ASSERT
+void JfrJavaSupport::check_java_thread_in_vm(Thread* t) {
+  assert(t != NULL, "invariant");
+  assert(t->is_Java_thread(), "invariant");
+  assert(((JavaThread*)t)->thread_state() == _thread_in_vm, "invariant");
+}
+
+void JfrJavaSupport::check_java_thread_in_native(Thread* t) {
+  assert(t != NULL, "invariant");
+  assert(t->is_Java_thread(), "invariant");
+  assert(((JavaThread*)t)->thread_state() == _thread_in_native, "invariant");
+}
+#endif
+
+/*
+ *  Handles and references
+ */
+jobject JfrJavaSupport::local_jni_handle(const oop obj, Thread* t) {
+  DEBUG_ONLY(check_java_thread_in_vm(t));
+  return t->active_handles()->allocate_handle(obj);
+}
+
+jobject JfrJavaSupport::local_jni_handle(const jobject handle, Thread* t) {
+  DEBUG_ONLY(check_java_thread_in_vm(t));
+  const oop obj = JNIHandles::resolve(handle);
+  return obj == NULL ? NULL : local_jni_handle(obj, t);
+}
+
+void JfrJavaSupport::destroy_local_jni_handle(jobject handle) {
+  JNIHandles::destroy_local(handle);
+}
+
+jobject JfrJavaSupport::global_jni_handle(const oop obj, Thread* t) {
+  DEBUG_ONLY(check_java_thread_in_vm(t));
+  HandleMark hm(t);
+  return JNIHandles::make_global(Handle(t, obj));
+}
+
+jobject JfrJavaSupport::global_jni_handle(const jobject handle, Thread* t) {
+  const oop obj = JNIHandles::resolve(handle);
+  return obj == NULL ? NULL : global_jni_handle(obj, t);
+}
+
+void JfrJavaSupport::destroy_global_jni_handle(jobject handle) {
+  JNIHandles::destroy_global(handle);
+}
+
+oop JfrJavaSupport::resolve_non_null(jobject obj) {
+  return JNIHandles::resolve_non_null(obj);
+}
+
+/*
+ *  Method invocation
+ */
+void JfrJavaSupport::call_static(JfrJavaArguments* args, TRAPS) {
+  JfrJavaCall::call_static(args, THREAD);
+}
+
+void JfrJavaSupport::call_special(JfrJavaArguments* args, TRAPS) {
+  JfrJavaCall::call_special(args, THREAD);
+}
+
+void JfrJavaSupport::call_virtual(JfrJavaArguments* args, TRAPS) {
+  JfrJavaCall::call_virtual(args, THREAD);
+}
+
+void JfrJavaSupport::notify_all(jobject object, TRAPS) {
+  assert(object != NULL, "invariant");
+  DEBUG_ONLY(check_java_thread_in_vm(THREAD));
+  HandleMark hm(THREAD);
+  Handle h_obj(THREAD, resolve_non_null(object));
+  assert(h_obj.not_null(), "invariant");
+  ObjectSynchronizer::jni_enter(h_obj, THREAD);
+  ObjectSynchronizer::notifyall(h_obj, THREAD);
+  ObjectSynchronizer::jni_exit(h_obj(), THREAD);
+  DEBUG_ONLY(check_java_thread_in_vm(THREAD));
+}
+
+/*
+ *  Object construction
+ */
+static void object_construction(JfrJavaArguments* args, JavaValue* result, InstanceKlass* klass, TRAPS) {
+  assert(args != NULL, "invariant");
+  assert(result != NULL, "invariant");
+  assert(klass != NULL, "invariant");
+  assert(klass->is_initialized(), "invariant");
+
+  HandleMark hm(THREAD);
+  instanceOop obj = klass->allocate_instance(CHECK);
+  instanceHandle h_obj(THREAD, obj);
+  assert(h_obj.not_null(), "invariant");
+  args->set_receiver(h_obj);
+  result->set_type(T_VOID); // constructor result type
+  JfrJavaSupport::call_special(args, CHECK);
+  result->set_type(T_OBJECT); // set back to original result type
+  result->set_jobject((jobject)h_obj());
+}
+
+static void array_construction(JfrJavaArguments* args, JavaValue* result, InstanceKlass* klass, int array_length, TRAPS) {
+  assert(args != NULL, "invariant");
+  assert(result != NULL, "invariant");
+  assert(klass != NULL, "invariant");
+  assert(klass->is_initialized(), "invariant");
+
+  Klass* const ak = klass->array_klass(THREAD);
+  ObjArrayKlass::cast(ak)->initialize(THREAD);
+  HandleMark hm(THREAD);
+  objArrayOop arr = ObjArrayKlass::cast(ak)->allocate(array_length, CHECK);
+  result->set_jobject((jobject)arr);
+}
+
+static void create_object(JfrJavaArguments* args, JavaValue* result, TRAPS) {
+  assert(args != NULL, "invariant");
+  assert(result != NULL, "invariant");
+  assert(result->get_type() == T_OBJECT, "invariant");
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
+
+  InstanceKlass* const klass = static_cast<InstanceKlass*>(args->klass());
+  klass->initialize(CHECK);
+
+  const int array_length = args->array_length();
+
+  if (array_length > 0) {
+    array_construction(args, result, klass, array_length, CHECK);
+  } else {
+    object_construction(args, result, klass, THREAD);
+  }
+}
+
+static void handle_result(JavaValue* result, bool global_ref, Thread* t) {
+  assert(result != NULL, "invariant");
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(t));
+  const oop result_oop = (const oop)result->get_jobject();
+  if (result_oop == NULL) {
+    return;
+  }
+  result->set_jobject(global_ref ?
+                      JfrJavaSupport::global_jni_handle(result_oop, t) :
+                      JfrJavaSupport::local_jni_handle(result_oop, t));
+}
+
+void JfrJavaSupport::new_object(JfrJavaArguments* args, TRAPS) {
+  assert(args != NULL, "invariant");
+  DEBUG_ONLY(check_java_thread_in_vm(THREAD));
+  create_object(args, args->result(), THREAD);
+}
+
+void JfrJavaSupport::new_object_local_ref(JfrJavaArguments* args, TRAPS) {
+  assert(args != NULL, "invariant");
+  DEBUG_ONLY(check_java_thread_in_vm(THREAD));
+  JavaValue* const result = args->result();
+  assert(result != NULL, "invariant");
+  create_object(args, result, CHECK);
+  handle_result(result, false, THREAD);
+}
+
+void JfrJavaSupport::new_object_global_ref(JfrJavaArguments* args, TRAPS) {
+  assert(args != NULL, "invariant");
+  DEBUG_ONLY(check_java_thread_in_vm(THREAD));
+  JavaValue* const result = args->result();
+  assert(result != NULL, "invariant");
+  create_object(args, result, CHECK);
+  handle_result(result, true, THREAD);
+}
+
+jstring JfrJavaSupport::new_string(const char* c_str, TRAPS) {
+  assert(c_str != NULL, "invariant");
+  DEBUG_ONLY(check_java_thread_in_vm(THREAD));
+  const oop result = java_lang_String::create_oop_from_str(c_str, THREAD);
+  return (jstring)local_jni_handle(result, THREAD);
+}
+
+jobjectArray JfrJavaSupport::new_string_array(int length, TRAPS) {
+  DEBUG_ONLY(check_java_thread_in_vm(THREAD));
+  JavaValue result(T_OBJECT);
+  JfrJavaArguments args(&result, "java/lang/String", "<init>", "()V", CHECK_NULL);
+  args.set_array_length(length);
+  new_object_local_ref(&args, THREAD);
+  return (jobjectArray)args.result()->get_jobject();
+}
+
+jobject JfrJavaSupport::new_java_lang_Boolean(bool value, TRAPS) {
+  DEBUG_ONLY(check_java_thread_in_vm(THREAD));
+  JavaValue result(T_OBJECT);
+  JfrJavaArguments args(&result, "java/lang/Boolean", "<init>", "(Z)V", CHECK_NULL);
+  args.push_int(value ? (jint)JNI_TRUE : (jint)JNI_FALSE);
+  new_object_local_ref(&args, THREAD);
+  return args.result()->get_jobject();
+}
+
+jobject JfrJavaSupport::new_java_lang_Integer(jint value, TRAPS) {
+  DEBUG_ONLY(check_java_thread_in_vm(THREAD));
+  JavaValue result(T_OBJECT);
+  JfrJavaArguments args(&result, "java/lang/Integer", "<init>", "(I)V", CHECK_NULL);
+  args.push_int(value);
+  new_object_local_ref(&args, THREAD);
+  return args.result()->get_jobject();
+}
+
+jobject JfrJavaSupport::new_java_lang_Long(jlong value, TRAPS) {
+  DEBUG_ONLY(check_java_thread_in_vm(THREAD));
+  JavaValue result(T_OBJECT);
+  JfrJavaArguments args(&result, "java/lang/Long", "<init>", "(J)V", CHECK_NULL);
+  args.push_long(value);
+  new_object_local_ref(&args, THREAD);
+  return args.result()->get_jobject();
+}
+
+void JfrJavaSupport::set_array_element(jobjectArray arr, jobject element, int index, Thread* t) {
+  assert(arr != NULL, "invariant");
+  DEBUG_ONLY(check_java_thread_in_vm(t));
+  HandleMark hm(t);
+  objArrayHandle a(t, (objArrayOop)resolve_non_null(arr));
+  a->obj_at_put(index, resolve_non_null(element));
+}
+
+/*
+ *  Field access
+ */
+static void write_int_field(const Handle& h_oop, fieldDescriptor* fd, jint value) {
+  assert(h_oop.not_null(), "invariant");
+  assert(fd != NULL, "invariant");
+  h_oop->int_field_put(fd->offset(), value);
+}
+
+static void write_float_field(const Handle& h_oop, fieldDescriptor* fd, jfloat value) {
+  assert(h_oop.not_null(), "invariant");
+  assert(fd != NULL, "invariant");
+  h_oop->float_field_put(fd->offset(), value);
+}
+
+static void write_double_field(const Handle& h_oop, fieldDescriptor* fd, jdouble value) {
+  assert(h_oop.not_null(), "invariant");
+  assert(fd != NULL, "invariant");
+  h_oop->double_field_put(fd->offset(), value);
+}
+
+static void write_long_field(const Handle& h_oop, fieldDescriptor* fd, jlong value) {
+  assert(h_oop.not_null(), "invariant");
+  assert(fd != NULL, "invariant");
+  h_oop->long_field_put(fd->offset(), value);
+}
+
+static void write_oop_field(const Handle& h_oop, fieldDescriptor* fd, const oop value) {
+  assert(h_oop.not_null(), "invariant");
+  assert(fd != NULL, "invariant");
+  h_oop->obj_field_put(fd->offset(), value);
+}
+
+static void write_specialized_field(JfrJavaArguments* args, const Handle& h_oop, fieldDescriptor* fd, bool static_field) {
+  assert(args != NULL, "invariant");
+  assert(h_oop.not_null(), "invariant");
+  assert(fd != NULL, "invariant");
+  assert(fd->offset() > 0, "invariant");
+  assert(args->length() >= 1, "invariant");
+
+  // attempt must set a real value
+  assert(args->param(1).get_type() != T_VOID, "invariant");
+
+  switch(fd->field_type()) {
+    case T_BOOLEAN:
+    case T_CHAR:
+    case T_SHORT:
+    case T_INT:
+      write_int_field(h_oop, fd, args->param(1).get_jint());
+      break;
+    case T_FLOAT:
+      write_float_field(h_oop, fd, args->param(1).get_jfloat());
+      break;
+    case T_DOUBLE:
+      write_double_field(h_oop, fd, args->param(1).get_jdouble());
+      break;
+    case T_LONG:
+      write_long_field(h_oop, fd, args->param(1).get_jlong());
+      break;
+    case T_OBJECT:
+      write_oop_field(h_oop, fd, (oop)args->param(1).get_jobject());
+      break;
+    case T_ADDRESS:
+      write_oop_field(h_oop, fd, JfrJavaSupport::resolve_non_null(args->param(1).get_jobject()));
+      break;
+    default:
+      ShouldNotReachHere();
+  }
+}
+
+static void read_specialized_field(JavaValue* result, const Handle& h_oop, fieldDescriptor* fd) {
+  assert(result != NULL, "invariant");
+  assert(h_oop.not_null(), "invariant");
+  assert(fd != NULL, "invariant");
+  assert(fd->offset() > 0, "invariant");
+
+  switch(fd->field_type()) {
+    case T_BOOLEAN:
+    case T_CHAR:
+    case T_SHORT:
+    case T_INT:
+      result->set_jint(h_oop->int_field(fd->offset()));
+      break;
+    case T_FLOAT:
+      result->set_jfloat(h_oop->float_field(fd->offset()));
+      break;
+    case T_DOUBLE:
+      result->set_jdouble(h_oop->double_field(fd->offset()));
+      break;
+    case T_LONG:
+      result->set_jlong(h_oop->long_field(fd->offset()));
+      break;
+    case T_OBJECT:
+      result->set_jobject((jobject)h_oop->obj_field(fd->offset()));
+      break;
+    default:
+      ShouldNotReachHere();
+  }
+}
+
+static bool find_field(InstanceKlass* ik,
+                       Symbol* name_symbol,
+                       Symbol* signature_symbol,
+                       fieldDescriptor* fd,
+                       bool is_static = false,
+                       bool allow_super = false) {
+  if (allow_super || is_static) {
+    return ik->find_field(name_symbol, signature_symbol, is_static, fd) != NULL;
+  }
+  return ik->find_local_field(name_symbol, signature_symbol, fd);
+}
+
+static void lookup_field(JfrJavaArguments* args, InstanceKlass* klass, fieldDescriptor* fd, bool static_field) {
+  assert(args != NULL, "invariant");
+  assert(klass != NULL, "invariant");
+  assert(klass->is_initialized(), "invariant");
+  assert(fd != NULL, "invariant");
+  find_field(klass, args->name(), args->signature(), fd, static_field, true);
+}
+
+static void read_field(JfrJavaArguments* args, JavaValue* result, TRAPS) {
+  assert(args != NULL, "invariant");
+  assert(result != NULL, "invariant");
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
+
+  InstanceKlass* const klass = static_cast<InstanceKlass*>(args->klass());
+  klass->initialize(CHECK);
+  const bool static_field = !args->has_receiver();
+  fieldDescriptor fd;
+  lookup_field(args, klass, &fd, static_field);
+  assert(fd.offset() > 0, "invariant");
+
+  HandleMark hm(THREAD);
+  Handle h_oop(static_field ? Handle(THREAD, klass->java_mirror()) : Handle(THREAD, args->receiver()));
+  read_specialized_field(result, h_oop, &fd);
+}
+
+static void write_field(JfrJavaArguments* args, JavaValue* result, TRAPS) {
+  assert(args != NULL, "invariant");
+  assert(result != NULL, "invariant");
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
+
+  InstanceKlass* const klass = static_cast<InstanceKlass*>(args->klass());
+  klass->initialize(CHECK);
+
+  const bool static_field = !args->has_receiver();
+  fieldDescriptor fd;
+  lookup_field(args, klass, &fd, static_field);
+  assert(fd.offset() > 0, "invariant");
+
+  HandleMark hm(THREAD);
+  Handle h_oop(static_field ? Handle(THREAD, klass->java_mirror()) : Handle(THREAD, args->receiver()));
+  write_specialized_field(args, h_oop, &fd, static_field);
+}
+
+void JfrJavaSupport::set_field(JfrJavaArguments* args, TRAPS) {
+  assert(args != NULL, "invariant");
+  write_field(args, args->result(), THREAD);
+}
+
+void JfrJavaSupport::get_field(JfrJavaArguments* args, TRAPS) {
+  assert(args != NULL, "invariant");
+  read_field(args, args->result(), THREAD);
+}
+
+void JfrJavaSupport::get_field_local_ref(JfrJavaArguments* args, TRAPS) {
+  assert(args != NULL, "invariant");
+  DEBUG_ONLY(check_java_thread_in_vm(THREAD));
+
+  JavaValue* const result = args->result();
+  assert(result != NULL, "invariant");
+  assert(result->get_type() == T_OBJECT, "invariant");
+
+  read_field(args, result, CHECK);
+  const oop obj = (const oop)result->get_jobject();
+
+  if (obj != NULL) {
+    result->set_jobject(local_jni_handle(obj, THREAD));
+  }
+}
+
+void JfrJavaSupport::get_field_global_ref(JfrJavaArguments* args, TRAPS) {
+  assert(args != NULL, "invariant");
+  DEBUG_ONLY(check_java_thread_in_vm(THREAD));
+
+  JavaValue* const result = args->result();
+  assert(result != NULL, "invariant");
+  assert(result->get_type() == T_OBJECT, "invariant");
+  read_field(args, result, CHECK);
+  const oop obj = (const oop)result->get_jobject();
+  if (obj != NULL) {
+    result->set_jobject(global_jni_handle(obj, THREAD));
+  }
+}
+
+/*
+ *  Misc
+ */
+Klass* JfrJavaSupport::klass(const jobject handle) {
+  const oop obj = resolve_non_null(handle);
+  assert(obj != NULL, "invariant");
+  return obj->klass();
+}
+
+// caller needs ResourceMark
+const char* JfrJavaSupport::c_str(jstring string, Thread* t) {
+  DEBUG_ONLY(check_java_thread_in_vm(t));
+  if (string == NULL) {
+    return NULL;
+  }
+  const char* temp = NULL;
+  const oop java_string = resolve_non_null(string);
+  if (java_lang_String::value(java_string) != NULL) {
+    const size_t length = java_lang_String::utf8_length(java_string);
+    temp = NEW_RESOURCE_ARRAY_IN_THREAD(t, const char, (length + 1));
+    if (temp == NULL) {
+       JfrJavaSupport::throw_out_of_memory_error("Unable to allocate thread local native memory", t);
+       return NULL;
+    }
+    assert(temp != NULL, "invariant");
+    java_lang_String::as_utf8_string(java_string, const_cast<char*>(temp), (int) length + 1);
+  }
+  return temp;
+}
+
+/*
+ *  Exceptions and errors
+ */
+static void create_and_throw(Symbol* name, const char* message, TRAPS) {
+  assert(name != NULL, "invariant");
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
+  assert(!HAS_PENDING_EXCEPTION, "invariant");
+  THROW_MSG(name, message);
+}
+
+void JfrJavaSupport::throw_illegal_state_exception(const char* message, TRAPS) {
+  create_and_throw(vmSymbols::java_lang_IllegalStateException(), message, THREAD);
+}
+
+void JfrJavaSupport::throw_internal_error(const char* message, TRAPS) {
+  create_and_throw(vmSymbols::java_lang_InternalError(), message, THREAD);
+}
+
+void JfrJavaSupport::throw_illegal_argument_exception(const char* message, TRAPS) {
+  create_and_throw(vmSymbols::java_lang_IllegalArgumentException(), message, THREAD);
+}
+
+void JfrJavaSupport::throw_out_of_memory_error(const char* message, TRAPS) {
+  create_and_throw(vmSymbols::java_lang_OutOfMemoryError(), message, THREAD);
+}
+
+void JfrJavaSupport::throw_class_format_error(const char* message, TRAPS) {
+  create_and_throw(vmSymbols::java_lang_ClassFormatError(), message, THREAD);
+}
+
+void JfrJavaSupport::abort(jstring errorMsg, Thread* t) {
+  DEBUG_ONLY(check_java_thread_in_vm(t));
+
+  ResourceMark rm(t);
+  const char* const error_msg = c_str(errorMsg, t);
+  if (error_msg != NULL) {
+    log_error(jfr, system)("%s",error_msg);
+  }
+  log_error(jfr, system)("%s", "An irrecoverable error in Jfr. Shutting down VM...");
+  vm_abort();
+}
+
+JfrJavaSupport::CAUSE JfrJavaSupport::_cause = JfrJavaSupport::VM_ERROR;
+void JfrJavaSupport::set_cause(jthrowable throwable, Thread* t) {
+  DEBUG_ONLY(check_java_thread_in_vm(t));
+
+  HandleMark hm(t);
+  Handle ex(t, JNIHandles::resolve_external_guard(throwable));
+
+  if (ex.is_null()) {
+    return;
+  }
+
+  if (ex->is_a(SystemDictionary::OutOfMemoryError_klass())) {
+    _cause = OUT_OF_MEMORY;
+    return;
+  }
+  if (ex->is_a(SystemDictionary::StackOverflowError_klass())) {
+    _cause = STACK_OVERFLOW;
+    return;
+  }
+  if (ex->is_a(SystemDictionary::Error_klass())) {
+    _cause = VM_ERROR;
+    return;
+  }
+  if (ex->is_a(SystemDictionary::RuntimeException_klass())) {
+    _cause = RUNTIME_EXCEPTION;
+    return;
+  }
+  if (ex->is_a(SystemDictionary::Exception_klass())) {
+    _cause = UNKNOWN;
+    return;
+  }
+}
+
+void JfrJavaSupport::uncaught_exception(jthrowable throwable, Thread* t) {
+  DEBUG_ONLY(check_java_thread_in_vm(t));
+  assert(throwable != NULL, "invariant");
+  set_cause(throwable, t);
+}
+
+JfrJavaSupport::CAUSE JfrJavaSupport::cause() {
+  return _cause;
+}
+
+const char* const JDK_JFR_MODULE_NAME = "jdk.jfr";
+const char* const JDK_JFR_PACKAGE_NAME = "jdk/jfr";
+
+static bool is_jdk_jfr_module_in_readability_graph() {
+  Thread* const t = Thread::current();
+  // take one of the packages in the module to be located and query for its definition.
+  TempNewSymbol pkg_sym = SymbolTable::new_symbol(JDK_JFR_PACKAGE_NAME, t);
+  return Modules::is_package_defined(pkg_sym, Handle(), t);
+}
+
+static void print_module_resolution_error(outputStream* stream) {
+  assert(stream != NULL, "invariant");
+  stream->print_cr("%s not found.", JDK_JFR_MODULE_NAME);
+  stream->print_cr("Flight Recorder can not be enabled.");
+  stream->print_cr("To use Flight Recorder, you might need to add" \
+    " \"--add-modules %s\" to the VM command-line options.", JDK_JFR_MODULE_NAME);
+}
+
+bool JfrJavaSupport::is_jdk_jfr_module_available() {
+  return is_jdk_jfr_module_in_readability_graph();
+}
+
+bool JfrJavaSupport::is_jdk_jfr_module_available(outputStream* stream, TRAPS) {
+  if (!JfrJavaSupport::is_jdk_jfr_module_available()) {
+    if (stream != NULL) {
+      print_module_resolution_error(stream);
+    }
+    return false;
+  }
+  return true;
+}
+
+jlong JfrJavaSupport::jfr_thread_id(jobject target_thread) {
+  ThreadsListHandle tlh;
+  JavaThread* native_thread = NULL;
+  (void)tlh.cv_internal_thread_to_JavaThread(target_thread, &native_thread, NULL);
+  return native_thread != NULL ? JFR_THREAD_ID(native_thread) : 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/jni/jfrJavaSupport.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_JNI_JFRJAVASUPPORT_HPP
+#define SHARE_VM_JFR_JNI_JFRJAVASUPPORT_HPP
+
+#include "jfr/jni/jfrJavaCall.hpp"
+#include "utilities/exceptions.hpp"
+
+class Klass;
+class JavaThread;
+class outputStream;
+
+class JfrJavaSupport : public AllStatic {
+ public:
+  static jobject local_jni_handle(const oop obj, Thread* t);
+  static jobject local_jni_handle(const jobject handle, Thread* t);
+  static void destroy_local_jni_handle(const jobject handle);
+
+  static jobject global_jni_handle(const oop obj, Thread* t);
+  static jobject global_jni_handle(const jobject handle, Thread* t);
+  static void destroy_global_jni_handle(const jobject handle);
+
+  static oop resolve_non_null(jobject obj);
+  static void notify_all(jobject obj, TRAPS);
+  static void set_array_element(jobjectArray arr, jobject element, int index, Thread* t);
+
+  // naked oop result
+  static void call_static(JfrJavaArguments* args, TRAPS);
+  static void call_special(JfrJavaArguments* args, TRAPS);
+  static void call_virtual(JfrJavaArguments* args, TRAPS);
+
+  static void set_field(JfrJavaArguments* args, TRAPS);
+  static void get_field(JfrJavaArguments* args, TRAPS);
+  static void new_object(JfrJavaArguments* args, TRAPS);
+
+  // global jni handle result
+  static void new_object_global_ref(JfrJavaArguments* args, TRAPS);
+  static void get_field_global_ref(JfrJavaArguments* args, TRAPS);
+
+  // local jni handle result
+  static void new_object_local_ref(JfrJavaArguments* args, TRAPS);
+  static void get_field_local_ref(JfrJavaArguments* args, TRAPS);
+
+  static jstring new_string(const char* c_str, TRAPS);
+  static jobjectArray new_string_array(int length, TRAPS);
+
+  static jobject new_java_lang_Boolean(bool value, TRAPS);
+  static jobject new_java_lang_Integer(jint value, TRAPS);
+  static jobject new_java_lang_Long(jlong value, TRAPS);
+
+  // misc
+  static Klass* klass(const jobject handle);
+  // caller needs ResourceMark
+  static const char* c_str(jstring string, Thread* jt);
+
+  // exceptions
+  static void throw_illegal_state_exception(const char* message, TRAPS);
+  static void throw_illegal_argument_exception(const char* message, TRAPS);
+  static void throw_internal_error(const char* message, TRAPS);
+  static void throw_out_of_memory_error(const char* message, TRAPS);
+  static void throw_class_format_error(const char* message, TRAPS);
+
+  static bool is_jdk_jfr_module_available();
+  static bool is_jdk_jfr_module_available(outputStream* stream, TRAPS);
+
+  static jlong jfr_thread_id(jobject target_thread);
+
+  // critical
+  static void abort(jstring errorMsg, TRAPS);
+  static void uncaught_exception(jthrowable throwable, Thread* t);
+
+  // asserts
+  DEBUG_ONLY(static void check_java_thread_in_vm(Thread* t);)
+  DEBUG_ONLY(static void check_java_thread_in_native(Thread* t);)
+
+  enum CAUSE {
+    VM_ERROR,
+    OUT_OF_MEMORY,
+    STACK_OVERFLOW,
+    RUNTIME_EXCEPTION,
+    UNKNOWN,
+    NOF_CAUSES
+  };
+
+  static CAUSE cause();
+
+ private:
+  static CAUSE _cause;
+  static void set_cause(jthrowable throwable, Thread* t);
+};
+
+#endif // SHARE_VM_JFR_JNI_JFRJAVASUPPORT_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jni.h"
+#include "jvm.h"
+#include "jfr/jfr.hpp"
+#include "jfr/jfrEvents.hpp"
+#include "jfr/periodic/sampling/jfrThreadSampler.hpp"
+#include "jfr/recorder/jfrEventSetting.hpp"
+#include "jfr/recorder/jfrRecorder.hpp"
+#include "jfr/recorder/checkpoint/jfrMetadataEvent.hpp"
+#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
+#include "jfr/recorder/repository/jfrRepository.hpp"
+#include "jfr/recorder/repository/jfrChunkSizeNotifier.hpp"
+#include "jfr/recorder/repository/jfrChunkWriter.hpp"
+#include "jfr/recorder/service/jfrOptionSet.hpp"
+#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
+#include "jfr/recorder/stringpool/jfrStringPool.hpp"
+#include "jfr/jni/jfrGetAllEventClasses.hpp"
+#include "jfr/jni/jfrJavaSupport.hpp"
+#include "jfr/jni/jfrJniMethodRegistration.hpp"
+#include "jfr/instrumentation/jfrEventClassTransformer.hpp"
+#include "jfr/instrumentation/jfrJvmtiAgent.hpp"
+#include "jfr/leakprofiler/leakProfiler.hpp"
+#include "jfr/utilities/jfrJavaLog.hpp"
+#include "jfr/utilities/jfrTimeConverter.hpp"
+#include "jfr/utilities/jfrTime.hpp"
+#include "jfr/writers/jfrJavaEventWriter.hpp"
+#include "jfrfiles/jfrPeriodic.hpp"
+#include "logging/log.hpp"
+#include "memory/resourceArea.hpp"
+#include "runtime/interfaceSupport.inline.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/os.hpp"
+#include "runtime/thread.hpp"
+#include "utilities/debug.hpp"
+
+#define NO_TRANSITION(result_type, header) extern "C" { result_type JNICALL header {
+#define NO_TRANSITION_END } }
+
+/*
+ * NO_TRANSITION entries
+ *
+ * Thread remains _thread_in_native
+ */
+
+NO_TRANSITION(void, jfr_register_natives(JNIEnv* env, jclass jvmclass))
+  JfrJniMethodRegistration register_native_methods(env);
+NO_TRANSITION_END
+
+NO_TRANSITION(jboolean, jfr_is_enabled())
+  return Jfr::is_enabled() ? JNI_TRUE : JNI_FALSE;
+NO_TRANSITION_END
+
+NO_TRANSITION(jboolean, jfr_is_disabled())
+  return Jfr::is_disabled() ? JNI_TRUE : JNI_FALSE;
+NO_TRANSITION_END
+
+NO_TRANSITION(jboolean, jfr_is_started())
+  return JfrRecorder::is_created() ? JNI_TRUE : JNI_FALSE;
+NO_TRANSITION_END
+
+NO_TRANSITION(jstring, jfr_get_pid(JNIEnv* env, jobject jvm))
+  char pid_buf[32] = { 0 };
+  jio_snprintf(pid_buf, sizeof(pid_buf), "%d", os::current_process_id());
+  jstring pid_string = env->NewStringUTF(pid_buf);
+  return pid_string; // exception pending if NULL
+NO_TRANSITION_END
+
+NO_TRANSITION(jlong, jfr_elapsed_frequency(JNIEnv* env, jobject jvm))
+  return JfrTime::frequency();
+NO_TRANSITION_END
+
+NO_TRANSITION(jlong, jfr_elapsed_counter(JNIEnv* env, jobject jvm))
+  return JfrTicks::now();
+NO_TRANSITION_END
+
+NO_TRANSITION(void, jfr_retransform_classes(JNIEnv* env, jobject jvm, jobjectArray classes))
+  JfrJvmtiAgent::retransform_classes(env, classes, JavaThread::thread_from_jni_environment(env));
+NO_TRANSITION_END
+
+NO_TRANSITION(void, jfr_set_enabled(JNIEnv* env, jobject jvm, jlong event_type_id, jboolean enabled))
+  JfrEventSetting::set_enabled(event_type_id, JNI_TRUE == enabled);
+  if (EventOldObjectSample::eventId == event_type_id) {
+    ThreadInVMfromNative transition(JavaThread::thread_from_jni_environment(env));
+    if (JNI_TRUE == enabled) {
+      LeakProfiler::start(JfrOptionSet::old_object_queue_size());
+    } else {
+      LeakProfiler::stop();
+    }
+  }
+NO_TRANSITION_END
+
+NO_TRANSITION(void, jfr_set_file_notification(JNIEnv* env, jobject jvm, jlong threshold))
+  JfrChunkSizeNotifier::set_chunk_size_threshold((size_t)threshold);
+NO_TRANSITION_END
+
+NO_TRANSITION(void, jfr_set_sample_threads(JNIEnv* env, jobject jvm, jboolean sampleThreads))
+  JfrOptionSet::set_sample_threads(sampleThreads);
+NO_TRANSITION_END
+
+NO_TRANSITION(void, jfr_set_stack_depth(JNIEnv* env, jobject jvm, jint depth))
+  JfrOptionSet::set_stackdepth((jlong)depth);
+NO_TRANSITION_END
+
+NO_TRANSITION(void, jfr_set_stacktrace_enabled(JNIEnv* env, jobject jvm, jlong event_type_id, jboolean enabled))
+  JfrEventSetting::set_stacktrace(event_type_id, JNI_TRUE == enabled);
+NO_TRANSITION_END
+
+NO_TRANSITION(void, jfr_set_global_buffer_count(JNIEnv* env, jobject jvm, jlong count))
+  JfrOptionSet::set_num_global_buffers(count);
+NO_TRANSITION_END
+
+NO_TRANSITION(void, jfr_set_global_buffer_size(JNIEnv* env, jobject jvm, jlong size))
+JfrOptionSet::set_global_buffer_size(size);
+NO_TRANSITION_END
+
+NO_TRANSITION(void, jfr_set_thread_buffer_size(JNIEnv* env, jobject jvm, jlong size))
+  JfrOptionSet::set_thread_buffer_size(size);
+NO_TRANSITION_END
+
+NO_TRANSITION(void, jfr_set_memory_size(JNIEnv* env, jobject jvm, jlong size))
+  JfrOptionSet::set_memory_size(size);
+NO_TRANSITION_END
+
+NO_TRANSITION(jboolean, jfr_set_threshold(JNIEnv* env, jobject jvm, jlong event_type_id, jlong thresholdTicks))
+  return JfrEventSetting::set_threshold(event_type_id, thresholdTicks) ? JNI_TRUE : JNI_FALSE;
+NO_TRANSITION_END
+
+NO_TRANSITION(jboolean, jfr_allow_event_retransforms(JNIEnv* env, jobject jvm))
+  return JfrOptionSet::allow_event_retransforms() ? JNI_TRUE : JNI_FALSE;
+NO_TRANSITION_END
+
+NO_TRANSITION(jboolean, jfr_is_available(JNIEnv* env, jclass jvm))
+  return !Jfr::is_disabled() ? JNI_TRUE : JNI_FALSE;
+NO_TRANSITION_END
+
+NO_TRANSITION(jlong, jfr_get_epoch_address(JNIEnv* env, jobject jvm))
+  return JfrTraceIdEpoch::epoch_address();
+NO_TRANSITION_END
+
+NO_TRANSITION(jlong, jfr_get_unloaded_event_classes_count(JNIEnv* env, jobject jvm))
+  return JfrEventClasses::unloaded_event_classes_count();
+NO_TRANSITION_END
+
+NO_TRANSITION(jdouble, jfr_time_conv_factor(JNIEnv* env, jobject jvm))
+  return (jdouble)JfrTimeConverter::nano_to_counter_multiplier();
+NO_TRANSITION_END
+
+NO_TRANSITION(jboolean, jfr_set_cutoff(JNIEnv* env, jobject jvm, jlong event_type_id, jlong cutoff_ticks))
+  return JfrEventSetting::set_cutoff(event_type_id, cutoff_ticks) ? JNI_TRUE : JNI_FALSE;
+NO_TRANSITION_END
+
+
+/*
+ * JVM_ENTRY_NO_ENV entries
+ *
+ * Transitions:
+ *   Entry: _thread_in_native -> _thread_in_vm
+ *   Exit:  _thread_in_vm -> _thread_in_native
+ *
+ * Current JavaThread available as "thread" variable
+ */
+
+JVM_ENTRY_NO_ENV(jboolean, jfr_create_jfr(JNIEnv* env, jobject jvm, jboolean simulate_failure))
+  if (JfrRecorder::is_created()) {
+    return JNI_TRUE;
+  }
+  if (!JfrRecorder::create(simulate_failure == JNI_TRUE)) {
+    JfrJavaSupport::throw_illegal_state_exception("Unable to start Jfr", thread);
+    return JNI_FALSE;
+  }
+  return JNI_TRUE;
+JVM_END
+
+JVM_ENTRY_NO_ENV(jboolean, jfr_destroy_jfr(JNIEnv* env, jobject jvm))
+  JfrRecorder::destroy();
+  return JNI_TRUE;
+JVM_END
+
+JVM_ENTRY_NO_ENV(void, jfr_begin_recording(JNIEnv* env, jobject jvm))
+  if (JfrRecorder::is_recording()) {
+    return;
+  }
+  JfrRecorder::start_recording();
+JVM_END
+
+JVM_ENTRY_NO_ENV(void, jfr_end_recording(JNIEnv* env, jobject jvm))
+  if (!JfrRecorder::is_recording()) {
+    return;
+  }
+  JfrRecorder::stop_recording();
+JVM_END
+
+
+JVM_ENTRY_NO_ENV(jboolean, jfr_emit_event(JNIEnv* env, jobject jvm, jlong eventTypeId, jlong timeStamp, jlong when))
+  JfrPeriodicEventSet::requestEvent((JfrEventId)eventTypeId);
+  return thread->has_pending_exception() ? JNI_FALSE : JNI_TRUE;
+JVM_END
+
+JVM_ENTRY_NO_ENV(jobject, jfr_get_all_event_classes(JNIEnv* env, jobject jvm))
+  return JfrEventClasses::get_all_event_classes(thread);
+JVM_END
+
+JVM_ENTRY_NO_ENV(jlong, jfr_class_id(JNIEnv* env, jclass jvm, jclass jc))
+  return JfrTraceId::use(jc);
+JVM_END
+
+JVM_ENTRY_NO_ENV(jlong, jfr_stacktrace_id(JNIEnv* env, jobject jvm, jint skip))
+  return JfrStackTraceRepository::record(thread, skip);
+JVM_END
+
+JVM_ENTRY_NO_ENV(void, jfr_log(JNIEnv* env, jobject jvm, jint tag_set, jint level, jstring message))
+  JfrJavaLog::log(tag_set, level, message, thread);
+JVM_END
+
+JVM_ENTRY_NO_ENV(void, jfr_subscribe_log_level(JNIEnv* env, jobject jvm, jobject log_tag, jint id))
+  JfrJavaLog::subscribe_log_level(log_tag, id, thread);
+JVM_END
+
+JVM_ENTRY_NO_ENV(void, jfr_set_output(JNIEnv* env, jobject jvm, jstring path))
+  JfrRepository::set_chunk_path(path, thread);
+JVM_END
+
+JVM_ENTRY_NO_ENV(void, jfr_set_method_sampling_interval(JNIEnv* env, jobject jvm, jlong type, jlong intervalMillis))
+  if (intervalMillis < 0) {
+    intervalMillis = 0;
+  }
+  JfrEventId typed_event_id = (JfrEventId)type;
+  assert(EventExecutionSample::eventId == typed_event_id || EventNativeMethodSample::eventId == typed_event_id, "invariant");
+  if (intervalMillis > 0) {
+    JfrEventSetting::set_enabled(typed_event_id, true); // ensure sampling event is enabled
+  }
+  if (EventExecutionSample::eventId == type) {
+    JfrThreadSampling::set_java_sample_interval(intervalMillis);
+  } else {
+    JfrThreadSampling::set_native_sample_interval(intervalMillis);
+  }
+JVM_END
+
+JVM_ENTRY_NO_ENV(void, jfr_store_metadata_descriptor(JNIEnv* env, jobject jvm, jbyteArray descriptor))
+  JfrMetadataEvent::update(descriptor);
+JVM_END
+
+// trace thread id for a thread object
+JVM_ENTRY_NO_ENV(jlong, jfr_id_for_thread(JNIEnv* env, jobject jvm, jobject t))
+  return JfrJavaSupport::jfr_thread_id(t);
+JVM_END
+
+JVM_ENTRY_NO_ENV(jobject, jfr_get_event_writer(JNIEnv* env, jclass cls))
+  return JfrJavaEventWriter::event_writer(thread);
+JVM_END
+
+JVM_ENTRY_NO_ENV(jobject, jfr_new_event_writer(JNIEnv* env, jclass cls))
+  return JfrJavaEventWriter::new_event_writer(thread);
+JVM_END
+
+JVM_ENTRY_NO_ENV(jboolean, jfr_event_writer_flush(JNIEnv* env, jclass cls, jobject writer, jint used_size, jint requested_size))
+  return JfrJavaEventWriter::flush(writer, used_size, requested_size, thread);
+JVM_END
+
+JVM_ENTRY_NO_ENV(void, jfr_set_repository_location(JNIEnv* env, jobject repo, jstring location))
+  return JfrRepository::set_path(location, thread);
+JVM_END
+
+JVM_ENTRY_NO_ENV(void, jfr_uncaught_exception(JNIEnv* env, jobject jvm, jobject t, jthrowable throwable))
+  JfrJavaSupport::uncaught_exception(throwable, thread);
+JVM_END
+
+JVM_ENTRY_NO_ENV(void, jfr_abort(JNIEnv* env, jobject jvm, jstring errorMsg))
+  JfrJavaSupport::abort(errorMsg, thread);
+JVM_END
+
+JVM_ENTRY_NO_ENV(jlong, jfr_type_id(JNIEnv* env, jobject jvm, jclass jc))
+  return JfrTraceId::get(jc);
+JVM_END
+
+JVM_ENTRY_NO_ENV(jboolean, jfr_add_string_constant(JNIEnv* env, jclass jvm, jboolean epoch, jlong id, jstring string))
+  return JfrStringPool::add(epoch == JNI_TRUE, id, string, thread);
+JVM_END
+
+JVM_ENTRY_NO_ENV(void, jfr_set_force_instrumentation(JNIEnv* env, jobject jvm, jboolean force_instrumentation))
+  JfrEventClassTransformer::set_force_instrumentation(force_instrumentation == JNI_TRUE ? true : false);
+JVM_END
+
+JVM_ENTRY_NO_ENV(void, jfr_emit_old_object_samples(JNIEnv* env, jobject jvm, jlong cutoff_ticks, jboolean emit_all))
+  LeakProfiler::emit_events(cutoff_ticks, emit_all == JNI_TRUE);
+JVM_END
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/jni/jfrJniMethod.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_JNI_JFRJNIMETHOD_HPP
+#define SHARE_VM_JFR_JNI_JFRJNIMETHOD_HPP
+
+#include "jni.h"
+
+/*
+ * Native methods for jdk.jfr.internal.JVM
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+jboolean JNICALL jfr_is_enabled();
+
+jboolean JNICALL jfr_is_disabled();
+
+jboolean JNICALL jfr_is_started();
+
+jlong JNICALL jfr_elapsed_counter(JNIEnv* env, jobject jvm);
+
+jboolean JNICALL jfr_create_jfr(JNIEnv* env, jobject jvm, jboolean simulate_failure);
+
+jboolean JNICALL jfr_destroy_jfr(JNIEnv* env, jobject jvm);
+
+void JNICALL jfr_begin_recording(JNIEnv* env, jobject jvm);
+
+void JNICALL jfr_end_recording(JNIEnv* env, jobject jvm);
+
+jboolean JNICALL jfr_emit_event(JNIEnv* env, jobject jvm, jlong eventTypeId, jlong timeStamp, jlong when);
+
+jobject JNICALL jfr_get_all_event_classes(JNIEnv* env, jobject jvm);
+
+jlong JNICALL jfr_class_id(JNIEnv* env, jclass jvm, jclass jc);
+
+jstring JNICALL jfr_get_pid(JNIEnv* env, jobject jvm);
+
+jlong JNICALL jfr_stacktrace_id(JNIEnv* env, jobject jvm, jint skip);
+
+jlong JNICALL jfr_elapsed_frequency(JNIEnv* env, jobject jvm);
+
+void JNICALL jfr_subscribe_log_level(JNIEnv* env, jobject jvm, jobject log_tag, jint id);
+
+void JNICALL jfr_log(JNIEnv* env, jobject jvm, jint tag_set, jint level, jstring message);
+
+void JNICALL jfr_retransform_classes(JNIEnv* env, jobject jvm, jobjectArray classes);
+
+void JNICALL jfr_set_enabled(JNIEnv* env, jobject jvm, jlong event_type_id, jboolean enabled);
+
+void JNICALL jfr_set_file_notification(JNIEnv* env, jobject jvm, jlong delta);
+
+void JNICALL jfr_set_global_buffer_count(JNIEnv* env, jobject jvm, jlong count);
+
+void JNICALL jfr_set_global_buffer_size(JNIEnv* env, jobject jvm, jlong size);
+
+void JNICALL jfr_set_method_sampling_interval(JNIEnv* env, jobject jvm, jlong type, jlong intervalMillis);
+
+void JNICALL jfr_set_output(JNIEnv* env, jobject jvm, jstring path);
+
+void JNICALL jfr_set_sample_threads(JNIEnv* env, jobject jvm, jboolean sampleThreads);
+
+void JNICALL jfr_set_stack_depth(JNIEnv* env, jobject jvm, jint depth);
+
+void JNICALL jfr_set_stacktrace_enabled(JNIEnv* env, jobject jvm, jlong event_type_id, jboolean enabled);
+
+void JNICALL jfr_set_thread_buffer_size(JNIEnv* env, jobject jvm, jlong size);
+
+void JNICALL jfr_set_memory_size(JNIEnv* env, jobject jvm, jlong size);
+
+jboolean JNICALL jfr_set_threshold(JNIEnv* env, jobject jvm, jlong event_type_id, jlong thresholdTicks);
+
+void JNICALL jfr_store_metadata_descriptor(JNIEnv* env, jobject jvm, jbyteArray descriptor);
+
+jlong JNICALL jfr_id_for_thread(JNIEnv* env, jobject jvm, jobject t);
+
+jboolean JNICALL jfr_allow_event_retransforms(JNIEnv* env, jobject jvm);
+
+jboolean JNICALL jfr_is_available(JNIEnv* env, jclass jvm);
+
+jdouble JNICALL jfr_time_conv_factor(JNIEnv* env, jobject jvm);
+
+jlong JNICALL jfr_type_id(JNIEnv* env, jobject jvm, jclass jc);
+
+void JNICALL jfr_set_repository_location(JNIEnv* env, jobject repo, jstring location);
+
+jobject JNICALL jfr_get_event_writer(JNIEnv* env, jclass cls);
+
+jobject JNICALL jfr_new_event_writer(JNIEnv* env, jclass cls);
+
+jboolean JNICALL jfr_event_writer_flush(JNIEnv* env, jclass cls, jobject writer, jint used_size, jint requested_size);
+
+void JNICALL jfr_abort(JNIEnv* env, jobject jvm, jstring errorMsg);
+
+jlong JNICALL jfr_get_epoch_address(JNIEnv* env, jobject jvm);
+
+jlong JNICALL jfr_add_string_constant(JNIEnv* env, jclass jvm, jlong gen, jlong id, jstring string);
+
+void JNICALL jfr_uncaught_exception(JNIEnv* env, jobject jvm, jobject thread, jthrowable throwable);
+
+void JNICALL jfr_set_force_instrumentation(JNIEnv* env, jobject jvm, jboolean force);
+
+jlong JNICALL jfr_get_unloaded_event_classes_count(JNIEnv* env, jobject jvm);
+
+jboolean JNICALL jfr_set_cutoff(JNIEnv* env, jobject jvm, jlong event_type_id, jlong cutoff_ticks);
+
+void JNICALL jfr_emit_old_object_samples(JNIEnv* env, jobject jvm, jlong cutoff_ticks, jboolean);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // SHARE_VM_JFR_JNI_JFRJNIMETHOD_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/jni/jfrJniMethod.hpp"
+#include "jfr/jni/jfrJniMethodRegistration.hpp"
+#include "logging/log.hpp"
+#include "runtime/interfaceSupport.inline.hpp"
+#include "runtime/thread.hpp"
+#include "utilities/exceptions.hpp"
+
+JfrJniMethodRegistration::JfrJniMethodRegistration(JNIEnv* env) {
+  assert(env != NULL, "invariant");
+  jclass jfr_clz = env->FindClass("jdk/jfr/internal/JVM");
+  if (jfr_clz != NULL) {
+    JNINativeMethod method[] = {
+      (char*)"beginRecording", (char*)"()V", (void*)jfr_begin_recording,
+      (char*)"endRecording", (char*)"()V", (void*)jfr_end_recording,
+      (char*)"counterTime", (char*)"()J", (void*)jfr_elapsed_counter,
+      (char*)"createJFR", (char*)"(Z)Z", (void*)jfr_create_jfr,
+      (char*)"destroyJFR", (char*)"()Z", (void*)jfr_destroy_jfr,
+      (char*)"emitEvent", (char*)"(JJJ)Z", (void*)jfr_emit_event,
+      (char*)"getAllEventClasses", (char*)"()Ljava/util/List;", (void*)jfr_get_all_event_classes,
+      (char*)"getClassIdNonIntrinsic", (char*)"(Ljava/lang/Class;)J", (void*)jfr_class_id,
+      (char*)"getPid", (char*)"()Ljava/lang/String;", (void*)jfr_get_pid,
+      (char*)"getStackTraceId", (char*)"(I)J", (void*)jfr_stacktrace_id,
+      (char*)"getThreadId", (char*)"(Ljava/lang/Thread;)J", (void*)jfr_id_for_thread,
+      (char*)"getTicksFrequency", (char*)"()J", (void*)jfr_elapsed_frequency,
+      (char*)"subscribeLogLevel", (char*)"(Ljdk/jfr/internal/LogTag;I)V", (void*)jfr_subscribe_log_level,
+      (char*)"log", (char*)"(IILjava/lang/String;)V", (void*)jfr_log,
+      (char*)"retransformClasses", (char*)"([Ljava/lang/Class;)V", (void*)jfr_retransform_classes,
+      (char*)"setEnabled", (char*)"(JZ)V", (void*)jfr_set_enabled,
+      (char*)"setFileNotification", (char*)"(J)V", (void*)jfr_set_file_notification,
+      (char*)"setGlobalBufferCount", (char*)"(J)V", (void*)jfr_set_global_buffer_count,
+      (char*)"setGlobalBufferSize", (char*)"(J)V", (void*)jfr_set_global_buffer_size,
+      (char*)"setMethodSamplingInterval", (char*)"(JJ)V", (void*)jfr_set_method_sampling_interval,
+      (char*)"setOutput", (char*)"(Ljava/lang/String;)V", (void*)jfr_set_output,
+      (char*)"setSampleThreads", (char*)"(Z)V", (void*)jfr_set_sample_threads,
+      (char*)"setStackDepth", (char*)"(I)V", (void*)jfr_set_stack_depth,
+      (char*)"setStackTraceEnabled", (char*)"(JZ)V", (void*)jfr_set_stacktrace_enabled,
+      (char*)"setThreadBufferSize", (char*)"(J)V", (void*)jfr_set_thread_buffer_size,
+      (char*)"setMemorySize", (char*)"(J)V", (void*)jfr_set_memory_size,
+      (char*)"setThreshold", (char*)"(JJ)Z", (void*)jfr_set_threshold,
+      (char*)"storeMetadataDescriptor", (char*)"([B)V", (void*)jfr_store_metadata_descriptor,
+      (char*)"getAllowedToDoEventRetransforms", (char*)"()Z", (void*)jfr_allow_event_retransforms,
+      (char*)"isAvailable", (char*)"()Z", (void*)jfr_is_available,
+      (char*)"getTimeConversionFactor", (char*)"()D", (void*)jfr_time_conv_factor,
+      (char*)"getTypeId", (char*)"(Ljava/lang/Class;)J", (void*)jfr_type_id,
+      (char*)"getEventWriter", (char*)"()Ljava/lang/Object;", (void*)jfr_get_event_writer,
+      (char*)"newEventWriter", (char*)"()Ljdk/jfr/internal/EventWriter;", (void*)jfr_new_event_writer,
+      (char*)"flush", (char*)"(Ljdk/jfr/internal/EventWriter;II)Z", (void*)jfr_event_writer_flush,
+      (char*)"setRepositoryLocation", (char*)"(Ljava/lang/String;)V", (void*)jfr_set_repository_location,
+      (char*)"abort", (char*)"(Ljava/lang/String;)V", (void*)jfr_abort,
+      (char*)"getEpochAddress", (char*)"()J",(void*)jfr_get_epoch_address,
+      (char*)"addStringConstant", (char*)"(ZJLjava/lang/String;)Z", (void*)jfr_add_string_constant,
+      (char*)"uncaughtException", (char*)"(Ljava/lang/Thread;Ljava/lang/Throwable;)V", (void*)jfr_uncaught_exception,
+      (char*)"setForceInstrumentation", (char*)"(Z)V", (void*)jfr_set_force_instrumentation,
+      (char*)"getUnloadedEventClassCount", (char*)"()J", (void*)jfr_get_unloaded_event_classes_count,
+      (char*)"setCutoff", (char*)"(JJ)Z", (void*)jfr_set_cutoff,
+      (char*)"emitOldObjectSamples", (char*)"(JZ)V", (void*)jfr_emit_old_object_samples
+    };
+
+    const size_t method_array_length = sizeof(method) / sizeof(JNINativeMethod);
+    if (env->RegisterNatives(jfr_clz, method, (jint)method_array_length) != JNI_OK) {
+      JavaThread* jt = JavaThread::thread_from_jni_environment(env);
+      assert(jt != NULL, "invariant");
+      assert(jt->thread_state() == _thread_in_native, "invariant");
+      ThreadInVMfromNative transition(jt);
+      log_error(jfr, system)("RegisterNatives for JVM class failed!");
+    }
+    env->DeleteLocalRef(jfr_clz);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_JNI_JFRJNIMETHODREGISTRATION_HPP
+#define SHARE_VM_JFR_JNI_JFRJNIMETHODREGISTRATION_HPP
+
+#include "jni.h"
+#include "memory/allocation.hpp"
+
+//
+// RegisterNatives for jdk.jfr.internal.JVM
+//
+class JfrJniMethodRegistration : public StackObj {
+ public:
+  JfrJniMethodRegistration(JNIEnv* env);
+};
+
+#endif // SHARE_VM_JFR_JNI_JFRJNIMETHODREGISTRATION_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/jni/jfrUpcalls.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/javaClasses.hpp"
+#include "classfile/symbolTable.hpp"
+#include "classfile/systemDictionary.hpp"
+#include "jfr/jni/jfrJavaSupport.hpp"
+#include "jfr/jni/jfrUpcalls.hpp"
+#include "jfr/support/jfrEventClass.hpp"
+#include "logging/log.hpp"
+#include "memory/oopFactory.hpp"
+#include "oops/oop.inline.hpp"
+#include "oops/typeArrayKlass.hpp"
+#include "oops/typeArrayOop.inline.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/os.hpp"
+#include "runtime/thread.inline.hpp"
+#include "utilities/exceptions.hpp"
+
+static Symbol* jvm_upcalls_class_sym = NULL;
+static Symbol* on_retransform_method_sym = NULL;
+static Symbol* on_retransform_signature_sym = NULL;
+static Symbol* bytes_for_eager_instrumentation_sym = NULL;
+static Symbol* bytes_for_eager_instrumentation_sig_sym = NULL;
+
+static bool initialize(TRAPS) {
+  static bool initialized = false;
+  if (!initialized) {
+    DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
+    jvm_upcalls_class_sym = SymbolTable::new_permanent_symbol("jdk/jfr/internal/JVMUpcalls", CHECK_false);
+    on_retransform_method_sym = SymbolTable::new_permanent_symbol("onRetransform", CHECK_false);
+    on_retransform_signature_sym = SymbolTable::new_permanent_symbol("(JZLjava/lang/Class;[B)[B", CHECK_false);
+    bytes_for_eager_instrumentation_sym = SymbolTable::new_permanent_symbol("bytesForEagerInstrumentation", CHECK_false);
+    bytes_for_eager_instrumentation_sig_sym = SymbolTable::new_permanent_symbol("(JZLjava/lang/Class;[B)[B", THREAD);
+    initialized = bytes_for_eager_instrumentation_sig_sym != NULL;
+  }
+  return initialized;
+}
+
+static const typeArrayOop invoke(jlong trace_id,
+                                 jboolean force_instrumentation,
+                                 jclass class_being_redefined,
+                                 jint class_data_len,
+                                 const unsigned char* class_data,
+                                 Symbol* method_sym,
+                                 Symbol* signature_sym,
+                                 jint& new_bytes_length,
+                                 TRAPS) {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
+  const Klass* klass = SystemDictionary::resolve_or_fail(jvm_upcalls_class_sym, true, CHECK_NULL);
+  assert(klass != NULL, "invariant");
+  typeArrayOop old_byte_array = oopFactory::new_byteArray(class_data_len, CHECK_NULL);
+  memcpy(old_byte_array->byte_at_addr(0), class_data, class_data_len);
+  JavaValue result(T_OBJECT);
+  JfrJavaArguments args(&result, klass, method_sym, signature_sym);
+  args.push_long(trace_id);
+  args.push_int(force_instrumentation);
+  args.push_jobject(class_being_redefined);
+  args.push_oop(old_byte_array);
+  JfrJavaSupport::call_static(&args, THREAD);
+  if (HAS_PENDING_EXCEPTION) {
+    log_error(jfr, system)("JfrUpcall failed");
+    return NULL;
+  }
+  // The result should be a [B
+  const oop res = (oop)result.get_jobject();
+  assert(res != NULL, "invariant");
+  assert(res->is_typeArray(), "invariant");
+  assert(TypeArrayKlass::cast(res->klass())->element_type() == T_BYTE, "invariant");
+  const typeArrayOop new_byte_array = typeArrayOop(res);
+  new_bytes_length = (jint)new_byte_array->length();
+  return new_byte_array;
+}
+
+static const size_t ERROR_MSG_BUFFER_SIZE = 256;
+static void log_error_and_throw_oom(jint new_bytes_length, TRAPS) {
+  char error_buffer[ERROR_MSG_BUFFER_SIZE];
+  jio_snprintf(error_buffer, ERROR_MSG_BUFFER_SIZE,
+    "Thread local allocation (native) for " SIZE_FORMAT " bytes failed in JfrUpcalls", (size_t)new_bytes_length);
+  log_error(jfr, system)("%s", error_buffer);
+  JfrJavaSupport::throw_out_of_memory_error(error_buffer, CHECK);
+}
+
+void JfrUpcalls::on_retransform(jlong trace_id,
+                                jclass class_being_redefined,
+                                jint class_data_len,
+                                const unsigned char* class_data,
+                                jint* new_class_data_len,
+                                unsigned char** new_class_data,
+                                TRAPS) {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
+  assert(class_being_redefined != NULL, "invariant");
+  assert(class_data != NULL, "invariant");
+  assert(new_class_data_len != NULL, "invariant");
+  assert(new_class_data != NULL, "invariant");
+  if (!JdkJfrEvent::is_visible(class_being_redefined)) {
+    return;
+  }
+  jint new_bytes_length = 0;
+  initialize(THREAD);
+  const typeArrayOop new_byte_array = invoke(trace_id,
+                                             false,
+                                             class_being_redefined,
+                                             class_data_len,
+                                             class_data,
+                                             on_retransform_method_sym,
+                                             on_retransform_signature_sym,
+                                             new_bytes_length,
+                                             CHECK);
+  assert(new_byte_array != NULL, "invariant");
+  assert(new_bytes_length > 0, "invariant");
+  // memory space must be malloced as mtInternal
+  // as it will be deallocated by JVMTI routines
+  unsigned char* const new_bytes = (unsigned char* const)os::malloc(new_bytes_length, mtInternal);
+  if (new_bytes == NULL) {
+    log_error_and_throw_oom(new_bytes_length, THREAD); // unwinds
+  }
+  assert(new_bytes != NULL, "invariant");
+  memcpy(new_bytes, new_byte_array->byte_at_addr(0), (size_t)new_bytes_length);
+  *new_class_data_len = new_bytes_length;
+  *new_class_data = new_bytes;
+}
+
+void JfrUpcalls::new_bytes_eager_instrumentation(jlong trace_id,
+                                                 jboolean force_instrumentation,
+                                                 jclass super,
+                                                 jint class_data_len,
+                                                 const unsigned char* class_data,
+                                                 jint* new_class_data_len,
+                                                 unsigned char** new_class_data,
+                                                 TRAPS) {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
+  assert(super != NULL, "invariant");
+  assert(class_data != NULL, "invariant");
+  assert(new_class_data_len != NULL, "invariant");
+  assert(new_class_data != NULL, "invariant");
+  jint new_bytes_length = 0;
+  initialize(THREAD);
+  const typeArrayOop new_byte_array = invoke(trace_id,
+                                             force_instrumentation,
+                                             super,
+                                             class_data_len,
+                                             class_data,
+                                             bytes_for_eager_instrumentation_sym,
+                                             bytes_for_eager_instrumentation_sig_sym,
+                                             new_bytes_length,
+                                             CHECK);
+  assert(new_byte_array != NULL, "invariant");
+  assert(new_bytes_length > 0, "invariant");
+  unsigned char* const new_bytes = NEW_RESOURCE_ARRAY_IN_THREAD_RETURN_NULL(THREAD, unsigned char, new_bytes_length);
+  if (new_bytes == NULL) {
+    log_error_and_throw_oom(new_bytes_length, THREAD); // this unwinds
+  }
+  assert(new_bytes != NULL, "invariant");
+  memcpy(new_bytes, new_byte_array->byte_at_addr(0), (size_t)new_bytes_length);
+  *new_class_data_len = new_bytes_length;
+  *new_class_data = new_bytes;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/jni/jfrUpcalls.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_JNI_JFRUPCALLS_HPP
+#define SHARE_VM_JFR_JNI_JFRUPCALLS_HPP
+
+#include "jni.h"
+#include "jfr/utilities/jfrAllocation.hpp"
+#include "utilities/exceptions.hpp"
+
+class JavaThread;
+
+//
+// Upcalls to Java for instrumentation purposes.
+// Targets are located in jdk.jfr.internal.JVMUpcalls.
+//
+class JfrUpcalls : AllStatic {
+ public:
+  static void new_bytes_eager_instrumentation(jlong trace_id,
+                                              jboolean force_instrumentation,
+                                              jclass super,
+                                              jint class_data_len,
+                                              const unsigned char* class_data,
+                                              jint* new_class_data_len,
+                                              unsigned char** new_class_data,
+                                              TRAPS);
+
+  static void on_retransform(jlong trace_id,
+                             jclass class_being_redefined,
+                             jint class_data_len,
+                             const unsigned char* class_data,
+                             jint* new_class_data_len,
+                             unsigned char** new_class_data,
+                             TRAPS);
+};
+
+#endif // SHARE_VM_JFR_JNI_JFRUPCALLS_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/chains/bfsClosure.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+#include "precompiled.hpp"
+#include "jfr/leakprofiler/chains/bitset.hpp"
+#include "jfr/leakprofiler/chains/bfsClosure.hpp"
+#include "jfr/leakprofiler/chains/dfsClosure.hpp"
+#include "jfr/leakprofiler/chains/edge.hpp"
+#include "jfr/leakprofiler/chains/edgeStore.hpp"
+#include "jfr/leakprofiler/chains/edgeQueue.hpp"
+#include "jfr/leakprofiler/utilities/granularTimer.hpp"
+#include "jfr/leakprofiler/utilities/unifiedOop.hpp"
+#include "logging/log.hpp"
+#include "memory/resourceArea.hpp"
+#include "oops/access.inline.hpp"
+#include "oops/oop.inline.hpp"
+#include "utilities/align.hpp"
+
+BFSClosure::BFSClosure(EdgeQueue* edge_queue, EdgeStore* edge_store, BitSet* mark_bits) :
+  _edge_queue(edge_queue),
+  _edge_store(edge_store),
+  _mark_bits(mark_bits),
+  _current_parent(NULL),
+  _current_frontier_level(0),
+  _next_frontier_idx(0),
+  _prev_frontier_idx(0),
+  _dfs_fallback_idx(0),
+  _use_dfs(false) {
+}
+
+static void log_frontier_level_summary(size_t level,
+                                       size_t high_idx,
+                                       size_t low_idx,
+                                       size_t edge_size) {
+  const size_t nof_edges_in_frontier = high_idx - low_idx;
+  log_trace(jfr, system)(
+      "BFS front: " SIZE_FORMAT " edges: " SIZE_FORMAT " size: " SIZE_FORMAT " [KB]",
+      level,
+      nof_edges_in_frontier,
+      (nof_edges_in_frontier * edge_size) / K
+                        );
+}
+
+void BFSClosure::log_completed_frontier() const {
+  log_frontier_level_summary(_current_frontier_level,
+                             _next_frontier_idx,
+                             _prev_frontier_idx,
+                             _edge_queue->sizeof_edge());
+}
+
+void BFSClosure::log_dfs_fallback() const {
+  const size_t edge_size = _edge_queue->sizeof_edge();
+  // first complete summary for frontier in progress
+  log_frontier_level_summary(_current_frontier_level,
+                             _next_frontier_idx,
+                             _prev_frontier_idx,
+                             edge_size);
+
+  // and then also complete the last frontier
+  log_frontier_level_summary(_current_frontier_level + 1,
+                             _edge_queue->bottom(),
+                             _next_frontier_idx,
+                             edge_size);
+
+  // additional information about DFS fallover
+  log_trace(jfr, system)(
+      "BFS front: " SIZE_FORMAT " filled edge queue at edge: " SIZE_FORMAT,
+      _current_frontier_level,
+      _dfs_fallback_idx
+                        );
+
+  const size_t nof_dfs_completed_edges = _edge_queue->bottom() - _dfs_fallback_idx;
+  log_trace(jfr, system)(
+      "DFS to complete " SIZE_FORMAT " edges size: " SIZE_FORMAT " [KB]",
+      nof_dfs_completed_edges,
+      (nof_dfs_completed_edges * edge_size) / K
+                        );
+}
+
+void BFSClosure::process() {
+
+  process_root_set();
+  process_queue();
+}
+
+void BFSClosure::process_root_set() {
+  for (size_t idx = _edge_queue->bottom(); idx < _edge_queue->top(); ++idx) {
+    const Edge* edge = _edge_queue->element_at(idx);
+    assert(edge->parent() == NULL, "invariant");
+    process(edge->reference(), edge->pointee());
+  }
+}
+
+void BFSClosure::process(const oop* reference, const oop pointee) {
+  closure_impl(reference, pointee);
+}
+void BFSClosure::closure_impl(const oop* reference, const oop pointee) {
+  assert(reference != NULL, "invariant");
+  assert(UnifiedOop::dereference(reference) == pointee, "invariant");
+
+  if (GranularTimer::is_finished()) {
+     return;
+  }
+
+  if (_use_dfs) {
+    assert(_current_parent != NULL, "invariant");
+    DFSClosure::find_leaks_from_edge(_edge_store, _mark_bits, _current_parent);
+    return;
+  }
+
+  if (!_mark_bits->is_marked(pointee)) {
+    _mark_bits->mark_obj(pointee);
+    // is the pointee a sample object?
+    if (NULL == pointee->mark()) {
+      add_chain(reference, pointee);
+    }
+
+    // if we are processinig initial root set, don't add to queue
+    if (_current_parent != NULL) {
+      assert(_current_parent->distance_to_root() == _current_frontier_level, "invariant");
+      _edge_queue->add(_current_parent, reference);
+    }
+
+    if (_edge_queue->is_full()) {
+      dfs_fallback();
+    }
+  }
+}
+
+void BFSClosure::add_chain(const oop* reference, const oop pointee) {
+  assert(pointee != NULL, "invariant");
+  assert(NULL == pointee->mark(), "invariant");
+
+  const size_t length = _current_parent == NULL ? 1 : _current_parent->distance_to_root() + 2;
+  ResourceMark rm;
+  Edge* const chain = NEW_RESOURCE_ARRAY(Edge, length);
+  size_t idx = 0;
+  chain[idx++] = Edge(NULL, reference);
+  // aggregate from breadth-first search
+  const Edge* current = _current_parent;
+  while (current != NULL) {
+    chain[idx++] = Edge(NULL, current->reference());
+    current = current->parent();
+  }
+  assert(length == idx, "invariant");
+  _edge_store->add_chain(chain, length);
+}
+
+void BFSClosure::dfs_fallback() {
+  assert(_edge_queue->is_full(), "invariant");
+  _use_dfs = true;
+  _dfs_fallback_idx = _edge_queue->bottom();
+  while (!_edge_queue->is_empty()) {
+    const Edge* edge = _edge_queue->remove();
+    if (edge->pointee() != NULL) {
+      DFSClosure::find_leaks_from_edge(_edge_store, _mark_bits, edge);
+    }
+  }
+}
+
+void BFSClosure::process_queue() {
+  assert(_current_frontier_level == 0, "invariant");
+  assert(_next_frontier_idx == 0, "invariant");
+  assert(_prev_frontier_idx == 0, "invariant");
+
+  _next_frontier_idx = _edge_queue->top();
+  while (!is_complete()) {
+    iterate(_edge_queue->remove()); // edge_queue.remove() increments bottom
+  }
+}
+
+void BFSClosure::step_frontier() const {
+  log_completed_frontier();
+  ++_current_frontier_level;
+  _prev_frontier_idx = _next_frontier_idx;
+  _next_frontier_idx = _edge_queue->top();
+}
+
+bool BFSClosure::is_complete() const {
+  if (_edge_queue->bottom() < _next_frontier_idx) {
+    return false;
+  }
+  if (_edge_queue->bottom() > _next_frontier_idx) {
+    // fallback onto DFS as part of processing the frontier
+    assert(_dfs_fallback_idx >= _prev_frontier_idx, "invariant");
+    assert(_dfs_fallback_idx < _next_frontier_idx, "invariant");
+    log_dfs_fallback();
+    return true;
+  }
+  assert(_edge_queue->bottom() == _next_frontier_idx, "invariant");
+  if (_edge_queue->is_empty()) {
+    return true;
+  }
+  step_frontier();
+  return false;
+}
+
+void BFSClosure::iterate(const Edge* parent) {
+  assert(parent != NULL, "invariant");
+  const oop pointee = parent->pointee();
+  assert(pointee != NULL, "invariant");
+  _current_parent = parent;
+  pointee->oop_iterate(this);
+}
+
+void BFSClosure::do_oop(oop* ref) {
+  assert(ref != NULL, "invariant");
+  assert(is_aligned(ref, HeapWordSize), "invariant");
+  const oop pointee = *ref;
+  if (pointee != NULL) {
+    closure_impl(ref, pointee);
+  }
+}
+
+void BFSClosure::do_oop(narrowOop* ref) {
+  assert(ref != NULL, "invariant");
+  assert(is_aligned(ref, sizeof(narrowOop)), "invariant");
+  const oop pointee = RawAccess<>::oop_load(ref);
+  if (pointee != NULL) {
+    closure_impl(UnifiedOop::encode(ref), pointee);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/chains/bfsClosure.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_LEAKPROFILER_CHAINS_BFSCLOSURE_HPP
+#define SHARE_VM_JFR_LEAKPROFILER_CHAINS_BFSCLOSURE_HPP
+
+#include "memory/iterator.hpp"
+#include "oops/oop.hpp"
+
+class BitSet;
+class Edge;
+class EdgeStore;
+class EdgeQueue;
+
+// Class responsible for iterating the heap breadth-first
+class BFSClosure : public ExtendedOopClosure {
+ private:
+  EdgeQueue* _edge_queue;
+  EdgeStore* _edge_store;
+  BitSet* _mark_bits;
+  const Edge* _current_parent;
+  mutable size_t _current_frontier_level;
+  mutable size_t _next_frontier_idx;
+  mutable size_t _prev_frontier_idx;
+  size_t _dfs_fallback_idx;
+  bool _use_dfs;
+
+  void log_completed_frontier() const;
+  void log_dfs_fallback() const;
+
+  bool is_complete() const;
+  void step_frontier() const;
+
+  void closure_impl(const oop* reference, const oop pointee);
+  void add_chain(const oop* reference, const oop pointee);
+  void dfs_fallback();
+
+  void iterate(const Edge* parent);
+  void process(const oop* reference, const oop pointee);
+
+  void process_root_set();
+  void process_queue();
+
+ public:
+  BFSClosure(EdgeQueue* edge_queue, EdgeStore* edge_store, BitSet* mark_bits);
+  void process();
+
+  virtual void do_oop(oop* ref);
+  virtual void do_oop(narrowOop* ref);
+};
+
+#endif // SHARE_VM_JFR_LEAKPROFILER_CHAINS_BFSCLOSURE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/chains/bitset.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+#include "precompiled.hpp"
+#include "jfr/leakprofiler/chains/bitset.hpp"
+#include "jfr/recorder/storage/jfrVirtualMemory.hpp"
+#include "memory/memRegion.hpp"
+
+BitSet::BitSet(const MemRegion& covered_region) :
+  _vmm(NULL),
+  _region_start(covered_region.start()),
+  _region_size(covered_region.word_size()) {
+}
+
+BitSet::~BitSet() {
+  delete _vmm;
+}
+
+bool BitSet::initialize() {
+  assert(_vmm == NULL, "invariant");
+  _vmm = new JfrVirtualMemory();
+  if (_vmm == NULL) {
+    return false;
+  }
+
+  const BitMap::idx_t bits = _region_size >> LogMinObjAlignment;
+  const size_t words = bits / BitsPerWord;
+  const size_t raw_bytes = words * sizeof(BitMap::idx_t);
+
+  // the virtual memory invocation will reserve and commit the entire space
+  BitMap::bm_word_t* map = (BitMap::bm_word_t*)_vmm->initialize(raw_bytes, raw_bytes);
+  if (map == NULL) {
+    return false;
+  }
+  _bits = BitMapView(map, bits);
+  return true;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/chains/bitset.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_LEAKPROFILER_CHAINS_BITSET_HPP
+#define SHARE_VM_JFR_LEAKPROFILER_CHAINS_BITSET_HPP
+
+#include "memory/allocation.hpp"
+#include "oops/oopsHierarchy.hpp"
+#include "utilities/bitMap.inline.hpp"
+
+class JfrVirtualMemory;
+class MemRegion;
+
+class BitSet : public CHeapObj<mtTracing> {
+ private:
+  JfrVirtualMemory* _vmm;
+  const HeapWord* const _region_start;
+  BitMapView _bits;
+  const size_t _region_size;
+
+ public:
+  BitSet(const MemRegion& covered_region);
+  ~BitSet();
+
+  bool initialize();
+
+  BitMap::idx_t mark_obj(const HeapWord* addr) {
+    const BitMap::idx_t bit = addr_to_bit(addr);
+    _bits.par_set_bit(bit);
+    return bit;
+  }
+
+  BitMap::idx_t mark_obj(oop obj) {
+    return mark_obj((HeapWord*)obj);
+  }
+
+  bool is_marked(const HeapWord* addr) const {
+    return is_marked(addr_to_bit(addr));
+  }
+
+  bool is_marked(oop obj) const {
+    return is_marked((HeapWord*)obj);
+  }
+
+  BitMap::idx_t size() const {
+    return _bits.size();
+  }
+
+  BitMap::idx_t addr_to_bit(const HeapWord* addr) const {
+    return pointer_delta(addr, _region_start) >> LogMinObjAlignment;
+  }
+
+  bool is_marked(const BitMap::idx_t bit) const {
+    return _bits.at(bit);
+  }
+};
+
+#endif  // SHARE_VM_JFR_LEAKPROFILER_CHAINS_BITSET_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/chains/dfsClosure.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/leakprofiler/chains/dfsClosure.hpp"
+#include "jfr/leakprofiler/chains/edge.hpp"
+#include "jfr/leakprofiler/chains/edgeStore.hpp"
+#include "jfr/leakprofiler/utilities/granularTimer.hpp"
+#include "jfr/leakprofiler/chains/bitset.hpp"
+#include "jfr/leakprofiler/utilities/unifiedOop.hpp"
+#include "jfr/leakprofiler/utilities/rootType.hpp"
+#include "jfr/leakprofiler/chains/rootSetClosure.hpp"
+#include "memory/resourceArea.hpp"
+#include "oops/access.inline.hpp"
+#include "oops/oop.inline.hpp"
+#include "utilities/align.hpp"
+
+// max dfs depth should not exceed size of stack
+static const size_t max_dfs_depth = 5000;
+
+EdgeStore* DFSClosure::_edge_store = NULL;
+BitSet* DFSClosure::_mark_bits = NULL;
+const Edge* DFSClosure::_start_edge = NULL;
+size_t DFSClosure::_max_depth = max_dfs_depth;
+bool DFSClosure::_ignore_root_set = false;
+
+DFSClosure::DFSClosure() :
+  _parent(NULL),
+  _reference(NULL),
+  _depth(0) {
+}
+
+DFSClosure::DFSClosure(DFSClosure* parent, size_t depth) :
+  _parent(parent),
+  _reference(NULL),
+  _depth(depth) {
+}
+
+void DFSClosure::find_leaks_from_edge(EdgeStore* edge_store,
+                                      BitSet* mark_bits,
+                                      const Edge* start_edge) {
+  assert(edge_store != NULL, "invariant");
+  assert(mark_bits != NULL," invariant");
+  assert(start_edge != NULL, "invariant");
+
+  _edge_store = edge_store;
+  _mark_bits = mark_bits;
+  _start_edge = start_edge;
+  _ignore_root_set = false;
+  assert(_max_depth == max_dfs_depth, "invariant");
+
+  // Depth-first search, starting from a BFS egde
+  DFSClosure dfs;
+  start_edge->pointee()->oop_iterate(&dfs);
+}
+
+void DFSClosure::find_leaks_from_root_set(EdgeStore* edge_store,
+                                          BitSet* mark_bits) {
+  assert(edge_store != NULL, "invariant");
+  assert(mark_bits != NULL, "invariant");
+
+  _edge_store = edge_store;
+  _mark_bits = mark_bits;
+  _start_edge = NULL;
+
+  // Mark root set, to avoid going sideways
+  _max_depth = 1;
+  _ignore_root_set = false;
+  DFSClosure dfs1;
+  RootSetClosure::process_roots(&dfs1);
+
+  // Depth-first search
+  _max_depth = max_dfs_depth;
+  _ignore_root_set = true;
+  assert(_start_edge == NULL, "invariant");
+  DFSClosure dfs2;
+  RootSetClosure::process_roots(&dfs2);
+}
+
+void DFSClosure::closure_impl(const oop* reference, const oop pointee) {
+  assert(pointee != NULL, "invariant");
+  assert(reference != NULL, "invariant");
+
+  if (GranularTimer::is_finished()) {
+     return;
+  }
+  if (_depth == 0 && _ignore_root_set) {
+    // Root set is already marked, but we want
+    // to continue, so skip is_marked check.
+    assert(_mark_bits->is_marked(pointee), "invariant");
+  } else {
+    if (_mark_bits->is_marked(pointee)) {
+      return;
+    }
+  }
+
+  _reference = reference;
+  _mark_bits->mark_obj(pointee);
+  assert(_mark_bits->is_marked(pointee), "invariant");
+
+  // is the pointee a sample object?
+  if (NULL == pointee->mark()) {
+    add_chain();
+  }
+
+  assert(_max_depth >= 1, "invariant");
+  if (_depth < _max_depth - 1) {
+    DFSClosure next_level(this, _depth + 1);
+    pointee->oop_iterate(&next_level);
+  }
+}
+
+void DFSClosure::add_chain() {
+  const size_t length = _start_edge == NULL ? _depth + 1 :
+                        _start_edge->distance_to_root() + 1 + _depth + 1;
+
+  ResourceMark rm;
+  Edge* const chain = NEW_RESOURCE_ARRAY(Edge, length);
+  size_t idx = 0;
+
+  // aggregate from depth-first search
+  const DFSClosure* c = this;
+  while (c != NULL) {
+    chain[idx++] = Edge(NULL, c->reference());
+    c = c->parent();
+  }
+
+  assert(idx == _depth + 1, "invariant");
+
+  // aggregate from breadth-first search
+  const Edge* current = _start_edge;
+  while (current != NULL) {
+    chain[idx++] = Edge(NULL, current->reference());
+    current = current->parent();
+  }
+  assert(idx == length, "invariant");
+  _edge_store->add_chain(chain, length);
+}
+
+void DFSClosure::do_oop(oop* ref) {
+  assert(ref != NULL, "invariant");
+  assert(is_aligned(ref, HeapWordSize), "invariant");
+  const oop pointee = *ref;
+  if (pointee != NULL) {
+    closure_impl(ref, pointee);
+  }
+}
+
+void DFSClosure::do_oop(narrowOop* ref) {
+  assert(ref != NULL, "invariant");
+  assert(is_aligned(ref, sizeof(narrowOop)), "invariant");
+  const oop pointee = RawAccess<>::oop_load(ref);
+  if (pointee != NULL) {
+    closure_impl(UnifiedOop::encode(ref), pointee);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/chains/dfsClosure.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_LEAKPROFILER_CHAINS_DFSCLOSURE_HPP
+#define SHARE_VM_JFR_LEAKPROFILER_CHAINS_DFSCLOSURE_HPP
+
+#include "memory/iterator.hpp"
+#include "oops/oop.hpp"
+
+class BitSet;
+class Edge;
+class EdgeStore;
+class EdgeQueue;
+
+// Class responsible for iterating the heap depth-first
+class DFSClosure: public ExtendedOopClosure {
+ private:
+  static EdgeStore* _edge_store;
+  static BitSet*    _mark_bits;
+  static const Edge*_start_edge;
+  static size_t _max_depth;
+  static bool _ignore_root_set;
+  DFSClosure* _parent;
+  const oop* _reference;
+  size_t _depth;
+
+  void add_chain();
+  void closure_impl(const oop* reference, const oop pointee);
+
+  DFSClosure* parent() const { return _parent; }
+  const oop* reference() const { return _reference; }
+
+  DFSClosure(DFSClosure* parent, size_t depth);
+  DFSClosure();
+
+ public:
+  static void find_leaks_from_edge(EdgeStore* edge_store, BitSet* mark_bits, const Edge* start_edge);
+  static void find_leaks_from_root_set(EdgeStore* edge_store, BitSet* mark_bits);
+
+  virtual void do_oop(oop* ref);
+  virtual void do_oop(narrowOop* ref);
+};
+
+#endif // SHARE_VM_JFR_LEAKPROFILER_CHAINS_DFSCLOSURE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/chains/edge.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+#include "precompiled.hpp"
+#include "classfile/javaClasses.inline.hpp"
+#include "jfr/leakprofiler/chains/edge.hpp"
+#include "jfr/leakprofiler/utilities/unifiedOop.hpp"
+
+Edge::Edge() : _parent(NULL), _reference(NULL) {}
+
+Edge::Edge(const Edge* parent, const oop* reference) : _parent(parent),
+                                                       _reference(reference) {}
+
+const oop Edge::pointee() const {
+  return UnifiedOop::dereference(_reference);
+}
+
+const oop Edge::reference_owner() const {
+  return is_root() ? (oop)NULL : UnifiedOop::dereference(_parent->reference());
+}
+
+static const Klass* resolve_klass(const oop obj) {
+  assert(obj != NULL, "invariant");
+  return java_lang_Class::is_instance(obj) ?
+    java_lang_Class::as_Klass(obj) : obj->klass();
+}
+
+const Klass* Edge::pointee_klass() const {
+  return resolve_klass(pointee());
+}
+
+const Klass* Edge::reference_owner_klass() const {
+  const oop ref_owner = reference_owner();
+  return ref_owner != NULL ? resolve_klass(ref_owner) : NULL;
+}
+
+size_t Edge::distance_to_root() const {
+  size_t depth = 0;
+  const Edge* current = _parent;
+  while (current != NULL) {
+    depth++;
+    current = current->parent();
+  }
+  return depth;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/chains/edge.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_LEAKPROFILER_CHAINS_EDGE_HPP
+#define SHARE_VM_JFR_LEAKPROFILER_CHAINS_EDGE_HPP
+
+#include "memory/allocation.hpp"
+#include "oops/oopsHierarchy.hpp"
+
+class Edge {
+ private:
+  const Edge* _parent;
+  const oop* _reference;
+ public:
+  Edge();
+  Edge(const Edge* parent, const oop* reference);
+
+  const oop* reference() const {
+    return _reference;
+  }
+  const Edge* parent() const {
+    return _parent;
+  }
+  bool is_root() const {
+    return _parent == NULL;
+  }
+  const oop pointee() const;
+  const Klass* pointee_klass() const;
+  const oop reference_owner() const;
+  const Klass* reference_owner_klass() const;
+  size_t distance_to_root() const;
+
+  void* operator new (size_t sz, void* here) {
+    return here;
+  }
+};
+
+#endif // SHARE_VM_JFR_LEAKPROFILER_CHAINS_EDGE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/chains/edgeQueue.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/leakprofiler/chains/edgeQueue.hpp"
+#include "jfr/recorder/storage/jfrVirtualMemory.hpp"
+
+EdgeQueue::EdgeQueue(size_t reservation_size_bytes, size_t commit_block_size_bytes) :
+  _vmm(NULL),
+  _reservation_size_bytes(reservation_size_bytes),
+  _commit_block_size_bytes(commit_block_size_bytes),
+  _top_index(0),
+  _bottom_index(0) {
+}
+
+bool EdgeQueue::initialize() {
+  assert(_reservation_size_bytes >= _commit_block_size_bytes, "invariant");
+  assert(_vmm == NULL, "invariant");
+  _vmm = new JfrVirtualMemory();
+  return _vmm != NULL && _vmm->initialize(_reservation_size_bytes, _commit_block_size_bytes, sizeof(Edge));
+}
+
+EdgeQueue::~EdgeQueue() {
+  delete _vmm;
+}
+
+void EdgeQueue::add(const Edge* parent, const oop* ref) {
+  assert(ref != NULL, "Null objects not allowed in EdgeQueue");
+  assert(!is_full(), "EdgeQueue is full. Check is_full before adding another Edge");
+  assert(!_vmm->is_full(), "invariant");
+  void* const allocation = _vmm->new_datum();
+  assert(allocation != NULL, "invariant");
+  new (allocation)Edge(parent, ref);
+  _top_index++;
+  assert(_vmm->count() == _top_index, "invariant");
+}
+
+size_t EdgeQueue::top() const {
+  return _top_index;
+}
+
+size_t EdgeQueue::bottom() const {
+  return EdgeQueue::_bottom_index;
+}
+
+bool EdgeQueue::is_empty() const {
+  return _top_index == _bottom_index;
+}
+
+bool EdgeQueue::is_full() const {
+  return _vmm->is_full();
+}
+
+const Edge* EdgeQueue::remove() const {
+  assert(!is_empty(), "EdgeQueue is empty. Check if empty before removing Edge");
+  assert(!_vmm->is_empty(), "invariant");
+  return (const Edge*)_vmm->get(_bottom_index++);
+}
+
+const Edge* EdgeQueue::element_at(size_t index) const {
+  assert(index >= _bottom_index, "invariant");
+  assert(index <_top_index, "invariant");
+  return (Edge*)_vmm->get(index);
+}
+
+size_t EdgeQueue::reserved_size() const {
+  assert(_vmm != NULL, "invariant");
+  return _vmm->reserved_size();
+}
+
+size_t EdgeQueue::live_set() const {
+  assert(_vmm != NULL, "invariant");
+  return _vmm->live_set();
+}
+
+size_t EdgeQueue::sizeof_edge() const {
+  assert(_vmm != NULL, "invariant");
+  return _vmm->aligned_datum_size_bytes();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/chains/edgeQueue.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_LEAKPROFILER_CHAINS_EDGEQUEUE_HPP
+#define SHARE_VM_JFR_LEAKPROFILER_CHAINS_EDGEQUEUE_HPP
+
+#include "memory/allocation.hpp"
+#include "jfr/leakprofiler/chains/edge.hpp"
+
+class JfrVirtualMemory;
+
+class EdgeQueue : public CHeapObj<mtTracing> {
+ private:
+  JfrVirtualMemory* _vmm;
+  const size_t _reservation_size_bytes;
+  const size_t _commit_block_size_bytes;
+  mutable size_t _top_index;
+  mutable size_t _bottom_index;
+ public:
+  EdgeQueue(size_t reservation_size_bytes, size_t commit_block_size_bytes);
+  ~EdgeQueue();
+
+  bool initialize();
+
+  void add(const Edge* parent, const oop* ref);
+  const Edge* remove() const;
+  const Edge* element_at(size_t index) const;
+
+  size_t top() const;
+  size_t bottom() const;
+  bool is_empty() const;
+  bool is_full() const;
+
+  size_t reserved_size() const;
+  size_t live_set() const;
+  size_t sizeof_edge() const; // with alignments
+};
+
+#endif // SHARE_VM_JFR_LEAKPROFILER_CHAINS_EDGEQUEUE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/chains/edgeStore.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/leakprofiler/chains/edgeStore.hpp"
+#include "jfr/leakprofiler/chains/edgeUtils.hpp"
+#include "oops/oop.inline.hpp"
+
+RoutableEdge::RoutableEdge() : Edge() {}
+RoutableEdge::RoutableEdge(const Edge* parent, const oop* reference) : Edge(parent, reference),
+                                                                       _skip_edge(NULL),
+                                                                       _skip_length(0),
+                                                                       _processed(false) {}
+
+RoutableEdge::RoutableEdge(const Edge& edge) : Edge(edge),
+                                               _skip_edge(NULL),
+                                               _skip_length(0),
+                                               _processed(false) {}
+
+RoutableEdge::RoutableEdge(const RoutableEdge& edge) : Edge(edge),
+                                                      _skip_edge(edge._skip_edge),
+                                                      _skip_length(edge._skip_length),
+                                                      _processed(edge._processed) {}
+
+void RoutableEdge::operator=(const RoutableEdge& edge) {
+  Edge::operator=(edge);
+  _skip_edge = edge._skip_edge;
+  _skip_length = edge._skip_length;
+  _processed = edge._processed;
+}
+
+size_t RoutableEdge::logical_distance_to_root() const {
+  size_t depth = 0;
+  const RoutableEdge* current = logical_parent();
+  while (current != NULL) {
+    depth++;
+    current = current->logical_parent();
+  }
+  return depth;
+}
+
+traceid EdgeStore::_edge_id_counter = 0;
+
+EdgeStore::EdgeStore() : _edges(NULL) {
+  _edges = new EdgeHashTable(this);
+}
+
+EdgeStore::~EdgeStore() {
+  assert(_edges != NULL, "invariant");
+  delete _edges;
+  _edges = NULL;
+}
+
+const Edge* EdgeStore::get_edge(const Edge* edge) const {
+  assert(edge != NULL, "invariant");
+  EdgeEntry* const entry = _edges->lookup_only(*edge, (uintptr_t)edge->reference());
+  return entry != NULL ? entry->literal_addr() : NULL;
+}
+
+const Edge* EdgeStore::put(const Edge* edge) {
+  assert(edge != NULL, "invariant");
+  const RoutableEdge e = *edge;
+  assert(NULL == _edges->lookup_only(e, (uintptr_t)e.reference()), "invariant");
+  EdgeEntry& entry = _edges->put(e, (uintptr_t)e.reference());
+  return entry.literal_addr();
+}
+
+traceid EdgeStore::get_id(const Edge* edge) const {
+  assert(edge != NULL, "invariant");
+  EdgeEntry* const entry = _edges->lookup_only(*edge, (uintptr_t)edge->reference());
+  assert(entry != NULL, "invariant");
+  return entry->id();
+}
+
+traceid EdgeStore::get_root_id(const Edge* edge) const {
+  assert(edge != NULL, "invariant");
+  const Edge* root = EdgeUtils::root(*edge);
+  assert(root != NULL, "invariant");
+  return get_id(root);
+}
+
+void EdgeStore::add_chain(const Edge* chain, size_t length) {
+  assert(chain != NULL, "invariant");
+  assert(length > 0, "invariant");
+
+  size_t bottom_index = length - 1;
+  const size_t top_index = 0;
+
+  const Edge* stored_parent_edge = NULL;
+
+  // determine level of shared ancestry
+  for (; bottom_index > top_index; --bottom_index) {
+    const Edge* stored_edge = get_edge(&chain[bottom_index]);
+    if (stored_edge != NULL) {
+      stored_parent_edge = stored_edge;
+      continue;
+    }
+    break;
+  }
+
+  // insertion of new Edges
+  for (int i = (int)bottom_index; i >= (int)top_index; --i) {
+    Edge edge(stored_parent_edge, chain[i].reference());
+    stored_parent_edge = put(&edge);
+  }
+
+  const oop sample_object = stored_parent_edge->pointee();
+  assert(sample_object != NULL, "invariant");
+  assert(NULL == sample_object->mark(), "invariant");
+
+  // Install the "top" edge of the chain into the sample object mark oop.
+  // This associates the sample object with its navigable reference chain.
+  sample_object->set_mark(markOop(stored_parent_edge));
+}
+
+bool EdgeStore::is_empty() const {
+  return !_edges->has_entries();
+}
+
+size_t EdgeStore::number_of_entries() const {
+  return _edges->cardinality();
+}
+
+void EdgeStore::assign_id(EdgeEntry* entry) {
+  assert(entry != NULL, "invariant");
+  assert(entry->id() == 0, "invariant");
+  entry->set_id(++_edge_id_counter);
+}
+
+bool EdgeStore::equals(const Edge& query, uintptr_t hash, const EdgeEntry* entry) {
+  assert(entry != NULL, "invariant");
+  assert(entry->hash() == hash, "invariant");
+  return true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/chains/edgeStore.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_LEAKPROFILER_CHAINS_EDGESTORE_HPP
+#define SHARE_VM_LEAKPROFILER_CHAINS_EDGESTORE_HPP
+
+#include "jfr/utilities/jfrHashtable.hpp"
+#include "jfr/leakprofiler/chains/edge.hpp"
+#include "memory/allocation.hpp"
+
+typedef u8 traceid;
+
+class RoutableEdge : public Edge {
+ private:
+  mutable const RoutableEdge* _skip_edge;
+  mutable size_t _skip_length;
+  mutable bool _processed;
+
+ public:
+  RoutableEdge();
+  RoutableEdge(const Edge* parent, const oop* reference);
+  RoutableEdge(const Edge& edge);
+  RoutableEdge(const RoutableEdge& edge);
+  void operator=(const RoutableEdge& edge);
+
+  const RoutableEdge* skip_edge() const { return _skip_edge; }
+  size_t skip_length() const { return _skip_length; }
+
+  bool is_skip_edge() const { return _skip_edge != NULL; }
+  bool processed() const { return _processed; }
+  bool is_sentinel() const {
+    return _skip_edge == NULL && _skip_length == 1;
+  }
+
+  void set_skip_edge(const RoutableEdge* edge) const {
+    assert(!is_skip_edge(), "invariant");
+    assert(edge != this, "invariant");
+    _skip_edge = edge;
+  }
+
+  void set_skip_length(size_t length) const {
+    _skip_length = length;
+  }
+
+  void set_processed() const {
+    assert(!_processed, "invariant");
+    _processed = true;
+  }
+
+  // true navigation according to physical tree representation
+  const RoutableEdge* physical_parent() const {
+    return static_cast<const RoutableEdge*>(parent());
+  }
+
+  // logical navigation taking skip levels into account
+  const RoutableEdge* logical_parent() const {
+    return is_skip_edge() ? skip_edge() : physical_parent();
+  }
+
+  size_t logical_distance_to_root() const;
+};
+
+class EdgeStore : public CHeapObj<mtTracing> {
+  typedef HashTableHost<RoutableEdge, traceid, Entry, EdgeStore> EdgeHashTable;
+  typedef EdgeHashTable::HashEntry EdgeEntry;
+  template <typename,
+            typename,
+            template<typename, typename> class,
+            typename,
+            size_t>
+  friend class HashTableHost;
+ private:
+  static traceid _edge_id_counter;
+  EdgeHashTable* _edges;
+
+  // Hash table callbacks
+  void assign_id(EdgeEntry* entry);
+  bool equals(const Edge& query, uintptr_t hash, const EdgeEntry* entry);
+
+  const Edge* get_edge(const Edge* edge) const;
+  const Edge* put(const Edge* edge);
+
+ public:
+  EdgeStore();
+  ~EdgeStore();
+
+  void add_chain(const Edge* chain, size_t length);
+  bool is_empty() const;
+  size_t number_of_entries() const;
+
+  traceid get_id(const Edge* edge) const;
+  traceid get_root_id(const Edge* edge) const;
+
+  template <typename T>
+  void iterate_edges(T& functor) const { _edges->iterate_value<T>(functor); }
+};
+
+#endif // SHARE_VM_LEAKPROFILER_CHAINS_EDGESTORE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,312 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/javaClasses.hpp"
+#include "jfr/leakprofiler/chains/edge.hpp"
+#include "jfr/leakprofiler/chains/edgeStore.hpp"
+#include "jfr/leakprofiler/chains/edgeUtils.hpp"
+#include "jfr/leakprofiler/utilities/unifiedOop.hpp"
+#include "oops/fieldStreams.hpp"
+#include "oops/instanceKlass.hpp"
+#include "oops/objArrayOop.inline.hpp"
+#include "oops/oopsHierarchy.hpp"
+#include "runtime/handles.inline.hpp"
+
+bool EdgeUtils::is_leak_edge(const Edge& edge) {
+  return (const Edge*)edge.pointee()->mark() == &edge;
+}
+
+bool EdgeUtils::is_root(const Edge& edge) {
+  return edge.is_root();
+}
+
+static int field_offset(const Edge& edge) {
+  assert(!edge.is_root(), "invariant");
+  const oop ref_owner = edge.reference_owner();
+  assert(ref_owner != NULL, "invariant");
+  const oop* reference = UnifiedOop::decode(edge.reference());
+  assert(reference != NULL, "invariant");
+  assert(!UnifiedOop::is_narrow(reference), "invariant");
+  assert(!ref_owner->is_array(), "invariant");
+  assert(ref_owner->is_instance(), "invariant");
+  const int offset = (int)pointer_delta(reference, ref_owner, sizeof(char));
+  assert(offset < (ref_owner->size() * HeapWordSize), "invariant");
+  return offset;
+}
+
+static const InstanceKlass* field_type(const Edge& edge) {
+  assert(!edge.is_root() || !EdgeUtils::is_array_element(edge), "invariant");
+  return (const InstanceKlass*)edge.reference_owner_klass();
+}
+
+const Symbol* EdgeUtils::field_name_symbol(const Edge& edge) {
+  assert(!edge.is_root(), "invariant");
+  assert(!is_array_element(edge), "invariant");
+  const int offset = field_offset(edge);
+  const InstanceKlass* ik = field_type(edge);
+  while (ik != NULL) {
+    JavaFieldStream jfs(ik);
+    while (!jfs.done()) {
+      if (offset == jfs.offset()) {
+        return jfs.name();
+      }
+      jfs.next();
+    }
+    ik = (InstanceKlass*)ik->super();
+  }
+  return NULL;
+}
+
+jshort EdgeUtils::field_modifiers(const Edge& edge) {
+  const int offset = field_offset(edge);
+  const InstanceKlass* ik = field_type(edge);
+
+  while (ik != NULL) {
+    JavaFieldStream jfs(ik);
+    while (!jfs.done()) {
+      if (offset == jfs.offset()) {
+        return jfs.access_flags().as_short();
+      }
+      jfs.next();
+    }
+    ik = (InstanceKlass*)ik->super();
+  }
+  return 0;
+}
+
+bool EdgeUtils::is_array_element(const Edge& edge) {
+  assert(!edge.is_root(), "invariant");
+  const oop ref_owner = edge.reference_owner();
+  assert(ref_owner != NULL, "invariant");
+  return ref_owner->is_objArray();
+}
+
+static int array_offset(const Edge& edge) {
+  assert(!edge.is_root(), "invariant");
+  const oop ref_owner = edge.reference_owner();
+  assert(ref_owner != NULL, "invariant");
+  const oop* reference = UnifiedOop::decode(edge.reference());
+  assert(reference != NULL, "invariant");
+  assert(!UnifiedOop::is_narrow(reference), "invariant");
+  assert(ref_owner->is_array(), "invariant");
+  const objArrayOop ref_owner_array = static_cast<const objArrayOop>(ref_owner);
+  const int offset = (int)pointer_delta(reference, ref_owner_array->base(), heapOopSize);
+  assert(offset >= 0 && offset < ref_owner_array->length(), "invariant");
+  return offset;
+}
+
+int EdgeUtils::array_index(const Edge& edge) {
+  return is_array_element(edge) ? array_offset(edge) : 0;
+}
+
+int EdgeUtils::array_size(const Edge& edge) {
+  if (is_array_element(edge)) {
+    const oop ref_owner = edge.reference_owner();
+    assert(ref_owner != NULL, "invariant");
+    assert(ref_owner->is_objArray(), "invariant");
+    return ((objArrayOop)(ref_owner))->length();
+  }
+  return 0;
+}
+
+const Edge* EdgeUtils::root(const Edge& edge) {
+  const Edge* current = &edge;
+  const Edge* parent = current->parent();
+  while (parent != NULL) {
+    current = parent;
+    parent = current->parent();
+  }
+  return current;
+}
+
+// The number of references associated with the leak node;
+// can be viewed as the leak node "context".
+// Used to provide leak context for a "capped/skipped" reference chain.
+static const size_t leak_context = 100;
+
+// The number of references associated with the root node;
+// can be viewed as the root node "context".
+// Used to provide root context for a "capped/skipped" reference chain.
+static const size_t root_context = 100;
+
+// A limit on the reference chain depth to be serialized,
+static const size_t max_ref_chain_depth = leak_context + root_context;
+
+const RoutableEdge* skip_to(const RoutableEdge& edge, size_t skip_length) {
+  const RoutableEdge* current = &edge;
+  const RoutableEdge* parent = current->physical_parent();
+  size_t seek = 0;
+  while (parent != NULL && seek != skip_length) {
+    seek++;
+    current = parent;
+    parent = parent->physical_parent();
+  }
+  return current;
+}
+
+#ifdef ASSERT
+static void validate_skip_target(const RoutableEdge* skip_target) {
+  assert(skip_target != NULL, "invariant");
+  assert(skip_target->distance_to_root() + 1 == root_context, "invariant");
+  assert(skip_target->is_sentinel(), "invariant");
+}
+
+static void validate_new_skip_edge(const RoutableEdge* new_skip_edge, const RoutableEdge* last_skip_edge, size_t adjustment) {
+  assert(new_skip_edge != NULL, "invariant");
+  assert(new_skip_edge->is_skip_edge(), "invariant");
+  if (last_skip_edge != NULL) {
+    const RoutableEdge* const target = skip_to(*new_skip_edge->logical_parent(), adjustment);
+    validate_skip_target(target->logical_parent());
+    return;
+  }
+  assert(last_skip_edge == NULL, "invariant");
+  // only one level of logical indirection
+  validate_skip_target(new_skip_edge->logical_parent());
+}
+#endif // ASSERT
+
+static void install_logical_route(const RoutableEdge* new_skip_edge, size_t skip_target_distance) {
+  assert(new_skip_edge != NULL, "invariant");
+  assert(!new_skip_edge->is_skip_edge(), "invariant");
+  assert(!new_skip_edge->processed(), "invariant");
+  const RoutableEdge* const skip_target = skip_to(*new_skip_edge, skip_target_distance);
+  assert(skip_target != NULL, "invariant");
+  new_skip_edge->set_skip_edge(skip_target);
+  new_skip_edge->set_skip_length(skip_target_distance);
+  assert(new_skip_edge->is_skip_edge(), "invariant");
+  assert(new_skip_edge->logical_parent() == skip_target, "invariant");
+}
+
+static const RoutableEdge* find_last_skip_edge(const RoutableEdge& edge, size_t& distance) {
+  assert(distance == 0, "invariant");
+  const RoutableEdge* current = &edge;
+  while (current != NULL) {
+    if (current->is_skip_edge() && current->skip_edge()->is_sentinel()) {
+      return current;
+    }
+    current = current->physical_parent();
+    ++distance;
+  }
+  return current;
+}
+
+static void collapse_overlapping_chain(const RoutableEdge& edge,
+                                       const RoutableEdge* first_processed_edge,
+                                       size_t first_processed_distance) {
+  assert(first_processed_edge != NULL, "invariant");
+  // first_processed_edge is already processed / written
+  assert(first_processed_edge->processed(), "invariant");
+  assert(first_processed_distance + 1 <= leak_context, "invariant");
+
+  // from this first processed edge, attempt to fetch the last skip edge
+  size_t last_skip_edge_distance = 0;
+  const RoutableEdge* const last_skip_edge = find_last_skip_edge(*first_processed_edge, last_skip_edge_distance);
+  const size_t distance_discovered = first_processed_distance + last_skip_edge_distance + 1;
+
+  if (distance_discovered <= leak_context || (last_skip_edge == NULL && distance_discovered <= max_ref_chain_depth)) {
+    // complete chain can be accommodated without modification
+    return;
+  }
+
+  // backtrack one edge from existing processed edge
+  const RoutableEdge* const new_skip_edge = skip_to(edge, first_processed_distance - 1);
+  assert(new_skip_edge != NULL, "invariant");
+  assert(!new_skip_edge->processed(), "invariant");
+  assert(new_skip_edge->parent() == first_processed_edge, "invariant");
+
+  size_t adjustment = 0;
+  if (last_skip_edge != NULL) {
+    assert(leak_context - 1 > first_processed_distance - 1, "invariant");
+    adjustment = leak_context - first_processed_distance - 1;
+    assert(last_skip_edge_distance + 1 > adjustment, "invariant");
+    install_logical_route(new_skip_edge, last_skip_edge_distance + 1 - adjustment);
+  } else {
+    install_logical_route(new_skip_edge, last_skip_edge_distance + 1 - root_context);
+    new_skip_edge->logical_parent()->set_skip_length(1); // sentinel
+  }
+
+  DEBUG_ONLY(validate_new_skip_edge(new_skip_edge, last_skip_edge, adjustment);)
+}
+
+static void collapse_non_overlapping_chain(const RoutableEdge& edge,
+                                           const RoutableEdge* first_processed_edge,
+                                           size_t first_processed_distance) {
+  assert(first_processed_edge != NULL, "invariant");
+  assert(!first_processed_edge->processed(), "invariant");
+  // this implies that the first "processed" edge is the leak context relative "leaf"
+  assert(first_processed_distance + 1 == leak_context, "invariant");
+
+  const size_t distance_to_root = edge.distance_to_root();
+  if (distance_to_root + 1 <= max_ref_chain_depth) {
+    // complete chain can be accommodated without constructing a skip edge
+    return;
+  }
+
+  install_logical_route(first_processed_edge, distance_to_root + 1 - first_processed_distance - root_context);
+  first_processed_edge->logical_parent()->set_skip_length(1); // sentinel
+
+  DEBUG_ONLY(validate_new_skip_edge(first_processed_edge, NULL, 0);)
+}
+
+static const RoutableEdge* processed_edge(const RoutableEdge& edge, size_t& distance) {
+  assert(distance == 0, "invariant");
+  const RoutableEdge* current = &edge;
+  while (current != NULL && distance < leak_context - 1) {
+    if (current->processed()) {
+      return current;
+    }
+    current = current->physical_parent();
+    ++distance;
+  }
+  assert(distance <= leak_context - 1, "invariant");
+  return current;
+}
+
+/*
+ * Some vocabulary:
+ * -----------
+ * "Context" is an interval in the chain, it is associcated with an edge and it signifies a number of connected edges.
+ * "Processed / written" means an edge that has already been serialized.
+ * "Skip edge" is an edge that contains additional information for logical routing purposes.
+ * "Skip target" is an edge used as a destination for a skip edge
+ */
+void EdgeUtils::collapse_chain(const RoutableEdge& edge) {
+  assert(is_leak_edge(edge), "invariant");
+
+  // attempt to locate an already processed edge inside current leak context (if any)
+  size_t first_processed_distance = 0;
+  const RoutableEdge* const first_processed_edge = processed_edge(edge, first_processed_distance);
+  if (first_processed_edge == NULL) {
+    return;
+  }
+
+  if (first_processed_edge->processed()) {
+    collapse_overlapping_chain(edge, first_processed_edge, first_processed_distance);
+  } else {
+    collapse_non_overlapping_chain(edge, first_processed_edge, first_processed_distance);
+  }
+
+  assert(edge.logical_distance_to_root() + 1 <= max_ref_chain_depth, "invariant");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_LEAKPROFILER_CHAINS_EDGEUTILS_HPP
+#define SHARE_VM_LEAKPROFILER_CHAINS_EDGEUTILS_HPP
+
+#include "memory/allocation.hpp"
+
+class Edge;
+class RoutableEdge;
+class Symbol;
+
+class EdgeUtils : public AllStatic {
+ public:
+  static bool is_leak_edge(const Edge& edge);
+
+  static const Edge* root(const Edge& edge);
+  static bool is_root(const Edge& edge);
+
+  static bool is_array_element(const Edge& edge);
+  static int array_index(const Edge& edge);
+  static int array_size(const Edge& edge);
+
+  static const Symbol* field_name_symbol(const Edge& edge);
+  static jshort field_modifiers(const Edge& edge);
+
+  static void collapse_chain(const RoutableEdge& edge);
+};
+
+#endif // SHARE_VM_LEAKPROFILER_CHAINS_EDGEUTILS_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/chains/objectSampleMarker.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_LEAKPROFILER_CHAINS_OBJECTSAMPLEMARKER_HPP
+#define SHARE_VM_JFR_LEAKPROFILER_CHAINS_OBJECTSAMPLEMARKER_HPP
+
+#include "memory/allocation.hpp"
+#include "oops/markOop.hpp"
+#include "utilities/growableArray.hpp"
+//
+// This class will save the original mark oop of a object sample object.
+// It will then install an "identifier" mark oop to be used for
+// identification purposes in the search for reference chains.
+// The destructor will restore each modified oop with its original mark oop.
+//
+class ObjectSampleMarker : public StackObj {
+ private:
+  class ObjectSampleMarkOop : public ResourceObj {
+    friend class ObjectSampleMarker;
+   private:
+    oop _obj;
+    markOop _mark_oop;
+    ObjectSampleMarkOop(const oop obj,
+                        const markOop mark_oop) : _obj(obj),
+                                                  _mark_oop(mark_oop) {}
+   public:
+    ObjectSampleMarkOop() : _obj(NULL), _mark_oop(NULL) {}
+  };
+
+  GrowableArray<ObjectSampleMarkOop>* _store;
+
+ public:
+  ObjectSampleMarker() :
+       _store(new GrowableArray<ObjectSampleMarkOop>(16)) {}
+  ~ObjectSampleMarker() {
+    assert(_store != NULL, "invariant");
+    // restore the saved, original, markOop for sample objects
+    while (_store->is_nonempty()) {
+      ObjectSampleMarkOop sample_oop = _store->pop();
+      sample_oop._obj->set_mark(sample_oop._mark_oop);
+      assert(sample_oop._obj->mark() == sample_oop._mark_oop, "invariant");
+    }
+  }
+
+  void mark(oop obj) {
+    assert(obj != NULL, "invariant");
+    // save the original markOop
+    _store->push(ObjectSampleMarkOop(obj, obj->mark()));
+    // now we will "poison" the mark word of the sample object
+    // to the intermediate monitor INFLATING state.
+    // This is an "impossible" state during a safepoint,
+    // hence we will use it to quickly identify sample objects
+    // during the reachability search from gc roots.
+    assert(NULL == markOopDesc::INFLATING(), "invariant");
+    obj->set_mark(markOopDesc::INFLATING());
+    assert(NULL == obj->mark(), "invariant");
+  }
+};
+
+#endif // SHARE_VM_JFR_LEAKPROFILER_CHAINS_OBJECTSAMPLEMARKER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/chains/rootSetClosure.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "aot/aotLoader.hpp"
+#include "classfile/classLoaderData.hpp"
+#include "classfile/stringTable.hpp"
+#include "classfile/systemDictionary.hpp"
+#include "gc/shared/strongRootsScope.hpp"
+#include "jfr/leakprofiler/chains/edgeQueue.hpp"
+#include "jfr/leakprofiler/chains/rootSetClosure.hpp"
+#include "jfr/leakprofiler/utilities/saveRestore.hpp"
+#include "jfr/leakprofiler/utilities/unifiedOop.hpp"
+#include "memory/universe.hpp"
+#include "oops/access.inline.hpp"
+#include "prims/jvmtiExport.hpp"
+#include "runtime/jniHandles.inline.hpp"
+#include "runtime/synchronizer.hpp"
+#include "runtime/thread.hpp"
+#include "services/management.hpp"
+#include "utilities/align.hpp"
+
+RootSetClosure::RootSetClosure(EdgeQueue* edge_queue) :
+  _edge_queue(edge_queue) {
+}
+
+void RootSetClosure::do_oop(oop* ref) {
+  assert(ref != NULL, "invariant");
+  // We discard unaligned root references because
+  // our reference tagging scheme will use
+  // the lowest bit in a represented reference
+  // to indicate the reference is narrow.
+  // It is mainly roots delivered via nmethods::do_oops()
+  // that come in unaligned. It should be ok to duck these
+  // since they are supposedly weak.
+  if (!is_aligned(ref, HeapWordSize)) {
+    return;
+  }
+
+  assert(is_aligned(ref, HeapWordSize), "invariant");
+  const oop pointee = *ref;
+  if (pointee != NULL) {
+    closure_impl(ref, pointee);
+  }
+}
+
+void RootSetClosure::do_oop(narrowOop* ref) {
+  assert(ref != NULL, "invariant");
+  assert(is_aligned(ref, sizeof(narrowOop)), "invariant");
+  const oop pointee = RawAccess<>::oop_load(ref);
+  if (pointee != NULL) {
+    closure_impl(UnifiedOop::encode(ref), pointee);
+  }
+}
+
+void RootSetClosure::closure_impl(const oop* reference, const oop pointee) {
+  if (!_edge_queue->is_full())  {
+    _edge_queue->add(NULL, reference);
+  }
+}
+
+void RootSetClosure::add_to_queue(EdgeQueue* edge_queue) {
+  RootSetClosure rs(edge_queue);
+  process_roots(&rs);
+}
+
+class RootSetClosureMarkScope : public MarkScope {
+};
+
+void RootSetClosure::process_roots(OopClosure* closure) {
+  SaveRestoreCLDClaimBits save_restore_cld_claim_bits;
+  RootSetClosureMarkScope mark_scope;
+
+  CLDToOopClosure cldt_closure(closure);
+  ClassLoaderDataGraph::always_strong_cld_do(&cldt_closure);
+  CodeBlobToOopClosure blobs(closure, false);
+  Threads::oops_do(closure, &blobs);
+  ObjectSynchronizer::oops_do(closure);
+  Universe::oops_do(closure);
+  JNIHandles::oops_do(closure);
+  JvmtiExport::oops_do(closure);
+  SystemDictionary::always_strong_oops_do(closure);
+  Management::oops_do(closure);
+  StringTable::oops_do(closure);
+  AOTLoader::oops_do(closure);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/chains/rootSetClosure.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_LEAKPROFILER_CHAINS_ROOTSETCLOSURE_HPP
+#define SHARE_VM_JFR_LEAKPROFILER_CHAINS_ROOTSETCLOSURE_HPP
+
+#include "memory/iterator.hpp"
+#include "oops/oop.hpp"
+
+class EdgeQueue;
+
+class RootSetClosure: public ExtendedOopClosure {
+ private:
+  RootSetClosure(EdgeQueue* edge_queue);
+  EdgeQueue* _edge_queue;
+  void closure_impl(const oop* reference, const oop pointee);
+ public:
+  static void add_to_queue(EdgeQueue* edge_queue);
+  static void process_roots(OopClosure* closure);
+
+  virtual void do_oop(oop* reference);
+  virtual void do_oop(narrowOop* reference);
+};
+
+#endif // SHARE_VM_JFR_LEAKPROFILER_CHAINS_ROOTSETCLOSURE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/jfrEvents.hpp"
+#include "jfr/recorder/jfrRecorder.hpp"
+#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
+#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
+#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
+#include "jfr/leakprofiler/chains/edgeStore.hpp"
+#include "jfr/leakprofiler/chains/objectSampleMarker.hpp"
+#include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp"
+#include "jfr/leakprofiler/checkpoint/objectSampleWriter.hpp"
+#include "jfr/leakprofiler/leakProfiler.hpp"
+#include "jfr/leakprofiler/sampling/objectSample.hpp"
+#include "jfr/leakprofiler/sampling/objectSampler.hpp"
+#include "jfr/leakprofiler/utilities/rootType.hpp"
+#include "jfr/metadata/jfrSerializer.hpp"
+#include "runtime/interfaceSupport.inline.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/thread.inline.hpp"
+
+template <typename SampleProcessor>
+static void do_samples(ObjectSample* sample, const ObjectSample* const end, SampleProcessor& processor) {
+  assert(sample != NULL, "invariant");
+  while (sample != end) {
+    processor.sample_do(sample);
+    sample = sample->next();
+  }
+}
+
+class RootSystemType : public JfrSerializer {
+ public:
+  void serialize(JfrCheckpointWriter& writer) {
+    const u4 nof_root_systems = OldObjectRoot::_number_of_systems;
+    writer.write_count(nof_root_systems);
+    for (u4 i = 0; i < nof_root_systems; ++i) {
+      writer.write_key(i);
+      writer.write(OldObjectRoot::system_description((OldObjectRoot::System)i));
+    }
+  }
+};
+
+class RootType : public JfrSerializer {
+ public:
+  void serialize(JfrCheckpointWriter& writer) {
+    const u4 nof_root_types = OldObjectRoot::_number_of_types;
+    writer.write_count(nof_root_types);
+    for (u4 i = 0; i < nof_root_types; ++i) {
+      writer.write_key(i);
+      writer.write(OldObjectRoot::type_description((OldObjectRoot::Type)i));
+    }
+  }
+};
+
+class CheckpointInstall {
+ private:
+  const JfrCheckpointBlobHandle& _cp;
+ public:
+  CheckpointInstall(const JfrCheckpointBlobHandle& cp) : _cp(cp) {}
+  void sample_do(ObjectSample* sample) {
+    assert(sample != NULL, "invariant");
+    if (!sample->is_dead()) {
+      sample->set_klass_checkpoint(_cp);
+    }
+  }
+};
+
+class CheckpointWrite {
+ private:
+  JfrCheckpointWriter& _writer;
+  const jlong _last_sweep;
+ public:
+  CheckpointWrite(JfrCheckpointWriter& writer, jlong last_sweep) : _writer(writer), _last_sweep(last_sweep) {}
+  void sample_do(ObjectSample* sample) {
+    assert(sample != NULL, "invariant");
+    if (sample->is_alive_and_older_than(_last_sweep)) {
+      if (sample->has_thread_checkpoint()) {
+        const JfrCheckpointBlobHandle& thread_cp = sample->thread_checkpoint();
+        thread_cp->exclusive_write(_writer);
+      }
+      if (sample->has_klass_checkpoint()) {
+        const JfrCheckpointBlobHandle& klass_cp = sample->klass_checkpoint();
+        klass_cp->exclusive_write(_writer);
+      }
+    }
+  }
+};
+
+class CheckpointStateReset {
+ private:
+  const jlong _last_sweep;
+ public:
+  CheckpointStateReset(jlong last_sweep) : _last_sweep(last_sweep) {}
+  void sample_do(ObjectSample* sample) {
+    assert(sample != NULL, "invariant");
+    if (sample->is_alive_and_older_than(_last_sweep)) {
+      if (sample->has_thread_checkpoint()) {
+        const JfrCheckpointBlobHandle& thread_cp = sample->thread_checkpoint();
+        thread_cp->reset_write_state();
+      }
+      if (sample->has_klass_checkpoint()) {
+        const JfrCheckpointBlobHandle& klass_cp = sample->klass_checkpoint();
+        klass_cp->reset_write_state();
+      }
+    }
+  }
+};
+
+class StackTraceWrite {
+ private:
+  JfrStackTraceRepository& _stack_trace_repo;
+  JfrCheckpointWriter& _writer;
+  int _count;
+ public:
+  StackTraceWrite(JfrStackTraceRepository& stack_trace_repo, JfrCheckpointWriter& writer) :
+    _stack_trace_repo(stack_trace_repo), _writer(writer), _count(0) {
+    JfrStacktrace_lock->lock();
+  }
+  ~StackTraceWrite() {
+    assert(JfrStacktrace_lock->owned_by_self(), "invariant");
+    JfrStacktrace_lock->unlock();
+  }
+
+  void sample_do(ObjectSample* sample) {
+    assert(sample != NULL, "invariant");
+    if (!sample->is_dead()) {
+      if (sample->has_stack_trace()) {
+        JfrTraceId::use(sample->klass(), true);
+        _stack_trace_repo.write(_writer, sample->stack_trace_id(), sample->stack_trace_hash());
+        ++_count;
+      }
+    }
+  }
+
+  int count() const {
+    return _count;
+  }
+};
+
+class SampleMark {
+ private:
+  ObjectSampleMarker& _marker;
+  jlong _last_sweep;
+  int _count;
+ public:
+  SampleMark(ObjectSampleMarker& marker, jlong last_sweep) : _marker(marker),
+                                                             _last_sweep(last_sweep),
+                                                             _count(0) {}
+  void sample_do(ObjectSample* sample) {
+    assert(sample != NULL, "invariant");
+    if (sample->is_alive_and_older_than(_last_sweep)) {
+      _marker.mark(sample->object());
+      ++_count;
+    }
+  }
+
+  int count() const {
+    return _count;
+  }
+};
+
+void ObjectSampleCheckpoint::install(JfrCheckpointWriter& writer, bool class_unload, bool resume) {
+  assert(class_unload ? SafepointSynchronize::is_at_safepoint() : LeakProfiler::is_suspended(), "invariant");
+
+  if (!writer.has_data()) {
+    if (!class_unload) {
+      LeakProfiler::resume();
+    }
+    assert(LeakProfiler::is_running(), "invariant");
+    return;
+  }
+
+  assert(writer.has_data(), "invariant");
+  const JfrCheckpointBlobHandle h_cp = writer.checkpoint_blob();
+
+  const ObjectSampler* const object_sampler = LeakProfiler::object_sampler();
+  assert(object_sampler != NULL, "invariant");
+
+  ObjectSample* const last = const_cast<ObjectSample*>(object_sampler->last());
+  const ObjectSample* const last_resolved = object_sampler->last_resolved();
+  CheckpointInstall install(h_cp);
+
+  if (class_unload) {
+    if (last != NULL) {
+      // all samples need the class unload information
+      do_samples(last, NULL, install);
+    }
+    assert(LeakProfiler::is_running(), "invariant");
+    return;
+  }
+
+  // only new samples since last resolved checkpoint
+  if (last != last_resolved) {
+    do_samples(last, last_resolved, install);
+    if (resume) {
+      const_cast<ObjectSampler*>(object_sampler)->set_last_resolved(last);
+    }
+  }
+  assert(LeakProfiler::is_suspended(), "invariant");
+  if (resume) {
+    LeakProfiler::resume();
+    assert(LeakProfiler::is_running(), "invariant");
+  }
+}
+
+void ObjectSampleCheckpoint::write(const EdgeStore* edge_store, bool emit_all, Thread* thread) {
+  assert(edge_store != NULL, "invariant");
+  assert(thread != NULL, "invariant");
+  static bool types_registered = false;
+  if (!types_registered) {
+    JfrSerializer::register_serializer(TYPE_OLDOBJECTROOTSYSTEM, false, true, new RootSystemType());
+    JfrSerializer::register_serializer(TYPE_OLDOBJECTROOTTYPE, false, true, new RootType());
+    types_registered = true;
+  }
+  const ObjectSampler* const object_sampler = LeakProfiler::object_sampler();
+  assert(object_sampler != NULL, "invariant");
+  const jlong last_sweep = emit_all ? max_jlong : object_sampler->last_sweep().value();
+  ObjectSample* const last = const_cast<ObjectSample*>(object_sampler->last());
+  {
+    JfrCheckpointWriter writer(false, false, thread);
+    CheckpointWrite checkpoint_write(writer, last_sweep);
+    do_samples(last, NULL, checkpoint_write);
+  }
+  CheckpointStateReset state_reset(last_sweep);
+  do_samples(last, NULL, state_reset);
+  if (!edge_store->is_empty()) {
+    // java object and chain representations
+    JfrCheckpointWriter writer(false, true, thread);
+    ObjectSampleWriter osw(writer, edge_store);
+    edge_store->iterate_edges(osw);
+  }
+}
+
+WriteObjectSampleStacktrace::WriteObjectSampleStacktrace(JfrStackTraceRepository& repo) :
+  _stack_trace_repo(repo) {
+}
+
+bool WriteObjectSampleStacktrace::process() {
+  assert(SafepointSynchronize::is_at_safepoint(), "invariant");
+  if (!LeakProfiler::is_running()) {
+    return true;
+  }
+  // Suspend the LeakProfiler subsystem
+  // to ensure stable samples even
+  // after we return from the safepoint.
+  LeakProfiler::suspend();
+  assert(!LeakProfiler::is_running(), "invariant");
+  assert(LeakProfiler::is_suspended(), "invariant");
+
+  const ObjectSampler* object_sampler = LeakProfiler::object_sampler();
+  assert(object_sampler != NULL, "invariant");
+  assert(LeakProfiler::is_suspended(), "invariant");
+
+  ObjectSample* const last = const_cast<ObjectSample*>(object_sampler->last());
+  const ObjectSample* const last_resolved = object_sampler->last_resolved();
+  if (last == last_resolved) {
+    assert(LeakProfiler::is_suspended(), "invariant");
+    return true;
+  }
+
+  JfrCheckpointWriter writer(false, true, Thread::current());
+  const JfrCheckpointContext ctx = writer.context();
+
+  writer.write_type(TYPE_STACKTRACE);
+  const jlong count_offset = writer.reserve(sizeof(u4));
+
+  int count = 0;
+  {
+    StackTraceWrite stack_trace_write(_stack_trace_repo, writer); // JfrStacktrace_lock
+    do_samples(last, last_resolved, stack_trace_write);
+    count = stack_trace_write.count();
+  }
+  if (count == 0) {
+    writer.set_context(ctx);
+    assert(LeakProfiler::is_suspended(), "invariant");
+    return true;
+  }
+  assert(count > 0, "invariant");
+  writer.write_count((u4)count, count_offset);
+  JfrStackTraceRepository::write_metadata(writer);
+
+  ObjectSampleCheckpoint::install(writer, false, false);
+  assert(LeakProfiler::is_suspended(), "invariant");
+  return true;
+}
+
+int ObjectSampleCheckpoint::mark(ObjectSampleMarker& marker, bool emit_all) {
+  const ObjectSampler* object_sampler = LeakProfiler::object_sampler();
+  assert(object_sampler != NULL, "invariant");
+  ObjectSample* const last = const_cast<ObjectSample*>(object_sampler->last());
+  if (last == NULL) {
+    return 0;
+  }
+  const jlong last_sweep = emit_all ? max_jlong : object_sampler->last_sweep().value();
+  SampleMark mark(marker, last_sweep);
+  do_samples(last, NULL, mark);
+  return mark.count();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_LEAKPROFILER_CHECKPOINT_OBJECTSAMPLECHECKPOINT_HPP
+#define SHARE_VM_LEAKPROFILER_CHECKPOINT_OBJECTSAMPLECHECKPOINT_HPP
+
+#include "memory/allocation.hpp"
+#include "utilities/exceptions.hpp"
+
+class EdgeStore;
+class JfrStackTraceRepository;
+class JfrCheckpointWriter;
+class ObjectSampleMarker;
+
+class ObjectSampleCheckpoint : AllStatic {
+ public:
+  static void install(JfrCheckpointWriter& writer, bool class_unload, bool resume);
+  static void write(const EdgeStore* edge_store, bool emit_all, Thread* thread);
+  static int mark(ObjectSampleMarker& marker, bool emit_all);
+};
+
+class WriteObjectSampleStacktrace : public StackObj {
+ private:
+  JfrStackTraceRepository& _stack_trace_repo;
+ public:
+  WriteObjectSampleStacktrace(JfrStackTraceRepository& repo);
+  bool process();
+};
+
+#endif // SHARE_VM_LEAKPROFILER_CHECKPOINT_OBJECTSAMPLECHECKPOINT_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleDescription.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/javaClasses.hpp"
+#include "classfile/symbolTable.hpp"
+#include "classfile/systemDictionary.hpp"
+#include "jfr/leakprofiler/checkpoint/objectSampleDescription.hpp"
+#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
+#include "oops/oop.inline.hpp"
+#include "runtime/thread.hpp"
+#include "utilities/ostream.hpp"
+
+static Symbol* symbol_size = NULL;
+
+ObjectDescriptionBuilder::ObjectDescriptionBuilder() {
+  reset();
+}
+
+void ObjectDescriptionBuilder::write_int(jint value) {
+  char buf[20];
+  jio_snprintf(buf, sizeof(buf), "%d", value);
+  write_text(buf);
+}
+
+void ObjectDescriptionBuilder::write_text(const char* text) {
+  if (_index == sizeof(_buffer) - 2) {
+    return;
+  }
+  while (*text != '\0' && _index < sizeof(_buffer) - 2) {
+    _buffer[_index] = *text;
+    _index++;
+    text++;
+  }
+  assert(_index < sizeof(_buffer) - 1, "index should not exceed buffer size");
+  // add ellipsis if we reached end
+  if (_index == sizeof(_buffer) - 2) {
+    _buffer[_index-3] = '.';
+    _buffer[_index-2] = '.';
+    _buffer[_index-1] = '.';
+  }
+  // terminate string
+  _buffer[_index] = '\0';
+}
+
+void ObjectDescriptionBuilder::reset() {
+  _index = 0;
+  _buffer[0] = '\0';
+}
+
+void ObjectDescriptionBuilder::print_description(outputStream* out) {
+  out->print("%s", (const char*)_buffer);
+}
+
+const char* ObjectDescriptionBuilder::description() {
+  if (_buffer[0] == '\0') {
+    return NULL;
+  }
+  const size_t len = strlen(_buffer);
+  char* copy = NEW_RESOURCE_ARRAY(char, len + 1);
+  assert(copy != NULL, "invariant");
+  strncpy(copy, _buffer, len + 1);
+  return copy;
+}
+
+ObjectSampleDescription::ObjectSampleDescription(oop object) :
+  _object(object) {
+}
+
+void ObjectSampleDescription::ensure_initialized() {
+  if (symbol_size == NULL) {
+    symbol_size = SymbolTable::new_permanent_symbol("size", Thread::current());
+  }
+}
+
+void ObjectSampleDescription::print_description(outputStream* out) {
+  write_object_to_buffer();
+  _description.print_description(out);
+}
+
+const char* ObjectSampleDescription::description() {
+  write_object_to_buffer();
+  return _description.description();
+}
+
+void ObjectSampleDescription::write_text(const char* text) {
+  _description.write_text(text);
+}
+
+void ObjectSampleDescription::write_int(jint value) {
+  _description.write_int(value);
+}
+
+void ObjectSampleDescription::write_object_to_buffer() {
+  ensure_initialized();
+  _description.reset();
+  write_object_details();
+}
+
+void ObjectSampleDescription::write_object_details() {
+  Klass* klass = _object->klass();
+  Symbol* class_name = klass->name();
+  jint size;
+
+  if (_object->is_a(SystemDictionary::Class_klass())) {
+    write_class_name();
+    return;
+  }
+
+  if (_object->is_a(SystemDictionary::Thread_klass())) {
+    write_thread_name();
+    return;
+  }
+
+  if (_object->is_a(SystemDictionary::ThreadGroup_klass())) {
+    write_thread_group_name();
+    return;
+  }
+
+  if (read_int_size(&size)) {
+    write_size(size);
+    return;
+  }
+}
+
+void ObjectSampleDescription::write_class_name() {
+  assert(_object->is_a(SystemDictionary::Class_klass()), "invariant");
+  const Klass* const k = java_lang_Class::as_Klass(_object);
+  if (k == NULL) {
+    // might represent a primitive
+    const Klass* const ak = java_lang_Class::array_klass_acquire(_object);
+    // If ak is NULL, this is most likely a mirror associated with a
+    // jvmti redefine/retransform scratch klass. We can't get any additional
+    // information from it.
+    if (ak != NULL) {
+      write_text(type2name(java_lang_Class::primitive_type(_object)));
+    }
+    return;
+  }
+
+  if (k->is_instance_klass()) {
+    const InstanceKlass* ik = InstanceKlass::cast(k);
+    if (ik->is_anonymous()) {
+      return;
+    }
+    assert(!ik->is_anonymous(), "invariant");
+    const Symbol* name = ik->name();
+    if (name != NULL) {
+      write_text("Class Name: ");
+      write_text(name->as_klass_external_name());
+    }
+  }
+}
+
+void ObjectSampleDescription::write_thread_group_name() {
+  assert(_object->is_a(SystemDictionary::ThreadGroup_klass()), "invariant");
+  const char* tg_name = java_lang_ThreadGroup::name(_object);
+  if (tg_name != NULL) {
+    write_text("Thread Group: ");
+    write_text(tg_name);
+  }
+}
+
+void ObjectSampleDescription::write_thread_name() {
+  assert(_object->is_a(SystemDictionary::Thread_klass()), "invariant");
+  oop name = java_lang_Thread::name(_object);
+  if (name != NULL) {
+    char* p = java_lang_String::as_utf8_string(name);
+    if (p != NULL) {
+      write_text("Thread Name: ");
+      write_text(p);
+    }
+  }
+}
+
+void ObjectSampleDescription::write_size(jint size) {
+  if (size >= 0) {
+    write_text("Size: ");
+    write_int(size);
+  }
+}
+
+bool ObjectSampleDescription::read_int_size(jint* result_size) {
+  fieldDescriptor fd;
+  Klass* klass = _object->klass();
+  if (klass->is_instance_klass()) {
+    InstanceKlass* ik = InstanceKlass::cast(klass);
+    if (ik->find_field(symbol_size, vmSymbols::int_signature(), false, &fd) != NULL) {
+       jint size = _object->int_field(fd.offset());
+       *result_size = size;
+       return true;
+    }
+  }
+  return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleDescription.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_LEAKPROFILER_CHECKPOINT_OBJECTSAMPLEDESCRIPTION_HPP
+#define SHARE_VM_LEAKPROFILER_CHECKPOINT_OBJECTSAMPLEDESCRIPTION_HPP
+
+#define OBJECT_SAMPLE_DESCRIPTION_BUFFER_SIZE 100
+
+#include "memory/allocation.hpp"
+
+class outputStream;
+
+class ObjectDescriptionBuilder : public StackObj {
+private:
+  char _buffer[OBJECT_SAMPLE_DESCRIPTION_BUFFER_SIZE];
+  size_t _index;
+
+public:
+  ObjectDescriptionBuilder();
+
+  void write_text(const char* text);
+  void write_int(jint value);
+  void reset();
+
+  void print_description(outputStream* out);
+  const char* description();
+};
+
+class ObjectSampleDescription : public StackObj {
+private:
+  ObjectDescriptionBuilder _description;
+  oop _object;
+
+  void write_text(const char* text);
+  void write_int(jint value);
+
+  void write_object_details();
+  void write_size(jint size);
+  void write_thread_name();
+  void write_thread_group_name();
+  void write_class_name();
+  void write_object_to_buffer();
+  bool is_class(Symbol* s1, const char* s2);
+  void ensure_initialized();
+  bool read_int_size(jint* result);
+
+public:
+  ObjectSampleDescription(oop object);
+  void print_description(outputStream* out);
+  const char* description();
+};
+
+#endif // SHARE_VM_LEAKPROFILER_CHECKPOINT_OBJECTSAMPLEDESCRIPTION_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,615 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfrfiles/jfrTypes.hpp"
+#include "jfr/leakprofiler/chains/edge.hpp"
+#include "jfr/leakprofiler/chains/edgeStore.hpp"
+#include "jfr/leakprofiler/chains/edgeUtils.hpp"
+#include "jfr/leakprofiler/checkpoint/objectSampleDescription.hpp"
+#include "jfr/leakprofiler/checkpoint/objectSampleWriter.hpp"
+#include "jfr/leakprofiler/checkpoint/rootResolver.hpp"
+#include "jfr/leakprofiler/sampling/objectSampler.hpp"
+#include "jfr/leakprofiler/utilities/rootType.hpp"
+#include "jfr/leakprofiler/utilities/unifiedOop.hpp"
+#include "jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp"
+#include "jfr/recorder/checkpoint/types/jfrTypeSetWriter.hpp"
+#include "oops/oop.inline.hpp"
+#include "oops/symbol.hpp"
+#include "utilities/growableArray.hpp"
+
+template <typename Data>
+class ObjectSampleAuxInfo : public ResourceObj {
+ public:
+  Data _data;
+  traceid _id;
+  ObjectSampleAuxInfo() : _data(), _id(0) {}
+};
+
+class ObjectSampleArrayData {
+ public:
+  int _array_size;
+  int _array_index;
+  ObjectSampleArrayData() : _array_size(0), _array_index(0) {}
+};
+
+class ObjectSampleFieldInfo : public ResourceObj {
+ public:
+  const Symbol* _field_name_symbol;
+  jshort _field_modifiers;
+  ObjectSampleFieldInfo() : _field_name_symbol(NULL), _field_modifiers(0) {}
+};
+
+class ObjectSampleRootDescriptionData {
+ public:
+  const Edge* _root_edge;
+  const char* _description;
+  OldObjectRoot::System _system;
+  OldObjectRoot::Type _type;
+  ObjectSampleRootDescriptionData() : _root_edge(NULL),
+                                      _description(NULL),
+                                      _system(OldObjectRoot::_system_undetermined),
+                                      _type(OldObjectRoot::_type_undetermined) {}
+};
+
+class OldObjectSampleData {
+ public:
+  oop _object;
+  traceid _reference_id;
+};
+
+class ReferenceData {
+ public:
+  traceid _field_info_id;
+  traceid _array_info_id;
+  traceid _old_object_sample_id;
+  size_t  _skip;
+};
+
+static int initial_storage_size = 16;
+
+template <typename Data>
+class SampleSet : public ResourceObj {
+ private:
+  GrowableArray<Data>* _storage;
+ public:
+  SampleSet() : _storage(NULL) {}
+
+  traceid store(Data data) {
+    assert(data != NULL, "invariant");
+    if (_storage == NULL) {
+      _storage = new GrowableArray<Data>(initial_storage_size);
+    }
+    assert(_storage != NULL, "invariant");
+    assert(_storage->find(data) == -1, "invariant");
+    _storage->append(data);
+    return data->_id;
+  }
+
+  size_t size() const {
+    return _storage != NULL ? (size_t)_storage->length() : 0;
+  }
+
+  template <typename Functor>
+  void iterate(Functor& functor) {
+    if (_storage != NULL) {
+      for (int i = 0; i < _storage->length(); ++i) {
+        functor(_storage->at(i));
+      }
+    }
+  }
+
+  const GrowableArray<Data>& storage() const {
+    return *_storage;
+  }
+};
+
+typedef ObjectSampleAuxInfo<ObjectSampleArrayData> ObjectSampleArrayInfo;
+typedef ObjectSampleAuxInfo<ObjectSampleRootDescriptionData> ObjectSampleRootDescriptionInfo;
+typedef ObjectSampleAuxInfo<OldObjectSampleData> OldObjectSampleInfo;
+typedef ObjectSampleAuxInfo<ReferenceData> ReferenceInfo;
+
+class FieldTable : public ResourceObj {
+  template <typename,
+            typename,
+            template<typename, typename> class,
+            typename,
+            size_t>
+  friend class HashTableHost;
+  typedef HashTableHost<const ObjectSampleFieldInfo*, traceid, Entry, FieldTable, 109> FieldInfoTable;
+ public:
+  typedef FieldInfoTable::HashEntry FieldInfoEntry;
+
+ private:
+  static traceid _field_id_counter;
+  FieldInfoTable* _table;
+
+  void assign_id(FieldInfoEntry* entry) {
+    assert(entry != NULL, "invariant");
+    entry->set_id(++_field_id_counter);
+  }
+
+  bool equals(const ObjectSampleFieldInfo* query, uintptr_t hash, const FieldInfoEntry* entry) {
+    assert(hash == entry->hash(), "invariant");
+    assert(query != NULL, "invariant");
+    const ObjectSampleFieldInfo* stored = entry->literal();
+    assert(stored != NULL, "invariant");
+    assert(stored->_field_name_symbol->identity_hash() == query->_field_name_symbol->identity_hash(), "invariant");
+    return stored->_field_modifiers == query->_field_modifiers;
+  }
+
+ public:
+  FieldTable() : _table(new FieldInfoTable(this)) {}
+  ~FieldTable() {
+    assert(_table != NULL, "invariant");
+    delete _table;
+  }
+
+  traceid store(const ObjectSampleFieldInfo* field_info) {
+    assert(field_info != NULL, "invariant");
+    const FieldInfoEntry& entry =_table->lookup_put(field_info,
+                                                    field_info->_field_name_symbol->identity_hash());
+    return entry.id();
+  }
+
+  size_t size() const {
+    return _table->cardinality();
+  }
+
+  template <typename T>
+  void iterate(T& functor) const {
+    _table->iterate_entry<T>(functor);
+  }
+};
+
+traceid FieldTable::_field_id_counter = 0;
+
+typedef SampleSet<const OldObjectSampleInfo*> SampleInfo;
+typedef SampleSet<const ReferenceInfo*> RefInfo;
+typedef SampleSet<const ObjectSampleArrayInfo*> ArrayInfo;
+typedef SampleSet<const ObjectSampleRootDescriptionInfo*> RootDescriptionInfo;
+
+static SampleInfo* sample_infos = NULL;
+static RefInfo* ref_infos = NULL;
+static ArrayInfo* array_infos = NULL;
+static FieldTable* field_infos = NULL;
+static RootDescriptionInfo* root_infos = NULL;
+
+int __write_sample_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* si) {
+  assert(writer != NULL, "invariant");
+  assert(si != NULL, "invariant");
+  const OldObjectSampleInfo* const oosi = (const OldObjectSampleInfo*)si;
+  oop object = oosi->_data._object;
+  assert(object != NULL, "invariant");
+  writer->write(oosi->_id);
+  writer->write((u8)(const HeapWord*)object);
+  writer->write(const_cast<const Klass*>(object->klass()));
+  ObjectSampleDescription od(object);
+  writer->write(od.description());
+  writer->write(oosi->_data._reference_id);
+  return 1;
+}
+
+typedef JfrArtifactWriterImplHost<const OldObjectSampleInfo*, __write_sample_info__> SampleWriterImpl;
+typedef JfrArtifactWriterHost<SampleWriterImpl, TYPE_OLDOBJECT> SampleWriter;
+
+static void write_sample_infos(JfrCheckpointWriter& writer) {
+  if (sample_infos != NULL) {
+    SampleWriter sw(&writer, NULL, false);
+    sample_infos->iterate(sw);
+  }
+}
+
+int __write_reference_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* ri) {
+  assert(writer != NULL, "invariant");
+  assert(ri != NULL, "invariant");
+  const ReferenceInfo* const ref_info = (const ReferenceInfo*)ri;
+  writer->write(ref_info->_id);
+  writer->write(ref_info->_data._array_info_id);
+  writer->write(ref_info->_data._field_info_id);
+  writer->write(ref_info->_data._old_object_sample_id);
+  writer->write<s4>((s4)ref_info->_data._skip);
+  return 1;
+}
+
+typedef JfrArtifactWriterImplHost<const ReferenceInfo*, __write_reference_info__> ReferenceWriterImpl;
+typedef JfrArtifactWriterHost<ReferenceWriterImpl, TYPE_REFERENCE> ReferenceWriter;
+
+static void write_reference_infos(JfrCheckpointWriter& writer) {
+  if (ref_infos != NULL) {
+    ReferenceWriter rw(&writer, NULL, false);
+    ref_infos->iterate(rw);
+  }
+}
+
+int __write_array_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* ai) {
+  assert(writer != NULL, "invariant");
+  assert(ai != NULL, "invariant");
+  const ObjectSampleArrayInfo* const osai = (const ObjectSampleArrayInfo*)ai;
+  writer->write(osai->_id);
+  writer->write(osai->_data._array_size);
+  writer->write(osai->_data._array_index);
+  return 1;
+}
+
+static traceid get_array_info_id(const Edge& edge, traceid id) {
+  if (edge.is_root() || !EdgeUtils::is_array_element(edge)) {
+    return 0;
+  }
+  if (array_infos == NULL) {
+    array_infos = new ArrayInfo();
+  }
+  assert(array_infos != NULL, "invariant");
+
+  ObjectSampleArrayInfo* const osai = new ObjectSampleArrayInfo();
+  assert(osai != NULL, "invariant");
+  osai->_id = id;
+  osai->_data._array_size = EdgeUtils::array_size(edge);
+  osai->_data._array_index = EdgeUtils::array_index(edge);
+  return array_infos->store(osai);
+}
+
+typedef JfrArtifactWriterImplHost<const ObjectSampleArrayInfo*, __write_array_info__> ArrayWriterImpl;
+typedef JfrArtifactWriterHost<ArrayWriterImpl, TYPE_OLDOBJECTARRAY> ArrayWriter;
+
+static void write_array_infos(JfrCheckpointWriter& writer) {
+  if (array_infos != NULL) {
+    ArrayWriter aw(&writer, NULL, false);
+    array_infos->iterate(aw);
+  }
+}
+
+int __write_field_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* fi) {
+  assert(writer != NULL, "invariant");
+  assert(fi != NULL, "invariant");
+  const FieldTable::FieldInfoEntry* field_info_entry = (const FieldTable::FieldInfoEntry*)fi;
+  writer->write(field_info_entry->id());
+  const ObjectSampleFieldInfo* const osfi = field_info_entry->literal();
+  writer->write(osfi->_field_name_symbol->as_C_string());
+  writer->write(osfi->_field_modifiers);
+  return 1;
+}
+
+static traceid get_field_info_id(const Edge& edge) {
+  if (edge.is_root()) {
+    return 0;
+  }
+
+  assert(!EdgeUtils::is_array_element(edge), "invariant");
+  const Symbol* const field_name_symbol = EdgeUtils::field_name_symbol(edge);
+  if (field_name_symbol == NULL) {
+    return 0;
+  }
+
+  if (field_infos == NULL) {
+    field_infos = new FieldTable();
+  }
+  assert(field_infos != NULL, "invariant");
+
+  ObjectSampleFieldInfo* const osfi = new ObjectSampleFieldInfo();
+  assert(osfi != NULL, "invariant");
+  osfi->_field_name_symbol = field_name_symbol;
+  osfi->_field_modifiers = EdgeUtils::field_modifiers(edge);
+  return field_infos->store(osfi);
+}
+
+typedef JfrArtifactWriterImplHost<const FieldTable::FieldInfoEntry*, __write_field_info__> FieldWriterImpl;
+typedef JfrArtifactWriterHost<FieldWriterImpl, TYPE_OLDOBJECTFIELD> FieldWriter;
+
+static void write_field_infos(JfrCheckpointWriter& writer) {
+  if (field_infos != NULL) {
+    FieldWriter fw(&writer, NULL, false);
+    field_infos->iterate(fw);
+  }
+}
+
+static const char* description(const ObjectSampleRootDescriptionInfo* osdi) {
+  assert(osdi != NULL, "invariant");
+
+  if (osdi->_data._description == NULL) {
+    return NULL;
+  }
+
+  ObjectDescriptionBuilder description;
+  if (osdi->_data._system == OldObjectRoot::_threads) {
+    description.write_text("Thread Name: ");
+  }
+  description.write_text(osdi->_data._description);
+  return description.description();
+}
+
+int __write_root_description_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* di) {
+  assert(writer != NULL, "invariant");
+  assert(di != NULL, "invariant");
+  const ObjectSampleRootDescriptionInfo* const osdi = (const ObjectSampleRootDescriptionInfo*)di;
+  writer->write(osdi->_id);
+  writer->write(description(osdi));
+  writer->write<u8>(osdi->_data._system);
+  writer->write<u8>(osdi->_data._type);
+  return 1;
+}
+
+static traceid get_root_description_info_id(const Edge& edge, traceid id) {
+  assert(edge.is_root(), "invariant");
+  if (EdgeUtils::is_leak_edge(edge)) {
+    return 0;
+  }
+
+  if (root_infos == NULL) {
+    root_infos = new RootDescriptionInfo();
+  }
+  assert(root_infos != NULL, "invariant");
+  ObjectSampleRootDescriptionInfo* const oodi = new ObjectSampleRootDescriptionInfo();
+  oodi->_id = id;
+  oodi->_data._root_edge = &edge;
+  return root_infos->store(oodi);
+}
+
+typedef JfrArtifactWriterImplHost<const ObjectSampleRootDescriptionInfo*, __write_root_description_info__> RootDescriptionWriterImpl;
+typedef JfrArtifactWriterHost<RootDescriptionWriterImpl, TYPE_OLDOBJECTGCROOT> RootDescriptionWriter;
+
+
+int _edge_reference_compare_(uintptr_t lhs, uintptr_t rhs) {
+  return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0;
+}
+
+int _root_desc_compare_(const ObjectSampleRootDescriptionInfo*const & lhs, const ObjectSampleRootDescriptionInfo* const& rhs) {
+  const uintptr_t lhs_ref = (uintptr_t)lhs->_data._root_edge->reference();
+  const uintptr_t rhs_ref = (uintptr_t)rhs->_data._root_edge->reference();
+  return _edge_reference_compare_(lhs_ref, rhs_ref);
+}
+
+static int find_sorted(const RootCallbackInfo& callback_info,
+                       const GrowableArray<const ObjectSampleRootDescriptionInfo*>* arr,
+                       int length,
+                       bool& found) {
+  assert(arr != NULL, "invariant");
+  assert(length >= 0, "invariant");
+  assert(length <= arr->length(), "invariant");
+
+  found = false;
+  int min = 0;
+  int max = length;
+  while (max >= min) {
+    const int mid = (int)(((uint)max + min) / 2);
+    int diff = _edge_reference_compare_((uintptr_t)callback_info._high,
+                                        (uintptr_t)arr->at(mid)->_data._root_edge->reference());
+    if (diff > 0) {
+      min = mid + 1;
+    } else if (diff < 0) {
+      max = mid - 1;
+    } else {
+      found = true;
+      return mid;
+    }
+  }
+  return min;
+}
+
+class RootResolutionSet : public ResourceObj, public RootCallback {
+ private:
+  GrowableArray<const ObjectSampleRootDescriptionInfo*>* _unresolved_roots;
+
+  const uintptr_t high() const {
+    return (uintptr_t)_unresolved_roots->last()->_data._root_edge->reference();
+  }
+
+  const uintptr_t low() const {
+    return (uintptr_t)_unresolved_roots->first()->_data._root_edge->reference();
+  }
+
+  bool in_set_address_range(const RootCallbackInfo& callback_info) const {
+    assert(callback_info._low == NULL, "invariant");
+    const uintptr_t addr = (uintptr_t)callback_info._high;
+    return low() <= addr && high() >= addr;
+  }
+
+  int compare_to_range(const RootCallbackInfo& callback_info) const {
+    assert(callback_info._high != NULL, "invariant");
+    assert(callback_info._low != NULL, "invariant");
+
+    for (int i = 0; i < _unresolved_roots->length(); ++i) {
+      const uintptr_t ref_addr = (uintptr_t)_unresolved_roots->at(i)->_data._root_edge->reference();
+      if ((uintptr_t)callback_info._low <= ref_addr && (uintptr_t)callback_info._high >= ref_addr) {
+        return i;
+      }
+    }
+    return -1;
+  }
+
+  int exact(const RootCallbackInfo& callback_info) const {
+    assert(callback_info._high != NULL, "invariant");
+    assert(in_set_address_range(callback_info), "invariant");
+
+    bool found;
+    const int idx = find_sorted(callback_info, _unresolved_roots, _unresolved_roots->length(), found);
+    return found ? idx : -1;
+  }
+
+  bool resolve_root(const RootCallbackInfo& callback_info, int idx) const {
+    assert(idx >= 0, "invariant");
+    assert(idx < _unresolved_roots->length(), "invariant");
+
+    ObjectSampleRootDescriptionInfo* const desc =
+      const_cast<ObjectSampleRootDescriptionInfo*>(_unresolved_roots->at(idx));
+    assert(desc != NULL, "invariant");
+    assert((uintptr_t)callback_info._high == (uintptr_t)desc->_data._root_edge->reference(), "invariant");
+
+    desc->_data._system = callback_info._system;
+    desc->_data._type = callback_info._type;
+
+    if (callback_info._system == OldObjectRoot::_threads) {
+      const JavaThread* jt = (const JavaThread*)callback_info._context;
+      assert(jt != NULL, "invariant");
+      desc->_data._description = jt->name();
+    }
+
+    _unresolved_roots->remove_at(idx);
+    return _unresolved_roots->is_empty();
+  }
+
+ public:
+  RootResolutionSet(RootDescriptionInfo* info) : _unresolved_roots(NULL) {
+    assert(info != NULL, "invariant");
+    // construct a sorted copy
+    const GrowableArray<const ObjectSampleRootDescriptionInfo*>& info_storage = info->storage();
+    const int length = info_storage.length();
+    _unresolved_roots = new GrowableArray<const ObjectSampleRootDescriptionInfo*>(length);
+    assert(_unresolved_roots != NULL, "invariant");
+
+    for (int i = 0; i < length; ++i) {
+      _unresolved_roots->insert_sorted<_root_desc_compare_>(info_storage.at(i));
+    }
+  }
+
+  bool process(const RootCallbackInfo& callback_info) {
+    if (NULL == callback_info._low) {
+      if (in_set_address_range(callback_info)) {
+        const int idx = exact(callback_info);
+        return idx == -1 ? false : resolve_root(callback_info, idx);
+      }
+      return false;
+    }
+    assert(callback_info._low != NULL, "invariant");
+    const int idx = compare_to_range(callback_info);
+    return idx == -1 ? false : resolve_root(callback_info, idx);
+  }
+
+  int entries() const {
+    return _unresolved_roots->length();
+  }
+
+  const void* at(int idx) const {
+    assert(idx >= 0, "invariant");
+    assert(idx < _unresolved_roots->length(), "invariant");
+    return _unresolved_roots->at(idx)->_data._root_edge->reference();
+  }
+};
+
+static void write_root_descriptors(JfrCheckpointWriter& writer) {
+  if (root_infos != NULL) {
+    // resolve roots
+    RootResolutionSet rrs(root_infos);
+    RootResolver::resolve(rrs);
+    // write roots
+    RootDescriptionWriter rw(&writer, NULL, false);
+    root_infos->iterate(rw);
+  }
+}
+
+static void add_old_object_sample_info(const Edge* current, traceid id) {
+  assert(current != NULL, "invariant");
+  if (sample_infos == NULL) {
+    sample_infos = new SampleInfo();
+  }
+  assert(sample_infos != NULL, "invariant");
+  OldObjectSampleInfo* const oosi = new OldObjectSampleInfo();
+  assert(oosi != NULL, "invariant");
+  oosi->_id = id;
+  oosi->_data._object = current->pointee();
+  oosi->_data._reference_id = current->is_root() ? (traceid)0 : id;
+  sample_infos->store(oosi);
+}
+
+static void add_reference_info(const RoutableEdge* current, traceid id, traceid parent_id) {
+  assert(current != NULL, "invariant");
+  if (ref_infos == NULL) {
+    ref_infos = new RefInfo();
+  }
+
+  assert(ref_infos != NULL, "invariant");
+  ReferenceInfo* const ri = new ReferenceInfo();
+  assert(ri != NULL, "invariant");
+
+  ri->_id = id;
+  ri->_data._array_info_id =  !current->is_skip_edge() ? get_array_info_id(*current, id) : 0;
+  ri->_data._field_info_id = ri->_data._array_info_id == 0 && !current->is_skip_edge() ?
+                               get_field_info_id(*current) : (traceid)0;
+  ri->_data._old_object_sample_id = parent_id;
+  ri->_data._skip = current->skip_length();
+  ref_infos->store(ri);
+}
+
+static traceid add_root_info(const Edge* root, traceid id) {
+  assert(root != NULL, "invariant");
+  assert(root->is_root(), "invariant");
+  return get_root_description_info_id(*root, id);
+}
+
+void ObjectSampleWriter::write(const RoutableEdge* edge) {
+  assert(edge != NULL, "invariant");
+  const traceid id = _store->get_id(edge);
+  add_old_object_sample_info(edge, id);
+  const RoutableEdge* parent = edge->logical_parent();
+  if (parent != NULL) {
+    add_reference_info(edge, id, _store->get_id(parent));
+  } else {
+    assert(edge->is_root(), "invariant");
+    add_root_info(edge, id);
+  }
+}
+
+ObjectSampleWriter::ObjectSampleWriter(JfrCheckpointWriter& writer, const EdgeStore* store) :
+  _writer(writer),
+  _store(store) {
+  assert(store != NULL, "invariant");
+  assert(store->number_of_entries() > 0, "invariant");
+  sample_infos = NULL;
+  ref_infos = NULL;
+  array_infos = NULL;
+  field_infos = NULL;
+  root_infos = NULL;
+}
+
+ObjectSampleWriter::~ObjectSampleWriter() {
+  write_sample_infos(_writer);
+  write_reference_infos(_writer);
+  write_array_infos(_writer);
+  write_field_infos(_writer);
+  write_root_descriptors(_writer);
+}
+
+void ObjectSampleWriter::write_chain(const RoutableEdge& edge) {
+  assert(EdgeUtils::is_leak_edge(edge), "invariant");
+  if (edge.processed()) {
+    return;
+  }
+  EdgeUtils::collapse_chain(edge);
+  const RoutableEdge* current = &edge;
+  while (current != NULL) {
+    if (current->processed()) {
+      return;
+    }
+    write(current);
+    current->set_processed();
+    current = current->logical_parent();
+  }
+}
+
+bool ObjectSampleWriter::operator()(const RoutableEdge& edge) {
+  if (EdgeUtils::is_leak_edge(edge)) {
+    write_chain(edge);
+  }
+  return true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_LEAKPROFILER_CHECKPOINT_OBJECTSAMPLEWRITER_HPP
+#define SHARE_VM_LEAKPROFILER_CHECKPOINT_OBJECTSAMPLEWRITER_HPP
+
+#include "memory/allocation.hpp"
+
+class Edge;
+class EdgeStore;
+class JfrCheckpointWriter;
+class RoutableEdge;
+
+class ObjectSampleWriter : public StackObj {
+ private:
+  JfrCheckpointWriter& _writer;
+  const EdgeStore* const _store;
+
+  void write(const RoutableEdge* edge);
+  void write_chain(const RoutableEdge& edge);
+
+ public:
+  ObjectSampleWriter(JfrCheckpointWriter& writer, const EdgeStore* store);
+  ~ObjectSampleWriter();
+
+  bool operator()(const RoutableEdge& edge);
+};
+
+#endif // SHARE_VM_LEAKPROFILER_CHECKPOINT_OBJECTSAMPLEWRITER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,437 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "aot/aotLoader.hpp"
+#include "classfile/stringTable.hpp"
+#include "gc/shared/strongRootsScope.hpp"
+#include "jfr/leakprofiler/utilities/unifiedOop.hpp"
+#include "jfr/leakprofiler/checkpoint/rootResolver.hpp"
+#include "memory/iterator.hpp"
+#include "oops/klass.hpp"
+#include "oops/markOop.hpp"
+#include "oops/oop.hpp"
+#include "prims/jvmtiThreadState.hpp"
+#include "prims/privilegedStack.hpp"
+#include "runtime/frame.inline.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/threadSMR.inline.hpp"
+#include "runtime/vframe_hp.hpp"
+#include "services/management.hpp"
+#include "utilities/growableArray.hpp"
+
+class ReferenceLocateClosure : public OopClosure {
+ protected:
+  RootCallback& _callback;
+  RootCallbackInfo _info;
+  bool _complete;
+
+  void do_oop_shared(const void* ref);
+
+ public:
+  ReferenceLocateClosure(RootCallback& callback,
+                         OldObjectRoot::System system,
+                         OldObjectRoot::Type type,
+                         const void* context) : _callback(callback),
+                                                _info(),
+                                                _complete(false) {
+    _info._high = NULL;
+    _info._low = NULL;
+    _info._system = system;
+    _info._type = type;
+    _info._context = context;
+  }
+
+  virtual void do_oop(oop* ref);
+  virtual void do_oop(narrowOop* ref);
+
+  bool complete() const {
+    return _complete;
+  }
+};
+
+void ReferenceLocateClosure::do_oop_shared(const void* ref) {
+  assert(ref != NULL, "invariant");
+  if (!_complete) {
+    _info._high = ref;
+    _complete = _callback.process(_info);
+  }
+}
+
+void ReferenceLocateClosure::do_oop(oop* ref) {
+  do_oop_shared(ref);
+}
+
+void ReferenceLocateClosure::do_oop(narrowOop* ref) {
+  do_oop_shared(ref);
+}
+
+class ReferenceToRootClosure : public StackObj {
+ private:
+  RootCallback& _callback;
+  RootCallbackInfo _info;
+  bool _complete;
+
+  bool do_cldg_roots();
+  bool do_object_synchronizer_roots();
+  bool do_universe_roots();
+  bool do_jni_handle_roots();
+  bool do_jvmti_roots();
+  bool do_system_dictionary_roots();
+  bool do_management_roots();
+  bool do_string_table_roots();
+  bool do_aot_loader_roots();
+
+  bool do_roots();
+
+ public:
+  ReferenceToRootClosure(RootCallback& callback) : _callback(callback),
+                                                   _info(),
+                                                   _complete(false) {
+    _info._high = NULL;
+    _info._low = NULL;
+    _info._context = NULL;
+    _info._system = OldObjectRoot::_system_undetermined;
+    _info._type = OldObjectRoot::_type_undetermined;
+
+    assert_locked_or_safepoint(Threads_lock);
+    do_roots();
+  }
+
+  bool complete() const {
+    return _complete;
+  }
+};
+
+bool ReferenceToRootClosure::do_cldg_roots() {
+  assert(!complete(), "invariant");
+  ReferenceLocateClosure rlc(_callback, OldObjectRoot::_class_loader_data, OldObjectRoot::_type_undetermined, NULL);
+  CLDToOopClosure cldt_closure(&rlc);
+  ClassLoaderDataGraph::always_strong_cld_do(&cldt_closure);
+  return rlc.complete();
+}
+
+bool ReferenceToRootClosure::do_object_synchronizer_roots() {
+  assert(!complete(), "invariant");
+  ReferenceLocateClosure rlc(_callback, OldObjectRoot::_object_synchronizer, OldObjectRoot::_type_undetermined, NULL);
+  ObjectSynchronizer::oops_do(&rlc);
+  return rlc.complete();
+}
+
+bool ReferenceToRootClosure::do_universe_roots() {
+  assert(!complete(), "invariant");
+  ReferenceLocateClosure rlc(_callback, OldObjectRoot::_universe, OldObjectRoot::_type_undetermined, NULL);
+  Universe::oops_do(&rlc);
+  return rlc.complete();
+}
+
+bool ReferenceToRootClosure::do_jni_handle_roots() {
+  assert(!complete(), "invariant");
+  ReferenceLocateClosure rlc(_callback, OldObjectRoot::_global_jni_handles, OldObjectRoot::_global_jni_handle, NULL);
+  JNIHandles::oops_do(&rlc);
+  return rlc.complete();
+}
+
+bool ReferenceToRootClosure::do_jvmti_roots() {
+  assert(!complete(), "invariant");
+  ReferenceLocateClosure rlc(_callback, OldObjectRoot::_jvmti, OldObjectRoot::_global_jni_handle, NULL);
+  JvmtiExport::oops_do(&rlc);
+  return rlc.complete();
+}
+
+bool ReferenceToRootClosure::do_system_dictionary_roots() {
+  assert(!complete(), "invariant");
+  ReferenceLocateClosure rlc(_callback, OldObjectRoot::_system_dictionary, OldObjectRoot::_type_undetermined, NULL);
+  SystemDictionary::oops_do(&rlc);
+  return rlc.complete();
+}
+
+bool ReferenceToRootClosure::do_management_roots() {
+  assert(!complete(), "invariant");
+  ReferenceLocateClosure rlc(_callback, OldObjectRoot::_management, OldObjectRoot::_type_undetermined, NULL);
+  Management::oops_do(&rlc);
+  return rlc.complete();
+}
+
+bool ReferenceToRootClosure::do_string_table_roots() {
+  assert(!complete(), "invariant");
+  ReferenceLocateClosure rlc(_callback, OldObjectRoot::_string_table, OldObjectRoot::_type_undetermined, NULL);
+  StringTable::oops_do(&rlc);
+  return rlc.complete();
+}
+
+bool ReferenceToRootClosure::do_aot_loader_roots() {
+  assert(!complete(), "invariant");
+  ReferenceLocateClosure rcl(_callback, OldObjectRoot::_aot, OldObjectRoot::_type_undetermined, NULL);
+  AOTLoader::oops_do(&rcl);
+  return rcl.complete();
+}
+
+bool ReferenceToRootClosure::do_roots() {
+  assert(!complete(), "invariant");
+  assert(OldObjectRoot::_system_undetermined == _info._system, "invariant");
+  assert(OldObjectRoot::_type_undetermined == _info._type, "invariant");
+
+  if (do_cldg_roots()) {
+    _complete = true;
+    return true;
+  }
+
+  if (do_object_synchronizer_roots()) {
+   _complete = true;
+    return true;
+  }
+
+  if (do_universe_roots()) {
+   _complete = true;
+    return true;
+  }
+
+  if (do_jni_handle_roots()) {
+   _complete = true;
+    return true;
+  }
+
+  if (do_jvmti_roots()) {
+   _complete = true;
+    return true;
+  }
+
+  if (do_system_dictionary_roots()) {
+   _complete = true;
+    return true;
+  }
+
+  if (do_management_roots()) {
+   _complete = true;
+    return true;
+  }
+
+  if (do_string_table_roots()) {
+   _complete = true;
+    return true;
+  }
+
+  if (do_aot_loader_roots()) {
+   _complete = true;
+    return true;
+  }
+
+  return false;
+}
+
+class ReferenceToThreadRootClosure : public StackObj {
+ private:
+  RootCallback& _callback;
+  bool _complete;
+
+  bool do_java_threads_oops(JavaThread* jt);
+  bool do_thread_roots(JavaThread* jt);
+  bool do_thread_stack_fast(JavaThread* jt);
+  bool do_thread_stack_detailed(JavaThread* jt);
+  bool do_thread_jni_handles(JavaThread* jt);
+  bool do_thread_handle_area(JavaThread* jt);
+
+ public:
+  ReferenceToThreadRootClosure(RootCallback& callback) :_callback(callback), _complete(false) {
+    assert_locked_or_safepoint(Threads_lock);
+    for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) {
+      if (do_thread_roots(jt)) {
+        return;
+      }
+    }
+  }
+
+  bool complete() const {
+    return _complete;
+  }
+};
+
+bool ReferenceToThreadRootClosure::do_thread_handle_area(JavaThread* jt) {
+  assert(jt != NULL, "invariant");
+  assert(!complete(), "invariant");
+  ReferenceLocateClosure rcl(_callback, OldObjectRoot::_threads, OldObjectRoot::_handle_area, jt);
+  jt->handle_area()->oops_do(&rcl);
+  return rcl.complete();
+}
+
+bool ReferenceToThreadRootClosure::do_thread_jni_handles(JavaThread* jt) {
+  assert(jt != NULL, "invariant");
+  assert(!complete(), "invariant");
+
+  ReferenceLocateClosure rcl(_callback, OldObjectRoot::_threads, OldObjectRoot::_local_jni_handle, jt);
+  jt->active_handles()->oops_do(&rcl);
+  return rcl.complete();
+}
+
+bool ReferenceToThreadRootClosure::do_thread_stack_fast(JavaThread* jt) {
+  assert(jt != NULL, "invariant");
+  assert(!complete(), "invariant");
+
+  if (_callback.entries() == 0) {
+    _complete = true;
+    return true;
+  }
+
+  RootCallbackInfo info;
+  info._high = NULL;
+  info._low = NULL;
+  info._context = jt;
+  info._system = OldObjectRoot::_threads;
+  info._type = OldObjectRoot::_stack_variable;
+
+  for (int i = 0; i < _callback.entries(); ++i) {
+    const address adr = (address)_callback.at(i);
+    if (jt->is_in_usable_stack(adr)) {
+      info._high = adr;
+      _complete = _callback.process(info);
+      if (_complete) {
+        return true;
+      }
+    }
+  }
+  assert(!complete(), "invariant");
+  return false;
+}
+
+bool ReferenceToThreadRootClosure::do_thread_stack_detailed(JavaThread* jt) {
+  assert(jt != NULL, "invariant");
+  assert(!complete(), "invariant");
+
+  ReferenceLocateClosure rcl(_callback, OldObjectRoot::_threads, OldObjectRoot::_stack_variable, jt);
+
+  if (jt->has_last_Java_frame()) {
+    PrivilegedElement* const pelem = jt->privileged_stack_top();
+    if (pelem != NULL) {
+      pelem->oops_do(&rcl);
+      if (rcl.complete()) {
+        return true;
+      }
+    }
+
+    // traverse the registered growable array gc_array
+    // can't do this as it is not reachable from outside
+
+    // Traverse the monitor chunks
+    MonitorChunk* chunk = jt->monitor_chunks();
+    for (; chunk != NULL; chunk = chunk->next()) {
+      chunk->oops_do(&rcl);
+    }
+
+    if (rcl.complete()) {
+      return true;
+    }
+
+    // Traverse the execution stack
+    for (StackFrameStream fst(jt); !fst.is_done(); fst.next()) {
+      fst.current()->oops_do(&rcl, NULL, fst.register_map());
+    }
+
+  } // last java frame
+
+  if (rcl.complete()) {
+    return true;
+  }
+
+  GrowableArray<jvmtiDeferredLocalVariableSet*>* const list = jt->deferred_locals();
+  if (list != NULL) {
+    for (int i = 0; i < list->length(); i++) {
+      list->at(i)->oops_do(&rcl);
+    }
+  }
+
+  if (rcl.complete()) {
+    return true;
+  }
+
+  // Traverse instance variables at the end since the GC may be moving things
+  // around using this function
+  /*
+  * // can't reach these oop* from the outside
+  f->do_oop((oop*) &_threadObj);
+  f->do_oop((oop*) &_vm_result);
+  f->do_oop((oop*) &_exception_oop);
+  f->do_oop((oop*) &_pending_async_exception);
+  */
+
+  JvmtiThreadState* const jvmti_thread_state = jt->jvmti_thread_state();
+  if (jvmti_thread_state != NULL) {
+    jvmti_thread_state->oops_do(&rcl);
+  }
+
+  return rcl.complete();
+}
+
+bool ReferenceToThreadRootClosure::do_java_threads_oops(JavaThread* jt) {
+  assert(jt != NULL, "invariant");
+  assert(!complete(), "invariant");
+
+  ReferenceLocateClosure rcl(_callback, OldObjectRoot::_threads, OldObjectRoot::_global_jni_handle, jt);
+  jt->oops_do(&rcl, NULL);
+  return rcl.complete();
+}
+
+bool ReferenceToThreadRootClosure::do_thread_roots(JavaThread* jt) {
+  assert(jt != NULL, "invariant");
+
+  if (do_thread_stack_fast(jt)) {
+    _complete = true;
+    return true;
+  }
+
+  if (do_thread_jni_handles(jt)) {
+    _complete = true;
+    return true;
+  }
+
+  if (do_thread_handle_area(jt)) {
+    _complete = true;
+    return true;
+  }
+
+  if (do_thread_stack_detailed(jt)) {
+    _complete = true;
+    return true;
+  }
+
+  return false;
+}
+
+class RootResolverMarkScope : public MarkScope {
+};
+
+void RootResolver::resolve(RootCallback& callback) {
+
+  // Need to clear cld claim bit before starting
+  ClassLoaderDataGraph::clear_claimed_marks();
+  RootResolverMarkScope mark_scope;
+
+  // thread local roots
+  ReferenceToThreadRootClosure rtrc(callback);
+  if (rtrc.complete()) {
+    return;
+  }
+  // system global roots
+  ReferenceToRootClosure rrc(callback);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_LEAKPROFILER_CHECKPOINT_ROOTRESOLVER_HPP
+#define SHARE_VM_JFR_LEAKPROFILER_CHECKPOINT_ROOTRESOLVER_HPP
+
+#include "memory/allocation.hpp"
+#include "jfr/leakprofiler/utilities/rootType.hpp"
+#include "oops/oopsHierarchy.hpp"
+
+struct RootCallbackInfo {
+  const void* _high;
+  const void* _low;
+  const void* _context;
+  OldObjectRoot::System _system;
+  OldObjectRoot::Type _type;
+};
+
+class RootCallback {
+ public:
+  virtual bool process(const RootCallbackInfo& info) = 0;
+  virtual int entries() const = 0;
+  virtual const void* at(int idx) const = 0;
+};
+
+class RootResolver : public AllStatic {
+ public:
+  static void resolve(RootCallback& callback);
+};
+
+#endif // SHARE_VM_JFR_LEAKPROFILER_CHECKPOINT_ROOTRESOLVER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/emitEventOperation.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+#include "precompiled.hpp"
+#include "gc/shared/collectedHeap.hpp"
+#include "jfr/jfrEvents.hpp"
+#include "jfr/leakprofiler/utilities/granularTimer.hpp"
+#include "jfr/leakprofiler/chains/rootSetClosure.hpp"
+#include "jfr/leakprofiler/chains/edge.hpp"
+#include "jfr/leakprofiler/chains/edgeQueue.hpp"
+#include "jfr/leakprofiler/chains/edgeStore.hpp"
+#include "jfr/leakprofiler/chains/bitset.hpp"
+#include "jfr/leakprofiler/sampling/objectSample.hpp"
+#include "jfr/leakprofiler/leakProfiler.hpp"
+#include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp"
+#include "jfr/leakprofiler/sampling/objectSampler.hpp"
+#include "jfr/leakprofiler/emitEventOperation.hpp"
+#include "jfr/leakprofiler/chains/bfsClosure.hpp"
+#include "jfr/leakprofiler/chains/dfsClosure.hpp"
+#include "jfr/leakprofiler/chains/objectSampleMarker.hpp"
+#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
+#include "jfr/support/jfrThreadId.hpp"
+#include "logging/log.hpp"
+#include "memory/resourceArea.hpp"
+#include "memory/universe.hpp"
+#include "oops/markOop.hpp"
+#include "oops/oop.inline.hpp"
+#include "runtime/safepoint.hpp"
+#include "runtime/vmThread.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+/* The EdgeQueue is backed by directly managed virtual memory.
+ * We will attempt to dimension an initial reservation
+ * in proportion to the size of the heap (represented by heap_region).
+ * Initial memory reservation: 5% of the heap OR at least 32 Mb
+ * Commit ratio: 1 : 10 (subject to allocation granularties)
+ */
+static size_t edge_queue_memory_reservation(const MemRegion& heap_region) {
+  const size_t memory_reservation_bytes = MAX2(heap_region.byte_size() / 20, 32*M);
+  assert(memory_reservation_bytes >= (size_t)32*M, "invariant");
+  return memory_reservation_bytes;
+}
+
+static size_t edge_queue_memory_commit_size(size_t memory_reservation_bytes) {
+  const size_t memory_commit_block_size_bytes = memory_reservation_bytes / 10;
+  assert(memory_commit_block_size_bytes >= (size_t)3*M, "invariant");
+  return memory_commit_block_size_bytes;
+}
+
+static void log_edge_queue_summary(const EdgeQueue& edge_queue) {
+  log_trace(jfr, system)("EdgeQueue reserved size total: " SIZE_FORMAT " [KB]", edge_queue.reserved_size() / K);
+  log_trace(jfr, system)("EdgeQueue edges total: " SIZE_FORMAT, edge_queue.top());
+  log_trace(jfr, system)("EdgeQueue liveset total: " SIZE_FORMAT " [KB]", edge_queue.live_set() / K);
+  if (edge_queue.reserved_size() > 0) {
+    log_trace(jfr, system)("EdgeQueue commit reserve ratio: %f\n",
+      ((double)edge_queue.live_set() / (double)edge_queue.reserved_size()));
+  }
+}
+
+void EmitEventOperation::doit() {
+  assert(LeakProfiler::is_running(), "invariant");
+  _object_sampler = LeakProfiler::object_sampler();
+  assert(_object_sampler != NULL, "invariant");
+
+  _vm_thread = VMThread::vm_thread();
+  assert(_vm_thread == Thread::current(), "invariant");
+  _vm_thread_local = _vm_thread->jfr_thread_local();
+  assert(_vm_thread_local != NULL, "invariant");
+  assert(_vm_thread->jfr_thread_local()->thread_id() == JFR_THREAD_ID(_vm_thread), "invariant");
+
+  // The VM_Operation::evaluate() which invoked doit()
+  // contains a top level ResourceMark
+
+  // save the original markWord for the potential leak objects
+  // to be restored on function exit
+  ObjectSampleMarker marker;
+  if (ObjectSampleCheckpoint::mark(marker, _emit_all) == 0) {
+    return;
+  }
+
+  EdgeStore edge_store;
+
+  GranularTimer::start(_cutoff_ticks, 1000000);
+  if (_cutoff_ticks <= 0) {
+    // no chains
+    write_events(&edge_store);
+    return;
+  }
+
+  assert(_cutoff_ticks > 0, "invariant");
+
+  // The bitset used for marking is dimensioned as a function of the heap size
+  const MemRegion heap_region = Universe::heap()->reserved_region();
+  BitSet mark_bits(heap_region);
+
+  // The edge queue is dimensioned as a fraction of the heap size
+  const size_t edge_queue_reservation_size = edge_queue_memory_reservation(heap_region);
+  EdgeQueue edge_queue(edge_queue_reservation_size, edge_queue_memory_commit_size(edge_queue_reservation_size));
+
+  // The initialize() routines will attempt to reserve and allocate backing storage memory.
+  // Failure to accommodate will render root chain processing impossible.
+  // As a fallback on failure, just write out the existing samples, flat, without chains.
+  if (!(mark_bits.initialize() && edge_queue.initialize())) {
+    log_warning(jfr)("Unable to allocate memory for root chain processing");
+    write_events(&edge_store);
+    return;
+  }
+
+  // necessary condition for attempting a root set iteration
+  Universe::heap()->ensure_parsability(false);
+
+  RootSetClosure::add_to_queue(&edge_queue);
+  if (edge_queue.is_full()) {
+    // Pathological case where roots don't fit in queue
+    // Do a depth-first search, but mark roots first
+    // to avoid walking sideways over roots
+    DFSClosure::find_leaks_from_root_set(&edge_store, &mark_bits);
+  } else {
+    BFSClosure bfs(&edge_queue, &edge_store, &mark_bits);
+    bfs.process();
+  }
+  GranularTimer::stop();
+  write_events(&edge_store);
+  log_edge_queue_summary(edge_queue);
+}
+
+int EmitEventOperation::write_events(EdgeStore* edge_store) {
+  assert(_object_sampler != NULL, "invariant");
+  assert(edge_store != NULL, "invariant");
+  assert(_vm_thread != NULL, "invariant");
+  assert(_vm_thread_local != NULL, "invariant");
+  assert(SafepointSynchronize::is_at_safepoint(), "invariant");
+
+  // save thread id in preparation for thread local trace data manipulations
+  const traceid vmthread_id = _vm_thread_local->thread_id();
+  assert(_vm_thread_local->thread_id() == JFR_THREAD_ID(_vm_thread), "invariant");
+
+  const jlong last_sweep = _emit_all ? max_jlong : _object_sampler->last_sweep().value();
+  int count = 0;
+
+  for (int i = 0; i < _object_sampler->item_count(); ++i) {
+    const ObjectSample* sample = _object_sampler->item_at(i);
+    if (sample->is_alive_and_older_than(last_sweep)) {
+      write_event(sample, edge_store);
+      ++count;
+    }
+  }
+
+  // restore thread local stack trace and thread id
+  _vm_thread_local->set_thread_id(vmthread_id);
+  _vm_thread_local->clear_cached_stack_trace();
+  assert(_vm_thread_local->thread_id() == JFR_THREAD_ID(_vm_thread), "invariant");
+
+  if (count > 0) {
+    // serialize assoicated checkpoints
+    ObjectSampleCheckpoint::write(edge_store, _emit_all, _vm_thread);
+  }
+  return count;
+}
+
+static int array_size(const oop object) {
+  assert(object != NULL, "invariant");
+  if (object->is_array()) {
+    return arrayOop(object)->length();
+  }
+  return -1;
+}
+
+void EmitEventOperation::write_event(const ObjectSample* sample, EdgeStore* edge_store) {
+  assert(sample != NULL, "invariant");
+  assert(!sample->is_dead(), "invariant");
+  assert(edge_store != NULL, "invariant");
+  assert(_vm_thread_local != NULL, "invariant");
+  const oop* object_addr = sample->object_addr();
+  assert(*object_addr != NULL, "invariant");
+
+  const Edge* edge = (const Edge*)(*object_addr)->mark();
+  traceid gc_root_id = 0;
+  if (edge == NULL) {
+    // In order to dump out a representation of the event
+    // even though it was not reachable / too long to reach,
+    // we need to register a top level edge for this object
+    Edge e(NULL, object_addr);
+    edge_store->add_chain(&e, 1);
+    edge = (const Edge*)(*object_addr)->mark();
+  } else {
+    gc_root_id = edge_store->get_root_id(edge);
+  }
+
+  assert(edge != NULL, "invariant");
+  assert(edge->pointee() == *object_addr, "invariant");
+  const traceid object_id = edge_store->get_id(edge);
+  assert(object_id != 0, "invariant");
+
+  EventOldObjectSample e(UNTIMED);
+  e.set_starttime(GranularTimer::start_time());
+  e.set_endtime(GranularTimer::end_time());
+  e.set_allocationTime(sample->allocation_time());
+  e.set_object(object_id);
+  e.set_arrayElements(array_size(*object_addr));
+  e.set_root(gc_root_id);
+
+  // Temporarily assigning both the stack trace id and thread id
+  // onto the thread local data structure of the VMThread (for the duration
+  // of the commit() call). This trick provides a means to override
+  // the event generation mechanism by injecting externally provided id's.
+  // Here, in particular, this allows us to emit an old object event
+  // supplying information from where the actual sampling occurred.
+  _vm_thread_local->set_cached_stack_trace_id(sample->stack_trace_id());
+  assert(sample->has_thread(), "invariant");
+  _vm_thread_local->set_thread_id(sample->thread_id());
+  e.commit();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/emitEventOperation.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_LEAKPROFILER_EMITEVENTOPERATION_HPP
+#define SHARE_VM_LEAKPROFILER_EMITEVENTOPERATION_HPP
+
+#include "runtime/vm_operations.hpp"
+
+class BFSClosure;
+class EdgeStore;
+class EdgeQueue;
+class JfrThreadData;
+class ObjectSample;
+class ObjectSampler;
+
+// Safepoint operation for emitting object sample events
+class EmitEventOperation : public VM_Operation {
+ private:
+  jlong _cutoff_ticks;
+  bool _emit_all;
+  VMThread* _vm_thread;
+  JfrThreadLocal* _vm_thread_local;
+  ObjectSampler* _object_sampler;
+
+  void write_event(const ObjectSample* sample, EdgeStore* edge_store);
+  int write_events(EdgeStore* edge_store);
+
+ public:
+  EmitEventOperation(jlong cutoff_ticks, bool emit_all) :
+    _cutoff_ticks(cutoff_ticks),
+    _emit_all(emit_all),
+    _vm_thread(NULL),
+    _vm_thread_local(NULL),
+    _object_sampler(NULL) {
+  }
+
+  VMOp_Type type() const {
+    return VMOp_GC_HeapInspection;
+  }
+
+  Mode evaluation_mode() const {
+    return _safepoint;
+  }
+
+  virtual void doit();
+};
+
+#endif // SHARE_VM_LEAKPROFILER_EMITEVENTOPERATION_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/leakProfiler.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/leakprofiler/emitEventOperation.hpp"
+#include "jfr/leakprofiler/leakProfiler.hpp"
+#include "jfr/leakprofiler/startOperation.hpp"
+#include "jfr/leakprofiler/stopOperation.hpp"
+#include "jfr/leakprofiler/sampling/objectSampler.hpp"
+#include "jfr/recorder/service/jfrOptionSet.hpp"
+#include "memory/iterator.hpp"
+#include "oops/oop.hpp"
+#include "runtime/atomic.hpp"
+#include "runtime/orderAccess.inline.hpp"
+#include "runtime/thread.hpp"
+#include "runtime/vmThread.hpp"
+#include "utilities/ostream.hpp"
+
+// Only to be updated during safepoint
+ObjectSampler* LeakProfiler::_object_sampler = NULL;
+
+static volatile jbyte suspended = 0;
+bool LeakProfiler::start(jint sample_count) {
+  if (_object_sampler != NULL) {
+    // already started
+    return true;
+  }
+  // Allows user to disable leak profiler on command line by setting queue size to zero.
+  if (sample_count > 0) {
+    StartOperation op(sample_count);
+    VMThread::execute(&op);
+    return _object_sampler != NULL;
+  }
+  return false;
+}
+
+bool LeakProfiler::stop() {
+  if (_object_sampler == NULL) {
+    // already stopped/not started
+    return true;
+  }
+  StopOperation op;
+  VMThread::execute(&op);
+  return _object_sampler == NULL;
+}
+
+void LeakProfiler::emit_events(jlong cutoff_ticks, bool emit_all) {
+  if (!is_running()) {
+    return;
+  }
+  EmitEventOperation op(cutoff_ticks, emit_all);
+  VMThread::execute(&op);
+}
+
+void LeakProfiler::oops_do(BoolObjectClosure* is_alive, OopClosure* f) {
+  assert(SafepointSynchronize::is_at_safepoint(),
+    "Leak Profiler::oops_do(...) may only be called during safepoint");
+
+  if (_object_sampler != NULL) {
+    _object_sampler->oops_do(is_alive, f);
+  }
+}
+
+void LeakProfiler::sample(HeapWord* object,
+                          size_t size,
+                          JavaThread* thread) {
+  assert(is_running(), "invariant");
+  assert(thread != NULL, "invariant");
+  assert(thread->thread_state() == _thread_in_vm, "invariant");
+
+  // exclude compiler threads and code sweeper thread
+  if (thread->is_hidden_from_external_view()) {
+    return;
+  }
+
+  _object_sampler->add(object, size, thread);
+}
+
+ObjectSampler* LeakProfiler::object_sampler() {
+  assert(is_suspended() || SafepointSynchronize::is_at_safepoint(),
+    "Leak Profiler::object_sampler() may only be called during safepoint");
+  return _object_sampler;
+}
+
+void LeakProfiler::set_object_sampler(ObjectSampler* object_sampler) {
+  assert(SafepointSynchronize::is_at_safepoint(),
+    "Leak Profiler::set_object_sampler() may only be called during safepoint");
+  _object_sampler = object_sampler;
+}
+
+bool LeakProfiler::is_running() {
+  return _object_sampler != NULL && !suspended;
+}
+
+bool LeakProfiler::is_suspended() {
+  return _object_sampler != NULL && suspended;
+}
+
+void LeakProfiler::resume() {
+  assert(is_suspended(), "invariant");
+  OrderAccess::storestore();
+  Atomic::store((jbyte)0, &suspended);
+  assert(is_running(), "invariant");
+}
+
+void LeakProfiler::suspend() {
+  assert(SafepointSynchronize::is_at_safepoint(), "invariant");
+  assert(_object_sampler != NULL, "invariant");
+  assert(!is_suspended(), "invariant");
+  suspended = (jbyte)1; // safepoint visible
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/leakProfiler.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_LEAKPROFILER_LEAKPROFILER_HPP
+#define SHARE_VM_JFR_LEAKPROFILER_LEAKPROFILER_HPP
+
+#include "memory/allocation.hpp"
+
+class BoolObjectClosure;
+class ObjectSampler;
+class OopClosure;
+class Thread;
+
+class LeakProfiler : public AllStatic {
+  friend class ClassUnloadTypeSet;
+  friend class EmitEventOperation;
+  friend class ObjectSampleCheckpoint;
+  friend class StartOperation;
+  friend class StopOperation;
+  friend class TypeSet;
+  friend class WriteObjectSampleStacktrace;
+
+ private:
+  static ObjectSampler* _object_sampler;
+
+  static void set_object_sampler(ObjectSampler* object_sampler);
+  static ObjectSampler* object_sampler();
+
+  static void suspend();
+  static void resume();
+  static bool is_suspended();
+
+ public:
+  static bool start(jint sample_count);
+  static bool stop();
+  static void emit_events(jlong cutoff_ticks, bool emit_all);
+  static bool is_running();
+
+  static void sample(HeapWord* object, size_t size, JavaThread* thread);
+
+  // Called by GC
+  static void oops_do(BoolObjectClosure* is_alive, OopClosure* f);
+};
+
+#endif // SHARE_VM_JFR_LEAKPROFILER_LEAKPROFILER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/sampling/objectSample.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_LEAKPROFILER_SAMPLING_OBJECTSAMPLE_HPP
+#define SHARE_VM_JFR_LEAKPROFILER_SAMPLING_OBJECTSAMPLE_HPP
+
+#include "jfr/recorder/checkpoint/jfrCheckpointBlob.hpp"
+#include "jfr/utilities/jfrAllocation.hpp"
+#include "jfr/utilities/jfrTime.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
+#include "memory/allocation.hpp"
+#include "oops/oop.hpp"
+#include "utilities/ticks.hpp"
+/*
+ * Handle for diagnosing Java memory leaks.
+ *
+ * The class tracks the time the object was
+ * allocated, the thread and the stack trace.
+ */
+class ObjectSample : public JfrCHeapObj {
+  friend class ObjectSampler;
+  friend class SampleList;
+ private:
+  ObjectSample* _next;
+  ObjectSample* _previous;
+  JfrCheckpointBlobHandle _thread_cp;
+  JfrCheckpointBlobHandle _klass_cp;
+  oop _object;
+  Ticks _allocation_time;
+  traceid _stack_trace_id;
+  traceid _thread_id;
+  int _index;
+  size_t _span;
+  size_t _allocated;
+  unsigned int _stack_trace_hash;
+  bool _dead;
+
+  void set_dead() {
+    _dead = true;
+  }
+
+  void release_references() {
+    if (_thread_cp.valid()) {
+      _thread_cp.~JfrCheckpointBlobHandle();
+    }
+    if (_klass_cp.valid()) {
+      _klass_cp.~JfrCheckpointBlobHandle();
+    }
+  }
+
+  void reset() {
+    set_stack_trace_id(0);
+    set_stack_trace_hash(0),
+    release_references();
+    _dead = false;
+  }
+
+ public:
+  ObjectSample() : _next(NULL),
+                   _previous(NULL),
+                   _thread_cp(),
+                   _klass_cp(),
+                   _object(NULL),
+                   _allocation_time(),
+                   _stack_trace_id(0),
+                   _thread_id(0),
+                   _index(0),
+                   _span(0),
+                   _allocated(0),
+                   _stack_trace_hash(0),
+                   _dead(false) {}
+
+  ObjectSample* next() const {
+    return _next;
+  }
+
+  void set_next(ObjectSample* next) {
+    _next = next;
+  }
+
+  ObjectSample* prev() const {
+    return _previous;
+  }
+
+  void set_prev(ObjectSample* prev) {
+    _previous = prev;
+  }
+
+  bool is_dead() const {
+    return _dead;
+  }
+
+  const oop object() const {
+    return _object;
+  }
+
+  const oop* object_addr() const {
+    return &_object;
+  }
+
+  void set_object(oop object) {
+    _object = object;
+  }
+
+  const Klass* klass() const {
+    assert(_object != NULL, "invariant");
+    return _object->klass();
+  }
+
+  int index() const {
+    return _index;
+  }
+
+  void set_index(int index) {
+    _index = index;
+  }
+
+  size_t span() const {
+    return _span;
+  }
+
+  void set_span(size_t span) {
+    _span = span;
+  }
+
+  void add_span(size_t span) {
+    _span += span;
+  }
+
+  size_t allocated() const {
+    return _allocated;
+  }
+
+  void set_allocated(size_t size) {
+    _allocated = size;
+  }
+
+  const Ticks& allocation_time() const {
+    return _allocation_time;
+  }
+
+  const void set_allocation_time(const JfrTicks& time) {
+    _allocation_time = Ticks(time.value());
+  }
+
+  bool has_stack_trace() const {
+    return stack_trace_id() != 0;
+  }
+
+  traceid stack_trace_id() const {
+    return _stack_trace_id;
+  }
+
+  void set_stack_trace_id(traceid id) {
+    _stack_trace_id = id;
+  }
+
+  unsigned int stack_trace_hash() const {
+    return _stack_trace_hash;
+  }
+
+  void set_stack_trace_hash(unsigned int hash) {
+    _stack_trace_hash = hash;
+  }
+
+  bool has_thread() const {
+    return _thread_id != 0;
+  }
+
+  traceid thread_id() const {
+    return _thread_id;
+  }
+
+  void set_thread_id(traceid id) {
+    _thread_id = id;
+  }
+
+  bool is_alive_and_older_than(jlong time_stamp) const {
+    return !is_dead() && (JfrTime::is_ft_enabled() ?
+      _allocation_time.ft_value() : _allocation_time.value()) < time_stamp;
+  }
+
+  const JfrCheckpointBlobHandle& thread_checkpoint() const {
+    return _thread_cp;
+  }
+
+  bool has_thread_checkpoint() const {
+    return _thread_cp.valid();
+  }
+
+  // JfrCheckpointBlobHandle assignment operator
+  // maintains proper reference counting
+  void set_thread_checkpoint(const JfrCheckpointBlobHandle& ref) {
+    if (_thread_cp != ref) {
+      _thread_cp = ref;
+    }
+  }
+
+  const JfrCheckpointBlobHandle& klass_checkpoint() const {
+    return _klass_cp;
+  }
+
+  bool has_klass_checkpoint() const {
+    return _klass_cp.valid();
+  }
+
+  void set_klass_checkpoint(const JfrCheckpointBlobHandle& ref) {
+    if (_klass_cp != ref) {
+      if (_klass_cp.valid()) {
+        _klass_cp->set_next(ref);
+        return;
+      }
+      _klass_cp = ref;
+    }
+  }
+};
+
+#endif // SHARE_VM_JFR_LEAKPROFILER_SAMPLING_OBJECTSAMPLE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+#include "precompiled.hpp"
+#include "jfr/jfrEvents.hpp"
+#include "jfr/leakprofiler/sampling/objectSample.hpp"
+#include "jfr/leakprofiler/sampling/objectSampler.hpp"
+#include "jfr/leakprofiler/sampling/sampleList.hpp"
+#include "jfr/leakprofiler/sampling/samplePriorityQueue.hpp"
+#include "jfr/recorder/jfrEventSetting.inline.hpp"
+#include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
+#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
+#include "jfr/support/jfrThreadLocal.hpp"
+#include "jfr/utilities/jfrTryLock.hpp"
+#include "oops/oop.inline.hpp"
+#include "runtime/thread.hpp"
+#include "logging/log.hpp"
+
+ObjectSampler::ObjectSampler(size_t size) :
+  _priority_queue(new SamplePriorityQueue(size)),
+  _list(new SampleList(size)),
+  _last_sweep(JfrTicks::now()),
+  _total_allocated(0),
+  _threshold(0),
+  _size(size),
+  _tryLock(0),
+  _dead_samples(false) {}
+
+ObjectSampler::~ObjectSampler() {
+  delete _priority_queue;
+  _priority_queue = NULL;
+  delete _list;
+  _list = NULL;
+}
+
+void ObjectSampler::add(HeapWord* obj, size_t allocated, JavaThread* thread) {
+  assert(thread != NULL, "invariant");
+  const traceid thread_id = thread->threadObj() != NULL ? thread->jfr_thread_local()->thread_id() : 0;
+  if (thread_id == 0) {
+    return;
+  }
+  assert(thread_id != 0, "invariant");
+
+  if (!thread->jfr_thread_local()->has_thread_checkpoint()) {
+    JfrCheckpointManager::create_thread_checkpoint(thread);
+    assert(thread->jfr_thread_local()->has_thread_checkpoint(), "invariant");
+  }
+
+  traceid stack_trace_id = 0;
+  unsigned int stack_trace_hash = 0;
+  if (JfrEventSetting::has_stacktrace(EventOldObjectSample::eventId)) {
+    stack_trace_id = JfrStackTraceRepository::record(thread, 0, &stack_trace_hash);
+    thread->jfr_thread_local()->set_cached_stack_trace_id(stack_trace_id, stack_trace_hash);
+  }
+
+  const JfrTicks allocation_time = JfrTicks::now();
+
+  JfrTryLock tryLock(&_tryLock);
+  if (!tryLock.has_lock()) {
+    log_trace(jfr, oldobject, sampling)("Skipping old object sample due to lock contention");
+    return;
+  }
+
+  if (_dead_samples) {
+    scavenge();
+    assert(!_dead_samples, "invariant");
+  }
+
+  _total_allocated += allocated;
+  const size_t span = _total_allocated - _priority_queue->total();
+  ObjectSample* sample;
+  if ((size_t)_priority_queue->count() == _size) {
+    assert(_list->count() == _size, "invariant");
+    const ObjectSample* peek = _priority_queue->peek();
+    if (peek->span() > span) {
+      // quick reject, will not fit
+      return;
+    }
+    sample = _list->reuse(_priority_queue->pop());
+  } else {
+    sample = _list->get();
+  }
+
+  assert(sample != NULL, "invariant");
+  assert(thread_id != 0, "invariant");
+  sample->set_thread_id(thread_id);
+  sample->set_thread_checkpoint(thread->jfr_thread_local()->thread_checkpoint());
+
+  if (stack_trace_id != 0) {
+    sample->set_stack_trace_id(stack_trace_id);
+    sample->set_stack_trace_hash(stack_trace_hash);
+  }
+
+  sample->set_span(allocated);
+  sample->set_object((oop)obj);
+  sample->set_allocated(allocated);
+  sample->set_allocation_time(allocation_time);
+  _priority_queue->push(sample);
+}
+
+const ObjectSample* ObjectSampler::last() const {
+  return _list->last();
+}
+
+const ObjectSample* ObjectSampler::last_resolved() const {
+  return _list->last_resolved();
+}
+
+void ObjectSampler::set_last_resolved(const ObjectSample* sample) {
+  _list->set_last_resolved(sample);
+}
+
+void ObjectSampler::oops_do(BoolObjectClosure* is_alive, OopClosure* f) {
+  ObjectSample* current = _list->last();
+  while (current != NULL) {
+    ObjectSample* next = current->next();
+    if (!current->is_dead()) {
+      if (is_alive->do_object_b(current->object())) {
+        // The weakly referenced object is alive, update pointer
+        f->do_oop(const_cast<oop*>(current->object_addr()));
+      } else {
+        current->set_dead();
+        _dead_samples = true;
+      }
+    }
+    current = next;
+  }
+  _last_sweep = JfrTicks::now();
+}
+
+void ObjectSampler::remove_dead(ObjectSample* sample) {
+  assert(sample != NULL, "invariant");
+  assert(sample->is_dead(), "invariant");
+  ObjectSample* const previous = sample->prev();
+  // push span on to previous
+  if (previous != NULL) {
+    _priority_queue->remove(previous);
+    previous->add_span(sample->span());
+    _priority_queue->push(previous);
+  }
+  _priority_queue->remove(sample);
+  _list->release(sample);
+}
+
+void ObjectSampler::scavenge() {
+  ObjectSample* current = _list->last();
+  while (current != NULL) {
+    ObjectSample* next = current->next();
+    if (current->is_dead()) {
+      remove_dead(current);
+    }
+    current = next;
+  }
+  _dead_samples = false;
+}
+
+int ObjectSampler::item_count() const {
+  return _priority_queue->count();
+}
+
+const ObjectSample* ObjectSampler::item_at(int index) const {
+  return _priority_queue->item_at(index);
+}
+
+ObjectSample* ObjectSampler::item_at(int index) {
+  return const_cast<ObjectSample*>(
+    const_cast<const ObjectSampler*>(this)->item_at(index)
+                                   );
+}
+
+const JfrTicks& ObjectSampler::last_sweep() const {
+  return _last_sweep;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_LEAKPROFILER_SAMPLING_OBJECTSAMPLER_HPP
+#define SHARE_VM_LEAKPROFILER_SAMPLING_OBJECTSAMPLER_HPP
+
+#include "memory/allocation.hpp"
+#include "jfr/utilities/jfrTime.hpp"
+
+class BoolObjectClosure;
+class OopClosure;
+class ObjectSample;
+class ObjectSampler;
+class SampleList;
+class SamplePriorityQueue;
+class Thread;
+
+// Class reponsible for holding samples and
+// making sure the samples are evenly distributed as
+// new entries are added and removed.
+class ObjectSampler : public CHeapObj<mtTracing> {
+  friend class LeakProfiler;
+  friend class ObjectSampleCheckpoint;
+  friend class StartOperation;
+  friend class StopOperation;
+  friend class EmitEventOperation;
+ private:
+  SamplePriorityQueue* _priority_queue;
+  SampleList* _list;
+  JfrTicks _last_sweep;
+  size_t _total_allocated;
+  size_t _threshold;
+  size_t _size;
+  volatile int _tryLock;
+  bool _dead_samples;
+
+  explicit ObjectSampler(size_t size);
+  ~ObjectSampler();
+
+  void add(HeapWord* object, size_t size, JavaThread* thread);
+  void remove_dead(ObjectSample* sample);
+  void scavenge();
+
+  // Called by GC
+  void oops_do(BoolObjectClosure* is_alive, OopClosure* f);
+
+ public:
+  const ObjectSample* item_at(int index) const;
+  ObjectSample* item_at(int index);
+  int item_count() const;
+  const ObjectSample* last() const;
+  const ObjectSample* last_resolved() const;
+  void set_last_resolved(const ObjectSample* sample);
+  const JfrTicks& last_sweep() const;
+};
+
+#endif // SHARE_VM_LEAKPROFILER_SAMPLING_OBJECTSAMPLER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/sampling/sampleList.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/leakprofiler/sampling/objectSample.hpp"
+#include "jfr/leakprofiler/sampling/sampleList.hpp"
+#include "oops/oop.inline.hpp"
+
+SampleList::SampleList(size_t limit, size_t cache_size) :
+  _free_list(),
+  _in_use_list(),
+  _last_resolved(NULL),
+  _limit(limit),
+  _cache_size(cache_size),
+  _allocated(0) {
+}
+
+SampleList::~SampleList() {
+  deallocate_samples(_free_list);
+  deallocate_samples(_in_use_list);
+}
+
+ObjectSample* SampleList::last() const {
+  return _in_use_list.head();
+}
+
+const ObjectSample* SampleList::last_resolved() const {
+  return _last_resolved;
+}
+
+void SampleList::set_last_resolved(const ObjectSample* sample) {
+  assert(last() == sample, "invariant");
+  _last_resolved = sample;
+}
+
+void SampleList::link(ObjectSample* sample) {
+  assert(sample != NULL, "invariant");
+  _in_use_list.prepend(sample);
+}
+
+void SampleList::unlink(ObjectSample* sample) {
+  assert(sample != NULL, "invariant");
+  if (_last_resolved == sample) {
+    _last_resolved = sample->next();
+  }
+  reset(_in_use_list.remove(sample));
+}
+
+ObjectSample* SampleList::reuse(ObjectSample* sample) {
+  assert(sample != NULL, "invariant");
+  unlink(sample);
+  link(sample);
+  return sample;
+}
+
+void SampleList::populate_cache() {
+  if (_free_list.count() < _cache_size) {
+    const size_t cache_delta = _cache_size - _free_list.count();
+    for (size_t i = 0; i < cache_delta; ++i) {
+      ObjectSample* sample = newSample();
+      if (sample != NULL) {
+        _free_list.append(sample);
+      }
+    }
+  }
+}
+
+ObjectSample* SampleList::newSample() const {
+  if (_limit == _allocated) {
+    return NULL;
+  }
+  ++_allocated;
+  return new ObjectSample();
+}
+
+ObjectSample* SampleList::get() {
+  ObjectSample* sample = _free_list.head();
+  if (sample != NULL) {
+    link(_free_list.remove(sample));
+  } else {
+    sample = newSample();
+    if (sample != NULL) {
+      _in_use_list.prepend(sample);
+    }
+  }
+  if (_cache_size > 0 && sample != NULL) {
+    populate_cache();
+  }
+  return sample;
+}
+
+void SampleList::release(ObjectSample* sample) {
+  assert(sample != NULL, "invariant");
+  unlink(sample);
+  _free_list.append(sample);
+}
+
+void SampleList::deallocate_samples(List& list) {
+  if (list.count() > 0) {
+    ObjectSample* sample = list.head();
+    while (sample != NULL) {
+      list.remove(sample);
+      delete sample;
+      sample = list.head();
+    }
+  }
+  assert(list.count() == 0, "invariant");
+}
+
+void SampleList::reset(ObjectSample* sample) {
+  assert(sample != NULL, "invariant");
+  sample->reset();
+}
+
+bool SampleList::is_full() const {
+  return _in_use_list.count() == _limit;
+}
+
+size_t SampleList::count() const {
+  return _in_use_list.count();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/sampling/sampleList.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_LEAKPROFILER_SAMPLING_SAMPLELIST_HPP
+#define SHARE_VM_JFR_LEAKPROFILER_SAMPLING_SAMPLELIST_HPP
+#include "jfr/utilities/jfrAllocation.hpp"
+#include "jfr/utilities/jfrDoublyLinkedList.hpp"
+
+class ObjectSample;
+
+class SampleList : public JfrCHeapObj {
+  typedef JfrDoublyLinkedList<ObjectSample> List;
+ private:
+  List _free_list;
+  List _in_use_list;
+  const ObjectSample* _last_resolved;
+  mutable size_t _allocated;
+  const size_t _limit;
+  const size_t _cache_size;
+
+  void populate_cache();
+  ObjectSample* newSample() const;
+  void link(ObjectSample* sample);
+  void unlink(ObjectSample* sample);
+  void deallocate_samples(List& list);
+  void reset(ObjectSample* sample);
+
+ public:
+  SampleList(size_t limit, size_t cache_size = 0);
+  ~SampleList();
+
+  void set_last_resolved(const ObjectSample* sample);
+  ObjectSample* get();
+  ObjectSample* last() const;
+  void release(ObjectSample* sample);
+  const ObjectSample* last_resolved() const;
+  ObjectSample* reuse(ObjectSample* sample);
+  bool is_full() const;
+  size_t count() const;
+};
+
+#endif // SHARE_VM_JFR_LEAKPROFILER_SAMPLING_SAMPLELIST_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/sampling/samplePriorityQueue.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/leakprofiler/sampling/objectSample.hpp"
+#include "jfr/leakprofiler/sampling/samplePriorityQueue.hpp"
+#include "memory/allocation.inline.hpp"
+#include "oops/oop.inline.hpp"
+
+SamplePriorityQueue::SamplePriorityQueue(size_t size) :
+  _allocated_size(size),
+  _count(0),
+  _total(0) {
+  _items =  NEW_C_HEAP_ARRAY(ObjectSample*, size, mtTracing);
+  memset(_items, 0, sizeof(ObjectSample*) * size);
+}
+
+SamplePriorityQueue::~SamplePriorityQueue() {
+  FREE_C_HEAP_ARRAY(ObjectSample*, _items);
+  _items = NULL;
+}
+
+void SamplePriorityQueue::push(ObjectSample* item) {
+  assert(item != NULL, "invariant");
+  assert(_items[_count] == NULL, "invariant");
+
+  _items[_count] = item;
+  _items[_count]->set_index(_count);
+  _count++;
+  moveUp(_count - 1);
+  _total += item->span();
+}
+
+size_t SamplePriorityQueue::total() const {
+  return _total;
+}
+
+ObjectSample* SamplePriorityQueue::pop() {
+  if (_count == 0) {
+    return NULL;
+  }
+
+  ObjectSample* const s = _items[0];
+  assert(s != NULL, "invariant");
+  swap(0, _count - 1);
+  _count--;
+  assert(s == _items[_count], "invariant");
+  // clear from heap
+  _items[_count] = NULL;
+  moveDown(0);
+  _total -= s->span();
+  return s;
+}
+
+void SamplePriorityQueue::swap(int i, int j) {
+  ObjectSample* tmp = _items[i];
+  _items[i] = _items[j];
+  _items[j] = tmp;
+  _items[i]->set_index(i);
+  _items[j]->set_index(j);
+}
+
+static int left(int i) {
+  return 2 * i + 1;
+}
+
+static int right(int i) {
+  return 2 * i + 2;
+}
+
+static int parent(int i) {
+  return (i - 1) / 2;
+}
+
+void SamplePriorityQueue::moveDown(int i) {
+  do {
+    int j = -1;
+    int r = right(i);
+    if (r < _count && _items[r]->span() < _items[i]->span()) {
+      int l = left(i);
+      if (_items[l]->span() < _items[r]->span()) {
+        j = l;
+      } else {
+        j = r;
+      }
+    } else {
+      int l = left(i);
+      if (l < _count && _items[l]->span() < _items[i]->span()) {
+        j = l;
+      }
+    }
+    if (j >= 0) {
+      swap(i, j);
+    }
+    i = j;
+  } while (i >= 0);
+
+}
+
+void SamplePriorityQueue::moveUp(int i) {
+  int p = parent(i);
+  while (i > 0 && _items[i]->span() < _items[p]->span()) {
+    swap(i,p);
+    i = p;
+    p = parent(i);
+  }
+}
+
+void SamplePriorityQueue::remove(ObjectSample* s) {
+  assert(s != NULL, "invariant");
+  const size_t realSpan = s->span();
+  s->set_span(0);
+  moveUp(s->index());
+  s->set_span(realSpan);
+  pop();
+}
+
+int SamplePriorityQueue::count() const {
+  return _count;
+}
+
+const ObjectSample* SamplePriorityQueue::peek() const {
+  return _count == 0 ? NULL : _items[0];
+}
+
+ObjectSample* SamplePriorityQueue::item_at(int index) {
+  assert(index >= 0 && index < _count, "out of range");
+  return _items[index];
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/sampling/samplePriorityQueue.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_LEAKPROFILER_SAMPLING_SAMPLEPRIORITYQUEUE_HPP
+#define SHARE_VM_JFR_LEAKPROFILER_SAMPLING_SAMPLEPRIORITYQUEUE_HPP
+
+#include "memory/allocation.hpp"
+
+class ObjectSample;
+
+// Priority queue that keeps object samples ordered
+// by the amount of allocation they span.
+class SamplePriorityQueue : public CHeapObj<mtTracing> {
+ private:
+  ObjectSample** _items;
+  size_t _allocated_size;
+  int _count;
+  size_t _total;
+
+  void swap(int i, int j);
+  void moveDown(int index);
+  void moveUp(int index);
+
+ public:
+  SamplePriorityQueue(size_t size);
+  ~SamplePriorityQueue();
+
+  void push(ObjectSample* sample);
+  ObjectSample* pop();
+  const ObjectSample* peek() const;
+  void remove(ObjectSample* sample);
+  ObjectSample* item_at(int index);
+  size_t total() const;
+  int count() const;
+};
+
+#endif // SHARE_VM_JFR_LEAKPROFILER_SAMPLING_SAMPLEPRIORITYQUEUE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/startOperation.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_LEAKPROFILER_STARTOPERATION_HPP
+#define SHARE_VM_LEAKPROFILER_STARTOPERATION_HPP
+
+#include "jfr/recorder/jfrRecorder.hpp"
+#include "jfr/leakprofiler/leakProfiler.hpp"
+#include "jfr/leakprofiler/sampling/objectSampler.hpp"
+#include "jfr/recorder/service/jfrOptionSet.hpp"
+#include "logging/log.hpp"
+#include "runtime/vm_operations.hpp"
+
+// Safepoint operation for starting leak profiler object sampler
+class StartOperation : public VM_Operation {
+ private:
+  jlong _sample_count;
+ public:
+  StartOperation(jlong sample_count) :
+    _sample_count(sample_count) {
+  }
+
+  Mode evaluation_mode() const {
+    return _safepoint;
+  }
+
+  VMOp_Type type() const {
+    return VMOp_GC_HeapInspection;
+  }
+
+  virtual void doit() {
+    assert(!LeakProfiler::is_running(), "invariant");
+    jint queue_size = JfrOptionSet::old_object_queue_size();
+    LeakProfiler::set_object_sampler(new ObjectSampler(queue_size));
+    log_trace(jfr, system)( "Object sampling started");
+  }
+};
+
+#endif // SHARE_VM_LEAKPROFILER_STARTOPERATION_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/stopOperation.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_LEAKPROFILER_STOPOPERATION_HPP
+#define SHARE_VM_LEAKPROFILER_STOPOPERATION_HPP
+
+#include "jfr/leakprofiler/leakProfiler.hpp"
+#include "jfr/leakprofiler/sampling/objectSampler.hpp"
+#include "jfr/recorder/service/jfrOptionSet.hpp"
+#include "logging/log.hpp"
+#include "runtime/vm_operations.hpp"
+
+// Safepoint operation for stopping leak profiler object sampler
+class StopOperation : public VM_Operation {
+ public:
+  StopOperation() {}
+
+  Mode evaluation_mode() const {
+    return _safepoint;
+  }
+
+  VMOp_Type type() const {
+    return VMOp_GC_HeapInspection;
+  }
+
+  virtual void doit() {
+    assert(LeakProfiler::is_running(), "invariant");
+    ObjectSampler* object_sampler = LeakProfiler::object_sampler();
+    delete object_sampler;
+    LeakProfiler::set_object_sampler(NULL);
+    log_trace(jfr, system)( "Object sampling stopped");
+  }
+};
+
+#endif // SHARE_VM_LEAKPROFILER_STOPOPERATION_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/utilities/granularTimer.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/leakprofiler/utilities/granularTimer.hpp"
+
+long GranularTimer::_granularity = 0;
+long GranularTimer::_counter = 0;
+JfrTicks GranularTimer::_finish_time_ticks = 0;
+JfrTicks GranularTimer::_start_time_ticks = 0;
+bool GranularTimer::_finished = false;
+
+void GranularTimer::start(jlong duration_ticks, long granularity) {
+  assert(granularity > 0, "granularity must be at least 1");
+  _granularity = granularity;
+  _counter = granularity;
+  _start_time_ticks = JfrTicks::now();
+  const jlong end_time_ticks = _start_time_ticks.value() + duration_ticks;
+  _finish_time_ticks = end_time_ticks < 0 ? JfrTicks(max_jlong) : JfrTicks(end_time_ticks);
+  _finished = _finish_time_ticks == _start_time_ticks;
+  assert(_finish_time_ticks.value() >= 0, "invariant");
+  assert(_finish_time_ticks >= _start_time_ticks, "invariant");
+}
+void GranularTimer::stop() {
+  if (!_finished) {
+    _finish_time_ticks = JfrTicks::now();
+  }
+}
+const JfrTicks& GranularTimer::start_time() {
+  return _start_time_ticks;
+}
+
+const JfrTicks& GranularTimer::end_time() {
+  return _finish_time_ticks;
+}
+
+bool GranularTimer::is_finished() {
+  assert(_granularity != 0, "GranularTimer::is_finished must be called after GranularTimer::start");
+  if (--_counter == 0) {
+    if (_finished) {
+      // reset so we decrease to zero at next iteration
+      _counter = 1;
+      return true;
+    }
+    if (JfrTicks::now() > _finish_time_ticks) {
+      _finished = true;
+      _counter = 1;
+      return true;
+    }
+    assert(_counter == 0, "invariant");
+    _counter = _granularity; // restore next batch
+  }
+  return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/utilities/granularTimer.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_LEAKPROFILER_UTILITIES_GRANULARTIMER_HPP
+#define SHARE_VM_LEAKPROFILER_UTILITIES_GRANULARTIMER_HPP
+
+#include "jfr/utilities/jfrTime.hpp"
+#include "memory/allocation.hpp"
+
+class GranularTimer : public AllStatic {
+ private:
+  static JfrTicks _finish_time_ticks;
+  static JfrTicks _start_time_ticks;
+  static long _counter;
+  static long _granularity;
+  static bool _finished;
+ public:
+  static void start(jlong duration_ticks, long granularity);
+  static void stop();
+  static const JfrTicks& start_time();
+  static const JfrTicks& end_time();
+  static bool is_finished();
+};
+
+#endif // SHARE_VM_LEAKPROFILER_UTILITIES_GRANULARTIMER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/utilities/rootType.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_LEAKPROFILER_UTILITIES_ROOTTYPE_HPP
+#define SHARE_VM_LEAKPROFILER_UTILITIES_ROOTTYPE_HPP
+
+#include "memory/allocation.hpp"
+#include "utilities/debug.hpp"
+
+class OldObjectRoot : public AllStatic {
+ public:
+  enum System {
+    _system_undetermined,
+    _universe,
+    _global_jni_handles,
+    _threads,
+    _object_synchronizer,
+    _system_dictionary,
+    _class_loader_data,
+    _management,
+    _jvmti,
+    _code_cache,
+    _string_table,
+    _aot,
+    _number_of_systems
+  };
+
+  enum Type {
+    _type_undetermined,
+    _stack_variable,
+    _local_jni_handle,
+    _global_jni_handle,
+    _handle_area,
+    _number_of_types
+  };
+
+  static const char* system_description(System system) {
+    switch (system) {
+      case _system_undetermined:
+        return "<unknown>";
+      case _universe:
+        return "Universe";
+      case _global_jni_handles:
+        return "Global JNI Handles";
+      case _threads:
+        return "Threads";
+      case _object_synchronizer:
+        return "Object Monitor";
+      case _system_dictionary:
+        return "System Dictionary";
+      case _class_loader_data:
+        return "Class Loader Data";
+      case _management:
+        return "Management";
+      case _jvmti:
+        return "JVMTI";
+      case _code_cache:
+        return "Code Cache";
+      case _string_table:
+        return "String Table";
+      case _aot:
+        return "AOT";
+      default:
+        ShouldNotReachHere();
+    }
+    return NULL;
+  }
+
+  static const char* type_description(Type type) {
+    switch (type) {
+      case _type_undetermined:
+        return "<unknown>";
+      case _stack_variable:
+        return "Stack Variable";
+      case _local_jni_handle:
+        return "Local JNI Handle";
+      case _global_jni_handle:
+        return "Global JNI Handle";
+      case _handle_area:
+        return "Handle Area";
+      default:
+        ShouldNotReachHere();
+    }
+    return NULL;
+  }
+};
+
+#endif // SHARE_VM_LEAKPROFILER_UTILITIES_ROOTTYPE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/utilities/saveRestore.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/classLoaderData.hpp"
+#include "jfr/leakprofiler/utilities/saveRestore.hpp"
+#include "oops/oop.inline.hpp"
+
+MarkOopContext::MarkOopContext() : _obj(NULL), _mark_oop(NULL) {}
+
+MarkOopContext::MarkOopContext(const oop obj) : _obj(obj), _mark_oop(obj->mark()) {
+  assert(_obj->mark() == _mark_oop, "invariant");
+  // now we will "poison" the mark word of the object
+  // to the intermediate monitor INFLATING state.
+  // This is an "impossible" state during a safepoint,
+  // hence we will use it to quickly identify objects
+  // during the reachability search from gc roots.
+  assert(NULL == markOopDesc::INFLATING(), "invariant");
+  _obj->set_mark(markOopDesc::INFLATING());
+  assert(NULL == obj->mark(), "invariant");
+}
+
+MarkOopContext::~MarkOopContext() {
+  if (_obj != NULL) {
+    _obj->set_mark(_mark_oop);
+    assert(_obj->mark() == _mark_oop, "invariant");
+  }
+}
+
+MarkOopContext::MarkOopContext(const MarkOopContext& rhs) : _obj(NULL), _mark_oop(NULL) {
+  swap(const_cast<MarkOopContext&>(rhs));
+}
+
+void MarkOopContext::operator=(MarkOopContext rhs) {
+  swap(rhs);
+}
+
+void MarkOopContext::swap(MarkOopContext& rhs) {
+  oop temp_obj = rhs._obj;
+  markOop temp_mark_oop = rhs._mark_oop;
+  rhs._obj = _obj;
+  rhs._mark_oop = _mark_oop;
+  _obj = temp_obj;
+  _mark_oop = temp_mark_oop;
+}
+
+CLDClaimContext::CLDClaimContext() : _cld(NULL) {}
+
+CLDClaimContext::CLDClaimContext(ClassLoaderData* cld) : _cld(cld) {
+  assert(_cld->claimed(), "invariant");
+  _cld->clear_claimed();
+}
+
+CLDClaimContext::~CLDClaimContext() {
+  if (_cld != NULL) {
+    assert(!_cld->claimed(), "invariant");
+    _cld->claim();
+    assert(_cld->claimed(), "invariant");
+  }
+}
+
+CLDClaimContext::CLDClaimContext(const CLDClaimContext& rhs) : _cld(NULL) {
+  swap(const_cast<CLDClaimContext&>(rhs));
+}
+
+void CLDClaimContext::operator=(CLDClaimContext rhs) {
+  swap(rhs);
+}
+
+void CLDClaimContext::swap(CLDClaimContext& rhs) {
+  ClassLoaderData* temp_cld = rhs._cld;
+  rhs._cld = _cld;
+  _cld = temp_cld;
+}
+
+CLDClaimStateClosure::CLDClaimStateClosure() : CLDClosure(), _state() {}
+
+void CLDClaimStateClosure::do_cld(ClassLoaderData* cld) {
+  assert(cld != NULL, "invariant");
+  if (cld->claimed()) {
+    _state.save(cld);
+  }
+}
+
+SaveRestoreCLDClaimBits::SaveRestoreCLDClaimBits() : _claim_state_closure() {
+  ClassLoaderDataGraph::cld_do(&_claim_state_closure);
+}
+
+SaveRestoreCLDClaimBits::~SaveRestoreCLDClaimBits() {
+  ClassLoaderDataGraph::clear_claimed_marks();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/utilities/saveRestore.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_LEAKPROFILER_UTILITIES_SAVERESTORE_HPP
+#define SHARE_VM_JFR_LEAKPROFILER_UTILITIES_SAVERESTORE_HPP
+
+#include "memory/allocation.hpp"
+#include "memory/iterator.hpp"
+#include "oops/markOop.hpp"
+#include "utilities/growableArray.hpp"
+
+template <typename T, typename Impl>
+class SaveRestore {
+ private:
+  Impl _impl;
+ public:
+  SaveRestore() : _impl() {
+    _impl.setup();
+  }
+
+  void save(T const& value) {
+    _impl.save(value);
+  }
+
+  ~SaveRestore() {
+    _impl.restore();
+  }
+};
+
+template <typename T, typename Context>
+class ContextStore {
+private:
+  GrowableArray<Context>* _storage;
+public:
+  ContextStore() : _storage(NULL) {}
+
+  void setup() {
+    assert(_storage == NULL, "invariant");
+    _storage = new GrowableArray<Context>(16);
+  }
+
+  void save(T const& value) {
+    _storage->push(Context(value));
+  }
+
+  void restore() {
+    for (int i = 0; i < _storage->length(); ++i) {
+      _storage->at(i).~Context();
+    }
+  }
+};
+
+/*
+* This class will save the original mark oop of an object sample object.
+* It will then install an "identifier" mark oop to be used for
+* identification purposes in the search for reference chains.
+* The destructor will restore the original mark oop.
+*/
+
+class MarkOopContext {
+ private:
+  oop _obj;
+  markOop _mark_oop;
+  void swap(MarkOopContext& rhs);
+ public:
+  MarkOopContext();
+  MarkOopContext(const oop obj);
+  MarkOopContext(const MarkOopContext& rhs);
+  void operator=(MarkOopContext rhs);
+  ~MarkOopContext();
+};
+
+typedef SaveRestore<oop, ContextStore<oop, MarkOopContext> > SaveRestoreMarkOops;
+
+class ClassLoaderData;
+
+class CLDClaimContext {
+ private:
+  ClassLoaderData* _cld;
+  void swap(CLDClaimContext& rhs);
+ public:
+  CLDClaimContext();
+  CLDClaimContext(ClassLoaderData* cld);
+  CLDClaimContext(const CLDClaimContext& rhs);
+  void operator=(CLDClaimContext rhs);
+  ~CLDClaimContext();
+};
+
+typedef SaveRestore<ClassLoaderData*, ContextStore<ClassLoaderData*, CLDClaimContext> > SaveRestoreCLDClaimState;
+
+class CLDClaimStateClosure : public CLDClosure {
+ private:
+  SaveRestoreCLDClaimState _state;
+ public:
+  CLDClaimStateClosure();
+  void do_cld(ClassLoaderData* cld);
+};
+
+class SaveRestoreCLDClaimBits : public StackObj {
+ private:
+  CLDClaimStateClosure _claim_state_closure;
+ public:
+  SaveRestoreCLDClaimBits();
+  ~SaveRestoreCLDClaimBits();
+};
+
+#endif // SHARE_VM_JFR_LEAKPROFILER_UTILITIES_SAVERESTORE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/utilities/unifiedOop.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_LEAKPROFILER_UTILITIES_UNIFIEDOOP_HPP
+#define SHARE_VM_JFR_LEAKPROFILER_UTILITIES_UNIFIEDOOP_HPP
+
+#include "oops/oop.inline.hpp"
+
+class UnifiedOop : public AllStatic {
+ public:
+  static const bool is_narrow(const oop* ref) {
+    assert(ref != NULL, "invariant");
+    return 1 == (((u8)ref) & 1);
+  }
+
+  static const oop* decode(const oop* ref) {
+    assert(ref != NULL, "invariant");
+    return is_narrow(ref) ? (const oop*)(((u8)ref) & ~1) : ref;
+  }
+
+  static const oop* encode(narrowOop* ref) {
+    assert(ref != NULL, "invariant");
+    return (const oop*)((u8)ref | 1);
+  }
+
+  static oop dereference(const oop* ref) {
+    assert(ref != NULL, "invariant");
+    return is_narrow(ref) ?
+      (oop)RawAccess<>::oop_load((narrowOop*)decode(ref)) :
+      (oop)RawAccess<>::oop_load(const_cast<oop*>(ref));
+
+  }
+};
+
+#endif // SHARE_VM_JFR_LEAKPROFILER_UTILITIES_UNIFIEDOOP_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/metadata/GenerateJfrFiles.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,692 @@
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.StringJoiner;
+import java.util.function.Predicate;
+
+import javax.xml.XMLConstants;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.validation.SchemaFactory;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.helpers.DefaultHandler;
+
+public class GenerateJfrFiles {
+
+    public static void main(String... args) throws Exception {
+        if (args.length != 3) {
+            System.err.println("Incorrect number of command line arguments.");
+            System.err.println("Usage:");
+            System.err.println("java GenerateJfrFiles[.java] <path-to-metadata.xml> <path-to-metadata.xsd> <output-directory>");
+            System.exit(1);
+        }
+        try {
+            File metadataXml = new File(args[0]);
+            File metadataSchema = new File(args[1]);
+            File outputDirectory = new File(args[2]);
+
+            Metadata metadata = new Metadata(metadataXml, metadataSchema);
+            metadata.verify();
+            metadata.wireUpTypes();
+
+            printJfrPeriodicHpp(metadata, outputDirectory);
+            printJfrEventIdsHpp(metadata, outputDirectory);
+            printJfrEventControlHpp(metadata, outputDirectory);
+            printJfrTypesHpp(metadata, outputDirectory);
+            printJfrEventClassesHpp(metadata, outputDirectory);
+
+        } catch (Exception e) {
+            e.printStackTrace();
+            System.exit(1);
+        }
+    }
+
+    static class XmlType {
+        final String fieldType;
+        final String parameterType;
+        XmlType(String fieldType, String parameterType) {
+            this.fieldType = fieldType;
+            this.parameterType = parameterType;
+        }
+    }
+
+    static class TypeElement {
+        List<FieldElement> fields = new ArrayList<>();
+        String name;
+        String fieldType;
+        String parameterType;
+        boolean supportStruct;
+    }
+
+    static class Metadata {
+        final Map<String, TypeElement> types = new LinkedHashMap<>();
+        final Map<String, XmlType> xmlTypes = new HashMap<>();
+        Metadata(File metadataXml, File metadataSchema) throws ParserConfigurationException, SAXException, FileNotFoundException, IOException {
+            SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+            SAXParserFactory factory = SAXParserFactory.newInstance();
+            factory.setSchema(schemaFactory.newSchema(metadataSchema));
+            SAXParser sp = factory.newSAXParser();
+            sp.parse(metadataXml, new MetadataHandler(this));
+        }
+
+        List<EventElement> getEvents() {
+            return getList(t -> t.getClass() == EventElement.class);
+        }
+
+        List<TypeElement> getEventsAndStructs() {
+            return getList(t -> t.getClass() == EventElement.class || t.supportStruct);
+        }
+
+        List<TypeElement> getTypesAndStructs() {
+            return getList(t -> t.getClass() == TypeElement.class || t.supportStruct);
+        }
+
+        @SuppressWarnings("unchecked")
+        <T> List<T> getList(Predicate<? super TypeElement> pred) {
+            List<T> result = new ArrayList<>(types.size());
+            for (TypeElement t : types.values()) {
+                if (pred.test(t)) {
+                    result.add((T) t);
+                }
+            }
+            return result;
+        }
+
+        List<EventElement> getPeriodicEvents() {
+            return getList(t -> t.getClass() == EventElement.class && ((EventElement) t).periodic);
+        }
+
+        List<TypeElement> getNonEventsAndNonStructs() {
+            return getList(t -> t.getClass() != EventElement.class && !t.supportStruct);
+        }
+
+        List<TypeElement> getTypes() {
+            return getList(t -> t.getClass() == TypeElement.class && !t.supportStruct);
+        }
+
+        List<TypeElement> getStructs() {
+            return getList(t -> t.getClass() == TypeElement.class && t.supportStruct);
+        }
+
+        void verify()  {
+            for (TypeElement t : types.values()) {
+                for (FieldElement f : t.fields) {
+                    if (!xmlTypes.containsKey(f.typeName)) { // ignore primitives
+                        if (!types.containsKey(f.typeName)) {
+                            throw new IllegalStateException("Could not find definition of type '" + f.typeName + "' used by " + t.name + "#" + f.name);
+                        }
+                    }
+                }
+            }
+        }
+
+        void wireUpTypes() {
+            for (TypeElement t : types.values()) {
+                for (FieldElement f : t.fields) {
+                    TypeElement type = types.get(f.typeName);
+                    if (f.struct) {
+                        type.supportStruct = true;
+                    }
+                    f.type = type;
+                }
+            }
+        }
+    }
+
+    static class EventElement extends TypeElement {
+        String representation;
+        boolean thread;
+        boolean stackTrace;
+        boolean startTime;
+        boolean periodic;
+        boolean cutoff;
+    }
+
+    static class FieldElement {
+        final Metadata metadata;
+        TypeElement type;
+        String name;
+        String typeName;
+        boolean struct;
+
+        FieldElement(Metadata metadata) {
+            this.metadata = metadata;
+        }
+
+        String getParameterType() {
+            if (struct) {
+                return "const JfrStruct" + typeName + "&";
+            }
+            XmlType xmlType = metadata.xmlTypes.get(typeName);
+            if (xmlType != null) {
+                return xmlType.parameterType;
+            }
+            return type != null ? "u8" : typeName;
+        }
+
+        String getParameterName() {
+            return struct ? "value" : "new_value";
+        }
+
+        String getFieldType() {
+            if (struct) {
+                return "JfrStruct" + typeName;
+            }
+            XmlType xmlType = metadata.xmlTypes.get(typeName);
+            if (xmlType != null) {
+                return xmlType.fieldType;
+            }
+            return type != null ? "u8" : typeName;
+        }
+    }
+
+    static class MetadataHandler extends DefaultHandler {
+        final Metadata metadata;
+        FieldElement currentField;
+        TypeElement currentType;
+        MetadataHandler(Metadata metadata) {
+            this.metadata = metadata;
+        }
+        @Override
+        public void error(SAXParseException e) throws SAXException {
+          throw e;
+        }
+        @Override
+        public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+            switch (qName) {
+            case "XmlType":
+                String name = attributes.getValue("name");
+                String parameterType = attributes.getValue("parameterType");
+                String fieldType = attributes.getValue("fieldType");
+                metadata.xmlTypes.put(name, new XmlType(fieldType, parameterType));
+                break;
+            case "Type":
+                currentType = new TypeElement();
+                currentType.name = attributes.getValue("name");
+                break;
+            case "Event":
+                EventElement eventtType = new EventElement();
+                eventtType.name = attributes.getValue("name");
+                eventtType.thread = getBoolean(attributes, "thread", false);
+                eventtType.stackTrace = getBoolean(attributes, "stackTrace", false);
+                eventtType.startTime = getBoolean(attributes, "startTime", true);
+                eventtType.periodic = attributes.getValue("period") != null;
+                eventtType.cutoff = getBoolean(attributes, "cutoff", false);
+                currentType = eventtType;
+                break;
+            case "Field":
+                currentField = new FieldElement(metadata);
+                currentField.struct = getBoolean(attributes, "struct", false);
+                currentField.name = attributes.getValue("name");
+                currentField.typeName = attributes.getValue("type");
+                break;
+            }
+        }
+
+        private boolean getBoolean(Attributes attributes, String name, boolean defaultValue) {
+            String value = attributes.getValue(name);
+            return value == null ? defaultValue : Boolean.valueOf(value);
+        }
+
+        @Override
+        public void endElement(String uri, String localName, String qName) {
+            switch (qName) {
+            case "Type":
+            case "Event":
+                metadata.types.put(currentType.name, currentType);
+                currentType = null;
+                break;
+            case "Field":
+                currentType.fields.add(currentField);
+                currentField = null;
+                break;
+            }
+        }
+    }
+
+    static class Printer implements AutoCloseable {
+        final PrintStream out;
+        Printer(File outputDirectory, String filename) throws FileNotFoundException {
+            out = new PrintStream(new BufferedOutputStream(new FileOutputStream(new File(outputDirectory, filename))));
+            write("/* AUTOMATICALLY GENERATED FILE - DO NOT EDIT */");
+            write("");
+        }
+
+        void write(String text) {
+            out.print(text);
+            out.print("\n"); // Don't use Windows line endings
+        }
+
+        @Override
+        public void close() throws Exception {
+            out.close();
+        }
+    }
+
+    private static void printJfrPeriodicHpp(Metadata metadata, File outputDirectory) throws Exception {
+        try (Printer out = new Printer(outputDirectory, "jfrPeriodic.hpp")) {
+            out.write("#ifndef JFRFILES_JFRPERIODICEVENTSET_HPP");
+            out.write("#define JFRFILES_JFRPERIODICEVENTSET_HPP");
+            out.write("");
+            out.write("#include \"utilities/macros.hpp\"");
+            out.write("#if INCLUDE_JFR");
+            out.write("#include \"jfrfiles/jfrEventIds.hpp\"");
+            out.write("#include \"memory/allocation.hpp\"");
+            out.write("");
+            out.write("class JfrPeriodicEventSet : public AllStatic {");
+            out.write(" public:");
+            out.write("  static void requestEvent(JfrEventId id) {");
+            out.write("    switch(id) {");
+            out.write("  ");
+            for (EventElement e : metadata.getPeriodicEvents()) {
+                out.write("      case Jfr" + e.name + "Event:");
+                out.write("        request" + e.name + "();");
+                out.write("        break;");
+                out.write("  ");
+            }
+            out.write("      default:");
+            out.write("        break;");
+            out.write("      }");
+            out.write("    }");
+            out.write("");
+            out.write(" private:");
+            out.write("");
+            for (EventElement e : metadata.getPeriodicEvents()) {
+                out.write("  static void request" + e.name + "(void);");
+                out.write("");
+            }
+            out.write("};");
+            out.write("");
+            out.write("#endif // INCLUDE_JFR");
+            out.write("#endif // JFRFILES_JFRPERIODICEVENTSET_HPP");
+        }
+    }
+
+    private static void printJfrEventControlHpp(Metadata metadata, File outputDirectory) throws Exception {
+        try (Printer out = new Printer(outputDirectory, "jfrEventControl.hpp")) {
+            out.write("#ifndef JFRFILES_JFR_NATIVE_EVENTSETTING_HPP");
+            out.write("#define JFRFILES_JFR_NATIVE_EVENTSETTING_HPP");
+            out.write("");
+            out.write("#include \"utilities/macros.hpp\"");
+            out.write("#if INCLUDE_JFR");
+            out.write("#include \"jfrfiles/jfrEventIds.hpp\"");
+            out.write("");
+            out.write("/**");
+            out.write(" * Event setting. We add some padding so we can use our");
+            out.write(" * event IDs as indexes into this.");
+            out.write(" */");
+            out.write("");
+            out.write("struct jfrNativeEventSetting {");
+            out.write("  jlong  threshold_ticks;");
+            out.write("  jlong  cutoff_ticks;");
+            out.write("  u1     stacktrace;");
+            out.write("  u1     enabled;");
+            out.write("  u1     pad[6]; // Because GCC on linux ia32 at least tries to pack this.");
+            out.write("};");
+            out.write("");
+            out.write("union JfrNativeSettings {");
+            out.write("  // Array version.");
+            out.write("  jfrNativeEventSetting bits[MaxJfrEventId];");
+            out.write("  // Then, to make it easy to debug,");
+            out.write("  // add named struct members also.");
+            out.write("  struct {");
+            out.write("    jfrNativeEventSetting pad[NUM_RESERVED_EVENTS];");
+            for (TypeElement t : metadata.getEventsAndStructs()) {
+                out.write("    jfrNativeEventSetting " + t.name + ";");
+            }
+            out.write("  } ev;");
+            out.write("};");
+            out.write("");
+            out.write("#endif // INCLUDE_JFR");
+            out.write("#endif // JFRFILES_JFR_NATIVE_EVENTSETTING_HPP");
+        }
+    }
+
+    private static void printJfrEventIdsHpp(Metadata metadata, File outputDirectory) throws Exception {
+        try (Printer out = new Printer(outputDirectory, "jfrEventIds.hpp")) {
+            out.write("#ifndef JFRFILES_JFREVENTIDS_HPP");
+            out.write("#define JFRFILES_JFREVENTIDS_HPP");
+            out.write("");
+            out.write("#include \"utilities/macros.hpp\"");
+            out.write("#if INCLUDE_JFR");
+            out.write("#include \"jfrfiles/jfrTypes.hpp\"");
+            out.write("");
+            out.write("/**");
+            out.write(" * Enum of the event types in the JVM");
+            out.write(" */");
+            out.write("enum JfrEventId {");
+            out.write("  _jfreventbase = (NUM_RESERVED_EVENTS-1), // Make sure we start at right index.");
+            out.write("  ");
+            out.write("  // Events -> enum entry");
+            for (TypeElement t : metadata.getEventsAndStructs()) {
+                out.write("  Jfr" + t.name + "Event,");
+            }
+            out.write("");
+            out.write("  MaxJfrEventId");
+            out.write("};");
+            out.write("");
+            out.write("/**");
+            out.write(" * Struct types in the JVM");
+            out.write(" */");
+            out.write("enum JfrStructId {");
+            for (TypeElement t : metadata.getNonEventsAndNonStructs()) {
+                out.write("  Jfr" + t.name + "Struct,");
+            }
+            for (TypeElement t : metadata.getEventsAndStructs()) {
+                out.write("  Jfr" + t.name + "Struct,");
+            }
+            out.write("");
+            out.write("  MaxJfrStructId");
+            out.write("};");
+            out.write("");
+            out.write("typedef enum JfrEventId JfrEventId;");
+            out.write("typedef enum JfrStructId JfrStructId;");
+            out.write("");
+            out.write("#endif // INCLUDE_JFR");
+            out.write("#endif // JFRFILES_JFREVENTIDS_HPP");
+        }
+    }
+
+    private static void printJfrTypesHpp(Metadata metadata, File outputDirectory) throws Exception {
+        List<String> knownTypes = List.of("Thread", "StackTrace", "Class", "StackFrame");
+        try (Printer out = new Printer(outputDirectory, "jfrTypes.hpp")) {
+            out.write("#ifndef JFRFILES_JFRTYPES_HPP");
+            out.write("#define JFRFILES_JFRTYPES_HPP");
+            out.write("");
+            out.write("#include \"utilities/macros.hpp\"");
+            out.write("#if INCLUDE_JFR");
+            out.write("");
+            out.write("enum JfrTypeId {");
+            out.write("  TYPE_NONE             = 0,");
+            out.write("  TYPE_CLASS            = 20,");
+            out.write("  TYPE_STRING           = 21,");
+            out.write("  TYPE_THREAD           = 22,");
+            out.write("  TYPE_STACKTRACE       = 23,");
+            out.write("  TYPE_BYTES            = 24,");
+            out.write("  TYPE_EPOCHMILLIS      = 25,");
+            out.write("  TYPE_MILLIS           = 26,");
+            out.write("  TYPE_NANOS            = 27,");
+            out.write("  TYPE_TICKS            = 28,");
+            out.write("  TYPE_ADDRESS          = 29,");
+            out.write("  TYPE_PERCENTAGE       = 30,");
+            out.write("  TYPE_DUMMY,");
+            out.write("  TYPE_DUMMY_1,");
+            for (TypeElement type : metadata.getTypes()) {
+                if (!knownTypes.contains(type.name)) {
+                    out.write("  TYPE_" + type.name.toUpperCase() + ",");
+                }
+            }
+            out.write("");
+            out.write("  NUM_JFR_TYPES,");
+            out.write("  TYPES_END             = 255");
+            out.write("};");
+            out.write("");
+            out.write("enum ReservedEvent {");
+            out.write("  EVENT_METADATA,");
+            out.write("  EVENT_CHECKPOINT,");
+            out.write("  EVENT_BUFFERLOST,");
+            out.write("  NUM_RESERVED_EVENTS = TYPES_END");
+            out.write("};");
+            out.write("");
+            out.write("#endif // INCLUDE_JFR");
+            out.write("#endif // JFRFILES_JFRTYPES_HPP");
+          };
+    }
+
+    private static void printJfrEventClassesHpp(Metadata metadata, File outputDirectory) throws Exception {
+        try (Printer out = new Printer(outputDirectory, "jfrEventClasses.hpp")) {
+            out.write("#ifndef JFRFILES_JFREVENTCLASSES_HPP");
+            out.write("#define JFRFILES_JFREVENTCLASSES_HPP");
+            out.write("");
+            out.write("#include \"jfrfiles/jfrTypes.hpp\"");
+            out.write("#include \"jfr/utilities/jfrTypes.hpp\"");
+            out.write("#include \"utilities/macros.hpp\"");
+            out.write("#include \"utilities/ticks.hpp\"");
+            out.write("#if INCLUDE_JFR");
+            out.write("#include \"jfr/recorder/service/jfrEvent.hpp\"");
+            out.write("/*");
+            out.write(" * Each event class has an assert member function verify() which is invoked");
+            out.write(" * just before the engine writes the event and its fields to the data stream.");
+            out.write(" * The purpose of verify() is to ensure that all fields in the event are initialized");
+            out.write(" * and set before attempting to commit.");
+            out.write(" *");
+            out.write(" * We enforce this requirement because events are generally stack allocated and therefore");
+            out.write(" * *not* initialized to default values. This prevents us from inadvertently committing");
+            out.write(" * uninitialized values to the data stream.");
+            out.write(" *");
+            out.write(" * The assert message contains both the index (zero based) as well as the name of the field.");
+            out.write(" */");
+            out.write("");
+            printTypes(out, metadata, false);
+            out.write("");
+            out.write("");
+            out.write("#else // !INCLUDE_JFR");
+            out.write("");
+            out.write("class JfrEvent {");
+            out.write(" public:");
+            out.write("  JfrEvent() {}");
+            out.write("  void set_starttime(const Ticks&) const {}");
+            out.write("  void set_endtime(const Ticks&) const {}");
+            out.write("  bool should_commit() const { return false; }");
+            out.write("  static bool is_enabled() { return false; }");
+            out.write("  void commit() {}");
+            out.write("};");
+            out.write("");
+            printTypes(out, metadata, true);
+            out.write("");
+            out.write("");
+            out.write("#endif // INCLUDE_JFR");
+            out.write("#endif // JFRFILES_JFREVENTCLASSES_HPP");
+        }
+    }
+
+    private static void printTypes(Printer out, Metadata metadata, boolean empty) {
+        for (TypeElement t : metadata.getStructs()) {
+            if (empty) {
+                out.write("");
+                printEmptyType(out, t);
+            } else {
+                printType(out, t);
+            }
+            out.write("");
+        }
+        for (EventElement e : metadata.getEvents()) {
+            if (empty) {
+                printEmptyEvent(out, e);
+            } else {
+                printEvent(out, e);
+            }
+            out.write("");
+        }
+    }
+
+    private static void printEmptyEvent(Printer out, EventElement event) {
+        out.write("class Event" + event.name + " : public JfrEvent");
+        out.write("{");
+        out.write(" public:");
+        out.write("  Event" + event.name + "(EventStartTime ignore=TIMED) {}");
+        if (event.startTime) {
+            StringJoiner sj = new StringJoiner(",\n    ");
+            for (FieldElement f : event.fields) {
+                sj.add(f.getParameterType());
+            }
+            out.write("  Event" + event.name + "(");
+            out.write("    " + sj.toString() + ") { }");
+        }
+        for (FieldElement f : event.fields) {
+            out.write("  void set_" + f.name + "(" + f.getParameterType() + ") { }");
+        }
+        out.write("};");
+    }
+
+    private static void printEmptyType(Printer out, TypeElement t) {
+        out.write("struct JfrStruct" + t.name);
+        out.write("{");
+        out.write(" public:");
+        for (FieldElement f : t.fields) {
+            out.write("  void set_" + f.name + "(" + f.getParameterType() + ") { }");
+        }
+        out.write("};");
+    }
+
+    private static void printType(Printer out, TypeElement t) {
+        out.write("struct JfrStruct" + t.name);
+        out.write("{");
+        out.write(" private:");
+        for (FieldElement f : t.fields) {
+            printField(out, f);
+        }
+        out.write("");
+        out.write(" public:");
+        for (FieldElement f : t.fields) {
+            printTypeSetter(out, f);
+        }
+        out.write("");
+        printWriteData(out, t.fields);
+        out.write("};");
+        out.write("");
+    }
+
+    private static void printEvent(Printer out, EventElement event) {
+        out.write("class Event" + event.name + " : public JfrEvent<Event" + event.name + ">");
+        out.write("{");
+        out.write(" private:");
+        for (FieldElement f : event.fields) {
+            printField(out, f);
+        }
+        out.write("");
+        out.write(" public:");
+        out.write("  static const bool hasThread = " + event.thread + ";");
+        out.write("  static const bool hasStackTrace = " + event.stackTrace + ";");
+        out.write("  static const bool isInstant = " + !event.startTime + ";");
+        out.write("  static const bool hasCutoff = " + event.cutoff + ";");
+        out.write("  static const bool isRequestable = " + event.periodic + ";");
+        out.write("  static const JfrEventId eventId = Jfr" + event.name + "Event;");
+        out.write("");
+        out.write("  Event" + event.name + "(EventStartTime timing=TIMED) : JfrEvent<Event" + event.name + ">(timing) {}");
+        out.write("");
+        int index = 0;
+        for (FieldElement f : event.fields) {
+            out.write("  void set_" + f.name + "(" + f.getParameterType() + " " + f.getParameterName() + ") {");
+            out.write("    this->_" + f.name + " = " + f.getParameterName() + ";");
+            out.write("    DEBUG_ONLY(set_field_bit(" + index++ + "));");
+            out.write("  }");
+        }
+        out.write("");
+        printWriteData(out, event.fields);
+        out.write("");
+        out.write("  using JfrEvent<Event" + event.name + ">::commit; // else commit() is hidden by overloaded versions in this class");
+        printConstructor2(out, event);
+        printCommitMethod(out, event);
+        printVerify(out, event.fields);
+        out.write("};");
+    }
+
+    private static void printWriteData(Printer out, List<FieldElement> fields) {
+        out.write("  template <typename Writer>");
+        out.write("  void writeData(Writer& w) {");
+        for (FieldElement field : fields) {
+            if (field.struct) {
+                out.write("    _" + field.name + ".writeData(w);");
+            } else {
+                out.write("    w.write(_" + field.name + ");");
+            }
+        }
+        out.write("  }");
+    }
+
+    private static void printTypeSetter(Printer out, FieldElement field) {
+        out.write("  void set_" + field.name + "(" + field.getParameterType() + " new_value) { this->_" + field.name + " = new_value; }");
+    }
+
+    private static void printVerify(Printer out, List<FieldElement> fields) {
+        out.write("");
+        out.write("#ifdef ASSERT");
+        out.write("  void verify() const {");
+        int index = 0;
+        for (FieldElement f : fields) {
+            out.write("    assert(verify_field_bit(" + index++ + "), \"Attempting to write an uninitialized event field: %s\", \"_" + f.name + "\");");
+        }
+        out.write("  }");
+        out.write("#endif");
+    }
+
+    private static void printCommitMethod(Printer out, EventElement event) {
+        if (event.startTime) {
+            StringJoiner sj = new StringJoiner(",\n              ");
+            for (FieldElement f : event.fields) {
+                sj.add(f.getParameterType() + " " + f.name);
+            }
+            out.write("");
+            out.write("  void commit(" + sj.toString() + ") {");
+            out.write("    if (should_commit()) {");
+            for (FieldElement f : event.fields) {
+                out.write("      set_" + f.name + "(" + f.name + ");");
+            }
+            out.write("      commit();");
+            out.write("    }");
+            out.write("  }");
+        }
+        out.write("");
+        StringJoiner sj = new StringJoiner(",\n                     ");
+        if (event.startTime) {
+            sj.add("const Ticks& startTicks");
+            sj.add("const Ticks& endTicks");
+        }
+        for (FieldElement f : event.fields) {
+            sj.add(f.getParameterType() + " " + f.name);
+        }
+        out.write("  static void commit(" + sj.toString() + ") {");
+        out.write("    Event" + event.name + " me(UNTIMED);");
+        out.write("");
+        out.write("    if (me.should_commit()) {");
+        if (event.startTime) {
+            out.write("      me.set_starttime(startTicks);");
+            out.write("      me.set_endtime(endTicks);");
+        }
+        for (FieldElement f : event.fields) {
+            out.write("      me.set_" + f.name + "(" + f.name + ");");
+        }
+        out.write("      me.commit();");
+        out.write("    }");
+        out.write("  }");
+    }
+
+    private static void printConstructor2(Printer out, EventElement event) {
+        if (!event.startTime) {
+            out.write("");
+            out.write("");
+        }
+        if (event.startTime) {
+            out.write("");
+            out.write("  Event" + event.name + "(");
+            StringJoiner sj = new StringJoiner(",\n    ");
+            for (FieldElement f : event.fields) {
+                sj.add(f.getParameterType() + " " + f.name);
+            }
+            out.write("    " + sj.toString() + ") : JfrEvent<Event" + event.name + ">(TIMED) {");
+            out.write("    if (should_commit()) {");
+            for (FieldElement f : event.fields) {
+                out.write("      set_" + f.name + "(" + f.name + ");");
+            }
+            out.write("    }");
+            out.write("  }");
+        }
+    }
+
+    private static void printField(Printer out, FieldElement field) {
+        out.write("  " + field.getFieldType() + " _" + field.name + ";");
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/metadata/jfrSerializer.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_METADATA_JFRSERIALIZER_HPP
+#define SHARE_VM_JFR_METADATA_JFRSERIALIZER_HPP
+
+#include "memory/allocation.hpp"
+#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
+#include "jfrfiles/jfrTypes.hpp"
+
+/*
+ * A "type" in Jfr is a binary relation defined by enumerating a set of <key, value> ordered pairs:
+ *
+ * { <1, myvalue>, <2, mysecondvalue>, ... }
+ *
+ * The key should be a type relative unique id. A value is an instance of the type.
+ *
+ * By defining and registering a type, keys can be written to event fields and the
+ * framework will maintain the mapping to the corresponding value (if you register as below).
+ *
+ * Inherit JfrSerializer, create a CHeapObj instance and then use JfrSerializer::register_serializer(...) to register.
+ * Once registered, the ownership of the serializer instance is transferred to Jfr.
+ *
+ * How to register:
+ *
+ * bool register_serializer(JfrTypeId id, bool require_safepoint, bool permit_cache, JfrSerializer* serializer)
+ *
+ * The type identifiers are machine generated into an enum located in jfrfiles/jfrTypes.hpp (included).
+ *
+ *  enum JfrTypeId {
+ *    ...
+ *    TYPE_THREADGROUP,
+ *    TYPE_CLASSLOADER,
+ *    TYPE_METHOD,
+ *    TYPE_SYMBOL,
+ *    TYPE_THREADSTATE,
+ *    TYPE_INFLATECAUSE,
+ *    ...
+ *
+ * id                 this is the id of the type your are defining (see the enum above).
+ * require_safepoint  indicate if your type need to be evaluated and serialized under a safepoint.
+ * permit_cache       indicate if your type constants are stable to be cached.
+ *                    (implies the callback is invoked only once and the contents will be cached. Set this to true for static information).
+ * serializer         the serializer instance.
+ *
+ * See below for guidance about how to implement serialize().
+ *
+ */
+class JfrSerializer : public CHeapObj<mtTracing> {
+ public:
+  virtual ~JfrSerializer() {}
+  static bool register_serializer(JfrTypeId id, bool require_safepoint, bool permit_cache, JfrSerializer* serializer);
+  virtual void serialize(JfrCheckpointWriter& writer) = 0;
+};
+
+/*
+ * Defining serialize(JfrCheckpointWriter& writer):
+ *
+ *  Invoke writer.write_count(N) for the number of ordered pairs (cardinality) to be defined.
+ *
+ *  You then write each individual ordered pair, <key, value> ...
+ *
+ *  Here is a simple example, describing a type defining string constants:
+ *
+ *  void MyType::serialize(JfrCheckpointWriter& writer) {
+ *    const int nof_causes = ObjectSynchronizer::inflate_cause_nof;
+ *    writer.write_count(nof_causes);                           // write number of ordered pairs (mappings) to follow
+ *    for (int i = 0; i < nof_causes; i++) {
+ *      writer.write_key(i);                                    // write key
+ *      writer.write(ObjectSynchronizer::inflate_cause_name((ObjectSynchronizer::InflateCause)i)); // write value
+ *    }
+ *  }
+ *
+ * Note that values can be complex, and can also referer to other types.
+ *
+ * Please see jfr/recorder/checkpoint/types/jfrType.cpp for reference.
+ */
+
+#endif // SHARE_VM_JFR_METADATA_JFRSERIALIZER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/metadata/metadata.xml	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,1092 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ This code is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License version 2 only, as
+ published by the Free Software Foundation.
+
+ This code is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ version 2 for more details (a copy is included in the LICENSE file that
+ accompanied this code).
+
+ You should have received a copy of the GNU General Public License version
+ 2 along with this work; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ or visit www.oracle.com if you need additional information or have any
+ questions.
+
+-->
+
+<Metadata>
+
+  <Event name="ThreadStart" category="Java Application" label="Java Thread Start" thread="true" startTime="false">
+    <Field type="Thread" name="thread" label="Java Thread" />
+  </Event>
+
+  <Event name="ThreadEnd" category="Java Application" label="Java Thread End" thread="true" startTime="false">
+    <Field type="Thread" name="thread" label="Java Thread" />
+  </Event>
+
+  <Event name="ThreadSleep" category="Java Application" label="Java Thread Sleep" thread="true" stackTrace="true">
+    <Field type="long" contentType="millis" name="time" label="Sleep Time" />
+  </Event>
+
+  <Event name="ThreadPark" category="Java Application" label="Java Thread Park" thread="true" stackTrace="true">
+    <Field type="Class" name="parkedClass" label="Class Parked On" />
+    <Field type="long" contentType="millis" name="timeout" label="Park Timeout" />
+    <Field type="ulong" contentType="address" name="address" label="Address of Object Parked" relation="JavaMonitorAddress" />
+  </Event>
+
+  <Event name="JavaMonitorEnter" category="Java Application" label="Java Monitor Blocked" thread="true" stackTrace="true">
+    <Field type="Class" name="monitorClass" label="Monitor Class" />
+    <Field type="Thread" name="previousOwner" label="Previous Monitor Owner" />
+    <Field type="ulong" contentType="address" name="address" label="Monitor Address" relation="JavaMonitorAddress" />
+  </Event>
+
+  <Event name="JavaMonitorWait" category="Java Application" label="Java Monitor Wait" description="Waiting on a Java monitor" thread="true" stackTrace="true">
+    <Field type="Class" name="monitorClass" label="Monitor Class" description="Class of object waited on" />
+    <Field type="Thread" name="notifier" label="Notifier Thread" description="Notifying Thread" />
+    <Field type="long" contentType="millis" name="timeout" label="Timeout" description="Maximum wait time" />
+    <Field type="boolean" name="timedOut" label="Timed Out" description="Wait has been timed out" />
+    <Field type="ulong" contentType="address" name="address" label="Monitor Address" description="Address of object waited on" relation="JavaMonitorAddress" />
+  </Event>
+
+  <Event name="JavaMonitorInflate" category="Java Application" label="Java Monitor Inflated" thread="true" stackTrace="true">
+    <Field type="Class" name="monitorClass" label="Monitor Class" />
+    <Field type="ulong" contentType="address" name="address" label="Monitor Address" relation="JavaMonitorAddress" />
+    <Field type="InflateCause" name="cause" label="Monitor Inflation Cause" description="Cause of inflation" />
+  </Event>
+
+  <Event name="BiasedLockRevocation" category="Java Application" label="Biased Lock Revocation" description="Revoked bias of object" thread="true"
+    stackTrace="true">
+    <Field type="Class" name="lockClass" label="Lock Class" description="Class of object whose biased lock was revoked" />
+    <Field type="int" name="safepointId" label="Safepoint Identifier" relation="SafepointId" />
+    <Field type="Thread" name="previousOwner" label="Previous Owner" description="Thread owning the bias before revocation" />
+  </Event>
+
+  <Event name="BiasedLockSelfRevocation" category="Java Application" label="Biased Lock Self Revocation" description="Revoked bias of object biased towards own thread"
+    thread="true" stackTrace="true">
+    <Field type="Class" name="lockClass" label="Lock Class" description="Class of object whose biased lock was revoked" />
+  </Event>
+
+  <Event name="BiasedLockClassRevocation" category="Java Application" label="Biased Lock Class Revocation" description="Revoked biases for all instances of a class"
+    thread="true" stackTrace="true">
+    <Field type="Class" name="revokedClass" label="Revoked Class" description="Class whose biased locks were revoked" />
+    <Field type="boolean" name="disableBiasing" label="Disable Further Biasing" description="Whether further biasing for instances of this class will be allowed" />
+    <Field type="int" name="safepointId" label="Safepoint Identifier" relation="SafepointId" />
+  </Event>
+
+  <Event name="ReservedStackActivation" category="Java Virtual Machine, Runtime" label="Reserved Stack Activation"
+    description="Activation of Reserved Stack Area caused by stack overflow with ReservedStackAccess annotated method in call stack" thread="true" stackTrace="true"
+    startTime="false">
+    <Field type="Method" name="method" label="Java Method" />
+  </Event>
+
+  <Event name="ClassLoad" category="Java Virtual Machine, Class Loading" label="Class Load" thread="true" stackTrace="true">
+    <Field type="Class" name="loadedClass" label="Loaded Class" />
+    <Field type="ClassLoader" name="definingClassLoader" label="Defining Class Loader" />
+    <Field type="ClassLoader" name="initiatingClassLoader" label="Initiating Class Loader" />
+  </Event>
+
+  <Event name="ClassDefine" category="Java Virtual Machine, Class Loading" label="Class Define" thread="true" stackTrace="true" startTime="false">
+    <Field type="Class" name="definedClass" label="Defined Class" />
+    <Field type="ClassLoader" name="definingClassLoader" label="Defining Class Loader" />
+  </Event>
+
+  <Event name="ClassUnload" category="Java Virtual Machine, Class Loading" label="Class Unload" thread="true" startTime="false">
+    <Field type="Class" name="unloadedClass" label="Unloaded Class" />
+    <Field type="ClassLoader" name="definingClassLoader" label="Defining Class Loader" />
+  </Event>
+
+  <Event name="IntFlagChanged" category="Java Virtual Machine, Flag" label="Int Flag Changed" startTime="false">
+    <Field type="string" name="name" label="Name" />
+    <Field type="int" name="oldValue" label="Old Value" />
+    <Field type="int" name="newValue" label="New Value" />
+    <Field type="FlagValueOrigin" name="origin" label="Origin" />
+  </Event>
+
+  <Event name="UnsignedIntFlagChanged" category="Java Virtual Machine, Flag" label="Unsigned Int Flag Changed" startTime="false">
+    <Field type="string" name="name" label="Name" />
+    <Field type="uint" name="oldValue" label="Old Value" />
+    <Field type="uint" name="newValue" label="New Value" />
+    <Field type="FlagValueOrigin" name="origin" label="Origin" />
+  </Event>
+
+  <Event name="LongFlagChanged" category="Java Virtual Machine, Flag" label="Long Flag Changed" startTime="false">
+    <Field type="string" name="name" label="Name" />
+    <Field type="long" name="oldValue" label="Old Value" />
+    <Field type="long" name="newValue" label="New Value" />
+    <Field type="FlagValueOrigin" name="origin" label="Origin" />
+  </Event>
+
+  <Event name="UnsignedLongFlagChanged" category="Java Virtual Machine, Flag" label="Unsigned Long Flag Changed" startTime="false">
+    <Field type="string" name="name" label="Name" />
+    <Field type="ulong" name="oldValue" label="Old Value" />
+    <Field type="ulong" name="newValue" label="New Value" />
+    <Field type="FlagValueOrigin" name="origin" label="Origin" />
+  </Event>
+
+  <Event name="DoubleFlagChanged" category="Java Virtual Machine, Flag" label="Double Flag Changed" startTime="false">
+    <Field type="string" name="name" label="Name" />
+    <Field type="double" name="oldValue" label="Old Value" />
+    <Field type="double" name="newValue" label="New Value" />
+    <Field type="FlagValueOrigin" name="origin" label="Origin" />
+  </Event>
+
+  <Event name="BooleanFlagChanged" category="Java Virtual Machine, Flag" label="Boolean Flag Changed" startTime="false">
+    <Field type="string" name="name" label="Name" />
+    <Field type="boolean" name="oldValue" label="Old Value" />
+    <Field type="boolean" name="newValue" label="New Value" />
+    <Field type="FlagValueOrigin" name="origin" label="Origin" />
+  </Event>
+
+  <Event name="StringFlagChanged" category="Java Virtual Machine, Flag" label="String Flag Changed" startTime="false">
+    <Field type="string" name="name" label="Name" />
+    <Field type="string" name="oldValue" label="Old Value" />
+    <Field type="string" name="newValue" label="New Value" />
+    <Field type="FlagValueOrigin" name="origin" label="Origin" />
+  </Event>
+ 
+  <Type name="VirtualSpace">
+    <Field type="ulong" contentType="address" name="start" label="Start Address" description="Start address of the virtual space" />
+    <Field type="ulong" contentType="address" name="committedEnd" label="Committed End Address" description="End address of the committed memory for the virtual space" />
+    <Field type="ulong" contentType="bytes" name="committedSize" label="Committed Size" description="Size of the committed memory for the virtual space" />
+    <Field type="ulong" contentType="address" name="reservedEnd" label="Reserved End Address" description="End address of the reserved memory for the virtual space" />
+    <Field type="ulong" contentType="bytes" name="reservedSize" label="Reserved Size" description="Size of the reserved memory for the virtual space" />
+  </Type>
+  
+  <Type name="ObjectSpace">
+    <Field type="ulong" contentType="address" name="start" label="Start Address" description="Start address of the space" />
+    <Field type="ulong" contentType="address" name="end" label="End Address" description="End address of the space" />
+    <Field type="ulong" contentType="bytes" name="used" label="Used" description="Bytes allocated by objects in the space" />
+    <Field type="ulong" contentType="bytes" name="size" label="Size" description="Size of the space" />
+  </Type>
+  
+  <Event name="GCHeapSummary" category="Java Virtual Machine, GC, Heap" label="Heap Summary" startTime="false">
+    <Field type="uint" name="gcId" label="GC Identifier" relation="GcId" />
+    <Field type="GCWhen" name="when" label="When" />
+    <Field type="VirtualSpace" struct="true" name="heapSpace" label="Heap Space" />
+    <Field type="ulong" contentType="bytes" name="heapUsed" label="Heap Used" description="Bytes allocated by objects in the heap" />
+  </Event>
+ 
+  <Type name="MetaspaceSizes">
+    <Field type="ulong" contentType="bytes" name="committed" label="Committed" description="Committed memory for this space" />
+    <Field type="ulong" contentType="bytes" name="used" label="Used" description="Bytes allocated by objects in the space" />
+    <Field type="ulong" contentType="bytes" name="reserved" label="Reserved" description="Reserved memory for this space" />
+  </Type>
+ 
+  <Event name="MetaspaceSummary" category="Java Virtual Machine, GC, Heap" label="Metaspace Summary" startTime="false">
+    <Field type="uint" name="gcId" label="GC Identifier" relation="GcId" />
+    <Field type="GCWhen" name="when" label="When" />
+    <Field type="ulong" contentType="bytes" name="gcThreshold" label="GC Threshold" />
+    <Field type="MetaspaceSizes" struct="true" name="metaspace" label="Total" />
+    <Field type="MetaspaceSizes" struct="true" name="dataSpace" label="Data" />
+    <Field type="MetaspaceSizes" struct="true" name="classSpace" label="Class" />
+  </Event>
+
+  <Event name="MetaspaceGCThreshold" category="Java Virtual Machine, GC, Metaspace" label="Metaspace GC Threshold" startTime="false">
+    <Field type="ulong" contentType="bytes" name="oldValue" label="Old Value" />
+    <Field type="ulong" contentType="bytes" name="newValue" label="New Value" />
+    <Field type="GCThresholdUpdater" name="updater" label="Updater" />
+  </Event>
+
+  <Event name="MetaspaceAllocationFailure" category="Java Virtual Machine, GC, Metaspace" label="Metaspace Allocation Failure" startTime="false"
+    stackTrace="true">
+    <Field type="ClassLoader" name="classLoader" label="Class Loader" />
+    <Field type="boolean" name="anonymousClassLoader" label="Anonymous Class Loader" />
+    <Field type="ulong" contentType="bytes" name="size" label="Size" />
+    <Field type="MetadataType" name="metadataType" label="Metadata Type" />
+    <Field type="MetaspaceObjectType" name="metaspaceObjectType" label="Metaspace Object Type" />
+  </Event>
+
+  <Event name="MetaspaceOOM" category="Java Virtual Machine, GC, Metaspace" label="Metaspace Out of Memory" startTime="false" stackTrace="true">
+    <Field type="ClassLoader" name="classLoader" label="Class Loader" />
+    <Field type="boolean" name="anonymousClassLoader" label="Anonymous Class Loader" />
+    <Field type="ulong" contentType="bytes" name="size" label="Size" />
+    <Field type="MetadataType" name="metadataType" label="Metadata Type" />
+    <Field type="MetaspaceObjectType" name="metaspaceObjectType" label="Metaspace Object Type" />
+  </Event>
+
+  <Event name="MetaspaceChunkFreeListSummary" category="Java Virtual Machine, GC, Metaspace" label="Metaspace Chunk Free List Summary" startTime="false">
+    <Field type="uint" name="gcId" label="GC Identifier" relation="GcId" />
+    <Field type="GCWhen" name="when" label="When" />
+    <Field type="MetadataType" name="metadataType" label="Metadata Type" />
+    <Field type="ulong" name="specializedChunks" label="Specialized Chunks" />
+    <Field type="ulong" contentType="bytes" name="specializedChunksTotalSize" label="Specialized Chunks Total Size" />
+    <Field type="ulong" name="smallChunks" label="Small Chunks" />
+    <Field type="ulong" contentType="bytes" name="smallChunksTotalSize" label="Small Chunks Total Size" />
+    <Field type="ulong" name="mediumChunks" label="Medium Chunks" />
+    <Field type="ulong" contentType="bytes" name="mediumChunksTotalSize" label="Medium Chunks Total Size" />
+    <Field type="ulong" name="humongousChunks" label="Humongous Chunks" />
+    <Field type="ulong" contentType="bytes" name="humongousChunksTotalSize" label="Humongous Chunks Total Size" />
+  </Event>
+
+  <Event name="PSHeapSummary" category="Java Virtual Machine, GC, Heap" label="Parallel Scavenge Heap Summary" startTime="false">
+    <Field type="uint" name="gcId" label="GC Identifier" relation="GcId" />
+    <Field type="GCWhen" name="when" label="When" />
+    <Field type="VirtualSpace" struct="true" name="oldSpace" label="Old Space" />
+    <Field type="ObjectSpace" struct="true" name="oldObjectSpace" label="Old Object Space" />
+    <Field type="VirtualSpace" struct="true" name="youngSpace" label="Young Space" />
+    <Field type="ObjectSpace" struct="true" name="edenSpace" label="Eden Space" />
+    <Field type="ObjectSpace" struct="true" name="fromSpace" label="From Space" />
+    <Field type="ObjectSpace" struct="true" name="toSpace" label="To Space" />
+  </Event>
+
+  <Event name="G1HeapSummary" category="Java Virtual Machine, GC, Heap" label="G1 Heap Summary" startTime="false">
+    <Field type="uint" name="gcId" label="GC Identifier" relation="GcId" />
+    <Field type="GCWhen" name="when" label="When" />
+    <Field type="ulong" contentType="bytes" name="edenUsedSize" label="Eden Used Size" />
+    <Field type="ulong" contentType="bytes" name="edenTotalSize" label="Eden Total Size" />
+    <Field type="ulong" contentType="bytes" name="survivorUsedSize" label="Survivor Used Size" />
+    <Field type="uint" name="numberOfRegions" label="Number of Regions" />
+  </Event>
+
+  <Event name="GarbageCollection" category="Java Virtual Machine, GC, Collector" label="Garbage Collection" description="Garbage collection performed by the JVM">
+    <Field type="uint" name="gcId" label="GC Identifier" relation="GcId" />
+    <Field type="GCName" name="name" label="Name" description="The name of the Garbage Collector" />
+    <Field type="GCCause" name="cause" label="Cause" description="The reason for triggering this Garbage Collection" />
+    <Field type="Tickspan" name="sumOfPauses" label="Sum of Pauses" description="Sum of all the times in which Java execution was paused during the garbage collection" />
+    <Field type="Tickspan" name="longestPause" label="Longest Pause" description="Longest individual pause during the garbage collection" />
+  </Event>
+
+  <Event name="ParallelOldGarbageCollection" category="Java Virtual Machine, GC, Collector" label="Parallel Old Garbage Collection"
+    description="Extra information specific to Parallel Old Garbage Collections">
+    <Field type="uint" name="gcId" label="GC Identifier" relation="GcId" />
+    <Field type="ulong" contentType="address" name="densePrefix" label="Dense Prefix" description="The address of the dense prefix, used when compacting" />
+  </Event>
+
+  <Event name="YoungGarbageCollection" category="Java Virtual Machine, GC, Collector" label="Young Garbage Collection" description="Extra information specific to Young Garbage Collections">
+    <Field type="uint" name="gcId" label="GC Identifier" relation="GcId" />
+    <Field type="uint" name="tenuringThreshold" label="Tenuring Threshold" />
+  </Event>
+
+  <Event name="OldGarbageCollection" category="Java Virtual Machine, GC, Collector" label="Old Garbage Collection" description="Extra information specific to Old Garbage Collections">
+    <Field type="uint" name="gcId" label="GC Identifier" relation="GcId" />
+  </Event>
+
+  <Event name="G1GarbageCollection" category="Java Virtual Machine, GC, Collector" label="G1 Garbage Collection" description="Extra information specific to G1 Garbage Collections">
+    <Field type="uint" name="gcId" label="GC Identifier" relation="GcId" />
+    <Field type="G1YCType" name="type" label="Type" />
+  </Event>
+
+  <Event name="G1MMU" category="Java Virtual Machine, GC, Detailed" label="G1 MMU Information" startTime="false">
+    <Field type="uint" name="gcId" label="GC Identifier" relation="GcId" />
+    <Field type="long" contentType="millis" name="timeSlice" label="Time Slice" description="Time slice used to calculate MMU" />
+    <Field type="long" contentType="millis" name="gcTime" label="GC Time" description="Time stopped because of GC during last time slice" />
+    <Field type="long" contentType="millis" name="pauseTarget" label="Pause Target" description="Max time allowed to be spent on GC during last time slice" />
+  </Event>
+
+  <Event name="EvacuationInformation" category="Java Virtual Machine, GC, Detailed" label="Evacuation Information" startTime="false">
+    <Field type="uint" name="gcId" label="GC Identifier" relation="GcId" />
+    <Field type="uint" name="cSetRegions" label="Collection Set Regions" />
+    <Field type="ulong" contentType="bytes" name="cSetUsedBefore" label="Collection Set Before" description="Memory usage before GC in the collection set regions" />
+    <Field type="ulong" contentType="bytes" name="cSetUsedAfter" label="Collection Set After" description="Memory usage after GC in the collection set regions" />
+    <Field type="uint" name="allocationRegions" label="Allocation Regions" description="Regions chosen as allocation regions during evacuation (includes survivors and old space regions)" />
+    <Field type="ulong" contentType="bytes" name="allocationRegionsUsedBefore" label="Allocation Regions Before" description="Memory usage before GC in allocation regions" />
+    <Field type="ulong" contentType="bytes" name="allocationRegionsUsedAfter" label="Allocation Regions After" description="Memory usage after GC in allocation regions" />
+    <Field type="ulong" contentType="bytes" name="bytesCopied" label="Bytes Copied" />
+    <Field type="uint" name="regionsFreed" label="Regions Freed" />
+  </Event>
+
+  <Event name="GCReferenceStatistics" category="Java Virtual Machine, GC, Reference" label="GC Reference Statistics" startTime="false"
+    description="Total count of processed references during GC">
+    <Field type="uint" name="gcId" label="GC Identifier" relation="GcId" />
+    <Field type="ReferenceType" name="type" label="Type" />
+    <Field type="ulong" name="count" label="Total Count" />
+  </Event>
+
+  <Type name="CopyFailed">
+    <Field type="ulong" name="objectCount" label="Object Count" />
+    <Field type="ulong" contentType="bytes" name="firstSize" label="First Failed Object Size" />
+    <Field type="ulong" contentType="bytes" name="smallestSize" label="Smallest Failed Object Size" />
+    <Field type="ulong" contentType="bytes" name="totalSize" label="Total Object Size" />
+  </Type>
+
+  <Event name="ObjectCountAfterGC" category="Java Virtual Machine, GC, Detailed" startTime="false" label="Object Count after GC">
+    <Field type="uint" name="gcId" label="GC Identifier" relation="GcId" />
+    <Field type="Class" name="objectClass" label="Object Class" />
+    <Field type="long" name="count" label="Count" />
+    <Field type="ulong" contentType="bytes" name="totalSize" label="Total Size" />
+  </Event>
+
+  <Type name="G1EvacuationStatistics">
+    <Field type="uint" name="gcId" label="GC Identifier" relation="GcId" />
+    <Field type="ulong" contentType="bytes" name="allocated" label="Allocated" description="Total memory allocated by PLABs" />
+    <Field type="ulong" contentType="bytes" name="wasted" label="Wasted" description="Total memory wasted within PLABs due to alignment or refill" />
+    <Field type="ulong" contentType="bytes" name="used" label="Used" description="Total memory occupied by objects within PLABs" />
+    <Field type="ulong" contentType="bytes" name="undoWaste" label="Undo Wasted" description="Total memory wasted due to allocation undo within PLABs" />
+    <Field type="ulong" contentType="bytes" name="regionEndWaste" label="Region End Wasted" description="Total memory wasted at the end of regions due to refill" />
+    <Field type="uint" contentType="bytes" name="regionsRefilled" label="Region Refills" description="Total memory wasted at the end of regions due to refill" />
+    <Field type="ulong" contentType="bytes" name="directAllocated" label="Allocated (direct)" description="Total memory allocated using direct allocation outside of PLABs" />
+    <Field type="ulong" contentType="bytes" name="failureUsed" label="Used (failure)" description="Total memory occupied by objects in regions where evacuation failed" />
+    <Field type="ulong" contentType="bytes" name="failureWaste" label="Wasted (failure)" description="Total memory left unused in regions where evacuation failed" />
+  </Type>
+
+  <Event name="G1EvacuationYoungStatistics" category="Java Virtual Machine, GC, Detailed" label="G1 Evacuation Statistics for Young" startTime="false"
+    description="Memory related evacuation statistics during GC for the young generation">
+    <Field type="G1EvacuationStatistics" struct="true" name="statistics" label="Evacuation Statistics" />
+  </Event>
+
+  <Event name="G1EvacuationOldStatistics" category="Java Virtual Machine, GC, Detailed" label="G1 Evacuation Memory Statistics for Old" startTime="false"
+    description="Memory related evacuation statistics during GC for the old generation">
+    <Field type="G1EvacuationStatistics" struct="true" name="statistics" label="Evacuation Statistics" />
+  </Event>
+
+  <Event name="G1BasicIHOP" category="Java Virtual Machine, GC, Detailed" label="G1 Basic IHOP Statistics" startTime="false"
+    description="Basic statistics related to current IHOP calculation">
+    <Field type="uint" name="gcId" label="GC Identifier" relation="GcId" />
+    <Field type="ulong" contentType="bytes" name="threshold" label="Current IHOP Threshold" description="Current IHOP threshold" />
+    <Field type="float" contentType="percentage" name="thresholdPercentage" label="Current IHOP Threshold" description="Current IHOP threshold in percent of old generation" />
+    <Field type="ulong" contentType="bytes" name="targetOccupancy" label="Target Occupancy" description="Target old generation occupancy to reach at the start of mixed GC" />
+    <Field type="ulong" contentType="bytes" name="currentOccupancy" label="Current Occupancy" description="Current old generation occupancy" />
+    <Field type="ulong" contentType="bytes" name="recentMutatorAllocationSize" label="Recent Mutator Allocation Size"
+      description="Mutator allocation during mutator operation in the most recent interval" />
+    <Field type="long" contentType="millis" name="recentMutatorDuration" label="Recent Mutator Duration" description="Time the mutator ran in the most recent interval" />
+    <Field type="double" name="recentAllocationRate" label="Recent Allocation Rate" description="Allocation rate of the mutator in the most recent interval in bytes/second" />
+    <Field type="long" contentType="millis" name="lastMarkingDuration" label="Last Marking Duration" description="Last time from the end of the last initial mark to the first mixed GC" />
+  </Event>
+
+  <Event name="G1AdaptiveIHOP" category="Java Virtual Machine, GC, Detailed" label="G1 Adaptive IHOP Statistics" startTime="false"
+    description="Statistics related to current adaptive IHOP calculation">
+    <Field type="uint" name="gcId" label="GC Identifier" relation="GcId" />
+    <Field type="ulong" contentType="bytes" name="threshold" label="Threshold" description="Current IHOP Threshold" />
+    <Field type="float" contentType="percentage" name="thresholdPercentage" label="Threshold" description="Current IHOP threshold in percent of the internal target occupancy" />
+    <Field type="ulong" contentType="bytes" name="ihopTargetOccupancy" label="IHOP Target Occupancy" description="Internal target old generation occupancy to reach at the start of mixed GC" />
+    <Field type="ulong" contentType="bytes" name="currentOccupancy" label="Current Occupancy" description="Current old generation occupancy" />
+    <Field type="ulong" contentType="bytes" name="additionalBufferSize" label="Additional Buffer" description="Additional buffer size" experimental="true" />
+    <Field type="double" name="predictedAllocationRate" label="Predicted Allocation Rate" description="Current predicted allocation rate for the mutator in bytes/second" />
+    <Field type="long" contentType="millis" name="predictedMarkingDuration" label="Predicted Marking Duration"
+      description="Current predicted time from the end of the last initial mark to the first mixed GC" />
+    <Field type="boolean" name="predictionActive" label="Prediction Active" description="Indicates whether the adaptive IHOP prediction is active" />
+  </Event>
+
+  <Event name="PromoteObjectInNewPLAB" category="Java Virtual Machine, GC, Detailed" label="Promotion in new PLAB"
+    description="Object survived scavenge and was copied to a new Promotion Local Allocation Buffer (PLAB). Supported GCs are Parallel Scavange, G1 and CMS with Parallel New. Due to promotion being done in parallel an object might be reported multiple times as the GC threads race to copy all objects."
+    thread="true" stackTrace="false" startTime="false">
+    <Field type="uint" name="gcId" label="GC Identifier" relation="GcId" description="Identifier signifying GC during which the object was promoted" />
+    <Field type="Class" name="objectClass" label="Object Class" description="Class of promoted object" />
+    <Field type="ulong" contentType="bytes" name="objectSize" label="Object Size" description="Size of promoted object" />
+    <Field type="uint" name="tenuringAge" label="Object Tenuring Age"
+      description="Tenuring age of a surviving object before being copied. The tenuring age of an object is a value between 0-15 and is incremented each scavange the object survives. Newly allocated objects have tenuring age 0." />
+    <Field type="boolean" name="tenured" label="Tenured" description="True if object was promoted to Old space, otherwise the object was aged and copied to a Survivor space" />
+    <Field type="ulong" contentType="bytes" name="plabSize" label="PLAB Size" description="Size of the allocated PLAB to which the object was copied" />
+  </Event>
+
+  <Event name="PromoteObjectOutsidePLAB" category="Java Virtual Machine, GC, Detailed" label="Promotion outside PLAB"
+    description="Object survived scavenge and was copied directly to the heap. Supported GCs are Parallel Scavange, G1 and CMS with Parallel New. Due to promotion being done in parallel an object might be reported multiple times as the GC threads race to copy all objects."
+    thread="true" stackTrace="false" startTime="false">
+    <Field type="uint" name="gcId" label="GC Identifier" relation="GcId" description="Identifier signifying GC during which the object was promoted" />
+    <Field type="Class" name="objectClass" label="Object Class" description="Class of promoted object" />
+    <Field type="ulong" contentType="bytes" name="objectSize" label="Object Size" description="Size of promoted object" />
+    <Field type="uint" name="tenuringAge" label="Object Tenuring Age"
+      description="Tenuring age of a surviving object before being copied. The tenuring age of an object is a value between 0-15 and is incremented each scavange the object survives. Newly allocated objects have tenuring age 0." />
+    <Field type="boolean" name="tenured" label="Tenured" description="True if object was promoted to Old space, otherwise the object was aged and copied to a Survivor space" />
+  </Event>
+
+  <Event name="PromotionFailed" category="Java Virtual Machine, GC, Detailed" label="Promotion Failed" startTime="false" description="Promotion of an object failed">
+    <Field type="uint" name="gcId" label="GC Identifier" relation="GcId" />
+    <Field type="CopyFailed" struct="true" name="promotionFailed" label="Promotion Failed Data" />
+    <Field type="Thread" name="thread" label="Running thread" />
+  </Event>
+
+  <Event name="EvacuationFailed" category="Java Virtual Machine, GC, Detailed" label="Evacuation Failed" startTime="false" description="Evacuation of an object failed">
+    <Field type="uint" name="gcId" label="GC Identifier" relation="GcId" />
+    <Field type="CopyFailed" struct="true" name="evacuationFailed" label="Evacuation Failed Data" />
+  </Event>
+
+  <Event name="ConcurrentModeFailure" category="Java Virtual Machine, GC, Detailed" label="Concurrent Mode Failure" startTime="false" description="Concurrent Mode failed">
+    <Field type="uint" name="gcId" label="GC Identifier" relation="GcId" />
+  </Event>
+
+  <Event name="GCPhasePause" category="Java Virtual Machine, GC, Phases" label="GC Phase Pause" thread="true">
+    <Field type="uint" name="gcId" label="GC Identifier" relation="GcId" />
+    <Field type="string" name="name" label="Name" />
+  </Event>
+
+  <Event name="GCPhasePauseLevel1" category="Java Virtual Machine, GC, Phases" label="GC Phase Pause Level 1" thread="true">
+    <Field type="uint" name="gcId" label="GC Identifier" relation="GcId" />
+    <Field type="string" name="name" label="Name" />
+  </Event>
+
+  <Event name="GCPhasePauseLevel2" category="Java Virtual Machine, GC, Phases" label="GC Phase Pause Level 2" thread="true">
+    <Field type="uint" name="gcId" label="GC Identifier" relation="GcId" />
+    <Field type="string" name="name" label="Name" />
+  </Event>
+
+  <Event name="GCPhasePauseLevel3" category="Java Virtual Machine, GC, Phases" label="GC Phase Pause Level 3" thread="true">
+    <Field type="uint" name="gcId" label="GC Identifier" relation="GcId" />
+    <Field type="string" name="name" label="Name" />
+  </Event>
+
+  <Event name="GCPhasePauseLevel4" category="Java Virtual Machine, GC, Phases" label="GC Phase Pause Level 4" thread="true">
+    <Field type="uint" name="gcId" label="GC Identifier" relation="GcId" />
+    <Field type="string" name="name" label="Name" />
+  </Event>
+
+  <Event name="GCPhaseConcurrent" category="Java Virtual Machine, GC, Phases" label="GC Phase Concurrent" thread="true">
+    <Field type="uint" name="gcId" label="GC Identifier" relation="GcId" />
+    <Field type="string" name="name" label="Name" />
+  </Event>
+
+  <Event name="AllocationRequiringGC" category="Java Virtual Machine, GC, Detailed" label="Allocation Requiring GC" thread="true" stackTrace="true"
+    startTime="false">
+    <Field type="uint" name="gcId" label="Pending GC Identifier" relation="GcId" />
+    <Field type="ulong" contentType="bytes" name="size" label="Allocation Size" />
+  </Event>
+
+  <Event name="TenuringDistribution" category="Java Virtual Machine, GC, Detailed" label="Tenuring Distribution" startTime="false">
+    <Field type="uint" name="gcId" label="GC Identifier" relation="GcId" />
+    <Field type="uint" name="age" label="Age" />
+    <Field type="ulong" contentType="bytes" name="size" label="Size" />
+  </Event>
+
+  <Event name="G1HeapRegionTypeChange" category="Java Virtual Machine, GC, Detailed" label="G1 Heap Region Type Change" description="Information about a G1 heap region type change"
+    startTime="false">
+    <Field type="uint" name="index" label="Index" />
+    <Field type="G1HeapRegionType" name="from" label="From" />
+    <Field type="G1HeapRegionType" name="to" label="To" />
+    <Field type="ulong" contentType="address" name="start" label="Start" />
+    <Field type="ulong" contentType="bytes" name="used" label="Used" />
+  </Event>
+
+  <Event name="Compilation" category="Java Virtual Machine, Compiler" label="Compilation" thread="true">
+    <Field type="Method" name="method" label="Java Method" />
+    <Field type="uint" name="compileId" label="Compilation Identifier" relation="CompileId" />
+    <Field type="ushort" name="compileLevel" label="Compilation Level" />
+    <Field type="boolean" name="succeded" label="Succeeded" />
+    <Field type="boolean" name="isOsr" label="On Stack Replacement" />
+    <Field type="ulong" contentType="bytes" name="codeSize" label="Compiled Code Size" />
+    <Field type="ulong" contentType="bytes" name="inlinedBytes" label="Inlined Code Size" />
+  </Event>
+
+  <Event name="CompilerPhase" category="Java Virtual Machine, Compiler" label="Compiler Phase" thread="true" >
+    <Field type="CompilerPhaseType" name="phase" label="Compile Phase" />
+    <Field type="uint" name="compileId" label="Compilation Identifier" relation="CompileId" />
+    <Field type="ushort" name="phaseLevel" label="Phase Level" />
+  </Event>
+
+  <Event name="CompilationFailure" category="Java Virtual Machine, Compiler" label="Compilation Failure" thread="true"  startTime="false">
+    <Field type="string" name="failureMessage" label="Failure Message" />
+    <Field type="uint" name="compileId" label="Compilation Identifier" relation="CompileId" />
+  </Event>
+  
+  <Type name="CalleeMethod">
+    <Field type="string" name="type" label="Class" />
+    <Field type="string" name="name" label="Method Name" />
+    <Field type="string" name="descriptor" label="Method Descriptor" />
+  </Type>
+
+  <Event name="CompilerInlining" category="Java Virtual Machine, Compiler, Optimization" label="Method Inlining" thread="true" startTime="false">
+    <Field type="uint" name="compileId" label="Compilation Identifier" relation="CompileId" />
+    <Field type="Method" name="caller" label="Caller Method" />
+    <Field type="CalleeMethod" name="callee" struct="true" label="Callee Method" />
+    <Field type="boolean" name="succeeded" label="Succeeded" />
+    <Field type="string" name="message" label="Message" />
+    <Field type="int" name="bci" label="Byte Code Index" />
+  </Event>
+
+  <Event name="SweepCodeCache" category="Java Virtual Machine, Code Sweeper" label="Sweep Code Cache" thread="true" >
+    <Field type="int" name="sweepId" label="Sweep Identifier" relation="SweepId" />
+    <Field type="uint" name="sweptCount" label="Methods Swept" />
+    <Field type="uint" name="flushedCount" label="Methods Flushed" />
+    <Field type="uint" name="zombifiedCount" label="Methods Zombified" />
+  </Event>
+
+  <Event name="CodeCacheFull" category="Java Virtual Machine, Code Cache" label="Code Cache Full" thread="true" startTime="false">
+    <Field type="CodeBlobType" name="codeBlobType" label="Code Heap" />
+    <Field type="ulong" contentType="address" name="startAddress" label="Start Address" />
+    <Field type="ulong" contentType="address" name="commitedTopAddress" label="Commited Top" />
+    <Field type="ulong" contentType="address" name="reservedTopAddress" label="Reserved Top" />
+    <Field type="int" name="entryCount" label="Entries" />
+    <Field type="int" name="methodCount" label="Methods" />
+    <Field type="int" name="adaptorCount" label="Adaptors" />
+    <Field type="ulong" contentType="bytes" name="unallocatedCapacity" label="Unallocated" />
+    <Field type="int" name="fullCount" label="Full Count" />
+  </Event>
+
+  <Event name="SafepointBegin" category="Java Virtual Machine, Runtime, Safepoint" label="Safepoint Begin" description="Safepointing begin" thread="true">
+    <Field type="int" name="safepointId" label="Safepoint Identifier" relation="SafepointId" />
+    <Field type="int" name="totalThreadCount" label="Total Threads" description="The total number of threads at the start of safe point" />
+    <Field type="int" name="jniCriticalThreadCount" label="JNI Critical Threads" description="The number of threads in JNI critical sections" />
+  </Event>
+
+  <Event name="SafepointStateSynchronization" category="Java Virtual Machine, Runtime, Safepoint" label="Safepoint State Synchronization" description="Synchronize run state of threads"
+    thread="true">
+    <Field type="int" name="safepointId" label="Safepoint Identifier" relation="SafepointId" />
+    <Field type="int" name="initialThreadCount" label="Initial Threads" description="The number of threads running at the beginning of state check" />
+    <Field type="int" name="runningThreadCount" label="Running Threads" description="The number of threads still running" />
+    <Field type="int" name="iterations" label="Iterations" description="Number of state check iterations" />
+  </Event>
+
+  <Event name="SafepointWaitBlocked" category="Java Virtual Machine, Runtime, Safepoint" label="Safepoint Wait Blocked" description="Safepointing begin waiting on running threads to block"
+    thread="true">
+    <Field type="int" name="safepointId" label="Safepoint Identifier" relation="SafepointId" />
+    <Field type="int" name="runningThreadCount" label="Running Threads" description="The number running of threads wait for safe point" />
+  </Event>
+
+  <Event name="SafepointCleanup" category="Java Virtual Machine, Runtime, Safepoint" label="Safepoint Cleanup" description="Safepointing begin running cleanup tasks"
+    thread="true">
+    <Field type="int" name="safepointId" label="Safepoint Identifier" relation="SafepointId" />
+  </Event>
+
+  <Event name="SafepointCleanupTask" category="Java Virtual Machine, Runtime, Safepoint" label="Safepoint Cleanup Task" description="Safepointing begin running cleanup tasks"
+    thread="true">
+    <Field type="int" name="safepointId" label="Safepoint Identifier" relation="SafepointId" />
+    <Field type="string" name="name" label="Task Name" description="The task name" />
+  </Event>
+
+  <Event name="SafepointEnd" category="Java Virtual Machine, Runtime, Safepoint" label="Safepoint End" description="Safepointing end" thread="true">
+    <Field type="int" name="safepointId" label="Safepoint Identifier" relation="SafepointId" />
+  </Event>
+
+  <Event name="ExecuteVMOperation" category="Java Virtual Machine, Runtime" label="VM Operation" description="Execution of a VM Operation" thread="true">
+    <Field type="VMOperationType" name="operation" label="Operation" />
+    <Field type="boolean" name="safepoint" label="At Safepoint" description="If the operation occured at a safepoint" />
+    <Field type="boolean" name="blocking" label="Caller Blocked" description="If the calling thread was blocked until the operation was complete" />
+    <Field type="Thread" name="caller" label="Caller" transition="from"
+      description="Thread requesting operation. If non-blocking, will be set to 0 indicating thread is unknown" />
+    <Field type="int" name="safepointId" label="Safepoint Identifier" description="The safepoint (if any) under which this operation was completed"
+      relation="SafepointId" />
+  </Event>
+
+  <Event name="Shutdown" category="Java Virtual Machine, Runtime" label="VM Shutdown" description="VM shutting down" thread="true" stackTrace="true"
+    startTime="false">
+    <Field type="string" name="reason" label="Reason" description="Reason for VM shutdown" />
+  </Event>
+
+  <Event name="ObjectAllocationInNewTLAB" category="Java Application" label="Allocation in new TLAB" description="Allocation in new Thread Local Allocation Buffer"
+    thread="true" stackTrace="true" startTime="false">
+    <Field type="Class" name="objectClass" label="Object Class" description="Class of allocated object" />
+    <Field type="ulong" contentType="bytes" name="allocationSize" label="Allocation Size" />
+    <Field type="ulong" contentType="bytes" name="tlabSize" label="TLAB Size" />
+  </Event>
+
+  <Event name="ObjectAllocationOutsideTLAB" category="Java Application" label="Allocation outside TLAB" description="Allocation outside Thread Local Allocation Buffers"
+    thread="true" stackTrace="true" startTime="false">
+    <Field type="Class" name="objectClass" label="Object Class" description="Class of allocated object" />
+    <Field type="ulong" contentType="bytes" name="allocationSize" label="Allocation Size" />
+  </Event>
+
+  <Event name="OldObjectSample" category="Java Application" label="Old Object Sample" description="A potential memory leak" stackTrace="true" thread="true"
+    startTime="false" cutoff="true">
+    <Field type="Ticks" name="allocationTime" label="Allocation Time" />
+    <Field type="OldObject" name="object" label="Object" />
+    <Field type="int" name="arrayElements" label="Array Elements" description="If the object is an array, the number of elements, or -1 if it is not an array" />
+    <Field type="OldObjectGcRoot" name="root" label="GC Root" />
+  </Event>
+
+  <Event name="DumpReason" category="Flight Recorder" label="Recording Reason" 
+         description="Who requested the recording and why" 
+         startTime="false">
+    <Field type="string" name="reason" label="Reason" description="Reason for writing recording data to disk" />
+    <Field type="int" name="recordingId" label="Recording Id" description="Id of the recording that triggered the dump, or -1 if it was not related to a recording" />
+  </Event>
+
+  <Event name="DataLoss" category="Flight Recorder" label="Data Loss" 
+         description="Data could not be copied out from a buffer, typically because of contention"
+         startTime="false">
+    <Field type="ulong" contentType="bytes" name="amount" label="Amount" description="Amount lost data" />
+    <Field type="ulong" contentType="bytes" name="total" label="Total" description="Total lost amount for thread" />
+  </Event>
+
+  <Event name="JVMInformation" category="Java Virtual Machine" label="JVM Information" 
+         description="Description of JVM and the Java application"
+         period="endChunk">
+    <Field type="string" name="jvmName" label="JVM Name" />
+    <Field type="string" name="jvmVersion" label="JVM Version" />
+    <Field type="string" name="jvmArguments" label="JVM Command Line Arguments" />
+    <Field type="string" name="jvmFlags" label="JVM Settings File Arguments" />
+    <Field type="string" name="javaArguments" label="Java Application Arguments" />
+    <Field type="long" contentType="epochmillis" name="jvmStartTime" label="JVM Start Time" />
+  </Event>
+
+  <Event name="OSInformation" category="Operating System" label="OS Information" period="endChunk">
+    <Field type="string" name="osVersion" label="OS Version" />
+  </Event>
+
+  <Event name="InitialSystemProperty" category="Java Virtual Machine" label="Initial System Property" description="System Property at JVM start" period="endChunk">
+    <Field type="string" name="key" label="Key" />
+    <Field type="string" name="value" label="Value" />
+  </Event>
+
+  <Event name="InitialEnvironmentVariable" category="Operating System" label="Initial Environment Variable" period="endChunk">
+    <Field type="string" name="key" label="Key" />
+    <Field type="string" name="value" label="Value" />
+  </Event>
+
+  <Event name="SystemProcess" category="Operating System" label="System Process" period="endChunk">
+    <Field type="string" name="pid" label="Process Identifier" />
+    <Field type="string" name="commandLine" label="Command Line" />
+  </Event>
+
+  <Event name="CPUInformation" category="Operating System, Processor" label="CPU Information" period="endChunk">
+    <Field type="string" name="cpu" label="Type" />
+    <Field type="string" name="description" label="Description" />
+    <Field type="uint" name="sockets" label="Sockets" />
+    <Field type="uint" name="cores" label="Cores" />
+    <Field type="uint" name="hwThreads" label="Hardware Threads" />
+  </Event>
+
+  <Event name="CPUTimeStampCounter" category="Operating System, Processor" label="CPU Time Stamp Counter" period="endChunk">
+    <Field type="boolean" name="fastTimeEnabled" label="Fast Time" />
+    <Field type="boolean" name="fastTimeAutoEnabled" label="Trusted Platform" />
+    <Field type="long" name="osFrequency" label="OS Frequency Per Second" />
+    <Field type="long" name="fastTimeFrequency" label="Fast Time Frequency per Second" />
+  </Event>
+
+  <Event name="CPULoad" category="Operating System, Processor" label="CPU Load" description="OS CPU Load" period="everyChunk">
+    <Field type="float" contentType="percentage" name="jvmUser" label="JVM User" />
+    <Field type="float" contentType="percentage" name="jvmSystem" label="JVM System" />
+    <Field type="float" contentType="percentage" name="machineTotal" label="Machine Total" />
+  </Event>
+
+  <Event name="ThreadCPULoad" category="Operating System, Processor" label="Thread CPU Load" period="everyChunk" thread="true">
+    <Field type="float" contentType="percentage" name="user" label="User Mode CPU Load" description="User mode thread CPU load" />
+    <Field type="float" contentType="percentage" name="system" label="System Mode CPU Load" description="System mode thread CPU load" />
+  </Event>
+
+  <Event name="ThreadContextSwitchRate" category="Operating System, Processor" label="Thread Context Switch Rate" period="everyChunk">
+    <Field type="float" name="switchRate" label="Switch Rate" description="Number of context switches per second" />
+  </Event>
+
+  <Event name="JavaThreadStatistics" category="Java Application, Statistics" label="Java Thread Statistics" period="everyChunk">
+    <Field type="long" name="activeCount" label="Active Threads" description="Number of live active threads including both daemon and non-daemon threads" />
+    <Field type="long" name="daemonCount" label="Daemon Threads" description="Number of live daemon threads" />
+    <Field type="long" name="accumulatedCount" label="Accumulated Threads" description="Number of threads created and also started since JVM start" />
+    <Field type="long" name="peakCount" label="Peak Threads" description="Peak live thread count since JVM start or when peak count was reset" />
+  </Event>
+
+  <Event name="ClassLoadingStatistics" category="Java Application, Statistics" label="Class Loading Statistics" period="everyChunk">
+    <Field type="long" name="loadedClassCount" label="Loaded Class Count" description="Number of classes loaded since JVM start" />
+    <Field type="long" name="unloadedClassCount" label="Unloaded Class Count" description="Number of classes unloaded since JVM start" />
+  </Event>
+
+  <Event name="ClassLoaderStatistics" category="Java Application, Statistics" label="Class Loader Statistics" period="everyChunk">
+    <Field type="ClassLoader" name="classLoader" label="Class Loader" />
+    <Field type="ClassLoader" name="parentClassLoader" label="Parent Class Loader" />
+    <Field type="ulong" contentType="address" name="classLoaderData" label="ClassLoaderData pointer" description="Pointer to the ClassLoaderData structure in the JVM" />
+    <Field type="long" name="classCount" label="Classes" description="Number of loaded classes" />
+    <Field type="ulong" contentType="bytes" name="chunkSize" label="Total Chunk Size" description="Total size of all allocated metaspace chunks (each chunk has several blocks)" />
+    <Field type="ulong" contentType="bytes" name="blockSize" label="Total Block Size" description="Total size of all allocated metaspace blocks (each chunk has several blocks)" />
+    <Field type="long" name="anonymousClassCount" label="Unsafe Anonymous Classes" description="Number of loaded classes to support invokedynamic" />
+    <Field type="ulong" contentType="bytes" name="anonymousChunkSize" label="Total Unsafe Anonymous Classes Chunk Size"
+      description="Total size of all allocated metaspace chunks for anonymous classes (each chunk has several blocks)" />
+    <Field type="ulong" contentType="bytes" name="anonymousBlockSize" label="Total Unsafe Anonymous Classes Block Size"
+      description="Total size of all allocated metaspace blocks for anonymous classes (each chunk has several blocks)" />
+  </Event>
+
+  <Event name="ThreadAllocationStatistics" category="Java Application, Statistics" label="Thread Allocation Statistics" period="everyChunk">
+    <Field type="ulong" contentType="bytes" name="allocated" label="Allocated" description="Approximate number of bytes allocated since thread start" />
+    <Field type="Thread" name="thread" label="Thread" />
+  </Event>
+
+  <Event name="PhysicalMemory" category="Operating System, Memory" label="Physical Memory" description="OS Physical Memory" period="everyChunk">
+    <Field type="ulong" contentType="bytes" name="totalSize" label="Total Size" description="Total amount of physical memory available to OS" />
+    <Field type="ulong" contentType="bytes" name="usedSize" label="Used Size" description="Total amount of physical memory in use" />
+  </Event>
+
+  <Event name="ExecutionSample" category="Java Virtual Machine, Profiling" label="Method Profiling Sample" description="Snapshot of a threads state"
+    period="everyChunk">
+    <Field type="Thread" name="sampledThread" label="Thread" />
+    <Field type="StackTrace" name="stackTrace" label="Stack Trace" />
+    <Field type="ThreadState" name="state" label="Thread State" />
+  </Event>
+
+  <Event name="NativeMethodSample" category="Java Virtual Machine, Profiling" label="Method Profiling Sample Native" description="Snapshot of a threads state when in native"
+    period="everyChunk">
+    <Field type="Thread" name="sampledThread" label="Thread" />
+    <Field type="StackTrace" name="stackTrace" label="Stack Trace" />
+    <Field type="ThreadState" name="state" label="Thread State" />
+  </Event>
+
+  <Event name="ThreadDump" category="Java Virtual Machine, Runtime" label="Thread Dump" period="everyChunk">
+    <Field type="string" name="result" label="Thread Dump" />
+  </Event>
+
+  <Event name="NativeLibrary" category="Java Virtual Machine, Runtime" label="Native Library" period="everyChunk">
+    <Field type="string" name="name" label="Name" />
+    <Field type="ulong" contentType="address" name="baseAddress" label="Base Address" description="Starting address of the module" />
+    <Field type="ulong" contentType="address" name="topAddress" label="Top Address" description="Ending address of the module" />
+  </Event>
+
+  <Event name="ModuleRequire" category="Java Virtual Machine, Runtime, Modules" label="Module Require" thread="false" period="everyChunk"
+    description="A directed edge representing a dependency">
+    <Field type="Module" name="source" label="Source Module" />
+    <Field type="Module" name="requiredModule" label="Required Module" />
+  </Event>
+
+  <Event name="ModuleExport" category="Java Virtual Machine, Runtime, Modules" label="Module Export" thread="false" period="everyChunk">
+    <Field type="Package" name="exportedPackage" label="Exported Package" />
+    <Field type="Module" name="targetModule" label="Target Module"
+      description="Module to which the package is qualifiedly exported.
+             If null, the package is unqualifiedly exported" />
+  </Event>
+
+  <Event name="CompilerStatistics" category="Java Virtual Machine, Compiler" label="Compiler Statistics" thread="false" period="everyChunk" startTime="false">
+    <Field type="int" name="compileCount" label="Compiled Methods" />
+    <Field type="int" name="bailoutCount" label="Bailouts" />
+    <Field type="int" name="invalidatedCount" label="Invalidated Compilations" />
+    <Field type="int" name="osrCompileCount" label="OSR Compilations" />
+    <Field type="int" name="standardCompileCount" label="Standard Compilations" />
+    <Field type="ulong" contentType="bytes" name="osrBytesCompiled" label="OSR Bytes Compiled" />
+    <Field type="ulong" contentType="bytes" name="standardBytesCompiled" label="Standard Bytes Compiled" />
+    <Field type="ulong" contentType="bytes" name="nmetodsSize" label="Compilation Resulting Size" />
+    <Field type="ulong" contentType="bytes" name="nmetodCodeSize" label="Compilation Resulting Code Size" />
+    <Field type="long" contentType="millis" name="peakTimeSpent" label="Peak Time" />
+    <Field type="long" contentType="millis" name="totalTimeSpent" label="Total time" />
+  </Event>
+
+  <Event name="CompilerConfiguration" category="Java Virtual Machine, Compiler" label="Compiler Configuration" thread="false" period="endChunk" startTime="false">
+    <Field type="int" name="threadCount" label="Thread Count" />
+    <Field type="boolean" name="tieredCompilation" label="Tiered Compilation" />
+  </Event>
+
+  <Event name="CodeCacheStatistics" category="Java Virtual Machine, Code Cache" label="Code Cache Statistics" thread="false" period="everyChunk" startTime="false">
+    <Field type="CodeBlobType" name="codeBlobType" label="Code Heap" />
+    <Field type="ulong" contentType="address" name="startAddress" label="Start Address" />
+    <Field type="ulong" contentType="address" name="reservedTopAddress" label="Reserved Top" />
+    <Field type="int" name="entryCount" label="Entries" />
+    <Field type="int" name="methodCount" label="Methods" />
+    <Field type="int" name="adaptorCount" label="Adaptors" />
+    <Field type="ulong" contentType="bytes" name="unallocatedCapacity" label="Unallocated" />
+    <Field type="int" name="fullCount" label="Full Count" />
+  </Event>
+
+  <Event name="CodeCacheConfiguration" category="Java Virtual Machine, Code Cache" label="Code Cache Configuration" thread="false" period="endChunk" startTime="false">
+    <Field type="ulong" contentType="bytes" name="initialSize" label="Initial Size" />
+    <Field type="ulong" contentType="bytes" name="reservedSize" label="Reserved Size" />
+    <Field type="ulong" contentType="bytes" name="nonNMethodSize" label="Non-nmethod Size" />
+    <Field type="ulong" contentType="bytes" name="profiledSize" label="Profiled Size" />
+    <Field type="ulong" contentType="bytes" name="nonProfiledSize" label="Non-profiled Size" />
+    <Field type="ulong" contentType="bytes" name="expansionSize" label="Expansion size" />
+    <Field type="ulong" contentType="bytes" name="minBlockLength" label="Minimum Block Length" />
+    <Field type="ulong" contentType="address" name="startAddress" label="Start Address" />
+    <Field type="ulong" contentType="address" name="reservedTopAddress" label="Reserved Top" />
+  </Event>
+
+  <Event name="CodeSweeperStatistics" category="Java Virtual Machine, Code Sweeper" label="Code Sweeper Statistics" thread="false" period="everyChunk" startTime="false">
+    <Field type="int" name="sweepCount" label="Sweeps" />
+    <Field type="int" name="methodReclaimedCount" label="Methods Reclaimed" />
+    <Field type="Tickspan" name="totalSweepTime" label="Time Spent Sweeping" />
+    <Field type="Tickspan" name="peakFractionTime" label="Peak Time Fraction Sweep" />
+    <Field type="Tickspan" name="peakSweepTime" label="Peak Time Full Sweep" />
+  </Event>
+
+  <Event name="CodeSweeperConfiguration" category="Java Virtual Machine, Code Sweeper" label="Code Sweeper Configuration" thread="false" period="endChunk" startTime="false">
+    <Field type="boolean" name="sweeperEnabled" label="Code Sweeper Enabled" />
+    <Field type="boolean" name="flushingEnabled" label="Code Cache Flushing Enabled" />
+  </Event>
+
+  <Event name="IntFlag" category="Java Virtual Machine, Flag" period="endChunk" label="Int Flag">
+    <Field type="string" name="name" label="Name" />
+    <Field type="int" name="value" label="Value" />
+    <Field type="FlagValueOrigin" name="origin" label="Origin" />
+  </Event>
+
+  <Event name="UnsignedIntFlag" category="Java Virtual Machine, Flag" period="endChunk" label="Unsigned Int Flag">
+    <Field type="string" name="name" label="Name" />
+    <Field type="uint" name="value" label="Value" />
+    <Field type="FlagValueOrigin" name="origin" label="Origin" />
+  </Event>
+
+  <Event name="LongFlag" category="Java Virtual Machine, Flag" period="endChunk" label="Long Flag">
+    <Field type="string" name="name" label="Name" />
+    <Field type="long" name="value" label="Value" />
+    <Field type="FlagValueOrigin" name="origin" label="Origin" />
+  </Event>
+
+  <Event name="UnsignedLongFlag" category="Java Virtual Machine, Flag" period="endChunk" label="Unsigned Long Flag">
+    <Field type="string" name="name" label="Name" />
+    <Field type="ulong" name="value" label="Value" />
+    <Field type="FlagValueOrigin" name="origin" label="Origin" />
+  </Event>
+
+  <Event name="DoubleFlag" category="Java Virtual Machine, Flag" period="endChunk" label="Double Flag">
+    <Field type="string" name="name" label="Name" />
+    <Field type="double" name="value" label="Value" />
+    <Field type="FlagValueOrigin" name="origin" label="Origin" />
+  </Event>
+
+  <Event name="BooleanFlag" category="Java Virtual Machine, Flag" period="endChunk" label="Boolean Flag">
+    <Field type="string" name="name" label="Name" />
+    <Field type="boolean" name="value" label="Value" />
+    <Field type="FlagValueOrigin" name="origin" label="Origin" />
+  </Event>
+
+  <Event name="StringFlag" category="Java Virtual Machine, Flag" period="endChunk" label="String Flag">
+    <Field type="string" name="name" label="Name" />
+    <Field type="string" name="value" label="Value" />
+    <Field type="FlagValueOrigin" name="origin" label="Origin" />
+  </Event>
+
+  <Event name="ObjectCount" category="Java Virtual Machine, GC, Detailed" startTime="false" period="everyChunk" label="Object Count">
+    <Field type="uint" name="gcId" label="GC Identifier" relation="GcId" />
+    <Field type="Class" name="objectClass" label="Object Class" />
+    <Field type="long" name="count" label="Count" />
+    <Field type="ulong" contentType="bytes" name="totalSize" label="Total Size" />
+  </Event>
+
+  <Event name="G1HeapRegionInformation" category="Java Virtual Machine, GC, Detailed" label="G1 Heap Region Information" description="Information about a specific heap region in the G1 GC"
+    period="everyChunk">
+    <Field type="uint" name="index" label="Index" />
+    <Field type="G1HeapRegionType" name="type" label="Type" />
+    <Field type="ulong" contentType="address" name="start" label="Start" />
+    <Field type="ulong" contentType="bytes" name="used" label="Used" />
+  </Event>
+
+  <Event name="GCConfiguration" category="Java Virtual Machine, GC, Configuration" label="GC Configuration" description="The configuration of the garbage collector"
+    period="endChunk">
+    <Field type="GCName" name="youngCollector" label="Young Garbage Collector" description="The garbage collector used for the young generation" />
+    <Field type="GCName" name="oldCollector" label="Old Garbage Collector" description="The garbage collector used for the old generation" />
+    <Field type="uint" name="parallelGCThreads" label="Parallel GC Threads" description="Number of parallel threads to use for garbage collection" />
+    <Field type="uint" name="concurrentGCThreads" label="Concurrent GC Threads" description="Number of concurrent threads to use for garbage collection" />
+    <Field type="boolean" name="usesDynamicGCThreads" label="Uses Dynamic GC Threads" description="Whether a dynamic number of GC threads are used or not" />
+    <Field type="boolean" name="isExplicitGCConcurrent" label="Concurrent Explicit GC" description="Whether System.gc() is concurrent or not" />
+    <Field type="boolean" name="isExplicitGCDisabled" label="Disabled Explicit GC" description="Whether System.gc() will cause a garbage collection or not" />
+    <Field type="long" contentType="millis" name="pauseTarget" label="Pause Target" description="Target for GC pauses" />
+    <Field type="uint" name="gcTimeRatio" label="GC Time Ratio" description="Target for runtime vs garbage collection time" />
+  </Event>
+
+  <Event name="GCSurvivorConfiguration" category="Java Virtual Machine, GC, Configuration" label="GC Survivor Configuration"
+    description="The configuration of the survivors of garbage collection" period="endChunk">
+    <Field type="ubyte" name="maxTenuringThreshold" label="Maximum Tenuring Threshold" description="Upper limit for the age of how old objects to keep in the survivor area" />
+    <Field type="ubyte" name="initialTenuringThreshold" label="Initial Tenuring Threshold" description="Initial age limit for how old objects to keep in survivor area" />
+  </Event>
+
+  <Event name="GCTLABConfiguration" category="Java Virtual Machine, GC, Configuration" label="TLAB Configuration"
+    description="The configuration of the Thread Local Allocation Buffers (TLABs)" period="endChunk">
+    <Field type="boolean" name="usesTLABs" label="TLABs Used" description="If Thread Local Allocation Buffers (TLABs) are in use" />
+    <Field type="ulong" contentType="bytes" name="minTLABSize" label="Minimum TLAB Size" />
+    <Field type="ulong" contentType="bytes" name="tlabRefillWasteLimit" label="TLAB Refill Waste Limit" />
+  </Event>
+
+  <Event name="GCHeapConfiguration" category="Java Virtual Machine, GC, Configuration" label="GC Heap Configuration" description="The configuration of the garbage collected heap"
+    period="endChunk">
+    <Field type="ulong" contentType="bytes" name="minSize" label="Minimum Heap Size" />
+    <Field type="ulong" contentType="bytes" name="maxSize" label="Maximum Heap Size" />
+    <Field type="ulong" contentType="bytes" name="initialSize" label="Initial Heap Size" />
+    <Field type="boolean" name="usesCompressedOops" label="If Compressed Oops Are Used" description="If compressed Oops (Ordinary Object Pointers) are enabled" />
+    <Field type="NarrowOopMode" name="compressedOopsMode" label="Compressed Oops Mode" description="The kind of compressed oops being used" />
+    <Field type="ulong" contentType="bytes" name="objectAlignment" label="Object Alignment" description="Object alignment (in bytes) on the heap" />
+    <Field type="ubyte" name="heapAddressBits" label="Heap Address Size" description="Heap Address Size (in bits)" />
+  </Event>
+
+  <Event name="YoungGenerationConfiguration" category="Java Virtual Machine, GC, Configuration" label="Young Generation Configuration"
+    description="The configuration of the young generation of the garbage collected heap" period="endChunk">
+    <Field type="ulong" contentType="bytes" name="minSize" label="Minimum Young Generation Size" />
+    <Field type="ulong" contentType="bytes" name="maxSize" label="Maximum Young Generation Size" />
+    <Field type="uint" name="newRatio" label="New Ratio" description="The size of the young generation relative to the tenured generation" />
+  </Event>
+
+  <Type name="Thread" label="Thread">
+    <Field type="string" name="osName" label="OS Thread Name" />
+    <Field type="long" name="osThreadId" label="OS Thread Id" />
+    <Field type="string" name="javaName" label="Java Thread Name" />
+    <Field type="long" name="javaThreadId" label="Java Thread Id" />
+    <Field type="ThreadGroup" name="group" label="Java Thread Group" />
+  </Type>
+
+  <Type name="ThreadGroup" label="Thread Group">
+    <Field type="ThreadGroup" name="parent" label="Parent" />
+    <Field type="string" name="name" label="Name" />
+  </Type>
+
+  <Type name="Class" label="Java Class">
+    <Field type="ClassLoader" name="classLoader" label="Class Loader" />
+    <Field type="Symbol" name="name" label="Name" />
+    <Field type="Package" name="package" label="Package" />
+    <Field type="int" name="modifiers" label="Access Modifiers" />
+  </Type>
+
+  <Type name="ClassLoader" label="Java Class Loader">
+    <Field type="Class" name="type" label="Type" />
+    <Field type="Symbol" name="name" label="Name" />
+  </Type>
+
+  <Type name="Method" label="Java Method">
+    <Field type="Class" name="type" label="Type" />
+    <Field type="Symbol" name="name" label="Name" />
+    <Field type="Symbol" name="descriptor" label="Descriptor" />
+    <Field type="int" name="modifiers" label="Access Modifiers" />
+    <Field type="boolean" name="hidden" label="Hidden" />
+  </Type>
+
+  <Type name="Symbol" label="Symbol">
+    <Field type="string" name="string" label="String" />
+  </Type>
+
+  <Type name="ThreadState" label="Java Thread State">
+    <Field type="string" name="name" label="Name" />
+  </Type>
+
+  <Type name="GCName" label="GC Name">
+    <Field type="string" name="name" label="Name" />
+  </Type>
+
+  <Type name="GCCause" label="GC Cause">
+    <Field type="string" name="cause" label="Cause" />
+  </Type>
+
+  <Type name="GCWhen" label="GC When">
+    <Field type="string" name="when" label="When" />
+  </Type>
+
+  <Type name="G1HeapRegionType" label="G1 Heap Region Type">
+    <Field type="string" name="type" label="Type" />
+  </Type>
+
+  <Type name="G1YCType" label="G1 YC Type">
+    <Field type="string" name="type" label="Type" />
+  </Type>
+
+  <Type name="GCThresholdUpdater" label="GC Threshold Updater">
+    <Field type="string" name="updater" label="Updater" />
+  </Type>
+
+  <Type name="ReferenceType" label="Reference Type">
+    <Field type="string" name="type" label="Type" />
+  </Type>
+
+  <Type name="MetadataType" label="Metadata Type">
+    <Field type="string" name="type" label="Type" />
+  </Type>
+
+  <Type name="MetaspaceObjectType" label="Metaspace Object Type">
+    <Field type="string" name="type" label="Type" />
+  </Type>
+
+  <Type name="NarrowOopMode" label="Narrow Oop Mode">
+    <Field type="string" name="mode" label="Mode" />
+  </Type>
+
+  <Type name="VMOperationType" label="VM Operation Type">
+    <Field type="string" name="type" label="Type" />
+  </Type>
+
+  <Type name="CompilerPhaseType" label="Compiler Phase Type">
+    <Field type="string" name="phase" label="Phase" />
+  </Type>
+
+  <Type name="FlagValueOrigin" label="Flag Value Origin">
+    <Field type="string" name="origin" label="Origin" />
+  </Type>
+
+  <Type name="CodeBlobType" label="Code Blob Type">
+    <Field type="string" name="type" label="Type" />
+  </Type>
+
+  <Type name="InflateCause" label="Inflation Cause">
+    <Field type="string" name="cause" label="Cause" />
+  </Type>
+
+  <Type name="Module" label="Module">
+    <Field type="Symbol" name="name" label="Name" />
+    <Field type="Symbol" name="version" label="Version" />
+    <Field type="Symbol" name="location" label="Location" />
+    <Field type="ClassLoader" name="classLoader" label="Class Loader" />
+  </Type>
+
+  <Type name="Package" label="Package">
+    <Field type="Symbol" name="name" label="Name" />
+    <Field type="Module" name="module" label="Module" />
+    <Field type="boolean" name="exported" label="Exported" />
+  </Type>
+
+  <Type name="StackTrace" label="Stacktrace">
+    <Field type="boolean" name="truncated" label="Truncated" />
+    <Field type="StackFrame" array="true" struct="true" name="frames" label="Stack Frames" />
+  </Type>
+
+  <Type name="FrameType" label="Frame type">
+    <Field type="string" name="description" label="Description" />
+  </Type>
+
+  <Type name="OldObjectRootSystem" label="GC Root System">
+    <Field type="string" name="system" label="System" />
+  </Type>
+
+  <Type name="OldObjectRootType" label="GC Root Type">
+    <Field type="string" name="type" label="Type" />
+  </Type>
+
+  <Type name="OldObjectGcRoot" label="GC Root">
+    <Field type="string" name="description" label="Root Description" description="Root information" />
+    <Field type="OldObjectRootSystem" name="system" label="System" description="The subsystem of origin for the root" />
+    <Field type="OldObjectRootType" name="type" label="Type" description="The root type" />
+  </Type>
+
+  <Type name="OldObjectArray" label="Old Object Array">
+    <Field type="int" name="size" label="Array Size" description="Size of array" />
+    <Field type="int" name="index" label="Index" description="Index in the array" />
+  </Type>
+
+  <Type name="OldObjectField" label="Old Object Field">
+    <Field type="string" name="name" label="Field" description="Name of field" />
+    <Field type="short" name="modifiers" label="Field Modifiers" description="Field modifiers" />
+  </Type>
+
+  <Type name="OldObject" label="Old Object">
+    <Field type="ulong" contentType="address" name="address" label="Memory Address" />
+    <Field type="Class" name="type" label="Java Class" />
+    <Field type="string" name="description" label="Object Description" description="Object description" />
+    <Field type="Reference" name="referrer" label="Referrer Object" description="Object referencing this object" />
+  </Type>
+
+  <Type name="Reference" label="Reference">
+    <Field type="OldObjectArray" name="array" label="Array Information" description="Array or null if it is not an array" />
+    <Field type="OldObjectField" name="field" label="Field Information" description="Field or null if it is an array" />
+    <Field type="OldObject" name="object" label="Object" description="Object holder for this reference" />
+    <Field type="int" name="skip" label="Skip value" description="The object is this many hops away" />
+  </Type>
+
+  <Type name="StackFrame">
+    <Field type="Method" name="method" label="Java Method" />
+    <Field type="int" name="lineNumber" label="Line Number" />
+    <Field type="int" name="bytecodeIndex" label="Bytecode Index" />
+    <Field type="FrameType" name="type" label="Frame Type" />
+  </Type>
+ 
+  <Relation name="JavaMonitorAddress"/>
+  <Relation name="SafepointId"/>
+  <Relation name="GcId"/>
+  <Relation name="CompileId" />
+  <Relation name="SweepId"/>
+ 
+  <XmlType name="Package" parameterType="const PackageEntry*" fieldType="const PackageEntry*"/> 
+  <XmlType name="Class" javaType="java.lang.Class" parameterType="const Klass*" fieldType="const Klass*"/> 
+  <XmlType name="Module"  parameterType="const ModuleEntry*" fieldType="const ModuleEntry*"/> 
+  <XmlType name="ClassLoader" parameterType="const ClassLoaderData*" fieldType="const ClassLoaderData*"/> 
+  <XmlType name="Method" parameterType="const Method*" fieldType="const Method*"/> 
+  <XmlType name="Thread" javaType="java.lang.Thread" parameterType="u8" fieldType="u8"/> 
+  <XmlType name="Tickspan" contentType="tickspan" javaType="long" parameterType="const Tickspan&amp;" fieldType="Tickspan"/> 
+  <XmlType name="Ticks" contentType="tickstamp" javaType="long" parameterType="const Ticks&amp;" fieldType="Ticks"/> 
+  <XmlType name="ulong" javaType="long" unsigned="true" parameterType="u8" fieldType="u8"/> 
+  <XmlType name="uint" javaType="int" unsigned="true" parameterType="unsigned" fieldType="unsigned"/> 
+  <XmlType name="ushort" javaType="short" unsigned="true" parameterType="u2" fieldType="u2"/> 
+  <XmlType name="ubyte" javaType="byte" unsigned="true" parameterType="u1" fieldType="u1"/> 
+  <XmlType name="long" javaType="long" parameterType="s8" fieldType="s8"/> 
+  <XmlType name="int" javaType="int" parameterType="s4" fieldType="s4"/> 
+  <XmlType name="short" javaType="short" parameterType="s2" fieldType="s2"/> 
+  <XmlType name="byte" javaType="byte"  parameterType="s1" fieldType="s1"/> 
+  <XmlType name="double" javaType="double" parameterType="double" fieldType="double"/> 
+  <XmlType name="float" javaType="float"  parameterType="float" fieldType="float"/> 
+  <XmlType name="boolean" javaType="boolean" parameterType="bool" fieldType="bool"/> 
+  <XmlType name="char" javaType="char" parameterType="char" fieldType="char"/> 
+  <XmlType name="string" javaType="java.lang.String" parameterType="const char*" fieldType="const char*"/> 
+ 
+  <XmlContentType name="bytes" annotationType="jdk.jfr.DataAmount" annotationValue="BYTES" />
+  <XmlContentType name="tickstamp" annotationType="jdk.jfr.Timestamp" annotationValue="TICKS" />
+  <XmlContentType name="epochmillis" annotationType="jdk.jfr.Timestamp" annotationValue="MILLISECONDS_SINCE_EPOCH" />
+  <XmlContentType name="tickspan" annotationType="jdk.jfr.Timespan" annotationValue="TICKS" />
+  <XmlContentType name="address" annotationType="jdk.jfr.MemoryAddress" />
+  <XmlContentType name="percentage" annotationType="jdk.jfr.Percentage" />
+  <XmlContentType name="millis" annotationType="jdk.jfr.Timespan" annotationValue="MILLISECONDS" />
+
+</Metadata>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/metadata/metadata.xsd	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ This code is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License version 2 only, as
+ published by the Free Software Foundation.
+
+ This code is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ version 2 for more details (a copy is included in the LICENSE file that
+ accompanied this code).
+
+ You should have received a copy of the GNU General Public License version
+ 2 along with this work; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ or visit www.oracle.com if you need additional information or have any
+ questions.
+
+-->
+
+<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+  <xs:simpleType name="periodType">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="beginChunk" />
+      <xs:enumeration value="endChunk" />
+      <xs:enumeration value="everyChunk" />
+    </xs:restriction>
+  </xs:simpleType>
+    <xs:simpleType name="transitionType">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="from" />
+      <xs:enumeration value="to" />
+    </xs:restriction>
+  </xs:simpleType> 
+  <xs:element name="Metadata">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:choice maxOccurs="unbounded">
+          <xs:element maxOccurs="unbounded" name="Event">
+            <xs:complexType>
+              <xs:sequence>
+                <xs:element maxOccurs="unbounded" name="Field">
+                  <xs:complexType>
+                    <xs:attribute name="type" type="xs:NMTOKEN" use="required" />
+                    <xs:attribute name="struct" type="xs:boolean" use="optional" />
+                    <xs:attribute name="array" type="xs:boolean" use="optional" />
+                    <xs:attribute name="name" type="xs:NMTOKEN" use="required" />
+                    <xs:attribute name="label" type="xs:string" use="required" />
+                    <xs:attribute name="description" type="xs:string" use="optional" />
+                    <xs:attribute name="contentType" type="xs:string" use="optional" />
+                    <xs:attribute name="relation" type="xs:string" use="optional" />
+                    <xs:attribute name="experimental" type="xs:boolean" use="optional" />
+                    <xs:attribute name="transition" type="transitionType" use="optional" />
+                  </xs:complexType>
+                </xs:element>
+              </xs:sequence>
+              <xs:attribute name="name" type="xs:NMTOKEN" use="required" />
+              <xs:attribute name="category" type="xs:string" use="required" />
+              <xs:attribute name="label" type="xs:string" use="required" />
+              <xs:attribute name="description" type="xs:string" use="optional" />
+              <xs:attribute name="experimental" type="xs:boolean" use="optional" />
+              <xs:attribute name="thread" type="xs:boolean" use="optional" />
+              <xs:attribute name="startTime" type="xs:boolean" use="optional" />
+              <xs:attribute name="stackTrace" type="xs:boolean" use="optional" />
+              <xs:attribute name="period" type="periodType" use="optional" />
+              <xs:attribute name="cutoff" type="xs:boolean" use="optional" />
+            </xs:complexType>
+          </xs:element>
+          <xs:element maxOccurs="unbounded" name="Type">
+            <xs:complexType>
+              <xs:sequence>
+                <xs:element maxOccurs="unbounded" name="Field">
+                  <xs:complexType>
+                    <xs:attribute name="type" type="xs:NMTOKEN" use="required" />
+                    <xs:attribute name="struct" type="xs:boolean" use="optional" />
+                    <xs:attribute name="array" type="xs:boolean" use="optional" />
+                    <xs:attribute name="name" type="xs:NMTOKEN" use="required" />
+                    <xs:attribute name="contentType" type="xs:string" use="optional" />
+                    <xs:attribute name="label" type="xs:string" use="required" />
+                    <xs:attribute name="description" type="xs:string" use="optional" />
+                    <xs:attribute name="experimental" type="xs:boolean" use="optional" />
+                    <xs:attribute name="relation" type="xs:string" use="optional" />
+                  </xs:complexType>
+                </xs:element>
+              </xs:sequence>
+              <xs:attribute name="name" type="xs:NMTOKEN" use="required" />
+              <xs:attribute name="label" type="xs:string" use="optional" />
+              <xs:attribute name="experimental" type="xs:boolean" use="optional" />
+            </xs:complexType>
+          </xs:element>
+          <xs:element name="XmlType">
+            <xs:complexType>
+              <xs:attribute name="name" type="xs:NMTOKEN" use="required" />
+              <xs:attribute name="contentType" type="xs:NMTOKEN" use="optional" />
+              <xs:attribute name="javaType" type="xs:NMTOKEN" use="optional" />
+              <xs:attribute name="unsigned" type="xs:boolean" use="optional" />
+              <xs:attribute name="parameterType" type="xs:string" use="required" />
+              <xs:attribute name="fieldType" type="xs:string" use="required" />
+             </xs:complexType>
+          </xs:element>
+          <xs:element name="XmlContentType">
+            <xs:complexType>
+              <xs:attribute name="name" type="xs:NMTOKEN" use="required" />
+              <xs:attribute name="annotationType" type="xs:NMTOKEN" use="required" />
+              <xs:attribute name="annotationValue" type="xs:string" use="optional" />
+            </xs:complexType>
+          </xs:element>
+          <xs:element name="Relation">
+            <xs:complexType>
+              <xs:attribute name="name" type="xs:NMTOKEN" use="required" />
+            </xs:complexType>
+          </xs:element>
+        </xs:choice>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+</xs:schema>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/periodic/jfrModuleEvent.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/classLoaderData.hpp"
+#include "classfile/moduleEntry.hpp"
+#include "classfile/packageEntry.hpp"
+#include "jfr/jfrEvents.hpp"
+#include "jfr/periodic/jfrModuleEvent.hpp"
+#include "jfr/utilities/jfrTime.hpp"
+#include "runtime/mutexLocker.hpp"
+
+// we want all periodic module events to have the same timestamp
+static JfrTicks invocation_time;
+
+typedef void (*EventFunc)(const void* iterated_address, const ModuleEntry* module);
+class ModuleEventCallbackClosure : public ModuleClosure {
+ protected:
+  const EventFunc _event_func;
+  ModuleEventCallbackClosure(EventFunc ef) : _event_func(ef) {}
+};
+
+class ModuleDependencyClosure : public ModuleEventCallbackClosure {
+ private:
+  const ModuleEntry* const _module;
+ public:
+   ModuleDependencyClosure(const ModuleEntry* module, EventFunc ef) : ModuleEventCallbackClosure(ef), _module(module) {}
+   void do_module(ModuleEntry* entry);
+};
+
+class ModuleExportClosure : public ModuleEventCallbackClosure {
+ private:
+  const PackageEntry* const _package;
+ public:
+  ModuleExportClosure(const PackageEntry* pkg, EventFunc ef) : ModuleEventCallbackClosure(ef), _package(pkg) {}
+  void do_module(ModuleEntry* entry);
+};
+
+static void write_module_dependency_event(const void* from_module, const ModuleEntry* to_module) {
+  EventModuleRequire event(UNTIMED);
+  event.set_endtime(invocation_time);
+  event.set_source((const ModuleEntry* const)from_module);
+  event.set_requiredModule(to_module);
+  event.commit();
+}
+
+static void write_module_export_event(const void* package, const ModuleEntry* qualified_export) {
+  EventModuleExport event(UNTIMED);
+  event.set_endtime(invocation_time);
+  event.set_exportedPackage((const PackageEntry*)package);
+  event.set_targetModule(qualified_export);
+  event.commit();
+}
+
+void ModuleDependencyClosure::do_module(ModuleEntry* to_module) {
+  assert_locked_or_safepoint(Module_lock);
+  assert(to_module != NULL, "invariant");
+  assert(_module != NULL, "invariant");
+  assert(_event_func != NULL, "invariant");
+  _event_func(_module, to_module);
+}
+
+void ModuleExportClosure::do_module(ModuleEntry* qualified_export) {
+  assert_locked_or_safepoint(Module_lock);
+  assert(qualified_export != NULL, "invariant");
+  assert(_package != NULL, "invariant");
+  assert(_event_func != NULL, "invariant");
+  _event_func(_package, qualified_export);
+}
+
+static void module_dependency_event_callback(ModuleEntry* module) {
+  assert_locked_or_safepoint(Module_lock);
+  assert(module != NULL, "invariant");
+  if (module->has_reads_list()) {
+    // create an individual event for each directed edge
+    ModuleDependencyClosure directed_edges(module, &write_module_dependency_event);
+    module->module_reads_do(&directed_edges);
+  }
+}
+
+static void module_export_event_callback(PackageEntry* package) {
+  assert_locked_or_safepoint(Module_lock);
+  assert(package != NULL, "invariant");
+  if (package->is_exported()) {
+    if (package->has_qual_exports_list()) {
+      // package is qualifiedly exported to a set of modules,
+      // create an event for each module in the qualified exported list
+      ModuleExportClosure qexports(package, &write_module_export_event);
+      package->package_exports_do(&qexports);
+      return;
+    }
+
+    assert(!package->is_qual_exported() || package->is_exported_allUnnamed(), "invariant");
+    // no qualified exports
+    // only create a single event with NULL
+    // for the qualified_exports module
+    write_module_export_event(package, NULL);
+  }
+}
+
+void JfrModuleEvent::generate_module_dependency_events() {
+  invocation_time = JfrTicks::now();
+  MutexLockerEx module_lock(Module_lock);
+  ClassLoaderDataGraph::modules_do(&module_dependency_event_callback);
+}
+
+void JfrModuleEvent::generate_module_export_events() {
+  invocation_time = JfrTicks::now();
+  MutexLockerEx module_lock(Module_lock);
+  ClassLoaderDataGraph::packages_do(&module_export_event_callback);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/periodic/jfrModuleEvent.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_EVENT_JFRMODULEEVENT_HPP
+#define SHARE_VM_JFR_EVENT_JFRMODULEEVENT_HPP
+
+#include "memory/allocation.hpp"
+
+class JfrModuleEvent : AllStatic {
+ public:
+  static void generate_module_dependency_events();
+  static void generate_module_export_events();
+};
+
+#endif // SHARE_VM_JFR_EVENT_JFRMODULEEVENT_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/periodic/jfrOSInterface.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/jfrEvents.hpp"
+#include "jfr/periodic/jfrOSInterface.hpp"
+#include "memory/allocation.inline.hpp"
+#include "memory/resourceArea.hpp"
+#include "runtime/os.hpp"
+#include "runtime/os_perf.hpp"
+#include "utilities/ostream.hpp"
+
+#include <stdlib.h> // for environment variables
+#ifdef __APPLE__
+#include <crt_externs.h>
+#define environ (*_NSGetEnviron())
+#endif
+
+#ifndef environ
+extern char** environ;
+#endif
+
+static JfrOSInterface* _instance = NULL;
+
+JfrOSInterface& JfrOSInterface::instance() {
+  return *_instance;
+}
+
+JfrOSInterface* JfrOSInterface::create() {
+  assert(_instance == NULL, "invariant");
+  _instance = new JfrOSInterface();
+  return _instance;
+}
+
+void JfrOSInterface::destroy() {
+  if (_instance != NULL) {
+    delete _instance;
+    _instance = NULL;
+  }
+}
+
+class JfrOSInterface::JfrOSInterfaceImpl : public JfrCHeapObj {
+  friend class JfrOSInterface;
+ private:
+  CPUInformationInterface* _cpu_info_interface;
+  CPUPerformanceInterface* _cpu_perf_interface;
+  SystemProcessInterface*  _system_process_interface;
+
+  // stub helper
+  void functionality_not_implemented(char** str) const;
+
+  JfrOSInterfaceImpl();
+  bool initialize();
+  ~JfrOSInterfaceImpl();
+
+  // cpu info
+  int cpu_information(CPUInformation& cpu_info);
+  int cpu_load(int which_logical_cpu, double* cpu_load);
+  int context_switch_rate(double* rate);
+  int cpu_load_total_process(double* cpu_load);
+  int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotal);
+
+  // os information
+  int os_version(char** os_version) const;
+
+  // environment information
+  void generate_environment_variables_events();
+
+   // system processes information
+  int system_processes(SystemProcess** system_processes, int* no_of_sys_processes);
+};
+
+JfrOSInterface::JfrOSInterfaceImpl::JfrOSInterfaceImpl() : _cpu_info_interface(NULL),
+                                                           _cpu_perf_interface(NULL),
+                                                           _system_process_interface(NULL) {}
+
+bool JfrOSInterface::JfrOSInterfaceImpl::initialize() {
+  _cpu_info_interface = new CPUInformationInterface();
+  bool success = _cpu_info_interface != NULL && _cpu_info_interface->initialize();
+  if (!success) {
+    return false;
+  }
+  _cpu_perf_interface = new CPUPerformanceInterface();
+  success = _cpu_perf_interface != NULL && _cpu_perf_interface->initialize();
+  if (!success) {
+    return false;
+  }
+  _system_process_interface = new SystemProcessInterface();
+  success = _system_process_interface != NULL && _system_process_interface->initialize();
+  return success;
+}
+
+JfrOSInterface::JfrOSInterfaceImpl::~JfrOSInterfaceImpl(void) {
+  if (_cpu_info_interface != NULL) {
+    delete _cpu_info_interface;
+    _cpu_info_interface = NULL;
+  }
+  if (_cpu_perf_interface != NULL) {
+    delete _cpu_perf_interface;
+    _cpu_perf_interface = NULL;
+  }
+  if (_system_process_interface != NULL) {
+    delete _system_process_interface;
+    _system_process_interface = NULL;
+  }
+}
+
+int JfrOSInterface::JfrOSInterfaceImpl::cpu_load(int which_logical_cpu, double* cpu_load) {
+  return _cpu_perf_interface->cpu_load(which_logical_cpu, cpu_load);
+}
+
+int JfrOSInterface::JfrOSInterfaceImpl::context_switch_rate(double* rate) {
+  return _cpu_perf_interface->context_switch_rate(rate);
+}
+
+int JfrOSInterface::JfrOSInterfaceImpl::cpu_load_total_process(double* cpu_load) {
+  return _cpu_perf_interface->cpu_load_total_process(cpu_load);
+}
+
+int JfrOSInterface::JfrOSInterfaceImpl::cpu_loads_process(double* pjvmUserLoad,
+                                                          double* pjvmKernelLoad,
+                                                          double* psystemTotal) {
+  return _cpu_perf_interface->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotal);
+}
+
+int JfrOSInterface::JfrOSInterfaceImpl::cpu_information(CPUInformation& cpu_info) {
+  return _cpu_info_interface->cpu_information(cpu_info);
+}
+
+int JfrOSInterface::JfrOSInterfaceImpl::system_processes(SystemProcess** system_processes, int* no_of_sys_processes) {
+  assert(system_processes != NULL, "system_processes pointer is NULL!");
+  assert(no_of_sys_processes != NULL, "no_of_sys_processes pointer is NULL!");
+  return _system_process_interface->system_processes(system_processes, no_of_sys_processes);
+}
+
+// assigned char* is RESOURCE_HEAP_ALLOCATED
+// caller need to ensure proper ResourceMark placement.
+int JfrOSInterface::JfrOSInterfaceImpl::os_version(char** os_version) const {
+  assert(os_version != NULL, "os_version pointer is NULL!");
+  stringStream os_ver_info;
+  os::print_os_info_brief(&os_ver_info);
+  *os_version = os_ver_info.as_string();
+  return OS_OK;
+}
+
+void JfrOSInterface::JfrOSInterfaceImpl::functionality_not_implemented(char** str) const {
+  assert(str != NULL, "address to string is NULL!");
+  const char* not_impl = "Functionality_not_implemented";
+  const size_t not_impl_len = strlen(not_impl);
+  *str = NEW_C_HEAP_ARRAY(char, not_impl_len+1, mtTracing);
+  strncpy(*str, not_impl, not_impl_len);
+  (*str)[not_impl_len] = '\0';
+}
+
+JfrOSInterface::JfrOSInterface() {
+  _impl = NULL;
+}
+
+bool JfrOSInterface::initialize() {
+  _impl = new JfrOSInterface::JfrOSInterfaceImpl();
+  return _impl != NULL && _impl->initialize();
+}
+
+JfrOSInterface::~JfrOSInterface() {
+  if (_impl != NULL) {
+    delete _impl;
+    _impl = NULL;
+  }
+}
+
+int JfrOSInterface::cpu_information(CPUInformation& cpu_info) {
+  return instance()._impl->cpu_information(cpu_info);
+}
+
+int JfrOSInterface::cpu_load(int which_logical_cpu, double* cpu_load) {
+  return instance()._impl->cpu_load(which_logical_cpu, cpu_load);
+}
+
+int JfrOSInterface::context_switch_rate(double* rate) {
+  return instance()._impl->context_switch_rate(rate);
+}
+
+int JfrOSInterface::cpu_load_total_process(double* cpu_load) {
+  return instance()._impl->cpu_load_total_process(cpu_load);
+}
+
+int JfrOSInterface::cpu_loads_process(double* jvm_user_load, double* jvm_kernel_load, double* system_total_load){
+  return instance()._impl->cpu_loads_process(jvm_user_load, jvm_kernel_load, system_total_load);
+}
+
+int JfrOSInterface::os_version(char** os_version) {
+  return instance()._impl->os_version(os_version);
+}
+
+int JfrOSInterface::generate_initial_environment_variable_events() {
+  if (environ == NULL) {
+    return OS_ERR;
+  }
+
+  if (EventInitialEnvironmentVariable::is_enabled()) {
+    // One time stamp for all events, so they can be grouped together
+    JfrTicks time_stamp = JfrTicks::now();
+    for (char** p = environ; *p != NULL; p++) {
+      char* variable = *p;
+      char* equal_sign = strchr(variable, '=');
+      if (equal_sign != NULL) {
+        // Extract key/value
+        ResourceMark rm;
+        ptrdiff_t key_length = equal_sign - variable;
+        char* key = NEW_RESOURCE_ARRAY(char, key_length + 1);
+        char* value = equal_sign + 1;
+        strncpy(key, variable, key_length);
+        key[key_length] = '\0';
+        EventInitialEnvironmentVariable event(UNTIMED);
+        event.set_endtime(time_stamp);
+        event.set_key(key);
+        event.set_value(value);
+        event.commit();
+      }
+    }
+  }
+  return OS_OK;
+}
+
+int JfrOSInterface::system_processes(SystemProcess** sys_processes, int* no_of_sys_processes) {
+  return instance()._impl->system_processes(sys_processes, no_of_sys_processes);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/periodic/jfrOSInterface.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_PERIODIC_JFROSINTERFACE_HPP
+#define SHARE_VM_JFR_PERIODIC_JFROSINTERFACE_HPP
+
+#include "jfr/utilities/jfrAllocation.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+class CPUInformation;
+class EnvironmentVariable;
+class SystemProcess;
+
+class JfrOSInterface: public JfrCHeapObj {
+  friend class JfrRecorder;
+ private:
+  class JfrOSInterfaceImpl;
+  JfrOSInterfaceImpl* _impl;
+
+  JfrOSInterface();
+  ~JfrOSInterface();
+  bool initialize();
+  static JfrOSInterface& instance();
+  static JfrOSInterface* create();
+  static void destroy();
+
+ public:
+  static int cpu_information(CPUInformation& cpu_info);
+  static int cpu_load(int which_logical_cpu, double* cpu_load);
+  static int context_switch_rate(double* rate);
+  static int cpu_load_total_process(double* cpu_load);
+  static int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad);
+  static int os_version(char** os_version);
+  static int generate_initial_environment_variable_events();
+  static int system_processes(SystemProcess** system_processes, int* no_of_sys_processes);
+};
+
+#endif // SHARE_VM_JFR_PERIODIC_JFROSINTERFACE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,572 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jvm.h"
+#include "classfile/classLoaderStats.hpp"
+#include "classfile/javaClasses.hpp"
+#include "code/codeCache.hpp"
+#include "compiler/compileBroker.hpp"
+#include "gc/g1/g1HeapRegionEventSender.hpp"
+#include "gc/shared/gcConfiguration.hpp"
+#include "gc/shared/gcTrace.hpp"
+#include "gc/shared/objectCountEventSender.hpp"
+#include "gc/shared/vmGCOperations.hpp"
+#include "jfr/jfrEvents.hpp"
+#include "jfr/periodic/jfrModuleEvent.hpp"
+#include "jfr/periodic/jfrOSInterface.hpp"
+#include "jfr/periodic/jfrThreadCPULoadEvent.hpp"
+#include "jfr/periodic/jfrThreadDumpEvent.hpp"
+#include "jfr/recorder/jfrRecorder.hpp"
+#include "jfr/support/jfrThreadId.hpp"
+#include "jfr/utilities/jfrTime.hpp"
+#include "jfrfiles/jfrPeriodic.hpp"
+#include "logging/log.hpp"
+#include "memory/heapInspection.hpp"
+#include "memory/resourceArea.hpp"
+#include "oops/oop.inline.hpp"
+#include "runtime/arguments.hpp"
+#include "runtime/flags/jvmFlag.hpp"
+#include "runtime/globals.hpp"
+#include "runtime/os.hpp"
+#include "runtime/os_perf.hpp"
+#include "runtime/thread.inline.hpp"
+#include "runtime/threadSMR.hpp"
+#include "runtime/sweeper.hpp"
+#include "runtime/vmThread.hpp"
+#include "services/classLoadingService.hpp"
+#include "services/management.hpp"
+#include "services/threadService.hpp"
+#include "utilities/exceptions.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+/**
+ *  JfrPeriodic class
+ *  Implementation of declarations in
+ *  xsl generated traceRequestables.hpp
+ */
+#define TRACE_REQUEST_FUNC(id)    void JfrPeriodicEventSet::request##id(void)
+
+TRACE_REQUEST_FUNC(JVMInformation) {
+  ResourceMark rm;
+  EventJVMInformation event;
+  event.set_jvmName(VM_Version::vm_name());
+  event.set_jvmVersion(VM_Version::internal_vm_info_string());
+  event.set_javaArguments(Arguments::java_command());
+  event.set_jvmArguments(Arguments::jvm_args());
+  event.set_jvmFlags(Arguments::jvm_flags());
+  event.set_jvmStartTime(Management::vm_init_done_time());
+  event.commit();
+ }
+
+TRACE_REQUEST_FUNC(OSInformation) {
+  ResourceMark rm;
+  char* os_name = NEW_RESOURCE_ARRAY(char, 2048);
+  JfrOSInterface::os_version(&os_name);
+  EventOSInformation event;
+  event.set_osVersion(os_name);
+  event.commit();
+}
+
+TRACE_REQUEST_FUNC(ModuleRequire) {
+  JfrModuleEvent::generate_module_dependency_events();
+}
+
+TRACE_REQUEST_FUNC(ModuleExport) {
+  JfrModuleEvent::generate_module_export_events();
+}
+
+/*
+ * This is left empty on purpose, having ExecutionSample as a requestable
+ * is a way of getting the period. The period is passed to ThreadSampling::update_period.
+ * Implementation in jfrSamples.cpp
+ */
+TRACE_REQUEST_FUNC(ExecutionSample) {
+}
+TRACE_REQUEST_FUNC(NativeMethodSample) {
+}
+
+TRACE_REQUEST_FUNC(ThreadDump) {
+  ResourceMark rm;
+  EventThreadDump event;
+  event.set_result(JfrDcmdEvent::thread_dump());
+  event.commit();
+}
+
+static int _native_library_callback(const char* name, address base, address top, void *param) {
+  EventNativeLibrary event(UNTIMED);
+  event.set_name(name);
+  event.set_baseAddress((u8)base);
+  event.set_topAddress((u8)top);
+  event.set_endtime(*(JfrTicks*) param);
+  event.commit();
+  return 0;
+}
+
+TRACE_REQUEST_FUNC(NativeLibrary) {
+  JfrTicks ts= JfrTicks::now();
+  os::get_loaded_modules_info(&_native_library_callback, (void *)&ts);
+}
+
+TRACE_REQUEST_FUNC(InitialEnvironmentVariable) {
+  JfrOSInterface::generate_initial_environment_variable_events();
+}
+
+TRACE_REQUEST_FUNC(CPUInformation) {
+  CPUInformation cpu_info;
+  int ret_val = JfrOSInterface::cpu_information(cpu_info);
+  if (ret_val == OS_ERR) {
+    log_debug(jfr, system)( "Unable to generate requestable event CPUInformation");
+    return;
+  }
+  if (ret_val == FUNCTIONALITY_NOT_IMPLEMENTED) {
+     return;
+  }
+  if (ret_val == OS_OK) {
+    EventCPUInformation event;
+    event.set_cpu(cpu_info.cpu_name());
+    event.set_description(cpu_info.cpu_description());
+    event.set_sockets(cpu_info.number_of_sockets());
+    event.set_cores(cpu_info.number_of_cores());
+    event.set_hwThreads(cpu_info.number_of_hardware_threads());
+    event.commit();
+  }
+}
+
+TRACE_REQUEST_FUNC(CPULoad) {
+  double u = 0; // user time
+  double s = 0; // kernel time
+  double t = 0; // total time
+  int ret_val = JfrOSInterface::cpu_loads_process(&u, &s, &t);
+  if (ret_val == OS_ERR) {
+    log_debug(jfr, system)( "Unable to generate requestable event CPULoad");
+    return;
+  }
+  if (ret_val == OS_OK) {
+    EventCPULoad event;
+    event.set_jvmUser((float)u);
+    event.set_jvmSystem((float)s);
+    event.set_machineTotal((float)t);
+    event.commit();
+  }
+}
+
+TRACE_REQUEST_FUNC(ThreadCPULoad) {
+  JfrThreadCPULoadEvent::send_events();
+}
+
+TRACE_REQUEST_FUNC(CPUTimeStampCounter) {
+  EventCPUTimeStampCounter event;
+  event.set_fastTimeEnabled(JfrTime::is_ft_enabled());
+  event.set_fastTimeAutoEnabled(JfrTime::is_ft_supported());
+  event.set_osFrequency(os::elapsed_frequency());
+  event.set_fastTimeFrequency(JfrTime::frequency());
+  event.commit();
+}
+
+TRACE_REQUEST_FUNC(SystemProcess) {
+  char pid_buf[16];
+  SystemProcess* processes = NULL;
+  int num_of_processes = 0;
+  JfrTicks start_time = JfrTicks::now();
+  int ret_val = JfrOSInterface::system_processes(&processes, &num_of_processes);
+  if (ret_val == OS_ERR) {
+    log_debug(jfr, system)( "Unable to generate requestable event SystemProcesses");
+    return;
+  }
+  JfrTicks end_time = JfrTicks::now();
+  if (ret_val == FUNCTIONALITY_NOT_IMPLEMENTED) {
+    return;
+  }
+  if (ret_val == OS_OK) {
+    // feature is implemented, write real event
+    while (processes != NULL) {
+      SystemProcess* tmp = processes;
+      const char* info = processes->command_line();
+      if (info == NULL) {
+         info = processes->path();
+      }
+      if (info == NULL) {
+         info = processes->name();
+      }
+      if (info == NULL) {
+         info = "?";
+      }
+      jio_snprintf(pid_buf, sizeof(pid_buf), "%d", processes->pid());
+      EventSystemProcess event(UNTIMED);
+      event.set_pid(pid_buf);
+      event.set_commandLine(info);
+      event.set_starttime(start_time);
+      event.set_endtime(end_time);
+      event.commit();
+      processes = processes->next();
+      delete tmp;
+    }
+  }
+}
+
+TRACE_REQUEST_FUNC(ThreadContextSwitchRate) {
+  double rate = 0.0;
+  int ret_val = JfrOSInterface::context_switch_rate(&rate);
+  if (ret_val == OS_ERR) {
+    log_debug(jfr, system)( "Unable to generate requestable event ThreadContextSwitchRate");
+    return;
+  }
+  if (ret_val == FUNCTIONALITY_NOT_IMPLEMENTED) {
+    return;
+  }
+  if (ret_val == OS_OK) {
+    EventThreadContextSwitchRate event;
+    event.set_switchRate((float)rate + 0.0f);
+    event.commit();
+  }
+}
+
+#define SEND_FLAGS_OF_TYPE(eventType, flagType)                   \
+  do {                                                            \
+    JVMFlag *flag = JVMFlag::flags;                               \
+    while (flag->_name != NULL) {                                 \
+      if (flag->is_ ## flagType()) {                              \
+        if (flag->is_unlocked()) {                                \
+          Event ## eventType event;                               \
+          event.set_name(flag->_name);                            \
+          event.set_value(flag->get_ ## flagType());              \
+          event.set_origin(flag->get_origin());                   \
+          event.commit();                                         \
+        }                                                         \
+      }                                                           \
+      ++flag;                                                     \
+    }                                                             \
+  } while (0)
+
+TRACE_REQUEST_FUNC(IntFlag) {
+  SEND_FLAGS_OF_TYPE(IntFlag, int);
+}
+
+TRACE_REQUEST_FUNC(UnsignedIntFlag) {
+  SEND_FLAGS_OF_TYPE(UnsignedIntFlag, uint);
+}
+
+TRACE_REQUEST_FUNC(LongFlag) {
+  SEND_FLAGS_OF_TYPE(LongFlag, intx);
+}
+
+TRACE_REQUEST_FUNC(UnsignedLongFlag) {
+  SEND_FLAGS_OF_TYPE(UnsignedLongFlag, uintx);
+  SEND_FLAGS_OF_TYPE(UnsignedLongFlag, uint64_t);
+  SEND_FLAGS_OF_TYPE(UnsignedLongFlag, size_t);
+}
+
+TRACE_REQUEST_FUNC(DoubleFlag) {
+  SEND_FLAGS_OF_TYPE(DoubleFlag, double);
+}
+
+TRACE_REQUEST_FUNC(BooleanFlag) {
+  SEND_FLAGS_OF_TYPE(BooleanFlag, bool);
+}
+
+TRACE_REQUEST_FUNC(StringFlag) {
+  SEND_FLAGS_OF_TYPE(StringFlag, ccstr);
+}
+
+class VM_GC_SendObjectCountEvent : public VM_GC_HeapInspection {
+ public:
+  VM_GC_SendObjectCountEvent() : VM_GC_HeapInspection(NULL, true) {}
+  virtual void doit() {
+    ObjectCountEventSender::enable_requestable_event();
+    collect();
+    ObjectCountEventSender::disable_requestable_event();
+  }
+};
+
+TRACE_REQUEST_FUNC(ObjectCount) {
+  VM_GC_SendObjectCountEvent op;
+  VMThread::execute(&op);
+}
+
+class VM_G1SendHeapRegionInfoEvents : public VM_Operation {
+  virtual void doit() {
+    G1HeapRegionEventSender::send_events();
+  }
+  virtual VMOp_Type type() const { return VMOp_HeapIterateOperation; }
+};
+
+TRACE_REQUEST_FUNC(G1HeapRegionInformation) {
+  if (UseG1GC) {
+    VM_G1SendHeapRegionInfoEvents op;
+    VMThread::execute(&op);
+  }
+}
+
+// Java Mission Control (JMC) uses (Java) Long.MIN_VALUE to describe that a
+// long value is undefined.
+static jlong jmc_undefined_long = min_jlong;
+
+TRACE_REQUEST_FUNC(GCConfiguration) {
+  GCConfiguration conf;
+  jlong pause_target = conf.has_pause_target_default_value() ? jmc_undefined_long : conf.pause_target();
+  EventGCConfiguration event;
+  event.set_youngCollector(conf.young_collector());
+  event.set_oldCollector(conf.old_collector());
+  event.set_parallelGCThreads(conf.num_parallel_gc_threads());
+  event.set_concurrentGCThreads(conf.num_concurrent_gc_threads());
+  event.set_usesDynamicGCThreads(conf.uses_dynamic_gc_threads());
+  event.set_isExplicitGCConcurrent(conf.is_explicit_gc_concurrent());
+  event.set_isExplicitGCDisabled(conf.is_explicit_gc_disabled());
+  event.set_gcTimeRatio(conf.gc_time_ratio());
+  event.set_pauseTarget((s8)pause_target);
+  event.commit();
+}
+
+TRACE_REQUEST_FUNC(GCTLABConfiguration) {
+  GCTLABConfiguration conf;
+  EventGCTLABConfiguration event;
+  event.set_usesTLABs(conf.uses_tlabs());
+  event.set_minTLABSize(conf.min_tlab_size());
+  event.set_tlabRefillWasteLimit(conf.tlab_refill_waste_limit());
+  event.commit();
+}
+
+TRACE_REQUEST_FUNC(GCSurvivorConfiguration) {
+  GCSurvivorConfiguration conf;
+  EventGCSurvivorConfiguration event;
+  event.set_maxTenuringThreshold(conf.max_tenuring_threshold());
+  event.set_initialTenuringThreshold(conf.initial_tenuring_threshold());
+  event.commit();
+}
+
+TRACE_REQUEST_FUNC(GCHeapConfiguration) {
+  GCHeapConfiguration conf;
+  EventGCHeapConfiguration event;
+  event.set_minSize(conf.min_size());
+  event.set_maxSize(conf.max_size());
+  event.set_initialSize(conf.initial_size());
+  event.set_usesCompressedOops(conf.uses_compressed_oops());
+  event.set_compressedOopsMode(conf.narrow_oop_mode());
+  event.set_objectAlignment(conf.object_alignment_in_bytes());
+  event.set_heapAddressBits(conf.heap_address_size_in_bits());
+  event.commit();
+}
+
+TRACE_REQUEST_FUNC(YoungGenerationConfiguration) {
+  GCYoungGenerationConfiguration conf;
+  jlong max_size = conf.has_max_size_default_value() ? jmc_undefined_long : conf.max_size();
+  EventYoungGenerationConfiguration event;
+  event.set_maxSize((u8)max_size);
+  event.set_minSize(conf.min_size());
+  event.set_newRatio(conf.new_ratio());
+  event.commit();
+}
+
+TRACE_REQUEST_FUNC(InitialSystemProperty) {
+  SystemProperty* p = Arguments::system_properties();
+  JfrTicks time_stamp = JfrTicks::now();
+  while (p !=  NULL) {
+    if (!p->internal()) {
+      EventInitialSystemProperty event(UNTIMED);
+      event.set_key(p->key());
+      event.set_value(p->value());
+      event.set_endtime(time_stamp);
+      event.commit();
+    }
+    p = p->next();
+  }
+}
+
+TRACE_REQUEST_FUNC(ThreadAllocationStatistics) {
+  ResourceMark rm;
+  int initial_size = Threads::number_of_threads();
+  GrowableArray<jlong> allocated(initial_size);
+  GrowableArray<traceid> thread_ids(initial_size);
+  JfrTicks time_stamp = JfrTicks::now();
+  {
+    // Collect allocation statistics while holding threads lock
+    MutexLockerEx ml(Threads_lock);
+    for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) {
+      allocated.append(jt->cooked_allocated_bytes());
+      thread_ids.append(JFR_THREAD_ID(jt));
+    }
+  }
+
+  // Write allocation statistics to buffer.
+  for(int i = 0; i < thread_ids.length(); i++) {
+    EventThreadAllocationStatistics event(UNTIMED);
+    event.set_allocated(allocated.at(i));
+    event.set_thread(thread_ids.at(i));
+    event.set_endtime(time_stamp);
+    event.commit();
+  }
+}
+
+/**
+ *  PhysicalMemory event represents:
+ *
+ *  @totalSize == The amount of physical memory (hw) installed and reported by the OS, in bytes.
+ *  @usedSize  == The amount of physical memory currently in use in the system (reserved/committed), in bytes.
+ *
+ *  Both fields are systemwide, i.e. represents the entire OS/HW environment.
+ *  These fields do not include virtual memory.
+ *
+ *  If running inside a guest OS on top of a hypervisor in a virtualized environment,
+ *  the total memory reported is the amount of memory configured for the guest OS by the hypervisor.
+ */
+TRACE_REQUEST_FUNC(PhysicalMemory) {
+  u8 totalPhysicalMemory = os::physical_memory();
+  EventPhysicalMemory event;
+  event.set_totalSize(totalPhysicalMemory);
+  event.set_usedSize(totalPhysicalMemory - os::available_memory());
+  event.commit();
+}
+
+TRACE_REQUEST_FUNC(JavaThreadStatistics) {
+  EventJavaThreadStatistics event;
+  event.set_activeCount(ThreadService::get_live_thread_count());
+  event.set_daemonCount(ThreadService::get_daemon_thread_count());
+  event.set_accumulatedCount(ThreadService::get_total_thread_count());
+  event.set_peakCount(ThreadService::get_peak_thread_count());
+  event.commit();
+}
+
+TRACE_REQUEST_FUNC(ClassLoadingStatistics) {
+  EventClassLoadingStatistics event;
+  event.set_loadedClassCount(ClassLoadingService::loaded_class_count());
+  event.set_unloadedClassCount(ClassLoadingService::unloaded_class_count());
+  event.commit();
+}
+
+class JfrClassLoaderStatsClosure : public ClassLoaderStatsClosure {
+public:
+  JfrClassLoaderStatsClosure() : ClassLoaderStatsClosure(NULL) {}
+
+  bool do_entry(oop const& key, ClassLoaderStats* const& cls) {
+    const ClassLoaderData* this_cld = cls->_class_loader != NULL ?
+      java_lang_ClassLoader::loader_data(cls->_class_loader) : (ClassLoaderData*)NULL;
+    const ClassLoaderData* parent_cld = cls->_parent != NULL ?
+      java_lang_ClassLoader::loader_data(cls->_parent) : (ClassLoaderData*)NULL;
+    EventClassLoaderStatistics event;
+    event.set_classLoader(this_cld);
+    event.set_parentClassLoader(parent_cld);
+    event.set_classLoaderData((intptr_t)cls->_cld);
+    event.set_classCount(cls->_classes_count);
+    event.set_chunkSize(cls->_chunk_sz);
+    event.set_blockSize(cls->_block_sz);
+    event.set_anonymousClassCount(cls->_anon_classes_count);
+    event.set_anonymousChunkSize(cls->_anon_chunk_sz);
+    event.set_anonymousBlockSize(cls->_anon_block_sz);
+    event.commit();
+    return true;
+  }
+
+  void createEvents(void) {
+    _stats->iterate(this);
+  }
+};
+
+class JfrClassLoaderStatsVMOperation : public ClassLoaderStatsVMOperation {
+ public:
+  JfrClassLoaderStatsVMOperation() : ClassLoaderStatsVMOperation(NULL) { }
+
+  void doit() {
+    JfrClassLoaderStatsClosure clsc;
+    ClassLoaderDataGraph::cld_do(&clsc);
+    clsc.createEvents();
+  }
+};
+
+TRACE_REQUEST_FUNC(ClassLoaderStatistics) {
+  JfrClassLoaderStatsVMOperation op;
+  VMThread::execute(&op);
+}
+
+TRACE_REQUEST_FUNC(CompilerStatistics) {
+  EventCompilerStatistics event;
+  event.set_compileCount(CompileBroker::get_total_compile_count());
+  event.set_bailoutCount(CompileBroker::get_total_bailout_count());
+  event.set_invalidatedCount(CompileBroker::get_total_invalidated_count());
+  event.set_osrCompileCount(CompileBroker::get_total_osr_compile_count());
+  event.set_standardCompileCount(CompileBroker::get_total_standard_compile_count());
+  event.set_osrBytesCompiled(CompileBroker::get_sum_osr_bytes_compiled());
+  event.set_standardBytesCompiled(CompileBroker::get_sum_standard_bytes_compiled());
+  event.set_nmetodsSize(CompileBroker::get_sum_nmethod_size());
+  event.set_nmetodCodeSize(CompileBroker::get_sum_nmethod_code_size());
+  event.set_peakTimeSpent(CompileBroker::get_peak_compilation_time());
+  event.set_totalTimeSpent(CompileBroker::get_total_compilation_time());
+  event.commit();
+}
+
+TRACE_REQUEST_FUNC(CompilerConfiguration) {
+  EventCompilerConfiguration event;
+  event.set_threadCount(CICompilerCount);
+  event.set_tieredCompilation(TieredCompilation);
+  event.commit();
+}
+
+TRACE_REQUEST_FUNC(CodeCacheStatistics) {
+  // Emit stats for all available code heaps
+  for (int bt = 0; bt < CodeBlobType::NumTypes; ++bt) {
+    if (CodeCache::heap_available(bt)) {
+      EventCodeCacheStatistics event;
+      event.set_codeBlobType((u1)bt);
+      event.set_startAddress((u8)CodeCache::low_bound(bt));
+      event.set_reservedTopAddress((u8)CodeCache::high_bound(bt));
+      event.set_entryCount(CodeCache::blob_count(bt));
+      event.set_methodCount(CodeCache::nmethod_count(bt));
+      event.set_adaptorCount(CodeCache::adapter_count(bt));
+      event.set_unallocatedCapacity(CodeCache::unallocated_capacity(bt));
+      event.set_fullCount(CodeCache::get_codemem_full_count(bt));
+      event.commit();
+    }
+  }
+}
+
+TRACE_REQUEST_FUNC(CodeCacheConfiguration) {
+  EventCodeCacheConfiguration event;
+  event.set_initialSize(InitialCodeCacheSize);
+  event.set_reservedSize(ReservedCodeCacheSize);
+  event.set_nonNMethodSize(NonNMethodCodeHeapSize);
+  event.set_profiledSize(ProfiledCodeHeapSize);
+  event.set_nonProfiledSize(NonProfiledCodeHeapSize);
+  event.set_expansionSize(CodeCacheExpansionSize);
+  event.set_minBlockLength(CodeCacheMinBlockLength);
+  event.set_startAddress((u8)CodeCache::low_bound());
+  event.set_reservedTopAddress((u8)CodeCache::high_bound());
+  event.commit();
+}
+
+TRACE_REQUEST_FUNC(CodeSweeperStatistics) {
+  EventCodeSweeperStatistics event;
+  event.set_sweepCount(NMethodSweeper::traversal_count());
+  event.set_methodReclaimedCount(NMethodSweeper::total_nof_methods_reclaimed());
+  event.set_totalSweepTime(NMethodSweeper::total_time_sweeping());
+  event.set_peakFractionTime(NMethodSweeper::peak_sweep_fraction_time());
+  event.set_peakSweepTime(NMethodSweeper::peak_sweep_time());
+  event.commit();
+}
+
+TRACE_REQUEST_FUNC(CodeSweeperConfiguration) {
+  EventCodeSweeperConfiguration event;
+  event.set_sweeperEnabled(MethodFlushing);
+  event.set_flushingEnabled(UseCodeCacheFlushing);
+  event.commit();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/periodic/jfrThreadCPULoadEvent.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "logging/log.hpp"
+#include "jfr/jfrEvents.hpp"
+#include "jfr/periodic/jfrThreadCPULoadEvent.hpp"
+#include "jfr/support/jfrThreadId.hpp"
+#include "jfr/support/jfrThreadLocal.hpp"
+#include "jfr/utilities/jfrTime.hpp"
+#include "utilities/globalDefinitions.hpp"
+#include "runtime/os.hpp"
+#include "runtime/thread.inline.hpp"
+#include "runtime/threadSMR.inline.hpp"
+
+jlong JfrThreadCPULoadEvent::get_wallclock_time() {
+  return os::javaTimeNanos();
+}
+
+int JfrThreadCPULoadEvent::_last_active_processor_count = 0;
+
+int JfrThreadCPULoadEvent::get_processor_count() {
+  int cur_processor_count = os::active_processor_count();
+  int last_processor_count = _last_active_processor_count;
+  _last_active_processor_count = cur_processor_count;
+
+  // If the number of processors decreases, we don't know at what point during
+  // the sample interval this happened, so use the largest number to try
+  // to avoid percentages above 100%
+  return MAX2(cur_processor_count, last_processor_count);
+}
+
+// Returns false if the thread has not been scheduled since the last call to updateEvent
+// (i.e. the delta for both system and user time is 0 milliseconds)
+bool JfrThreadCPULoadEvent::update_event(EventThreadCPULoad& event, JavaThread* thread, jlong cur_wallclock_time, int processor_count) {
+  JfrThreadLocal* const tl = thread->jfr_thread_local();
+
+  jlong cur_cpu_time = os::thread_cpu_time(thread, true);
+  jlong prev_cpu_time = tl->get_cpu_time();
+
+  jlong prev_wallclock_time = tl->get_wallclock_time();
+  tl->set_wallclock_time(cur_wallclock_time);
+
+  // Threshold of 1 ms
+  if (cur_cpu_time - prev_cpu_time < 1 * NANOSECS_PER_MILLISEC) {
+    return false;
+  }
+
+  jlong cur_user_time = os::thread_cpu_time(thread, false);
+  jlong prev_user_time = tl->get_user_time();
+
+  jlong cur_system_time = cur_cpu_time - cur_user_time;
+  jlong prev_system_time = prev_cpu_time - prev_user_time;
+
+  // The user and total cpu usage clocks can have different resolutions, which can
+  // make us see decreasing system time. Ensure time doesn't go backwards.
+  if (prev_system_time > cur_system_time) {
+    cur_cpu_time += prev_system_time - cur_system_time;
+    cur_system_time = prev_system_time;
+  }
+
+  jlong user_time = cur_user_time - prev_user_time;
+  jlong system_time = cur_system_time - prev_system_time;
+  jlong wallclock_time = cur_wallclock_time - prev_wallclock_time;
+  jlong total_available_time = wallclock_time * processor_count;
+
+  // Avoid reporting percentages above the theoretical max
+  if (user_time + system_time > wallclock_time) {
+    jlong excess = user_time + system_time - wallclock_time;
+    if (user_time > excess) {
+      user_time -= excess;
+      cur_user_time -= excess;
+      cur_cpu_time -= excess;
+    } else {
+      cur_cpu_time -= excess;
+      excess -= user_time;
+      user_time = 0;
+      cur_user_time = 0;
+      system_time -= excess;
+    }
+  }
+  event.set_user(total_available_time > 0 ? (double)user_time / total_available_time : 0);
+  event.set_system(total_available_time > 0 ? (double)system_time / total_available_time : 0);
+  tl->set_user_time(cur_user_time);
+  tl->set_cpu_time(cur_cpu_time);
+  return true;
+}
+
+void JfrThreadCPULoadEvent::send_events() {
+  Thread* periodic_thread = Thread::current();
+  JfrThreadLocal* const periodic_thread_tl = periodic_thread->jfr_thread_local();
+  traceid periodic_thread_id = periodic_thread_tl->thread_id();
+  const int processor_count = JfrThreadCPULoadEvent::get_processor_count();
+  JfrTicks event_time = JfrTicks::now();
+  jlong cur_wallclock_time = JfrThreadCPULoadEvent::get_wallclock_time();
+
+  JavaThreadIteratorWithHandle jtiwh;
+  while (JavaThread* jt = jtiwh.next()) {
+    EventThreadCPULoad event(UNTIMED);
+    if (JfrThreadCPULoadEvent::update_event(event, jt, cur_wallclock_time, processor_count)) {
+      event.set_starttime(event_time);
+      if (jt != periodic_thread) {
+        // Commit reads the thread id from this thread's trace data, so put it there temporarily
+        periodic_thread_tl->set_thread_id(JFR_THREAD_ID(jt));
+      } else {
+        periodic_thread_tl->set_thread_id(periodic_thread_id);
+      }
+      event.commit();
+    }
+  }
+  log_trace(jfr)("Measured CPU usage for %d threads in %.3f milliseconds", jtiwh.length(),
+    (double)(JfrTicks::now() - event_time).milliseconds());
+  // Restore this thread's thread id
+  periodic_thread_tl->set_thread_id(periodic_thread_id);
+}
+
+void JfrThreadCPULoadEvent::send_event_for_thread(JavaThread* jt) {
+  EventThreadCPULoad event;
+  if (event.should_commit()) {
+    if (update_event(event, jt, get_wallclock_time(), get_processor_count())) {
+      event.commit();
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/periodic/jfrThreadCPULoadEvent.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_PERIODIC_JFRTHREADCPULOAD_HPP
+#define SHARE_VM_JFR_PERIODIC_JFRTHREADCPULOAD_HPP
+
+#include "jni.h"
+#include "memory/allocation.hpp"
+
+class JavaThread;
+class EventThreadCPULoad;
+
+class JfrThreadCPULoadEvent : public AllStatic {
+  static int _last_active_processor_count;
+ public:
+  static jlong get_wallclock_time();
+  static int get_processor_count();
+  static bool update_event(EventThreadCPULoad& event, JavaThread* thread, jlong cur_wallclock_time, int processor_count);
+  static void send_events();
+  static void send_event_for_thread(JavaThread* jt);
+};
+
+#endif // SHARE_VM_JFR_PERIODIC_JFRTHREADCPULOAD_HPP
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/periodic/jfrThreadDumpEvent.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/dcmd/jfrDcmds.hpp"
+#include "jfr/jfrEvents.hpp"
+#include "jfr/periodic/jfrThreadDumpEvent.hpp"
+#include "logging/log.hpp"
+#include "utilities/exceptions.hpp"
+#include "utilities/ostream.hpp"
+
+/**
+*  Worker impl for generating and writing dcmd commands
+*  as jfr events.
+*  dispatch to diagnosticcommands "parse_and_execute"
+*
+*  param: cmd = the DCMD to execute (including options)
+*/
+static bool execute_dcmd(bufferedStream& st, const char* const cmd) {
+  Thread* THREAD = Thread::current();
+  assert(!HAS_PENDING_EXCEPTION, "dcmd does not expect pending exceptions on entry!");
+  // delegate to DCmd execution
+  DCmd::parse_and_execute(DCmd_Source_Internal, &st, cmd, ' ', THREAD);
+  if (HAS_PENDING_EXCEPTION) {
+    log_debug(jfr, system)("unable to create jfr event for DCMD %s", cmd);
+    log_debug(jfr, system)("exception type: %s", PENDING_EXCEPTION->klass()->external_name());
+    // don't unwind this exception
+    CLEAR_PENDING_EXCEPTION;
+    // if exception occurred,
+    // reset stream.
+    st.reset();
+    return false;
+  }
+  return true;
+}
+
+// caller needs ResourceMark
+const char* JfrDcmdEvent::thread_dump() {
+  assert(EventThreadDump::is_enabled(), "invariant");
+  bufferedStream st;
+  execute_dcmd(st, "Thread.print");
+  return st.as_string();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/periodic/jfrThreadDumpEvent.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_PERIODIC_JFRDCMDEVENT_HPP
+#define SHARE_VM_JFR_PERIODIC_JFRDCMDEVENT_HPP
+
+#include "memory/allocation.hpp"
+
+/*
+ *  Helper for generating jfr events using output data from Dcmd's.
+ */
+class JfrDcmdEvent : public AllStatic {
+ public:
+  // caller needs ResourceMark
+  static const char* thread_dump();
+};
+
+#endif // SHARE_VM_JFR_PERIODIC_JFRDCMDEVENT_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/periodic/sampling/jfrCallTrace.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "code/debugInfoRec.hpp"
+#include "code/nmethod.hpp"
+#include "code/pcDesc.hpp"
+#include "jfr/periodic/sampling/jfrCallTrace.hpp"
+#include "oops/method.hpp"
+#include "runtime/javaCalls.hpp"
+#include "runtime/frame.inline.hpp"
+#include "runtime/registerMap.hpp"
+#include "runtime/thread.inline.hpp"
+
+bool JfrGetCallTrace::find_top_frame(frame& top_frame, Method** method, frame& first_frame) {
+  assert(top_frame.cb() != NULL, "invariant");
+  RegisterMap map(_thread, false);
+  frame candidate = top_frame;
+  for (int i = 0; i < MaxJavaStackTraceDepth * 2; ++i) {
+    if (candidate.is_entry_frame()) {
+      JavaCallWrapper *jcw = candidate.entry_frame_call_wrapper_if_safe(_thread);
+      if (jcw == NULL || jcw->is_first_frame()) {
+        return false;
+      }
+    }
+
+    if (candidate.is_interpreted_frame()) {
+      JavaThreadState state = _thread->thread_state();
+      const bool known_valid = (state == _thread_in_native || state == _thread_in_vm || state == _thread_blocked);
+      if (known_valid || candidate.is_interpreted_frame_valid(_thread)) {
+        Method* im = candidate.interpreter_frame_method();
+        if (known_valid && !im->is_valid_method()) {
+          return false;
+        }
+        *method = im;
+        first_frame = candidate;
+        return true;
+      }
+    }
+
+    if (candidate.cb()->is_nmethod()) {
+      // first check to make sure that we have a sane stack,
+      // the PC is actually inside the code part of the codeBlob,
+      // and we are past is_frame_complete_at (stack has been setup)
+      if (!candidate.safe_for_sender(_thread)) {
+        return false;
+      }
+      nmethod* nm = (nmethod*)candidate.cb();
+      *method = nm->method();
+
+      if (_in_java) {
+        PcDesc* pc_desc = nm->pc_desc_near(candidate.pc() + 1);
+        if (pc_desc == NULL || pc_desc->scope_decode_offset() == DebugInformationRecorder::serialized_null) {
+          return false;
+        }
+        candidate.set_pc(pc_desc->real_pc(nm));
+        assert(nm->pc_desc_at(candidate.pc()) != NULL, "invalid pc");
+      }
+      first_frame = candidate;
+      return true;
+    }
+
+    if (!candidate.safe_for_sender(_thread) ||
+      candidate.is_stub_frame() ||
+      candidate.cb()->frame_size() <= 0) {
+      return false;
+    }
+
+    candidate = candidate.sender(&map);
+    if (candidate.cb() == NULL) {
+      return false;
+    }
+  }
+  return false;
+}
+
+bool JfrGetCallTrace::get_topframe(void* ucontext, frame& topframe) {
+  if (!_thread->pd_get_top_frame_for_profiling(&topframe, ucontext, _in_java)) {
+    return false;
+  }
+
+  if (topframe.cb() == NULL) {
+    return false;
+  }
+
+  frame first_java_frame;
+  Method* method = NULL;
+  if (find_top_frame(topframe, &method, first_java_frame)) {
+    if (method == NULL) {
+      return false;
+    }
+    topframe = first_java_frame;
+    return true;
+  }
+  return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/periodic/sampling/jfrCallTrace.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_ENGINE_SAMPLING_JFRCALLTRACE_HPP
+#define SHARE_VM_JFR_ENGINE_SAMPLING_JFRCALLTRACE_HPP
+
+#include "memory/allocation.hpp"
+
+class frame;
+class Method;
+class JavaThread;
+
+class JfrGetCallTrace : public StackObj {
+ private:
+  JavaThread* _thread;
+  bool _in_java;
+
+ public:
+  JfrGetCallTrace(bool in_java, JavaThread* thread) : _in_java(in_java), _thread(thread) {}
+  bool find_top_frame(frame& topframe, Method** method, frame& first_frame);
+  bool get_topframe(void* ucontext, frame& top);
+};
+
+#endif // SHARE_VM_JFR_ENGINE_SAMPLING_JFRCALLTRACE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,637 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/jfrEvents.hpp"
+#include "jfr/recorder/jfrRecorder.hpp"
+#include "jfr/periodic/sampling/jfrCallTrace.hpp"
+#include "jfr/periodic/sampling/jfrThreadSampler.hpp"
+#include "jfr/recorder/service/jfrOptionSet.hpp"
+#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
+#include "jfr/support/jfrThreadId.hpp"
+#include "jfr/utilities/jfrTime.hpp"
+#include "logging/log.hpp"
+#include "runtime/frame.inline.hpp"
+#include "runtime/os.hpp"
+#include "runtime/semaphore.hpp"
+#include "runtime/thread.inline.hpp"
+#include "runtime/threadSMR.hpp"
+
+enum JfrSampleType {
+  NO_SAMPLE = 0,
+  JAVA_SAMPLE = 1,
+  NATIVE_SAMPLE = 2
+};
+
+static bool in_java_sample(JavaThread* thread) {
+  switch (thread->thread_state()) {
+  case _thread_new:
+  case _thread_uninitialized:
+  case _thread_new_trans:
+  case _thread_in_vm_trans:
+  case _thread_blocked_trans:
+  case _thread_in_native_trans:
+  case _thread_blocked:
+  case _thread_in_vm:
+  case _thread_in_native:
+  case _thread_in_Java_trans:
+    break;
+  case _thread_in_Java:
+    return true;
+  default:
+    ShouldNotReachHere();
+    break;
+  }
+  return false;
+}
+
+static bool in_native_sample(JavaThread* thread) {
+  switch (thread->thread_state()) {
+  case _thread_new:
+  case _thread_uninitialized:
+  case _thread_new_trans:
+  case _thread_blocked_trans:
+  case _thread_blocked:
+  case _thread_in_vm:
+  case _thread_in_vm_trans:
+  case _thread_in_Java_trans:
+  case _thread_in_Java:
+  case _thread_in_native_trans:
+    break;
+  case _thread_in_native:
+    return true;
+  default:
+    ShouldNotReachHere();
+    break;
+  }
+  return false;
+}
+
+class JfrThreadSampleClosure {
+ public:
+  JfrThreadSampleClosure(EventExecutionSample* events, EventNativeMethodSample* events_native);
+  ~JfrThreadSampleClosure() {}
+  EventExecutionSample* next_event() { return &_events[_added_java++]; }
+  EventNativeMethodSample* next_event_native() { return &_events_native[_added_native++]; }
+  void commit_events();
+  int added() const { return _added_java; }
+  JfrSampleType do_sample_thread(JavaThread* thread, JfrStackFrame* frames, u4 max_frames, bool java_sample, bool native_sample);
+  int java_entries() { return _added_java; }
+  int native_entries() { return _added_native; }
+
+ private:
+  bool sample_thread_in_java(JavaThread* thread, JfrStackFrame* frames, u4 max_frames);
+  bool sample_thread_in_native(JavaThread* thread, JfrStackFrame* frames, u4 max_frames);
+  EventExecutionSample* _events;
+  EventNativeMethodSample* _events_native;
+  Thread* _self;
+  int _added_java;
+  int _added_native;
+};
+
+class OSThreadSampler : public os::SuspendedThreadTask {
+ public:
+  OSThreadSampler(JavaThread* thread,
+                  JfrThreadSampleClosure& closure,
+                  JfrStackFrame *frames,
+                  u4 max_frames) : os::SuspendedThreadTask((Thread*)thread),
+    _success(false),
+    _stacktrace(frames, max_frames),
+    _closure(closure),
+    _suspend_time() {}
+
+  void take_sample();
+  void do_task(const os::SuspendedThreadTaskContext& context);
+  void protected_task(const os::SuspendedThreadTaskContext& context);
+  bool success() const { return _success; }
+  const JfrStackTrace& stacktrace() const { return _stacktrace; }
+
+ private:
+  bool _success;
+  JfrStackTrace _stacktrace;
+  JfrThreadSampleClosure& _closure;
+  JfrTicks _suspend_time;
+};
+
+class OSThreadSamplerCallback : public os::CrashProtectionCallback {
+ public:
+  OSThreadSamplerCallback(OSThreadSampler& sampler, const os::SuspendedThreadTaskContext &context) :
+    _sampler(sampler), _context(context) {
+  }
+  virtual void call() {
+    _sampler.protected_task(_context);
+  }
+ private:
+  OSThreadSampler& _sampler;
+  const os::SuspendedThreadTaskContext& _context;
+};
+
+void OSThreadSampler::do_task(const os::SuspendedThreadTaskContext& context) {
+#ifndef ASSERT
+  guarantee(JfrOptionSet::sample_protection(), "Sample Protection should be on in product builds");
+#endif
+  assert(_suspend_time.value() == 0, "already timestamped!");
+  _suspend_time = JfrTicks::now();
+
+  if (JfrOptionSet::sample_protection()) {
+    OSThreadSamplerCallback cb(*this, context);
+    os::ThreadCrashProtection crash_protection;
+    if (!crash_protection.call(cb)) {
+      log_error(jfr)("Thread method sampler crashed");
+    }
+  } else {
+    protected_task(context);
+  }
+}
+
+/*
+* From this method and down the call tree we attempt to protect against crashes
+* using a signal handler / __try block. Don't take locks, rely on destructors or
+* leave memory (in case of signal / exception) in an inconsistent state. */
+void OSThreadSampler::protected_task(const os::SuspendedThreadTaskContext& context) {
+  JavaThread* jth = (JavaThread*)context.thread();
+  // Skip sample if we signaled a thread that moved to other state
+  if (!in_java_sample(jth)) {
+    return;
+  }
+  JfrGetCallTrace trace(true, jth);
+  frame topframe;
+  if (trace.get_topframe(context.ucontext(), topframe)) {
+    if (_stacktrace.record_thread(*jth, topframe)) {
+      /* If we managed to get a topframe and a stacktrace, create an event
+      * and put it into our array. We can't call Jfr::_stacktraces.add()
+      * here since it would allocate memory using malloc. Doing so while
+      * the stopped thread is inside malloc would deadlock. */
+      _success = true;
+      EventExecutionSample *ev = _closure.next_event();
+      ev->set_starttime(_suspend_time);
+      ev->set_endtime(_suspend_time); // fake to not take an end time
+      ev->set_sampledThread(JFR_THREAD_ID(jth));
+      ev->set_state(java_lang_Thread::get_thread_status(jth->threadObj()));
+    }
+  }
+}
+
+void OSThreadSampler::take_sample() {
+  run();
+}
+
+class JfrNativeSamplerCallback : public os::CrashProtectionCallback {
+ public:
+  JfrNativeSamplerCallback(JfrThreadSampleClosure& closure, JavaThread* jt, JfrStackFrame* frames, u4 max_frames) :
+    _closure(closure), _jt(jt), _stacktrace(frames, max_frames), _success(false) {
+  }
+  virtual void call();
+  bool success() { return _success; }
+  JfrStackTrace& stacktrace() { return _stacktrace; }
+
+ private:
+  JfrThreadSampleClosure& _closure;
+  JavaThread* _jt;
+  JfrStackTrace _stacktrace;
+  bool _success;
+};
+
+static void write_native_event(JfrThreadSampleClosure& closure, JavaThread* jt) {
+  EventNativeMethodSample *ev = closure.next_event_native();
+  ev->set_starttime(JfrTicks::now());
+  ev->set_sampledThread(JFR_THREAD_ID(jt));
+  ev->set_state(java_lang_Thread::get_thread_status(jt->threadObj()));
+}
+
+void JfrNativeSamplerCallback::call() {
+  // When a thread is only attach it will be native without a last java frame
+  if (!_jt->has_last_Java_frame()) {
+    return;
+  }
+
+  frame topframe = _jt->last_frame();
+  frame first_java_frame;
+  Method* method = NULL;
+  JfrGetCallTrace gct(false, _jt);
+  if (!gct.find_top_frame(topframe, &method, first_java_frame)) {
+    return;
+  }
+  if (method == NULL) {
+    return;
+  }
+  topframe = first_java_frame;
+  _success = _stacktrace.record_thread(*_jt, topframe);
+  if (_success) {
+    write_native_event(_closure, _jt);
+  }
+}
+
+bool JfrThreadSampleClosure::sample_thread_in_java(JavaThread* thread, JfrStackFrame* frames, u4 max_frames) {
+  OSThreadSampler sampler(thread, *this, frames, max_frames);
+  sampler.take_sample();
+  /* We don't want to allocate any memory using malloc/etc while the thread
+  * is stopped, so everything is stored in stack allocated memory until this
+  * point where the thread has been resumed again, if the sampling was a success
+  * we need to store the stacktrace in the stacktrace repository and update
+  * the event with the id that was returned. */
+  if (!sampler.success()) {
+    return false;
+  }
+  EventExecutionSample *event = &_events[_added_java - 1];
+  traceid id = JfrStackTraceRepository::add(sampler.stacktrace());
+  assert(id != 0, "Stacktrace id should not be 0");
+  event->set_stackTrace(id);
+  return true;
+}
+
+bool JfrThreadSampleClosure::sample_thread_in_native(JavaThread* thread, JfrStackFrame* frames, u4 max_frames) {
+  JfrNativeSamplerCallback cb(*this, thread, frames, max_frames);
+  if (JfrOptionSet::sample_protection()) {
+    os::ThreadCrashProtection crash_protection;
+    if (!crash_protection.call(cb)) {
+      log_error(jfr)("Thread method sampler crashed for native");
+    }
+  } else {
+    cb.call();
+  }
+  if (!cb.success()) {
+    return false;
+  }
+  EventNativeMethodSample *event = &_events_native[_added_native - 1];
+  traceid id = JfrStackTraceRepository::add(cb.stacktrace());
+  assert(id != 0, "Stacktrace id should not be 0");
+  event->set_stackTrace(id);
+  return true;
+}
+
+void JfrThreadSampleClosure::commit_events() {
+  for (int i = 0; i < _added_java; ++i) {
+    _events[i].commit();
+  }
+  for (int i = 0; i < _added_native; ++i) {
+    _events_native[i].commit();
+  }
+}
+
+JfrThreadSampleClosure::JfrThreadSampleClosure(EventExecutionSample* events, EventNativeMethodSample* events_native) :
+  _events(events),
+  _events_native(events_native),
+  _self(Thread::current()),
+  _added_java(0),
+  _added_native(0) {
+}
+
+class JfrThreadSampler : public Thread {
+  friend class JfrThreadSampling;
+ private:
+  Semaphore _sample;
+  Thread* _sampler_thread;
+  JfrStackFrame* const _frames;
+  JavaThread* _last_thread_java;
+  JavaThread* _last_thread_native;
+  size_t _interval_java;
+  size_t _interval_native;
+  int _cur_index;
+  const u4 _max_frames;
+  volatile bool _disenrolled;
+  static Monitor* _transition_block_lock;
+
+  JavaThread* next_thread(ThreadsList* t_list, JavaThread* first_sampled, JavaThread* current);
+  void task_stacktrace(JfrSampleType type, JavaThread** last_thread);
+  JfrThreadSampler(size_t interval_java, size_t interval_native, u4 max_frames);
+  ~JfrThreadSampler();
+
+  void start_thread();
+
+  void enroll();
+  void disenroll();
+  void set_java_interval(size_t interval) { _interval_java = interval; };
+  void set_native_interval(size_t interval) { _interval_native = interval; };
+  size_t get_java_interval() { return _interval_java; };
+  size_t get_native_interval() { return _interval_native; };
+
+ public:
+  void run();
+  static Monitor* transition_block() { return _transition_block_lock; }
+  static void on_javathread_suspend(JavaThread* thread);
+};
+
+Monitor* JfrThreadSampler::_transition_block_lock = new Monitor(Mutex::leaf, "Trace block", true, Monitor::_safepoint_check_never);
+
+static void clear_transition_block(JavaThread* jt) {
+  jt->clear_trace_flag();
+  JfrThreadLocal* const tl = jt->jfr_thread_local();
+  if (tl->is_trace_block()) {
+    MutexLockerEx ml(JfrThreadSampler::transition_block(), Mutex::_no_safepoint_check_flag);
+    JfrThreadSampler::transition_block()->notify_all();
+  }
+}
+
+JfrSampleType JfrThreadSampleClosure::do_sample_thread(JavaThread* thread, JfrStackFrame* frames, u4 max_frames, bool java_sample, bool native_sample) {
+  assert(Threads_lock->owned_by_self(), "Holding the thread table lock.");
+  if (thread->is_hidden_from_external_view()) {
+    return NO_SAMPLE;
+  }
+  if (thread->in_deopt_handler()) {
+    return NO_SAMPLE;
+  }
+  JfrSampleType ret = NO_SAMPLE;
+  thread->set_trace_flag();
+  if (!UseMembar) {
+    os::serialize_thread_states();
+  }
+  if (in_java_sample(thread) && java_sample) {
+    ret = sample_thread_in_java(thread, frames, max_frames) ? JAVA_SAMPLE : NO_SAMPLE;
+  } else if (in_native_sample(thread) && native_sample) {
+    ret = sample_thread_in_native(thread, frames, max_frames) ? NATIVE_SAMPLE : NO_SAMPLE;
+  }
+  clear_transition_block(thread);
+  return ret;
+}
+
+JfrThreadSampler::JfrThreadSampler(size_t interval_java, size_t interval_native, u4 max_frames) :
+  _sample(),
+  _sampler_thread(NULL),
+  _frames(JfrCHeapObj::new_array<JfrStackFrame>(max_frames)),
+  _last_thread_java(NULL),
+  _last_thread_native(NULL),
+  _interval_java(interval_java),
+  _interval_native(interval_native),
+  _cur_index(-1),
+  _max_frames(max_frames),
+  _disenrolled(true) {
+}
+
+JfrThreadSampler::~JfrThreadSampler() {
+  JfrCHeapObj::free(_frames, sizeof(JfrStackFrame) * _max_frames);
+}
+
+void JfrThreadSampler::on_javathread_suspend(JavaThread* thread) {
+  JfrThreadLocal* const tl = thread->jfr_thread_local();
+  tl->set_trace_block();
+  {
+    MutexLockerEx ml(transition_block(), Mutex::_no_safepoint_check_flag);
+    while (thread->is_trace_suspend()) {
+      transition_block()->wait(true);
+    }
+    tl->clear_trace_block();
+  }
+}
+
+JavaThread* JfrThreadSampler::next_thread(ThreadsList* t_list, JavaThread* first_sampled, JavaThread* current) {
+  assert(Threads_lock->owned_by_self(), "Holding the thread table lock.");
+  if (current == NULL) {
+    _cur_index = 0;
+    return t_list->thread_at(_cur_index);
+  }
+
+  if (_cur_index == -1 || t_list->thread_at(_cur_index) != current) {
+    // 'current' is not at '_cur_index' so find it:
+    _cur_index = t_list->find_index_of_JavaThread(current);
+    assert(_cur_index != -1, "current JavaThread should be findable.");
+  }
+  _cur_index++;
+
+  JavaThread* next = NULL;
+  // wrap
+  if ((uint)_cur_index >= t_list->length()) {
+    _cur_index = 0;
+  }
+  next = t_list->thread_at(_cur_index);
+
+  // sample wrap
+  if (next == first_sampled) {
+    return NULL;
+  }
+  return next;
+}
+
+void JfrThreadSampler::start_thread() {
+  if (os::create_thread(this, os::os_thread)) {
+    os::start_thread(this);
+  } else {
+    log_error(jfr)("Failed to create thread for thread sampling");
+  }
+}
+
+void JfrThreadSampler::enroll() {
+  if (_disenrolled) {
+    log_info(jfr)("Enrolling thread sampler");
+    _sample.signal();
+    _disenrolled = false;
+  }
+}
+
+void JfrThreadSampler::disenroll() {
+  if (!_disenrolled) {
+    _sample.wait();
+    _disenrolled = true;
+    log_info(jfr)("Disenrolling thread sampler");
+  }
+}
+
+static jlong get_monotonic_ms() {
+  return os::javaTimeNanos() / 1000000;
+}
+
+void JfrThreadSampler::run() {
+  assert(_sampler_thread == NULL, "invariant");
+  _sampler_thread = this;
+
+  jlong last_java_ms = get_monotonic_ms();
+  jlong last_native_ms = last_java_ms;
+  while (true) {
+    if (!_sample.trywait()) {
+      // disenrolled
+      _sample.wait();
+      last_java_ms = get_monotonic_ms();
+      last_native_ms = last_java_ms;
+    }
+    _sample.signal();
+    jlong java_interval = _interval_java == 0 ? max_jlong : MAX2<jlong>(_interval_java, 10);
+    jlong native_interval = _interval_native == 0 ? max_jlong : MAX2<jlong>(_interval_native, 10);
+
+    jlong now_ms = get_monotonic_ms();
+
+    jlong next_j = java_interval + last_java_ms - now_ms;
+    jlong next_n = native_interval + last_native_ms - now_ms;
+
+    jlong sleep_to_next = MIN2<jlong>(next_j, next_n);
+
+    if (sleep_to_next > 0) {
+      os::naked_short_sleep(sleep_to_next);
+    }
+
+    if ((next_j - sleep_to_next) <= 0) {
+      task_stacktrace(JAVA_SAMPLE, &_last_thread_java);
+      last_java_ms = get_monotonic_ms();
+    }
+    if ((next_n - sleep_to_next) <= 0) {
+      task_stacktrace(NATIVE_SAMPLE, &_last_thread_native);
+      last_native_ms = get_monotonic_ms();
+    }
+  }
+  delete this;
+}
+
+static const int MAX_NR_OF_SAMPLES = 5;
+
+void JfrThreadSampler::task_stacktrace(JfrSampleType type, JavaThread** last_thread) {
+  ResourceMark rm;
+  EventExecutionSample samples[MAX_NR_OF_SAMPLES];
+  EventNativeMethodSample samples_native[MAX_NR_OF_SAMPLES];
+  JfrThreadSampleClosure sample_task(samples, samples_native);
+
+  int num_samples = 0;
+  {
+    elapsedTimer sample_time;
+    sample_time.start();
+
+    {
+      MonitorLockerEx tlock(Threads_lock, Mutex::_allow_vm_block_flag);
+      ThreadsListHandle tlh;
+      JavaThread* current = tlh.includes(*last_thread) ? *last_thread : NULL;
+      JavaThread* start = NULL;
+
+      while (num_samples < MAX_NR_OF_SAMPLES) {
+        current = next_thread(tlh.list(), start, current);
+        if (current == NULL) {
+          break;
+        }
+        if (start == NULL) {
+          start = current;  // remember thread where we started sampling
+        }
+        if (current->is_Compiler_thread()) {
+          continue;
+        }
+        *last_thread = current;  // remember thread we last sampled
+        JfrSampleType ret = sample_task.do_sample_thread(current, _frames, _max_frames, type == JAVA_SAMPLE, type == NATIVE_SAMPLE);
+        switch (type) {
+        case JAVA_SAMPLE:
+        case NATIVE_SAMPLE:
+          ++num_samples;
+          break;
+        default:
+          break;
+        }
+      }
+    }
+    sample_time.stop();
+    log_trace(jfr)("JFR thread sampling done in %3.7f secs with %d java %d native samples",
+      sample_time.seconds(), sample_task.java_entries(), sample_task.native_entries());
+  }
+  if (num_samples > 0) {
+    sample_task.commit_events();
+  }
+}
+
+static JfrThreadSampling* _instance = NULL;
+
+JfrThreadSampling& JfrThreadSampling::instance() {
+  return *_instance;
+}
+
+JfrThreadSampling* JfrThreadSampling::create() {
+  assert(_instance == NULL, "invariant");
+  _instance = new JfrThreadSampling();
+  return _instance;
+}
+
+void JfrThreadSampling::destroy() {
+  if (_instance != NULL) {
+    delete _instance;
+    _instance = NULL;
+  }
+}
+
+JfrThreadSampling::JfrThreadSampling() : _sampler(NULL) {}
+
+JfrThreadSampling::~JfrThreadSampling() {
+  if (_sampler != NULL) {
+    _sampler->disenroll();
+  }
+}
+
+static void log(size_t interval_java, size_t interval_native) {
+  log_info(jfr)("Updated thread sampler for java: " SIZE_FORMAT"  ms, native " SIZE_FORMAT " ms", interval_java, interval_native);
+}
+
+void JfrThreadSampling::start_sampler(size_t interval_java, size_t interval_native) {
+  assert(_sampler == NULL, "invariant");
+  log_info(jfr)("Enrolling thread sampler");
+  _sampler = new JfrThreadSampler(interval_java, interval_native, JfrOptionSet::stackdepth());
+  _sampler->start_thread();
+  _sampler->enroll();
+}
+
+void JfrThreadSampling::set_sampling_interval(bool java_interval, size_t period) {
+  size_t interval_java = 0;
+  size_t interval_native = 0;
+  if (_sampler != NULL) {
+    interval_java = _sampler->get_java_interval();
+    interval_native = _sampler->get_native_interval();
+  }
+
+  if (java_interval) {
+    interval_java = period;
+  } else {
+    interval_native = period;
+  }
+
+  if (interval_java > 0 || interval_native > 0) {
+    if (_sampler == NULL) {
+      log_info(jfr)("Creating thread sampler for java:%zu ms, native %zu ms", interval_java, interval_native);
+      start_sampler(interval_java, interval_native);
+    } else {
+      _sampler->set_java_interval(interval_java);
+      _sampler->set_native_interval(interval_native);
+      _sampler->enroll();
+    }
+    assert(_sampler != NULL, "invariant");
+    log(interval_java, interval_native);
+  } else if (_sampler != NULL) {
+    _sampler->disenroll();
+  }
+}
+
+void JfrThreadSampling::set_java_sample_interval(size_t period) {
+  if (_instance == NULL && 0 == period) {
+    return;
+  }
+  instance().set_sampling_interval(true, period);
+}
+
+void JfrThreadSampling::set_native_sample_interval(size_t period) {
+  if (_instance == NULL && 0 == period) {
+    return;
+  }
+  instance().set_sampling_interval(false, period);
+}
+
+void JfrThreadSampling::on_javathread_suspend(JavaThread* thread) {
+  JfrThreadSampler::on_javathread_suspend(thread);
+}
+
+Thread* JfrThreadSampling::sampler_thread() {
+  if (_instance == NULL) {
+    return NULL;
+  }
+  return _instance->_sampler != NULL ? _instance->_sampler->_sampler_thread : NULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_PERIODIC_SAMPLING_JFRTHREADSAMPLER_HPP
+#define SHARE_VM_JFR_PERIODIC_SAMPLING_JFRTHREADSAMPLER_HPP
+
+#include "jfr/utilities/jfrAllocation.hpp"
+
+class Monitor;
+class JavaThread;
+class JfrStackFrame;
+class JfrThreadSampler;
+class Thread;
+
+class JfrThreadSampling : public JfrCHeapObj {
+  friend class JfrRecorder;
+ private:
+  JfrThreadSampler* _sampler;
+  void start_sampler(size_t interval_java, size_t interval_native);
+  void set_sampling_interval(bool java_interval, size_t period);
+
+  JfrThreadSampling();
+  ~JfrThreadSampling();
+
+  static JfrThreadSampling& instance();
+  static JfrThreadSampling* create();
+  static void destroy();
+
+ public:
+  static void set_java_sample_interval(size_t period);
+  static void set_native_sample_interval(size_t period);
+  static void on_javathread_suspend(JavaThread* thread);
+  static Thread* sampler_thread();
+};
+
+#endif // SHARE_VM_JFR_PERIODIC_SAMPLING_JFRTHREADSAMPLER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointBlob.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/recorder/checkpoint/jfrCheckpointBlob.hpp"
+#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
+
+JfrCheckpointBlob::JfrCheckpointBlob(const u1* checkpoint, size_t size) :
+  _checkpoint(JfrCHeapObj::new_array<u1>(size)),
+  _size(size),
+  _next(),
+  _written(false) {
+  assert(checkpoint != NULL, "invariant");
+  assert(_checkpoint != NULL, "invariant");
+  memcpy(const_cast<u1*>(_checkpoint), checkpoint, size);
+}
+
+JfrCheckpointBlob::~JfrCheckpointBlob() {
+  JfrCHeapObj::free(const_cast<u1*>(_checkpoint), _size);
+}
+
+const JfrCheckpointBlobHandle& JfrCheckpointBlob::next() const {
+  return _next;
+}
+
+void JfrCheckpointBlob::write_this(JfrCheckpointWriter& writer) const {
+  writer.bytes(_checkpoint, _size);
+}
+
+void JfrCheckpointBlob::exclusive_write(JfrCheckpointWriter& writer) const {
+  if (!_written) {
+    write_this(writer);
+    _written = true;
+  }
+  if (_next.valid()) {
+    _next->exclusive_write(writer);
+  }
+}
+
+void JfrCheckpointBlob::write(JfrCheckpointWriter& writer) const {
+  write_this(writer);
+  if (_next.valid()) {
+    _next->write(writer);
+  }
+}
+
+void JfrCheckpointBlob::reset_write_state() const {
+  if (_written) {
+    _written = false;
+  }
+  if (_next.valid()) {
+    _next->reset_write_state();
+  }
+}
+
+void JfrCheckpointBlob::set_next(const JfrCheckpointBlobHandle& ref) {
+  if (_next == ref) {
+    return;
+  }
+  assert(_next != ref, "invariant");
+  if (_next.valid()) {
+    _next->set_next(ref);
+    return;
+  }
+  _next = ref;
+}
+
+JfrCheckpointBlobHandle JfrCheckpointBlob::make(const u1* checkpoint, size_t size) {
+  const JfrCheckpointBlob* cp_blob = new JfrCheckpointBlob(checkpoint, size);
+  assert(cp_blob != NULL, "invariant");
+  return JfrCheckpointBlobReference::make(cp_blob);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointBlob.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_RECORDER_CHECKPOINT_JFRCHECKPOINTBLOB_HPP
+#define SHARE_VM_JFR_RECORDER_CHECKPOINT_JFRCHECKPOINTBLOB_HPP
+
+#include "jfr/utilities/jfrAllocation.hpp"
+#include "jfr/utilities/jfrRefCountPointer.hpp"
+
+class JfrCheckpointBlob;
+class JfrCheckpointWriter;
+
+typedef RefCountPointer<JfrCheckpointBlob, MultiThreadedRefCounter> JfrCheckpointBlobReference;
+typedef RefCountHandle<JfrCheckpointBlobReference> JfrCheckpointBlobHandle;
+
+class JfrCheckpointBlob : public JfrCHeapObj {
+  template <typename, typename>
+  friend class RefCountPointer;
+ private:
+  const u1* _checkpoint;
+  const size_t _size;
+  JfrCheckpointBlobHandle _next;
+  mutable bool _written;
+
+  JfrCheckpointBlob(const u1* checkpoint, size_t size);
+  ~JfrCheckpointBlob();
+  const JfrCheckpointBlobHandle& next() const;
+  void write_this(JfrCheckpointWriter& writer) const;
+
+ public:
+  void write(JfrCheckpointWriter& writer) const;
+  void exclusive_write(JfrCheckpointWriter& writer) const;
+  void reset_write_state() const;
+  void set_next(const JfrCheckpointBlobHandle& ref);
+  static JfrCheckpointBlobHandle make(const u1* checkpoint, size_t size);
+};
+
+#endif // SHARE_VM_JFR_RECORDER_CHECKPOINT_JFRCHECKPOINTBLOB_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/javaClasses.inline.hpp"
+#include "jfr/recorder/jfrRecorder.hpp"
+#include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
+#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
+#include "jfr/recorder/checkpoint/types/jfrTypeManager.hpp"
+#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp"
+#include "jfr/recorder/service/jfrOptionSet.hpp"
+#include "jfr/recorder/storage/jfrMemorySpace.inline.hpp"
+#include "jfr/recorder/storage/jfrStorageUtils.inline.hpp"
+#include "jfr/recorder/repository/jfrChunkWriter.hpp"
+#include "jfr/utilities/jfrBigEndian.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
+#include "logging/log.hpp"
+#include "memory/resourceArea.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/orderAccess.inline.hpp"
+#include "runtime/safepoint.hpp"
+
+typedef JfrCheckpointManager::Buffer* BufferPtr;
+
+static JfrCheckpointManager* _instance = NULL;
+
+JfrCheckpointManager& JfrCheckpointManager::instance() {
+  return *_instance;
+}
+
+JfrCheckpointManager* JfrCheckpointManager::create(JfrChunkWriter& cw) {
+  assert(_instance == NULL, "invariant");
+  _instance = new JfrCheckpointManager(cw);
+  return _instance;
+}
+
+void JfrCheckpointManager::destroy() {
+  assert(_instance != NULL, "invariant");
+  delete _instance;
+  _instance = NULL;
+}
+
+JfrCheckpointManager::JfrCheckpointManager(JfrChunkWriter& cw) :
+  _free_list_mspace(NULL),
+  _epoch_transition_mspace(NULL),
+  _lock(NULL),
+  _type_manager(NULL),
+  _service_thread(NULL),
+  _chunkwriter(cw),
+  _checkpoint_epoch_state(JfrTraceIdEpoch::epoch()) {}
+
+JfrCheckpointManager::~JfrCheckpointManager() {
+  if (_free_list_mspace != NULL) {
+    delete _free_list_mspace;
+  }
+  if (_epoch_transition_mspace != NULL) {
+    delete _epoch_transition_mspace;
+  }
+  if (_lock != NULL) {
+    delete _lock;
+  }
+  if (_type_manager) {
+    delete _type_manager;
+  }
+}
+
+static const size_t unlimited_mspace_size = 0;
+static const size_t checkpoint_buffer_cache_count = 2;
+static const size_t checkpoint_buffer_size = 512 * K;
+
+static JfrCheckpointMspace* create_mspace(size_t buffer_size, size_t limit, size_t cache_count, JfrCheckpointManager* system) {
+  JfrCheckpointMspace* mspace = new JfrCheckpointMspace(buffer_size, limit, cache_count, system);
+  if (mspace != NULL) {
+    mspace->initialize();
+  }
+  return mspace;
+}
+
+bool JfrCheckpointManager::initialize() {
+  assert(_free_list_mspace == NULL, "invariant");
+  _free_list_mspace = create_mspace(checkpoint_buffer_size, unlimited_mspace_size, checkpoint_buffer_cache_count, this);
+  if (_free_list_mspace == NULL) {
+    return false;
+  }
+  assert(_epoch_transition_mspace == NULL, "invariant");
+  _epoch_transition_mspace = create_mspace(checkpoint_buffer_size, unlimited_mspace_size, checkpoint_buffer_cache_count, this);
+  if (_epoch_transition_mspace == NULL) {
+    return false;
+  }
+  assert(_type_manager == NULL, "invariant");
+  _type_manager = new JfrTypeManager();
+  if (_type_manager == NULL || !_type_manager->initialize()) {
+    return false;
+  }
+  assert(_lock == NULL, "invariant");
+  _lock = new Mutex(Monitor::leaf - 1, "Checkpoint mutex", Mutex::_allow_vm_block_flag, Monitor::_safepoint_check_never);
+  return _lock != NULL;
+}
+
+bool JfrCheckpointManager::use_epoch_transition_mspace(const Thread* thread) const {
+  return _service_thread != thread && OrderAccess::load_acquire(&_checkpoint_epoch_state) != JfrTraceIdEpoch::epoch();
+}
+
+void JfrCheckpointManager::synchronize_epoch() {
+  assert(_checkpoint_epoch_state != JfrTraceIdEpoch::epoch(), "invariant");
+  OrderAccess::storestore();
+  _checkpoint_epoch_state = JfrTraceIdEpoch::epoch();
+}
+
+void JfrCheckpointManager::shift_epoch() {
+  debug_only(const u1 current_epoch = JfrTraceIdEpoch::current();)
+  JfrTraceIdEpoch::shift_epoch();
+  assert(current_epoch != JfrTraceIdEpoch::current(), "invariant");
+}
+
+void JfrCheckpointManager::register_service_thread(const Thread* thread) {
+  _service_thread = thread;
+}
+
+void JfrCheckpointManager::register_full(BufferPtr t, Thread* thread) {
+  // nothing here at the moment
+  assert(t->retired(), "invariant");
+}
+
+void JfrCheckpointManager::lock() {
+  assert(!_lock->owned_by_self(), "invariant");
+  _lock->lock_without_safepoint_check();
+}
+
+void JfrCheckpointManager::unlock() {
+  _lock->unlock();
+}
+
+#ifdef ASSERT
+
+bool JfrCheckpointManager::is_locked() const {
+  return _lock->owned_by_self();
+}
+
+static void assert_free_lease(const BufferPtr buffer) {
+  assert(buffer != NULL, "invariant");
+  assert(buffer->acquired_by_self(), "invariant");
+  assert(buffer->lease(), "invariant");
+}
+
+static void assert_release(const BufferPtr buffer) {
+  assert(buffer != NULL, "invariant");
+  assert(buffer->lease(), "invariant");
+  assert(buffer->acquired_by_self(), "invariant");
+}
+
+#endif // ASSERT
+
+static BufferPtr lease_free(size_t size, JfrCheckpointMspace* mspace, size_t retry_count, Thread* thread) {
+  static const size_t max_elem_size = mspace->min_elem_size(); // min is max
+  BufferPtr buffer;
+  if (size <= max_elem_size) {
+    BufferPtr buffer = mspace_get_free_lease_with_retry(size, mspace, retry_count, thread);
+    if (buffer != NULL) {
+      DEBUG_ONLY(assert_free_lease(buffer);)
+      return buffer;
+    }
+  }
+  buffer = mspace_allocate_transient_lease_to_free(size, mspace, thread);
+  DEBUG_ONLY(assert_free_lease(buffer);)
+  return buffer;
+}
+
+static const size_t lease_retry = 10;
+
+BufferPtr JfrCheckpointManager::lease_buffer(Thread* thread, size_t size /* 0 */) {
+  JfrCheckpointManager& manager = instance();
+  if (manager.use_epoch_transition_mspace(thread)) {
+    return lease_free(size, manager._epoch_transition_mspace, lease_retry, thread);
+  }
+  return lease_free(size, manager._free_list_mspace, lease_retry, thread);
+}
+
+/*
+* If the buffer was a "lease" from the free list, release back.
+*
+* The buffer is effectively invalidated for the thread post-return,
+* and the caller should take means to ensure that it is not referenced.
+*/
+static void release(BufferPtr const buffer, Thread* thread) {
+  DEBUG_ONLY(assert_release(buffer);)
+  buffer->clear_lease();
+  buffer->release();
+}
+
+BufferPtr JfrCheckpointManager::flush(BufferPtr old, size_t used, size_t requested, Thread* thread) {
+  assert(old != NULL, "invariant");
+  assert(old->lease(), "invariant");
+  if (0 == requested) {
+    // indicates a lease is being returned
+    release(old, thread);
+    return NULL;
+  }
+  // migration of in-flight information
+  BufferPtr const new_buffer = lease_buffer(thread, used + requested);
+  if (new_buffer != NULL) {
+    migrate_outstanding_writes(old, new_buffer, used, requested);
+  }
+  release(old, thread);
+  return new_buffer; // might be NULL
+}
+
+// offsets into the JfrCheckpointEntry
+static const juint starttime_offset = sizeof(jlong);
+static const juint duration_offset = starttime_offset + sizeof(jlong);
+static const juint flushpoint_offset = duration_offset + sizeof(jlong);
+static const juint types_offset = flushpoint_offset + sizeof(juint);
+static const juint payload_offset = types_offset + sizeof(juint);
+
+template <typename Return>
+static Return read_data(const u1* data) {
+  return JfrBigEndian::read<Return>(data);
+}
+
+static jlong total_size(const u1* data) {
+  return read_data<jlong>(data);
+}
+
+static jlong starttime(const u1* data) {
+  return read_data<jlong>(data + starttime_offset);
+}
+
+static jlong duration(const u1* data) {
+  return read_data<jlong>(data + duration_offset);
+}
+
+static bool is_flushpoint(const u1* data) {
+  return read_data<juint>(data + flushpoint_offset) == (juint)1;
+}
+
+static juint number_of_types(const u1* data) {
+  return read_data<juint>(data + types_offset);
+}
+
+static void write_checkpoint_header(JfrChunkWriter& cw, intptr_t offset_prev_cp_event, const u1* data) {
+  cw.reserve(sizeof(u4));
+  cw.write((u8)EVENT_CHECKPOINT);
+  cw.write(starttime(data));
+  cw.write(duration(data));
+  cw.write((jlong)offset_prev_cp_event);
+  cw.write(is_flushpoint(data));
+  cw.write(number_of_types(data));
+}
+
+static void write_checkpoint_content(JfrChunkWriter& cw, const u1* data, size_t size) {
+  assert(data != NULL, "invariant");
+  cw.write_unbuffered(data + payload_offset, size);
+}
+
+static size_t write_checkpoint_event(JfrChunkWriter& cw, const u1* data) {
+  assert(data != NULL, "invariant");
+  const intptr_t previous_checkpoint_event = cw.previous_checkpoint_offset();
+  const intptr_t event_begin = cw.current_offset();
+  const intptr_t offset_to_previous_checkpoint_event = 0 == previous_checkpoint_event ? 0 : previous_checkpoint_event - event_begin;
+  const jlong total_checkpoint_size = total_size(data);
+  write_checkpoint_header(cw, offset_to_previous_checkpoint_event, data);
+  write_checkpoint_content(cw, data, total_checkpoint_size - sizeof(JfrCheckpointEntry));
+  const jlong checkpoint_event_size = cw.current_offset() - event_begin;
+  cw.write_padded_at_offset<u4>(checkpoint_event_size, event_begin);
+  cw.set_previous_checkpoint_offset(event_begin);
+  return (size_t)total_checkpoint_size;
+}
+
+static size_t write_checkpoints(JfrChunkWriter& cw, const u1* data, size_t size) {
+  assert(cw.is_valid(), "invariant");
+  assert(data != NULL, "invariant");
+  assert(size > 0, "invariant");
+  const u1* const limit = data + size;
+  const u1* next_entry = data;
+  size_t processed = 0;
+  while (next_entry < limit) {
+    const size_t checkpoint_size = write_checkpoint_event(cw, next_entry);
+    processed += checkpoint_size;
+    next_entry += checkpoint_size;
+  }
+  assert(next_entry == limit, "invariant");
+  return processed;
+}
+
+template <typename T>
+class CheckpointWriteOp {
+ private:
+  JfrChunkWriter& _writer;
+  size_t _processed;
+ public:
+  typedef T Type;
+  CheckpointWriteOp(JfrChunkWriter& writer) : _writer(writer), _processed(0) {}
+  bool write(Type* t, const u1* data, size_t size) {
+    _processed += write_checkpoints(_writer, data, size);
+    return true;
+  }
+  size_t processed() const { return _processed; }
+};
+
+typedef CheckpointWriteOp<JfrCheckpointMspace::Type> WriteOperation;
+typedef MutexedWriteOp<WriteOperation> MutexedWriteOperation;
+typedef ReleaseOp<JfrCheckpointMspace> CheckpointReleaseOperation;
+typedef CompositeOperation<MutexedWriteOperation, CheckpointReleaseOperation> CheckpointWriteOperation;
+
+static size_t write_mspace_exclusive(JfrCheckpointMspace* mspace, JfrChunkWriter& chunkwriter) {
+  Thread* const thread = Thread::current();
+  WriteOperation wo(chunkwriter);
+  MutexedWriteOperation mwo(wo);
+  CheckpointReleaseOperation cro(mspace, thread, false);
+  CheckpointWriteOperation cpwo(&mwo, &cro);
+  assert(mspace->is_full_empty(), "invariant");
+  process_free_list(cpwo, mspace);
+  return wo.processed();
+}
+
+size_t JfrCheckpointManager::write() {
+  const size_t processed = write_mspace_exclusive(_free_list_mspace, _chunkwriter);
+  synchronize_epoch();
+  return processed;
+}
+
+size_t JfrCheckpointManager::write_epoch_transition_mspace() {
+  return write_mspace_exclusive(_epoch_transition_mspace, _chunkwriter);
+}
+
+typedef DiscardOp<DefaultDiscarder<JfrBuffer> > DiscardOperation;
+size_t JfrCheckpointManager::clear() {
+  DiscardOperation discarder(mutexed); // mutexed discard mode
+  process_free_list(discarder, _free_list_mspace);
+  process_free_list(discarder, _epoch_transition_mspace);
+  synchronize_epoch();
+  return discarder.processed();
+}
+
+bool JfrCheckpointManager::register_serializer(JfrTypeId id, bool require_safepoint, bool permit_cache, JfrSerializer* cs) {
+  assert(cs != NULL, "invariant");
+  return instance()._type_manager->register_serializer(id, require_safepoint, permit_cache, cs);
+}
+
+size_t JfrCheckpointManager::write_types() {
+  JfrCheckpointWriter writer(false, true, Thread::current());
+  _type_manager->write_types(writer);
+  return writer.used_size();
+}
+
+size_t JfrCheckpointManager::write_safepoint_types() {
+  // this is also a "flushpoint"
+  JfrCheckpointWriter writer(true, true, Thread::current());
+  _type_manager->write_safepoint_types(writer);
+  return writer.used_size();
+}
+
+void JfrCheckpointManager::write_type_set() {
+  _type_manager->write_type_set();
+}
+
+void JfrCheckpointManager::write_type_set_for_unloaded_classes() {
+  assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
+  instance()._type_manager->write_type_set_for_unloaded_classes();
+}
+
+void JfrCheckpointManager::create_thread_checkpoint(JavaThread* jt) {
+  instance()._type_manager->create_thread_checkpoint(jt);
+}
+
+void JfrCheckpointManager::write_thread_checkpoint(JavaThread* jt) {
+  instance()._type_manager->write_thread_checkpoint(jt);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_RECORDER_CHECKPOINT_JFRCHECKPOINTMANAGER_HPP
+#define SHARE_VM_JFR_RECORDER_CHECKPOINT_JFRCHECKPOINTMANAGER_HPP
+
+#include "jfr/recorder/storage/jfrBuffer.hpp"
+#include "jfr/recorder/storage/jfrMemorySpace.hpp"
+#include "jfr/recorder/storage/jfrMemorySpaceRetrieval.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
+
+class JfrCheckpointManager;
+class JfrChunkWriter;
+class JfrSerializer;
+class JfrTypeManager;
+class Mutex;
+class Thread;
+
+struct JfrCheckpointEntry {
+  jlong size;
+  jlong start_time;
+  jlong duration;
+  juint flushpoint;
+  juint nof_segments;
+};
+
+typedef JfrMemorySpace<JfrBuffer, JfrMspaceSequentialRetrieval, JfrCheckpointManager> JfrCheckpointMspace;
+
+//
+// Responsible for maintaining checkpoints and by implication types.
+// A checkpoint is an event that has a payload consisting of constant types.
+// A constant type is a binary relation, a set of key-value pairs.
+//
+class JfrCheckpointManager : public JfrCHeapObj {
+ public:
+  typedef JfrCheckpointMspace::Type Buffer;
+ private:
+  JfrCheckpointMspace* _free_list_mspace;
+  JfrCheckpointMspace* _epoch_transition_mspace;
+  Mutex* _lock;
+  JfrTypeManager* _type_manager;
+  const Thread* _service_thread;
+  JfrChunkWriter& _chunkwriter;
+  bool _checkpoint_epoch_state;
+
+  // mspace callback
+  void register_full(Buffer* t, Thread* thread);
+  void lock();
+  void unlock();
+  DEBUG_ONLY(bool is_locked() const;)
+
+  static Buffer* lease_buffer(Thread* t, size_t size = 0);
+  static Buffer* flush(Buffer* old, size_t used, size_t requested, Thread* t);
+
+  size_t clear();
+  size_t write();
+  size_t write_epoch_transition_mspace();
+  size_t write_types();
+  size_t write_safepoint_types();
+  void write_type_set();
+  void shift_epoch();
+  void synchronize_epoch();
+  bool use_epoch_transition_mspace(const Thread* t) const;
+
+  JfrCheckpointManager(JfrChunkWriter& cw);
+  ~JfrCheckpointManager();
+
+  static JfrCheckpointManager& instance();
+  static JfrCheckpointManager* create(JfrChunkWriter& cw);
+  bool initialize();
+  static void destroy();
+
+  static bool register_serializer(JfrTypeId id, bool require_safepoint, bool permit_cache, JfrSerializer* serializer);
+
+ public:
+  void register_service_thread(const Thread* t);
+  static void write_type_set_for_unloaded_classes();
+  static void create_thread_checkpoint(JavaThread* jt);
+  static void write_thread_checkpoint(JavaThread* jt);
+
+  friend class JfrRecorder;
+  friend class JfrRecorderService;
+  friend class JfrCheckpointFlush;
+  friend class JfrCheckpointWriter;
+  friend class JfrSerializer;
+  friend class JfrStackTraceRepository;
+  template <typename, template <typename> class, typename>
+  friend class JfrMemorySpace;
+};
+
+#endif //SHARE_VM_JFR_RECORDER_CHECKPOINT_JFRCHECKPOINTMANAGER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
+#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
+#include "jfr/writers/jfrBigEndianWriter.hpp"
+
+JfrCheckpointFlush::JfrCheckpointFlush(Type* old, size_t used, size_t requested, Thread* t) :
+  _result(JfrCheckpointManager::flush(old, used, requested, t)) {}
+
+JfrCheckpointWriter::JfrCheckpointWriter(bool flushpoint, bool header, Thread* thread) :
+  JfrCheckpointWriterBase(JfrCheckpointManager::lease_buffer(thread), thread),
+  _time(JfrTicks::now()),
+  _offset(0),
+  _count(0),
+  _flushpoint(flushpoint),
+  _header(header) {
+  assert(this->is_acquired(), "invariant");
+  assert(0 == this->current_offset(), "invariant");
+  if (_header) {
+    reserve(sizeof(JfrCheckpointEntry));
+  }
+}
+
+static void write_checkpoint_header(u1* pos, jlong size, jlong time, bool flushpoint, juint type_count) {
+  assert(pos != NULL, "invariant");
+  JfrBigEndianWriter be_writer(pos, sizeof(JfrCheckpointEntry));
+  be_writer.write(size);
+  be_writer.write(time);
+  be_writer.write(JfrTicks::now().value() - time);
+  be_writer.write(flushpoint ? (juint)1 : (juint)0);
+  be_writer.write(type_count);
+  assert(be_writer.is_valid(), "invariant");
+}
+
+JfrCheckpointWriter::~JfrCheckpointWriter() {
+  assert(this->is_acquired(), "invariant");
+  if (!this->is_valid() || !_header) {
+    release();
+    return;
+  }
+  if (0 == count()) {
+    assert(this->used_size() == sizeof(JfrCheckpointEntry), "invariant");
+    this->seek(_offset);
+    release();
+    return;
+  }
+  assert(_header, "invariant");
+  assert(this->is_valid(), "invariant");
+  assert(count() > 0, "invariant");
+  assert(this->used_size() > sizeof(JfrCheckpointEntry), "invariant");
+  const jlong size = this->current_offset();
+  assert(size + this->start_pos() == this->current_pos(), "invariant");
+  write_checkpoint_header(const_cast<u1*>(this->start_pos()), size, _time, is_flushpoint(), count());
+  release();
+}
+
+void JfrCheckpointWriter::set_flushpoint(bool flushpoint) {
+  _flushpoint = flushpoint;
+}
+
+bool JfrCheckpointWriter::is_flushpoint() const {
+  return _flushpoint;
+}
+
+juint JfrCheckpointWriter::count() const {
+  return _count;
+}
+
+void JfrCheckpointWriter::set_count(juint count) {
+  _count = count;
+}
+
+void JfrCheckpointWriter::release() {
+  assert(this->is_acquired(), "invariant");
+  if (!this->is_valid() || this->used_size() == 0) {
+    return;
+  }
+  assert(this->used_size() > 0, "invariant");
+  // write through to backing storage
+  this->commit();
+  assert(0 == this->current_offset(), "invariant");
+}
+
+void JfrCheckpointWriter::write_type(JfrTypeId type_id) {
+  assert(type_id < TYPES_END, "invariant");
+  write<u8>(type_id);
+  increment();
+}
+
+void JfrCheckpointWriter::write_key(u8 key) {
+  write<u8>(key);
+}
+
+void JfrCheckpointWriter::increment() {
+  ++_count;
+}
+
+void JfrCheckpointWriter::write_count(u4 nof_entries) {
+  write<u4>((u4)nof_entries);
+}
+
+void JfrCheckpointWriter::write_count(u4 nof_entries, jlong offset) {
+  write_padded_at_offset(nof_entries, offset);
+}
+
+const u1* JfrCheckpointWriter::session_data(size_t* size, const JfrCheckpointContext* ctx /* 0 */) {
+  assert(this->is_acquired(), "wrong state!");
+  if (!this->is_valid()) {
+    *size = 0;
+    return NULL;
+  }
+  if (ctx != NULL) {
+    const u1* session_start_pos = this->start_pos() + ctx->offset;
+    *size = this->current_pos() - session_start_pos;
+    return session_start_pos;
+  }
+  *size = this->used_size();
+  assert(this->start_pos() + *size == this->current_pos(), "invariant");
+  write_checkpoint_header(const_cast<u1*>(this->start_pos()), this->used_offset(), _time, is_flushpoint(), count());
+  this->seek(_offset + (_header ? sizeof(JfrCheckpointEntry) : 0));
+  set_count(0);
+  return this->start_pos();
+}
+
+const JfrCheckpointContext JfrCheckpointWriter::context() const {
+  JfrCheckpointContext ctx;
+  ctx.offset = this->current_offset();
+  ctx.count = this->count();
+  return ctx;
+}
+
+void JfrCheckpointWriter::set_context(const JfrCheckpointContext ctx) {
+  this->seek(ctx.offset);
+  set_count(ctx.count);
+}
+bool JfrCheckpointWriter::has_data() const {
+  return this->used_size() > sizeof(JfrCheckpointEntry);
+}
+
+JfrCheckpointBlobHandle JfrCheckpointWriter::checkpoint_blob() {
+  size_t size = 0;
+  const u1* data = session_data(&size);
+  return JfrCheckpointBlob::make(data, size);
+}
+
+JfrCheckpointBlobHandle JfrCheckpointWriter::copy(const JfrCheckpointContext* ctx /* 0 */) {
+  if (ctx == NULL) {
+    return checkpoint_blob();
+  }
+  size_t size = 0;
+  const u1* data = session_data(&size, ctx);
+  return JfrCheckpointBlob::make(data, size);
+}
+
+JfrCheckpointBlobHandle JfrCheckpointWriter::move(const JfrCheckpointContext* ctx /* 0 */) {
+  JfrCheckpointBlobHandle data = copy(ctx);
+  if (ctx != NULL) {
+    const_cast<JfrCheckpointContext*>(ctx)->count = 0;
+    set_context(*ctx);
+  }
+  return data;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_RECORDER_CHECKPOINT_JFRCHECKPOINTWRITER_HPP
+#define SHARE_VM_JFR_RECORDER_CHECKPOINT_JFRCHECKPOINTWRITER_HPP
+
+#include "jfr/recorder/checkpoint/jfrCheckpointBlob.hpp"
+#include "jfr/recorder/storage/jfrBuffer.hpp"
+#include "jfr/utilities/jfrTime.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
+#include "jfr/writers/jfrEventWriterHost.inline.hpp"
+#include "jfr/writers/jfrMemoryWriterHost.inline.hpp"
+#include "jfr/writers/jfrStorageAdapter.hpp"
+
+class Thread;
+
+class JfrCheckpointFlush : public StackObj {
+ public:
+  typedef JfrBuffer Type;
+  JfrCheckpointFlush(Type* old, size_t used, size_t requested, Thread* t);
+  Type* result() { return _result; }
+ private:
+  Type* _result;
+};
+
+typedef Adapter<JfrCheckpointFlush> JfrCheckpointAdapter;
+typedef AcquireReleaseMemoryWriterHost<JfrCheckpointAdapter, StackObj > JfrTransactionalCheckpointWriter;
+typedef EventWriterHost<BigEndianEncoder, CompressedIntegerEncoder, JfrTransactionalCheckpointWriter> JfrCheckpointWriterBase;
+
+struct JfrCheckpointContext {
+  jlong offset;
+  juint count;
+};
+
+class JfrCheckpointWriter : public JfrCheckpointWriterBase {
+  friend class JfrSerializerRegistration;
+ private:
+  JfrTicks _time;
+  jlong _offset;
+  juint _count;
+  bool _flushpoint;
+  bool _header;
+
+  juint count() const;
+  void set_count(juint count);
+  void increment();
+  void set_flushpoint(bool flushpoint);
+  bool is_flushpoint() const;
+  const u1* session_data(size_t* size, const JfrCheckpointContext* ctx = NULL);
+  void release();
+
+ public:
+  JfrCheckpointWriter(bool flushpoint, bool header, Thread* thread);
+  ~JfrCheckpointWriter();
+  void write_type(JfrTypeId type_id);
+  void write_count(u4 nof_entries);
+  void write_count(u4 nof_entries, jlong offset);
+  void write_key(u8 key);
+  const JfrCheckpointContext context() const;
+  void set_context(const JfrCheckpointContext ctx);
+  bool has_data() const;
+  JfrCheckpointBlobHandle checkpoint_blob();
+  JfrCheckpointBlobHandle copy(const JfrCheckpointContext* ctx = NULL);
+  JfrCheckpointBlobHandle move(const JfrCheckpointContext* ctx = NULL);
+};
+
+#endif // SHARE_VM_JFR_RECORDER_CHECKPOINT_JFRCHECKPOINTWRITER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/jni/jfrJavaSupport.hpp"
+#include "jfr/recorder/checkpoint/jfrMetadataEvent.hpp"
+#include "jfr/recorder/repository/jfrChunkWriter.hpp"
+#include "oops/klass.inline.hpp"
+#include "oops/oop.inline.hpp"
+#include "oops/typeArrayOop.inline.hpp"
+#include "runtime/semaphore.hpp"
+#include "runtime/thread.inline.hpp"
+
+static jbyteArray _metadata_blob = NULL;
+static Semaphore metadata_mutex_semaphore(1);
+
+void JfrMetadataEvent::lock() {
+  metadata_mutex_semaphore.wait();
+}
+
+void JfrMetadataEvent::unlock() {
+  metadata_mutex_semaphore.signal();
+}
+
+static void write_metadata_blob(JfrChunkWriter& chunkwriter, jbyteArray metadata_blob) {
+  if (metadata_blob != NULL) {
+    const typeArrayOop arr = (typeArrayOop)JfrJavaSupport::resolve_non_null(metadata_blob);
+    assert(arr != NULL, "invariant");
+    const int length = arr->length();
+    const Klass* const k = arr->klass();
+    assert(k != NULL && k->is_array_klass(), "invariant");
+    const TypeArrayKlass* const byte_arr_klass = TypeArrayKlass::cast(k);
+    const jbyte* const data_address = arr->byte_at_addr(0);
+    chunkwriter.write_unbuffered(data_address, length);
+  }
+}
+
+// the semaphore is assumed to be locked  (was locked previous safepoint)
+size_t JfrMetadataEvent::write(JfrChunkWriter& chunkwriter, jlong metadata_offset) {
+  assert(chunkwriter.is_valid(), "invariant");
+  assert(chunkwriter.current_offset() == metadata_offset, "invariant");
+  // header
+  chunkwriter.reserve(sizeof(u4));
+  chunkwriter.write<u8>(EVENT_METADATA); // ID 0
+  // time data
+  chunkwriter.write(JfrTicks::now());
+  chunkwriter.write((u8)0); // duration
+  chunkwriter.write((u8)0); // metadata id
+  write_metadata_blob(chunkwriter, _metadata_blob); // payload
+  unlock(); // open up for java to provide updated metadata
+  // fill in size of metadata descriptor event
+  const jlong size_written = chunkwriter.current_offset() - metadata_offset;
+  chunkwriter.write_padded_at_offset((u4)size_written, metadata_offset);
+  return size_written;
+}
+
+void JfrMetadataEvent::update(jbyteArray metadata) {
+  JavaThread* thread = (JavaThread*)Thread::current();
+  assert(thread->is_Java_thread(), "invariant");
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(thread));
+  lock();
+  if (_metadata_blob != NULL) {
+    JfrJavaSupport::destroy_global_jni_handle(_metadata_blob);
+  }
+  const oop new_desc_oop = JfrJavaSupport::resolve_non_null(metadata);
+  _metadata_blob = new_desc_oop != NULL ? (jbyteArray)JfrJavaSupport::global_jni_handle(new_desc_oop, thread) : NULL;
+  unlock();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_RECORDER_CHECKPOINT_JFRMETADATAEVENT_HPP
+#define SHARE_VM_JFR_RECORDER_CHECKPOINT_JFRMETADATAEVENT_HPP
+
+#include "jni.h"
+#include "memory/allocation.hpp"
+
+class JfrChunkWriter;
+
+//
+// Metadata is continuously updated in Java as event classes are loaded / unloaded.
+// Using update(), Java stores a binary representation back to native.
+// This is for easy access on chunk finalization as well as having it readily available in the case of fatal error.
+//
+class JfrMetadataEvent : AllStatic {
+ public:
+  static void lock();
+  static void unlock();
+  static size_t write(JfrChunkWriter& writer, jlong metadata_offset);
+  static void update(jbyteArray metadata);
+};
+
+#endif // SHARE_VM_JFR_RECORDER_CHECKPOINT_JFRMETADATAEVENT_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrThreadGroup.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,412 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
+#include "jfr/recorder/checkpoint/types/jfrThreadGroup.hpp"
+#include "jfr/utilities/jfrResourceManager.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/jniHandles.inline.hpp"
+#include "runtime/safepoint.hpp"
+#include "runtime/semaphore.hpp"
+#include "utilities/growableArray.hpp"
+
+class ThreadGroupExclusiveAccess : public StackObj {
+ private:
+  static Semaphore _mutex_semaphore;
+ public:
+  ThreadGroupExclusiveAccess() { _mutex_semaphore.wait(); }
+  ~ThreadGroupExclusiveAccess() { _mutex_semaphore.signal(); }
+};
+
+Semaphore ThreadGroupExclusiveAccess::_mutex_semaphore(1);
+JfrThreadGroup* JfrThreadGroup::_instance = NULL;
+
+class JfrThreadGroupPointers : public ResourceObj {
+ private:
+  const Handle _thread_group_handle;
+  jweak _thread_group_weak_ref;
+ public:
+  JfrThreadGroupPointers(Handle thread_group_handle, jweak thread_group_weak_ref);
+  Handle thread_group_handle() const;
+  jweak thread_group_weak_ref() const;
+  oopDesc* const thread_group_oop() const;
+  jweak transfer_weak_global_handle_ownership();
+  void clear_weak_ref();
+};
+
+JfrThreadGroupPointers::JfrThreadGroupPointers(Handle thread_group_handle, jweak thread_group_weak_ref) :
+  _thread_group_handle(thread_group_handle),
+  _thread_group_weak_ref(thread_group_weak_ref) {}
+
+Handle JfrThreadGroupPointers::thread_group_handle() const {
+  return _thread_group_handle;
+}
+
+jweak JfrThreadGroupPointers::thread_group_weak_ref() const {
+  return _thread_group_weak_ref;
+}
+
+oopDesc* const JfrThreadGroupPointers::thread_group_oop() const {
+  assert(_thread_group_weak_ref == NULL ||
+         JNIHandles::resolve_non_null(_thread_group_weak_ref) == _thread_group_handle(), "invariant");
+  return _thread_group_handle();
+}
+
+jweak JfrThreadGroupPointers::transfer_weak_global_handle_ownership() {
+  jweak temp = _thread_group_weak_ref;
+  _thread_group_weak_ref = NULL;
+  return temp;
+}
+
+void JfrThreadGroupPointers::clear_weak_ref() {
+  if (NULL != _thread_group_weak_ref) {
+    JNIHandles::destroy_weak_global(_thread_group_weak_ref);
+  }
+}
+
+class JfrThreadGroupsHelper : public ResourceObj {
+ private:
+  static const int invalid_iterator_pos = -1;
+  GrowableArray<JfrThreadGroupPointers*>* _thread_group_hierarchy;
+  int _current_iterator_pos;
+
+  int populate_thread_group_hierarchy(const JavaThread* jt, Thread* current);
+  JfrThreadGroupPointers& at(int index);
+
+ public:
+  JfrThreadGroupsHelper(const JavaThread* jt, Thread* current);
+  ~JfrThreadGroupsHelper();
+  JfrThreadGroupPointers& next();
+  bool is_valid() const;
+  bool has_next() const;
+};
+
+JfrThreadGroupsHelper::JfrThreadGroupsHelper(const JavaThread* jt, Thread* current) {
+  _thread_group_hierarchy = new GrowableArray<JfrThreadGroupPointers*>(10, false, mtTracing);
+  _current_iterator_pos = populate_thread_group_hierarchy(jt, current) - 1;
+}
+
+JfrThreadGroupsHelper::~JfrThreadGroupsHelper() {
+  assert(_current_iterator_pos == invalid_iterator_pos, "invariant");
+  for (int i = 0; i < _thread_group_hierarchy->length(); ++i) {
+    _thread_group_hierarchy->at(i)->clear_weak_ref();
+  }
+}
+
+JfrThreadGroupPointers& JfrThreadGroupsHelper::at(int index) {
+  assert(_thread_group_hierarchy != NULL, "invariant");
+  assert(index > invalid_iterator_pos && index < _thread_group_hierarchy->length(), "invariant");
+  return *(_thread_group_hierarchy->at(index));
+}
+
+bool JfrThreadGroupsHelper::has_next() const {
+  return _current_iterator_pos > invalid_iterator_pos;
+}
+
+bool JfrThreadGroupsHelper::is_valid() const {
+  return (_thread_group_hierarchy != NULL && _thread_group_hierarchy->length() > 0);
+}
+
+JfrThreadGroupPointers& JfrThreadGroupsHelper::next() {
+  assert(is_valid(), "invariant");
+  return at(_current_iterator_pos--);
+}
+
+/*
+ * If not at a safepoint, we create global weak references for
+ * all reachable threadgroups for this thread.
+ * If we are at a safepoint, the caller is the VMThread during
+ * JFR checkpointing. It can use naked oops, because nothing
+ * will move before the list of threadgroups is cleared and
+ * mutator threads restarted. The threadgroup list is cleared
+ * later by the VMThread as one of the final steps in JFR checkpointing
+ * (not here).
+ */
+int JfrThreadGroupsHelper::populate_thread_group_hierarchy(const JavaThread* jt, Thread* current) {
+  assert(jt != NULL && jt->is_Java_thread(), "invariant");
+  assert(current != NULL, "invariant");
+  assert(_thread_group_hierarchy != NULL, "invariant");
+
+  // immediate thread group
+  Handle thread_group_handle(current, java_lang_Thread::threadGroup(jt->threadObj()));
+  if (thread_group_handle == NULL) {
+    return 0;
+  }
+
+  const bool use_weak_handles = !SafepointSynchronize::is_at_safepoint();
+  jweak thread_group_weak_ref = use_weak_handles ? JNIHandles::make_weak_global(thread_group_handle) : NULL;
+
+  JfrThreadGroupPointers* thread_group_pointers = new JfrThreadGroupPointers(thread_group_handle, thread_group_weak_ref);
+  _thread_group_hierarchy->append(thread_group_pointers);
+  // immediate parent thread group
+  oop parent_thread_group_obj = java_lang_ThreadGroup::parent(thread_group_handle());
+  Handle parent_thread_group_handle(current, parent_thread_group_obj);
+
+  // and check parents parents...
+  while (!(parent_thread_group_handle == NULL)) {
+    const jweak parent_group_weak_ref = use_weak_handles ? JNIHandles::make_weak_global(parent_thread_group_handle) : NULL;
+    thread_group_pointers = new JfrThreadGroupPointers(parent_thread_group_handle, parent_group_weak_ref);
+    _thread_group_hierarchy->append(thread_group_pointers);
+    parent_thread_group_obj = java_lang_ThreadGroup::parent(parent_thread_group_handle());
+    parent_thread_group_handle = Handle(current, parent_thread_group_obj);
+  }
+  return _thread_group_hierarchy->length();
+}
+
+static traceid next_id() {
+  static traceid _current_threadgroup_id = 0;
+  return ++_current_threadgroup_id;
+}
+
+class JfrThreadGroup::JfrThreadGroupEntry : public JfrCHeapObj {
+  friend class JfrThreadGroup;
+ private:
+  traceid _thread_group_id;
+  traceid _parent_group_id;
+  char* _thread_group_name; // utf8 format
+  // If an entry is created during a safepoint, the
+  // _thread_group_oop contains a direct oop to
+  // the java.lang.ThreadGroup object.
+  // If an entry is created on javathread exit time (not at safepoint),
+  // _thread_group_weak_ref contains a JNI weak global handle
+  // indirection to the java.lang.ThreadGroup object.
+  // Note: we cannot use a union here since CHECK_UNHANDLED_OOPS makes oop have
+  //       a ctor which isn't allowed in a union by the SunStudio compiler
+  oop _thread_group_oop;
+  jweak _thread_group_weak_ref;
+
+  JfrThreadGroupEntry(const char* tgstr, JfrThreadGroupPointers& ptrs);
+  ~JfrThreadGroupEntry();
+
+  traceid thread_group_id() const { return _thread_group_id; }
+  void set_thread_group_id(traceid tgid) { _thread_group_id = tgid; }
+
+  const char* const thread_group_name() const { return _thread_group_name; }
+  void set_thread_group_name(const char* tgname);
+
+  traceid parent_group_id() const { return _parent_group_id; }
+  void set_parent_group_id(traceid pgid) { _parent_group_id = pgid; }
+
+  void set_thread_group(JfrThreadGroupPointers& ptrs);
+  bool is_equal(const JfrThreadGroupPointers& ptrs) const;
+  const oop thread_group() const;
+};
+
+JfrThreadGroup::JfrThreadGroupEntry::JfrThreadGroupEntry(const char* tgname, JfrThreadGroupPointers& ptrs) :
+  _thread_group_id(0),
+  _parent_group_id(0),
+  _thread_group_name(NULL),
+  _thread_group_oop(NULL),
+  _thread_group_weak_ref(NULL) {
+  set_thread_group_name(tgname);
+  set_thread_group(ptrs);
+}
+
+JfrThreadGroup::JfrThreadGroupEntry::~JfrThreadGroupEntry() {
+  if (_thread_group_name != NULL) {
+    JfrCHeapObj::free(_thread_group_name, strlen(_thread_group_name) + 1);
+  }
+  if (_thread_group_weak_ref != NULL) {
+    JNIHandles::destroy_weak_global(_thread_group_weak_ref);
+  }
+}
+
+void JfrThreadGroup::JfrThreadGroupEntry::set_thread_group_name(const char* tgname) {
+  assert(_thread_group_name == NULL, "invariant");
+  if (tgname != NULL) {
+    size_t len = strlen(tgname);
+    _thread_group_name = JfrCHeapObj::new_array<char>(len+1);
+    strncpy(_thread_group_name, tgname, len);
+    _thread_group_name[len] = '\0';
+  }
+}
+
+const oop JfrThreadGroup::JfrThreadGroupEntry::thread_group() const {
+  return _thread_group_weak_ref != NULL ? JNIHandles::resolve(_thread_group_weak_ref) : _thread_group_oop;
+}
+
+void JfrThreadGroup::JfrThreadGroupEntry::set_thread_group(JfrThreadGroupPointers& ptrs) {
+  _thread_group_weak_ref = ptrs.transfer_weak_global_handle_ownership();
+  if (_thread_group_weak_ref == NULL) {
+    _thread_group_oop = ptrs.thread_group_oop();
+    assert(_thread_group_oop != NULL, "invariant");
+  } else {
+    _thread_group_oop = NULL;
+  }
+}
+
+JfrThreadGroup::JfrThreadGroup() : _list(NULL) {
+  _list = new (ResourceObj::C_HEAP, mtTracing) GrowableArray<JfrThreadGroupEntry*>(30, true);
+}
+
+JfrThreadGroup::~JfrThreadGroup() {
+  assert(SafepointSynchronize::is_at_safepoint(), "invariant");
+  if (_list != NULL) {
+    for (int i = 0; i < _list->length(); i++) {
+      JfrThreadGroupEntry* e = _list->at(i);
+      delete e;
+    }
+    delete _list;
+  }
+}
+
+JfrThreadGroup* JfrThreadGroup::instance() {
+  return _instance;
+}
+
+void JfrThreadGroup::set_instance(JfrThreadGroup* new_instance) {
+  _instance = new_instance;
+}
+
+traceid JfrThreadGroup::thread_group_id(const JavaThread* jt, Thread* current) {
+  ResourceMark rm(current);
+  HandleMark hm(current);
+  JfrThreadGroupsHelper helper(jt, current);
+  return helper.is_valid() ? thread_group_id_internal(helper) : 0;
+}
+
+traceid JfrThreadGroup::thread_group_id(JavaThread* const jt) {
+  assert(!JfrStream_lock->owned_by_self(), "holding stream lock but should not hold it here");
+  return thread_group_id(jt, jt);
+}
+
+traceid JfrThreadGroup::thread_group_id_internal(JfrThreadGroupsHelper& helper) {
+  ThreadGroupExclusiveAccess lock;
+  JfrThreadGroup* tg_instance = instance();
+  if (tg_instance == NULL) {
+    tg_instance = new JfrThreadGroup();
+    if (tg_instance == NULL) {
+      return 0;
+    }
+    set_instance(tg_instance);
+  }
+
+  JfrThreadGroupEntry* tge = NULL;
+  int parent_thread_group_id = 0;
+  while (helper.has_next()) {
+    JfrThreadGroupPointers& ptrs = helper.next();
+    tge = tg_instance->find_entry(ptrs);
+    if (NULL == tge) {
+      tge = tg_instance->new_entry(ptrs);
+      assert(tge != NULL, "invariant");
+      tge->set_parent_group_id(parent_thread_group_id);
+    }
+    parent_thread_group_id = tge->thread_group_id();
+  }
+  // the last entry in the hierarchy is the immediate thread group
+  return tge->thread_group_id();
+}
+
+bool JfrThreadGroup::JfrThreadGroupEntry::is_equal(const JfrThreadGroupPointers& ptrs) const {
+  return ptrs.thread_group_oop() == thread_group();
+}
+
+JfrThreadGroup::JfrThreadGroupEntry*
+JfrThreadGroup::find_entry(const JfrThreadGroupPointers& ptrs) const {
+  for (int index = 0; index < _list->length(); ++index) {
+    JfrThreadGroupEntry* curtge = _list->at(index);
+    if (curtge->is_equal(ptrs)) {
+      return curtge;
+    }
+  }
+  return (JfrThreadGroupEntry*) NULL;
+}
+
+// Assumes you already searched for the existence
+// of a corresponding entry in find_entry().
+JfrThreadGroup::JfrThreadGroupEntry*
+JfrThreadGroup::new_entry(JfrThreadGroupPointers& ptrs) {
+  JfrThreadGroupEntry* const tge = new JfrThreadGroupEntry(java_lang_ThreadGroup::name(ptrs.thread_group_oop()), ptrs);
+  add_entry(tge);
+  return tge;
+}
+
+int JfrThreadGroup::add_entry(JfrThreadGroupEntry* tge) {
+  assert(tge != NULL, "attempting to add a null entry!");
+  assert(0 == tge->thread_group_id(), "id must be unassigned!");
+  tge->set_thread_group_id(next_id());
+  return _list->append(tge);
+}
+
+void JfrThreadGroup::write_thread_group_entries(JfrCheckpointWriter& writer) const {
+  assert(_list != NULL && !_list->is_empty(), "should not need be here!");
+  const int number_of_tg_entries = _list->length();
+  writer.write_count(number_of_tg_entries);
+  for (int index = 0; index < number_of_tg_entries; ++index) {
+    const JfrThreadGroupEntry* const curtge = _list->at(index);
+    writer.write_key(curtge->thread_group_id());
+    writer.write(curtge->parent_group_id());
+    writer.write(curtge->thread_group_name());
+  }
+}
+
+void JfrThreadGroup::write_selective_thread_group(JfrCheckpointWriter* writer, traceid thread_group_id) const {
+  assert(writer != NULL, "invariant");
+  assert(_list != NULL && !_list->is_empty(), "should not need be here!");
+  const int number_of_tg_entries = _list->length();
+
+  // save context
+  const JfrCheckpointContext ctx = writer->context();
+  writer->write_type(TYPE_THREADGROUP);
+  const jlong count_offset = writer->reserve(sizeof(u4)); // Don't know how many yet
+  int number_of_entries_written = 0;
+  for (int index = number_of_tg_entries - 1; index >= 0; --index) {
+    const JfrThreadGroupEntry* const curtge = _list->at(index);
+    if (thread_group_id == curtge->thread_group_id()) {
+      writer->write_key(curtge->thread_group_id());
+      writer->write(curtge->parent_group_id());
+      writer->write(curtge->thread_group_name());
+      ++number_of_entries_written;
+      thread_group_id = curtge->parent_group_id();
+    }
+  }
+  if (number_of_entries_written == 0) {
+    // nothing to write, restore context
+    writer->set_context(ctx);
+    return;
+  }
+  assert(number_of_entries_written > 0, "invariant");
+  writer->write_count(number_of_entries_written, count_offset);
+}
+
+// Write out JfrThreadGroup instance and then delete it
+void JfrThreadGroup::serialize(JfrCheckpointWriter& writer) {
+  ThreadGroupExclusiveAccess lock;
+  JfrThreadGroup* tg_instance = instance();
+  assert(tg_instance != NULL, "invariant");
+  ResourceManager<JfrThreadGroup> tg_handle(tg_instance);
+  set_instance(NULL);
+  tg_handle->write_thread_group_entries(writer);
+}
+
+// for writing a particular thread group
+void JfrThreadGroup::serialize(JfrCheckpointWriter* writer, traceid thread_group_id) {
+  assert(writer != NULL, "invariant");
+  ThreadGroupExclusiveAccess lock;
+  JfrThreadGroup* const tg_instance = instance();
+  assert(tg_instance != NULL, "invariant");
+  tg_instance->write_selective_thread_group(writer, thread_group_id);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrThreadGroup.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_RECORDER_CHECKPOINT_TYPES_JFRTHREADGROUP_HPP
+#define SHARE_VM_JFR_RECORDER_CHECKPOINT_TYPES_JFRTHREADGROUP_HPP
+
+#include "jni.h"
+#include "jfr/utilities/jfrAllocation.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
+
+class JfrCheckpointWriter;
+template <typename>
+class GrowableArray;
+class JfrThreadGroupsHelper;
+class JfrThreadGroupPointers;
+
+class JfrThreadGroup : public JfrCHeapObj {
+  friend class JfrCheckpointThreadClosure;
+ private:
+  static JfrThreadGroup* _instance;
+  class JfrThreadGroupEntry;
+  GrowableArray<JfrThreadGroupEntry*>* _list;
+
+  JfrThreadGroup();
+  JfrThreadGroupEntry* find_entry(const JfrThreadGroupPointers& ptrs) const;
+  JfrThreadGroupEntry* new_entry(JfrThreadGroupPointers& ptrs);
+  int add_entry(JfrThreadGroupEntry* const tge);
+
+  void write_thread_group_entries(JfrCheckpointWriter& writer) const;
+  void write_selective_thread_group(JfrCheckpointWriter* writer, traceid thread_group_id) const;
+
+  static traceid thread_group_id_internal(JfrThreadGroupsHelper& helper);
+  static JfrThreadGroup* instance();
+  static void set_instance(JfrThreadGroup* new_instance);
+
+ public:
+  ~JfrThreadGroup();
+  static void serialize(JfrCheckpointWriter& w);
+  static void serialize(JfrCheckpointWriter* w, traceid thread_group_id);
+  static traceid thread_group_id(JavaThread* thread);
+  static traceid thread_group_id(const JavaThread* thread, Thread* current);
+};
+
+#endif // SHARE_VM_JFR_RECORDER_CHECKPOINT_TYPES_JFRTHREADGROUP_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrThreadState.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,82 @@
+/*
+* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* This code is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License version 2 only, as
+* published by the Free Software Foundation.
+*
+* This code is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* version 2 for more details (a copy is included in the LICENSE file that
+* accompanied this code).
+*
+* You should have received a copy of the GNU General Public License version
+* 2 along with this work; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+* or visit www.oracle.com if you need additional information or have any
+* questions.
+*
+*/
+
+#include "precompiled.hpp"
+#include "jfr/recorder/checkpoint/types/jfrThreadState.hpp"
+#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
+#include "jvmtifiles/jvmti.h"
+
+struct jvmti_thread_state {
+  u8 id;
+  const char* description;
+};
+
+static jvmti_thread_state states[] = {
+  {
+    JVMTI_JAVA_LANG_THREAD_STATE_NEW,
+    "STATE_NEW"
+  },
+  {
+    JVMTI_THREAD_STATE_TERMINATED,
+    "STATE_TERMINATED"
+  },
+  {
+    JVMTI_JAVA_LANG_THREAD_STATE_RUNNABLE,
+    "STATE_RUNNABLE"
+  },
+  {
+    (JVMTI_THREAD_STATE_ALIVE | JVMTI_THREAD_STATE_WAITING | JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT | JVMTI_THREAD_STATE_SLEEPING),
+    "STATE_SLEEPING"
+  },
+  {
+    (JVMTI_THREAD_STATE_ALIVE | JVMTI_THREAD_STATE_WAITING | JVMTI_THREAD_STATE_WAITING_INDEFINITELY | JVMTI_THREAD_STATE_IN_OBJECT_WAIT),
+    "STATE_IN_OBJECT_WAIT"
+  },
+  {
+    (JVMTI_THREAD_STATE_ALIVE | JVMTI_THREAD_STATE_WAITING | JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT | JVMTI_THREAD_STATE_IN_OBJECT_WAIT),
+    "STATE_IN_OBJECT_WAIT_TIMED"
+  },
+  {
+    (JVMTI_THREAD_STATE_ALIVE | JVMTI_THREAD_STATE_WAITING | JVMTI_THREAD_STATE_WAITING_INDEFINITELY | JVMTI_THREAD_STATE_PARKED),
+    "STATE_PARKED"
+  },
+  {
+    (JVMTI_THREAD_STATE_ALIVE | JVMTI_THREAD_STATE_WAITING | JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT | JVMTI_THREAD_STATE_PARKED),
+    "STATE_PARKED_TIMED"
+  },
+  {
+    JVMTI_JAVA_LANG_THREAD_STATE_BLOCKED,
+    "STATE_BLOCKED_ON_MONITOR_ENTER"
+  }
+};
+
+void JfrThreadState::serialize(JfrCheckpointWriter& writer) {
+  const u4 number_of_states = sizeof(states) / sizeof(jvmti_thread_state);
+  writer.write_count(number_of_states);
+  for (u4 i = 0; i < number_of_states; ++i) {
+    writer.write_key(states[i].id);
+    writer.write(states[i].description);
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrThreadState.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,37 @@
+/*
+* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* This code is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License version 2 only, as
+* published by the Free Software Foundation.
+*
+* This code is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* version 2 for more details (a copy is included in the LICENSE file that
+* accompanied this code).
+*
+* You should have received a copy of the GNU General Public License version
+* 2 along with this work; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+* or visit www.oracle.com if you need additional information or have any
+* questions.
+*
+*/
+
+#ifndef SHARE_VM_JFR_RECORDER_CHECKPOINT_TYPES_JFRTHREADSTATE_HPP
+#define SHARE_VM_JFR_RECORDER_CHECKPOINT_TYPES_JFRTHREADSTATE_HPP
+
+#include "memory/allocation.hpp"
+
+class JfrCheckpointWriter;
+
+class JfrThreadState : public AllStatic {
+ public:
+  static void serialize(JfrCheckpointWriter& writer);
+};
+
+#endif // SHARE_VM_JFR_RECORDER_CHECKPOINT_TYPES_JFRTHREADSTATE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/javaClasses.inline.hpp"
+#include "code/codeBlob.hpp"
+#include "code/codeCache.hpp"
+#include "gc/shared/gcCause.hpp"
+#include "gc/shared/gcName.hpp"
+#include "gc/shared/gcTrace.hpp"
+#include "gc/shared/gcWhen.hpp"
+#include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp"
+#include "jfr/leakprofiler/leakProfiler.hpp"
+#include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
+#include "jfr/recorder/checkpoint/types/jfrType.hpp"
+#include "jfr/recorder/jfrRecorder.hpp"
+#include "jfr/recorder/checkpoint/types/jfrThreadGroup.hpp"
+#include "jfr/recorder/checkpoint/types/jfrThreadState.hpp"
+#include "jfr/recorder/checkpoint/types/jfrTypeSet.hpp"
+#include "jfr/support/jfrThreadLocal.hpp"
+#include "jfr/writers/jfrJavaEventWriter.hpp"
+#include "memory/metaspaceGCThresholdUpdater.hpp"
+#include "memory/referenceType.hpp"
+#include "memory/universe.hpp"
+#include "runtime/flags/jvmFlag.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/osThread.hpp"
+#include "runtime/safepoint.hpp"
+#include "runtime/synchronizer.hpp"
+#include "runtime/thread.inline.hpp"
+#include "runtime/vm_operations.hpp"
+
+#ifdef COMPILER2
+#include "opto/compile.hpp"
+#include "opto/node.hpp"
+#endif
+#if INCLUDE_G1GC
+#include "gc/g1/g1HeapRegionTraceType.hpp"
+#include "gc/g1/g1YCTypes.hpp"
+#endif
+
+// implementation for the static registration function exposed in the api
+bool JfrSerializer::register_serializer(JfrTypeId id, bool require_safepoint, bool permit_cache, JfrSerializer* cs) {
+  assert(cs != NULL, "invariant");
+  return JfrCheckpointManager::register_serializer(id, require_safepoint, permit_cache, cs);
+}
+
+class JfrCheckpointThreadCountClosure : public ThreadClosure {
+private:
+  u4 _total_threads;
+public:
+  JfrCheckpointThreadCountClosure() : _total_threads(0) {}
+  u4 total_threads() { return _total_threads; }
+  void do_thread(Thread *t) { _total_threads++; }
+};
+
+// Requires a ResourceMark for get_thread_name/as_utf8
+class JfrCheckpointThreadClosure : public ThreadClosure {
+ private:
+  JfrCheckpointWriter& _writer;
+  Thread* _curthread;
+ public:
+  JfrCheckpointThreadClosure(JfrCheckpointWriter& writer) : _writer(writer), _curthread(Thread::current()) {}
+  void do_thread(Thread* t);
+};
+
+// Requires a ResourceMark for get_thread_name/as_utf8
+void JfrCheckpointThreadClosure::do_thread(Thread* t) {
+  assert(t != NULL, "invariant");
+  assert_locked_or_safepoint(Threads_lock);
+  _writer.write_key(t->jfr_thread_local()->thread_id());
+  _writer.write(t->name());
+  const OSThread* const os_thread = t->osthread();
+  _writer.write<traceid>(os_thread != NULL ? os_thread->thread_id() : (u8)0);
+  if (t->is_Java_thread()) {
+    JavaThread* const jt = (JavaThread*)t;
+    _writer.write(jt->name());
+    _writer.write(java_lang_Thread::thread_id(jt->threadObj()));
+    _writer.write(JfrThreadGroup::thread_group_id(jt, _curthread));
+    // since we are iterating threads during a safepoint, also issue notification
+    JfrJavaEventWriter::notify(jt);
+    return;
+  }
+  _writer.write((const char*)NULL); // java name
+  _writer.write<traceid>((traceid)0); // java thread id
+  _writer.write<traceid>((traceid)0); // java thread group
+}
+
+void JfrThreadConstantSet::serialize(JfrCheckpointWriter& writer) {
+  assert(SafepointSynchronize::is_at_safepoint(), "invariant");
+  JfrCheckpointThreadCountClosure tcc;
+  Threads::threads_do(&tcc);
+  const u4 total_threads = tcc.total_threads();
+  // THREADS
+  writer.write_count(total_threads);
+  JfrCheckpointThreadClosure tc(writer);
+  Threads::threads_do(&tc);
+}
+
+void JfrThreadGroupConstant::serialize(JfrCheckpointWriter& writer) {
+  assert(SafepointSynchronize::is_at_safepoint(), "invariant");
+  JfrThreadGroup::serialize(writer);
+}
+
+static const char* flag_value_origin_to_string(JVMFlag::Flags origin) {
+  switch (origin) {
+    case JVMFlag::DEFAULT: return "Default";
+    case JVMFlag::COMMAND_LINE: return "Command line";
+    case JVMFlag::ENVIRON_VAR: return "Environment variable";
+    case JVMFlag::CONFIG_FILE: return "Config file";
+    case JVMFlag::MANAGEMENT: return "Management";
+    case JVMFlag::ERGONOMIC: return "Ergonomic";
+    case JVMFlag::ATTACH_ON_DEMAND: return "Attach on demand";
+    case JVMFlag::INTERNAL: return "Internal";
+    default: ShouldNotReachHere(); return "";
+  }
+}
+
+void FlagValueOriginConstant::serialize(JfrCheckpointWriter& writer) {
+  static const u4 nof_entries = JVMFlag::LAST_VALUE_ORIGIN + 1;
+  writer.write_count(nof_entries);
+  for (u4 i = 0; i < nof_entries; ++i) {
+    writer.write_key(i);
+    writer.write(flag_value_origin_to_string((JVMFlag::Flags)i));
+  }
+}
+
+void MonitorInflateCauseConstant::serialize(JfrCheckpointWriter& writer) {
+  static const u4 nof_entries = ObjectSynchronizer::inflate_cause_nof;
+  writer.write_count(nof_entries);
+  for (u4 i = 0; i < nof_entries; ++i) {
+    writer.write_key(i);
+    writer.write(ObjectSynchronizer::inflate_cause_name((ObjectSynchronizer::InflateCause)i));
+  }
+}
+
+void GCCauseConstant::serialize(JfrCheckpointWriter& writer) {
+  static const u4 nof_entries = GCCause::_last_gc_cause;
+  writer.write_count(nof_entries);
+  for (u4 i = 0; i < nof_entries; ++i) {
+    writer.write_key(i);
+    writer.write(GCCause::to_string((GCCause::Cause)i));
+  }
+}
+
+void GCNameConstant::serialize(JfrCheckpointWriter& writer) {
+  static const u4 nof_entries = GCNameEndSentinel;
+  writer.write_count(nof_entries);
+  for (u4 i = 0; i < nof_entries; ++i) {
+    writer.write_key(i);
+    writer.write(GCNameHelper::to_string((GCName)i));
+  }
+}
+
+void GCWhenConstant::serialize(JfrCheckpointWriter& writer) {
+  static const u4 nof_entries = GCWhen::GCWhenEndSentinel;
+  writer.write_count(nof_entries);
+  for (u4 i = 0; i < nof_entries; ++i) {
+    writer.write_key(i);
+    writer.write(GCWhen::to_string((GCWhen::Type)i));
+  }
+}
+
+void G1HeapRegionTypeConstant::serialize(JfrCheckpointWriter& writer) {
+  static const u4 nof_entries = G1HeapRegionTraceType::G1HeapRegionTypeEndSentinel;
+  writer.write_count(nof_entries);
+  for (u4 i = 0; i < nof_entries; ++i) {
+    writer.write_key(i);
+    writer.write(G1HeapRegionTraceType::to_string((G1HeapRegionTraceType::Type)i));
+  }
+}
+
+void GCThresholdUpdaterConstant::serialize(JfrCheckpointWriter& writer) {
+  static const u4 nof_entries = MetaspaceGCThresholdUpdater::Last;
+  writer.write_count(nof_entries);
+  for (u4 i = 0; i < nof_entries; ++i) {
+    writer.write_key(i);
+    writer.write(MetaspaceGCThresholdUpdater::to_string((MetaspaceGCThresholdUpdater::Type)i));
+  }
+}
+
+void MetadataTypeConstant::serialize(JfrCheckpointWriter& writer) {
+  static const u4 nof_entries = Metaspace::MetadataTypeCount;
+  writer.write_count(nof_entries);
+  for (u4 i = 0; i < nof_entries; ++i) {
+    writer.write_key(i);
+    writer.write(Metaspace::metadata_type_name((Metaspace::MetadataType)i));
+  }
+}
+
+void MetaspaceObjectTypeConstant::serialize(JfrCheckpointWriter& writer) {
+  static const u4 nof_entries = MetaspaceObj::_number_of_types;
+  writer.write_count(nof_entries);
+  for (u4 i = 0; i < nof_entries; ++i) {
+    writer.write_key(i);
+    writer.write(MetaspaceObj::type_name((MetaspaceObj::Type)i));
+  }
+}
+
+void G1YCTypeConstant::serialize(JfrCheckpointWriter& writer) {
+#if INCLUDE_G1GC
+  static const u4 nof_entries = G1YCTypeEndSentinel;
+  writer.write_count(nof_entries);
+  for (u4 i = 0; i < nof_entries; ++i) {
+    writer.write_key(i);
+    writer.write(G1YCTypeHelper::to_string((G1YCType)i));
+  }
+#endif
+}
+
+static const char* reference_type_to_string(ReferenceType rt) {
+  switch (rt) {
+    case REF_NONE: return "None reference";
+    case REF_OTHER: return "Other reference";
+    case REF_SOFT: return "Soft reference";
+    case REF_WEAK: return "Weak reference";
+    case REF_FINAL: return "Final reference";
+    case REF_PHANTOM: return "Phantom reference";
+    default:
+      ShouldNotReachHere();
+    return NULL;
+  }
+}
+
+void ReferenceTypeConstant::serialize(JfrCheckpointWriter& writer) {
+  static const u4 nof_entries = REF_PHANTOM + 1;
+  writer.write_count(nof_entries);
+  for (u4 i = 0; i < nof_entries; ++i) {
+    writer.write_key(i);
+    writer.write(reference_type_to_string((ReferenceType)i));
+  }
+}
+
+void NarrowOopModeConstant::serialize(JfrCheckpointWriter& writer) {
+  static const u4 nof_entries = Universe::HeapBasedNarrowOop + 1;
+  writer.write_count(nof_entries);
+  for (u4 i = 0; i < nof_entries; ++i) {
+    writer.write_key(i);
+    writer.write(Universe::narrow_oop_mode_to_string((Universe::NARROW_OOP_MODE)i));
+  }
+}
+
+void CompilerPhaseTypeConstant::serialize(JfrCheckpointWriter& writer) {
+#ifdef COMPILER2
+  static const u4 nof_entries = PHASE_NUM_TYPES;
+  writer.write_count(nof_entries);
+  for (u4 i = 0; i < nof_entries; ++i) {
+    writer.write_key(i);
+    writer.write(CompilerPhaseTypeHelper::to_string((CompilerPhaseType)i));
+  }
+#endif
+}
+
+void CodeBlobTypeConstant::serialize(JfrCheckpointWriter& writer) {
+  static const u4 nof_entries = CodeBlobType::NumTypes;
+  writer.write_count(nof_entries);
+  for (u4 i = 0; i < nof_entries; ++i) {
+    writer.write_key(i);
+    writer.write(CodeCache::get_code_heap_name(i));
+  }
+};
+
+void VMOperationTypeConstant::serialize(JfrCheckpointWriter& writer) {
+  static const u4 nof_entries = VM_Operation::VMOp_Terminating;
+  writer.write_count(nof_entries);
+  for (u4 i = 0; i < nof_entries; ++i) {
+    writer.write_key(i);
+    writer.write(VM_Operation::name(VM_Operation::VMOp_Type(i)));
+  }
+}
+
+class TypeSetSerialization {
+ private:
+  bool _class_unload;
+ public:
+  explicit TypeSetSerialization(bool class_unload) : _class_unload(class_unload) {}
+  void write(JfrCheckpointWriter& writer, JfrCheckpointWriter* leakp_writer) {
+    JfrTypeSet::serialize(&writer, leakp_writer, _class_unload);
+  }
+};
+
+void ClassUnloadTypeSet::serialize(JfrCheckpointWriter& writer) {
+  TypeSetSerialization type_set(true);
+  if (LeakProfiler::is_running()) {
+    JfrCheckpointWriter leakp_writer(false, true, Thread::current());
+    type_set.write(writer, &leakp_writer);
+    ObjectSampleCheckpoint::install(leakp_writer, true, true);
+    return;
+  }
+  type_set.write(writer, NULL);
+};
+
+void TypeSet::serialize(JfrCheckpointWriter& writer) {
+  TypeSetSerialization type_set(false);
+  if (LeakProfiler::is_suspended()) {
+    JfrCheckpointWriter leakp_writer(false, true, Thread::current());
+    type_set.write(writer, &leakp_writer);
+    ObjectSampleCheckpoint::install(leakp_writer, false, true);
+    return;
+  }
+  type_set.write(writer, NULL);
+};
+
+void ThreadStateConstant::serialize(JfrCheckpointWriter& writer) {
+  JfrThreadState::serialize(writer);
+}
+
+void JfrThreadConstant::serialize(JfrCheckpointWriter& writer) {
+  assert(_thread != NULL, "invariant");
+  assert(_thread == Thread::current(), "invariant");
+  assert(_thread->is_Java_thread(), "invariant");
+  assert(!_thread->jfr_thread_local()->has_thread_checkpoint(), "invariant");
+  ResourceMark rm(_thread);
+  const oop threadObj = _thread->threadObj();
+  assert(threadObj != NULL, "invariant");
+  const u8 java_lang_thread_id = java_lang_Thread::thread_id(threadObj);
+  const char* const thread_name = _thread->name();
+  const traceid thread_group_id = JfrThreadGroup::thread_group_id(_thread);
+  writer.write_count(1);
+  writer.write_key(_thread->jfr_thread_local()->thread_id());
+  writer.write(thread_name);
+  writer.write((u8)_thread->osthread()->thread_id());
+  writer.write(thread_name);
+  writer.write(java_lang_thread_id);
+  writer.write(thread_group_id);
+  JfrThreadGroup::serialize(&writer, thread_group_id);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_CHECKPOINT_TYPES_JFRTYPE_HPP
+#define SHARE_VM_JFR_CHECKPOINT_TYPES_JFRTYPE_HPP
+
+#include "jfr/metadata/jfrSerializer.hpp"
+
+class JfrThreadConstantSet : public JfrSerializer {
+ public:
+  void serialize(JfrCheckpointWriter& writer);
+};
+
+class JfrThreadGroupConstant : public JfrSerializer {
+ public:
+  void serialize(JfrCheckpointWriter& writer);
+};
+
+class ClassUnloadTypeSet : public JfrSerializer {
+ public:
+  void serialize(JfrCheckpointWriter& writer);
+};
+
+class FlagValueOriginConstant : public JfrSerializer {
+ public:
+  void serialize(JfrCheckpointWriter& writer);
+};
+
+class MonitorInflateCauseConstant : public JfrSerializer {
+ public:
+  void serialize(JfrCheckpointWriter& writer);
+};
+
+class GCCauseConstant : public JfrSerializer {
+ public:
+  void serialize(JfrCheckpointWriter& writer);
+};
+
+class GCNameConstant : public JfrSerializer {
+ public:
+  void serialize(JfrCheckpointWriter& writer);
+};
+
+class GCWhenConstant : public JfrSerializer {
+ public:
+  void serialize(JfrCheckpointWriter& writer);
+};
+
+class G1HeapRegionTypeConstant : public JfrSerializer {
+ public:
+  void serialize(JfrCheckpointWriter& writer);
+};
+
+class GCThresholdUpdaterConstant : public JfrSerializer {
+ public:
+  void serialize(JfrCheckpointWriter& writer);
+};
+
+class MetadataTypeConstant : public JfrSerializer {
+ public:
+  void serialize(JfrCheckpointWriter& writer);
+};
+
+class MetaspaceObjectTypeConstant : public JfrSerializer {
+ public:
+  void serialize(JfrCheckpointWriter& writer);
+};
+
+class G1YCTypeConstant : public JfrSerializer {
+ public:
+  void serialize(JfrCheckpointWriter& writer);
+};
+
+class ReferenceTypeConstant : public JfrSerializer {
+ public:
+  void serialize(JfrCheckpointWriter& writer);
+};
+
+class NarrowOopModeConstant : public JfrSerializer {
+ public:
+  void serialize(JfrCheckpointWriter& writer);
+};
+
+class CompilerPhaseTypeConstant : public JfrSerializer {
+ public:
+  void serialize(JfrCheckpointWriter& writer);
+};
+
+class CodeBlobTypeConstant : public JfrSerializer {
+ public:
+  void serialize(JfrCheckpointWriter& writer);
+};
+
+class VMOperationTypeConstant : public JfrSerializer {
+ public:
+  void serialize(JfrCheckpointWriter& writer);
+};
+
+class TypeSet : public JfrSerializer {
+ public:
+  void serialize(JfrCheckpointWriter& writer);
+};
+
+class ThreadStateConstant : public JfrSerializer {
+ public:
+  void serialize(JfrCheckpointWriter& writer);
+};
+
+class JfrThreadConstant : public JfrSerializer {
+ private:
+  JavaThread* _thread;
+ public:
+  JfrThreadConstant(JavaThread* jt) : _thread(jt) {}
+  void serialize(JfrCheckpointWriter& writer);
+};
+
+#endif // SHARE_VM_JFR_CHECKPOINT_CONSTANT_JFRCONSTANT_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
+#include "jfr/recorder/checkpoint/types/jfrType.hpp"
+#include "jfr/recorder/checkpoint/types/jfrTypeManager.hpp"
+#include "jfr/utilities/jfrIterator.hpp"
+#include "runtime/safepoint.hpp"
+#include "runtime/thread.inline.hpp"
+#include "utilities/exceptions.hpp"
+
+JfrSerializerRegistration::JfrSerializerRegistration(JfrTypeId id, bool permit_cache, JfrSerializer* cs) :
+  _next(NULL),
+  _prev(NULL),
+  _serializer(cs),
+  _cache(),
+  _id(id),
+  _permit_cache(permit_cache) {}
+
+JfrSerializerRegistration::~JfrSerializerRegistration() {
+  delete _serializer;
+}
+
+JfrSerializerRegistration* JfrSerializerRegistration::next() const {
+  return _next;
+}
+
+void JfrSerializerRegistration::set_next(JfrSerializerRegistration* next) {
+  _next = next;
+}
+
+JfrSerializerRegistration* JfrSerializerRegistration::prev() const {
+  return _prev;
+}
+
+void JfrSerializerRegistration::set_prev(JfrSerializerRegistration* prev) {
+  _prev = prev;
+}
+
+JfrTypeId JfrSerializerRegistration::id() const {
+  return _id;
+}
+
+void JfrSerializerRegistration::invoke_serializer(JfrCheckpointWriter& writer) const {
+  if (_cache.valid()) {
+    writer.increment();
+    _cache->write(writer);
+    return;
+  }
+  const JfrCheckpointContext ctx = writer.context();
+  writer.write_type(_id);
+  _serializer->serialize(writer);
+  if (_permit_cache) {
+    _cache = writer.copy(&ctx);
+  }
+}
+
+JfrTypeManager::~JfrTypeManager() {
+  Iterator iter(_types);
+  JfrSerializerRegistration* registration;
+  while (iter.has_next()) {
+    registration = _types.remove(iter.next());
+    assert(registration != NULL, "invariant");
+    delete registration;
+  }
+  Iterator sp_type_iter(_safepoint_types);
+  while (sp_type_iter.has_next()) {
+    registration = _safepoint_types.remove(sp_type_iter.next());
+    assert(registration != NULL, "invariant");
+    delete registration;
+  }
+}
+
+size_t JfrTypeManager::number_of_registered_types() const {
+  size_t count = 0;
+  const Iterator iter(_types);
+  while (iter.has_next()) {
+    ++count;
+    iter.next();
+  }
+  const Iterator sp_type_iter(_safepoint_types);
+  while (sp_type_iter.has_next()) {
+    ++count;
+    sp_type_iter.next();
+  }
+  return count;
+}
+
+void JfrTypeManager::write_types(JfrCheckpointWriter& writer) const {
+  const Iterator iter(_types);
+  while (iter.has_next()) {
+    iter.next()->invoke_serializer(writer);
+  }
+}
+
+void JfrTypeManager::write_safepoint_types(JfrCheckpointWriter& writer) const {
+  assert(SafepointSynchronize::is_at_safepoint(), "invariant");
+  const Iterator iter(_safepoint_types);
+  while (iter.has_next()) {
+    iter.next()->invoke_serializer(writer);
+  }
+}
+
+void JfrTypeManager::write_type_set() const {
+  assert(!SafepointSynchronize::is_at_safepoint(), "invariant");
+  // can safepoint here because of Module_lock
+  MutexLockerEx lock(Module_lock);
+  JfrCheckpointWriter writer(true, true, Thread::current());
+  TypeSet set;
+  set.serialize(writer);
+}
+
+void JfrTypeManager::write_type_set_for_unloaded_classes() const {
+  assert(SafepointSynchronize::is_at_safepoint(), "invariant");
+  JfrCheckpointWriter writer(false, true, Thread::current());
+  ClassUnloadTypeSet class_unload_set;
+  class_unload_set.serialize(writer);
+}
+
+void JfrTypeManager::create_thread_checkpoint(JavaThread* jt) const {
+  assert(jt != NULL, "invariant");
+  JfrThreadConstant type_thread(jt);
+  JfrCheckpointWriter writer(false, true, jt);
+  writer.write_type(TYPE_THREAD);
+  type_thread.serialize(writer);
+  // create and install a checkpoint blob
+  jt->jfr_thread_local()->set_thread_checkpoint(writer.checkpoint_blob());
+  assert(jt->jfr_thread_local()->has_thread_checkpoint(), "invariant");
+}
+
+void JfrTypeManager::write_thread_checkpoint(JavaThread* jt) const {
+  assert(jt != NULL, "JavaThread is NULL!");
+  ResourceMark rm(jt);
+  if (jt->jfr_thread_local()->has_thread_checkpoint()) {
+    JfrCheckpointWriter writer(false, false, jt);
+    jt->jfr_thread_local()->thread_checkpoint()->write(writer);
+  } else {
+    JfrThreadConstant type_thread(jt);
+    JfrCheckpointWriter writer(false, true, jt);
+    writer.write_type(TYPE_THREAD);
+    type_thread.serialize(writer);
+  }
+}
+
+#ifdef ASSERT
+static void assert_not_registered_twice(JfrTypeId id, JfrTypeManager::List& list) {
+  const JfrTypeManager::Iterator iter(list);
+  while (iter.has_next()) {
+    assert(iter.next()->id() != id, "invariant");
+  }
+}
+#endif
+
+bool JfrTypeManager::register_serializer(JfrTypeId id, bool require_safepoint, bool permit_cache, JfrSerializer* cs) {
+  assert(cs != NULL, "invariant");
+  JfrSerializerRegistration* const registration = new JfrSerializerRegistration(id, permit_cache, cs);
+  if (registration == NULL) {
+    delete cs;
+    return false;
+  }
+  if (require_safepoint) {
+    assert(!_safepoint_types.in_list(registration), "invariant");
+    DEBUG_ONLY(assert_not_registered_twice(id, _safepoint_types);)
+      _safepoint_types.prepend(registration);
+  }
+  else {
+    assert(!_types.in_list(registration), "invariant");
+    DEBUG_ONLY(assert_not_registered_twice(id, _types);)
+      _types.prepend(registration);
+  }
+  return true;
+}
+
+bool JfrTypeManager::initialize() {
+  // register non-safepointing type serialization
+  for (size_t i = 0; i < 16; ++i) {
+    switch (i) {
+    case 0: register_serializer(TYPE_FLAGVALUEORIGIN, false, true, new FlagValueOriginConstant()); break;
+    case 1: register_serializer(TYPE_INFLATECAUSE, false, true, new MonitorInflateCauseConstant()); break;
+    case 2: register_serializer(TYPE_GCCAUSE, false, true, new GCCauseConstant()); break;
+    case 3: register_serializer(TYPE_GCNAME, false, true, new GCNameConstant()); break;
+    case 4: register_serializer(TYPE_GCWHEN, false, true, new GCWhenConstant()); break;
+    case 5: register_serializer(TYPE_G1HEAPREGIONTYPE, false, true, new G1HeapRegionTypeConstant()); break;
+    case 6: register_serializer(TYPE_GCTHRESHOLDUPDATER, false, true, new GCThresholdUpdaterConstant()); break;
+    case 7: register_serializer(TYPE_METADATATYPE, false, true, new MetadataTypeConstant()); break;
+    case 8: register_serializer(TYPE_METASPACEOBJECTTYPE, false, true, new MetaspaceObjectTypeConstant()); break;
+    case 9: register_serializer(TYPE_G1YCTYPE, false, true, new G1YCTypeConstant()); break;
+    case 10: register_serializer(TYPE_REFERENCETYPE, false, true, new ReferenceTypeConstant()); break;
+    case 11: register_serializer(TYPE_NARROWOOPMODE, false, true, new NarrowOopModeConstant()); break;
+    case 12: register_serializer(TYPE_COMPILERPHASETYPE, false, true, new CompilerPhaseTypeConstant()); break;
+    case 13: register_serializer(TYPE_CODEBLOBTYPE, false, true, new CodeBlobTypeConstant()); break;
+    case 14: register_serializer(TYPE_VMOPERATIONTYPE, false, true, new VMOperationTypeConstant()); break;
+    case 15: register_serializer(TYPE_THREADSTATE, false, true, new ThreadStateConstant()); break;
+    default:
+      guarantee(false, "invariant");
+    }
+  }
+
+  // register safepointing type serialization
+  for (size_t i = 0; i < 2; ++i) {
+    switch (i) {
+    case 0: register_serializer(TYPE_THREADGROUP, true, false, new JfrThreadGroupConstant()); break;
+    case 1: register_serializer(TYPE_THREAD, true, false, new JfrThreadConstantSet()); break;
+    default:
+      guarantee(false, "invariant");
+    }
+  }
+  return true;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+#ifndef SHARE_VM_JFR_CHECKPOINT_TYPES_JFRTYPEMANAGER_HPP
+#define SHARE_VM_JFR_CHECKPOINT_TYPES_JFRTYPEMANAGER_HPP
+
+#include "jfr/metadata/jfrSerializer.hpp"
+#include "jfr/utilities/jfrAllocation.hpp"
+#include "jfr/utilities/jfrDoublyLinkedList.hpp"
+#include "jfr/utilities/jfrIterator.hpp"
+
+class JfrSerializerRegistration : public JfrCHeapObj {
+ private:
+  JfrSerializerRegistration* _next;
+  JfrSerializerRegistration* _prev;
+  JfrSerializer* _serializer;
+  mutable JfrCheckpointBlobHandle _cache;
+  JfrTypeId _id;
+  bool _permit_cache;
+
+ public:
+  JfrSerializerRegistration(JfrTypeId id, bool permit_cache, JfrSerializer* serializer);
+  ~JfrSerializerRegistration();
+  JfrSerializerRegistration* next() const;
+  void set_next(JfrSerializerRegistration* next);
+  JfrSerializerRegistration* prev() const;
+  void set_prev(JfrSerializerRegistration* prev);
+  void invoke_serializer(JfrCheckpointWriter& writer) const;
+  JfrTypeId id() const;
+};
+
+class JfrTypeManager : public JfrCHeapObj {
+  friend class JfrCheckpointManager;
+ public:
+  typedef JfrDoublyLinkedList<JfrSerializerRegistration> List;
+  typedef StopOnNullIterator<const List> Iterator;
+ private:
+  List _types;
+  List _safepoint_types;
+
+  ~JfrTypeManager();
+  bool initialize();
+  size_t number_of_registered_types() const;
+  void write_types(JfrCheckpointWriter& writer) const;
+  void write_safepoint_types(JfrCheckpointWriter& writer) const;
+  void write_type_set() const;
+  void write_type_set_for_unloaded_classes() const;
+  void create_thread_checkpoint(JavaThread* jt) const;
+  void write_thread_checkpoint(JavaThread* jt) const;
+  bool register_serializer(JfrTypeId id, bool require_safepoint, bool permit_cache, JfrSerializer* serializer);
+};
+#endif // SHARE_VM_JFR_CHECKPOINT_TYPES_JFRTYPEMANAGER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,988 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/classLoaderData.inline.hpp"
+#include "classfile/javaClasses.inline.hpp"
+#include "classfile/moduleEntry.hpp"
+#include "classfile/packageEntry.hpp"
+#include "classfile/symbolTable.hpp"
+#include "classfile/systemDictionary.hpp"
+#include "jfr/jfr.hpp"
+#include "jfr/jni/jfrGetAllEventClasses.hpp"
+#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
+#include "jfr/recorder/checkpoint/types/jfrTypeSet.hpp"
+#include "jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp"
+#include "jfr/recorder/checkpoint/types/jfrTypeSetWriter.hpp"
+#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
+#include "jfr/recorder/storage/jfrBuffer.hpp"
+#include "jfr/utilities/jfrHashtable.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
+#include "memory/iterator.hpp"
+#include "memory/resourceArea.hpp"
+#include "oops/instanceKlass.hpp"
+#include "oops/objArrayKlass.hpp"
+#include "oops/oop.inline.hpp"
+#include "memory/resourceArea.hpp"
+#include "utilities/accessFlags.hpp"
+
+// incremented on each checkpoint
+static u8 checkpoint_id = 0;
+
+// creates a unique id by combining a checkpoint relative symbol id (2^24)
+// with the current checkpoint id (2^40)
+#define CREATE_SYMBOL_ID(sym_id) (((u8)((checkpoint_id << 24) | sym_id)))
+
+typedef const Klass* KlassPtr;
+typedef const PackageEntry* PkgPtr;
+typedef const ModuleEntry* ModPtr;
+typedef const ClassLoaderData* CldPtr;
+typedef const Method* MethodPtr;
+typedef const Symbol* SymbolPtr;
+typedef const JfrSymbolId::SymbolEntry* SymbolEntryPtr;
+typedef const JfrSymbolId::CStringEntry* CStringEntryPtr;
+
+static traceid module_id(PkgPtr pkg) {
+  assert(pkg != NULL, "invariant");
+  ModPtr module_entry = pkg->module();
+  return module_entry != NULL && module_entry->is_named() ? TRACE_ID(module_entry) : 0;
+}
+
+static traceid package_id(KlassPtr klass) {
+  assert(klass != NULL, "invariant");
+  PkgPtr pkg_entry = klass->package();
+  return pkg_entry == NULL ? 0 : TRACE_ID(pkg_entry);
+}
+
+static traceid cld_id(CldPtr cld) {
+  assert(cld != NULL, "invariant");
+  return cld->is_anonymous() ? 0 : TRACE_ID(cld);
+}
+
+static void tag_leakp_klass_artifacts(KlassPtr k, bool class_unload) {
+  assert(k != NULL, "invariant");
+  PkgPtr pkg = k->package();
+  if (pkg != NULL) {
+    tag_leakp_artifact(pkg, class_unload);
+    ModPtr module = pkg->module();
+    if (module != NULL) {
+      tag_leakp_artifact(module, class_unload);
+    }
+  }
+  CldPtr cld = k->class_loader_data();
+  assert(cld != NULL, "invariant");
+  if (!cld->is_anonymous()) {
+    tag_leakp_artifact(cld, class_unload);
+  }
+}
+
+class TagLeakpKlassArtifact {
+  bool _class_unload;
+ public:
+  TagLeakpKlassArtifact(bool class_unload) : _class_unload(class_unload) {}
+  bool operator()(KlassPtr klass) {
+    if (_class_unload) {
+      if (LEAKP_USED_THIS_EPOCH(klass)) {
+        tag_leakp_klass_artifacts(klass, _class_unload);
+      }
+    } else {
+      if (LEAKP_USED_PREV_EPOCH(klass)) {
+        tag_leakp_klass_artifacts(klass, _class_unload);
+      }
+    }
+    return true;
+  }
+};
+
+/*
+ * In C++03, functions used as template parameters must have external linkage;
+ * this restriction was removed in C++11. Change back to "static" and
+ * rename functions when C++11 becomes available.
+ *
+ * The weird naming is an effort to decrease the risk of name clashes.
+ */
+
+int write__artifact__klass(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* k) {
+  assert(writer != NULL, "invariant");
+  assert(artifacts != NULL, "invariant");
+  assert(k != NULL, "invariant");
+  KlassPtr klass = (KlassPtr)k;
+  traceid pkg_id = 0;
+  KlassPtr theklass = klass;
+  if (theklass->is_objArray_klass()) {
+    const ObjArrayKlass* obj_arr_klass = ObjArrayKlass::cast(klass);
+    theklass = obj_arr_klass->bottom_klass();
+  }
+  if (theklass->is_instance_klass()) {
+    pkg_id = package_id(theklass);
+  } else {
+    assert(theklass->is_typeArray_klass(), "invariant");
+  }
+  const traceid symbol_id = artifacts->mark(klass);
+  assert(symbol_id > 0, "need to have an address for symbol!");
+  writer->write(TRACE_ID(klass));
+  writer->write(cld_id(klass->class_loader_data()));
+  writer->write((traceid)CREATE_SYMBOL_ID(symbol_id));
+  writer->write(pkg_id);
+  writer->write((s4)klass->access_flags().get_flags());
+  return 1;
+}
+
+typedef LeakPredicate<KlassPtr> LeakKlassPredicate;
+typedef JfrPredicatedArtifactWriterImplHost<KlassPtr, LeakKlassPredicate, write__artifact__klass> LeakKlassWriterImpl;
+typedef JfrArtifactWriterHost<LeakKlassWriterImpl, TYPE_CLASS> LeakKlassWriter;
+typedef JfrArtifactWriterImplHost<KlassPtr, write__artifact__klass> KlassWriterImpl;
+typedef JfrArtifactWriterHost<KlassWriterImpl, TYPE_CLASS> KlassWriter;
+
+int write__artifact__method(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* m) {
+  assert(writer != NULL, "invariant");
+  assert(artifacts != NULL, "invariant");
+  assert(m != NULL, "invariant");
+  MethodPtr method = (MethodPtr)m;
+  const traceid method_name_symbol_id = artifacts->mark(method->name());
+  assert(method_name_symbol_id > 0, "invariant");
+  const traceid method_sig_symbol_id = artifacts->mark(method->signature());
+  assert(method_sig_symbol_id > 0, "invariant");
+  KlassPtr klass = method->method_holder();
+  assert(klass != NULL, "invariant");
+  assert(METHOD_USED_ANY_EPOCH(klass), "invariant");
+  writer->write((u8)METHOD_ID(klass, method));
+  writer->write((u8)TRACE_ID(klass));
+  writer->write((u8)CREATE_SYMBOL_ID(method_name_symbol_id));
+  writer->write((u8)CREATE_SYMBOL_ID(method_sig_symbol_id));
+  writer->write((u2)method->access_flags().get_flags());
+  writer->write(const_cast<Method*>(method)->is_hidden() ? (u1)1 : (u1)0);
+  return 1;
+}
+
+typedef JfrArtifactWriterImplHost<MethodPtr, write__artifact__method> MethodWriterImplTarget;
+typedef JfrArtifactWriterHost<MethodWriterImplTarget, TYPE_METHOD> MethodWriterImpl;
+
+int write__artifact__package(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* p) {
+  assert(writer != NULL, "invariant");
+  assert(artifacts != NULL, "invariant");
+  assert(p != NULL, "invariant");
+  PkgPtr pkg = (PkgPtr)p;
+  Symbol* const pkg_name = pkg->name();
+  const traceid package_name_symbol_id = pkg_name != NULL ? artifacts->mark(pkg_name) : 0;
+  assert(package_name_symbol_id > 0, "invariant");
+  writer->write((traceid)TRACE_ID(pkg));
+  writer->write((traceid)CREATE_SYMBOL_ID(package_name_symbol_id));
+  writer->write(module_id(pkg));
+  writer->write((bool)pkg->is_exported());
+  return 1;
+}
+
+typedef LeakPredicate<PkgPtr> LeakPackagePredicate;
+int _compare_pkg_ptr_(PkgPtr const& lhs, PkgPtr const& rhs) { return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0; }
+typedef UniquePredicate<PkgPtr, _compare_pkg_ptr_> PackagePredicate;
+typedef JfrPredicatedArtifactWriterImplHost<PkgPtr, LeakPackagePredicate, write__artifact__package> LeakPackageWriterImpl;
+typedef JfrPredicatedArtifactWriterImplHost<PkgPtr, PackagePredicate, write__artifact__package> PackageWriterImpl;
+typedef JfrArtifactWriterHost<LeakPackageWriterImpl, TYPE_PACKAGE> LeakPackageWriter;
+typedef JfrArtifactWriterHost<PackageWriterImpl, TYPE_PACKAGE> PackageWriter;
+
+int write__artifact__module(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* m) {
+  assert( m != NULL, "invariant");
+  ModPtr entry = (ModPtr)m;
+  Symbol* const module_name = entry->name();
+  const traceid module_name_symbol_id = module_name != NULL ? artifacts->mark(module_name) : 0;
+  Symbol* const module_version = entry->version();
+  const traceid module_version_symbol_id = module_version != NULL ? artifacts->mark(module_version) : 0;
+  Symbol* const module_location = entry->location();
+  const traceid module_location_symbol_id = module_location != NULL ? artifacts->mark(module_location) : 0;
+  writer->write((traceid)TRACE_ID(entry));
+  writer->write(module_name_symbol_id == 0 ? (traceid)0 : (traceid)CREATE_SYMBOL_ID(module_name_symbol_id));
+  writer->write(module_version_symbol_id == 0 ? (traceid)0 : (traceid)CREATE_SYMBOL_ID(module_version_symbol_id));
+  writer->write(module_location_symbol_id == 0 ? (traceid)0 : (traceid)CREATE_SYMBOL_ID(module_location_symbol_id));
+  writer->write(cld_id(entry->loader_data()));
+  return 1;
+}
+
+typedef LeakPredicate<ModPtr> LeakModulePredicate;
+int _compare_mod_ptr_(ModPtr const& lhs, ModPtr const& rhs) { return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0; }
+typedef UniquePredicate<ModPtr, _compare_mod_ptr_> ModulePredicate;
+typedef JfrPredicatedArtifactWriterImplHost<ModPtr, LeakModulePredicate, write__artifact__module> LeakModuleWriterImpl;
+typedef JfrPredicatedArtifactWriterImplHost<ModPtr, ModulePredicate, write__artifact__module> ModuleWriterImpl;
+typedef JfrArtifactWriterHost<LeakModuleWriterImpl, TYPE_MODULE> LeakModuleWriter;
+typedef JfrArtifactWriterHost<ModuleWriterImpl, TYPE_MODULE> ModuleWriter;
+
+int write__artifact__classloader(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* c) {
+  assert(c != NULL, "invariant");
+  CldPtr cld = (CldPtr)c;
+  assert(!cld->is_anonymous(), "invariant");
+  const traceid cld_id = TRACE_ID(cld);
+  // class loader type
+  const Klass* class_loader_klass = cld->class_loader_klass();
+  if (class_loader_klass == NULL) {
+    // (primordial) boot class loader
+    writer->write(cld_id); // class loader instance id
+    writer->write((traceid)0);  // class loader type id (absence of)
+    writer->write((traceid)CREATE_SYMBOL_ID(1)); // 1 maps to synthetic name -> "boot"
+  } else {
+    Symbol* symbol_name = cld->class_loader_name();
+    const traceid symbol_name_id = symbol_name != NULL ? artifacts->mark(symbol_name) : 0;
+    writer->write(cld_id); // class loader instance id
+    writer->write(TRACE_ID(class_loader_klass)); // class loader type id
+    writer->write(symbol_name_id == 0 ? (traceid)0 :
+      (traceid)CREATE_SYMBOL_ID(symbol_name_id)); // class loader instance name
+  }
+  return 1;
+}
+
+typedef LeakPredicate<CldPtr> LeakCldPredicate;
+int _compare_cld_ptr_(CldPtr const& lhs, CldPtr const& rhs) { return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0; }
+typedef UniquePredicate<CldPtr, _compare_cld_ptr_> CldPredicate;
+typedef JfrPredicatedArtifactWriterImplHost<CldPtr, LeakCldPredicate, write__artifact__classloader> LeakCldWriterImpl;
+typedef JfrPredicatedArtifactWriterImplHost<CldPtr, CldPredicate, write__artifact__classloader> CldWriterImpl;
+typedef JfrArtifactWriterHost<LeakCldWriterImpl, TYPE_CLASSLOADER> LeakCldWriter;
+typedef JfrArtifactWriterHost<CldWriterImpl, TYPE_CLASSLOADER> CldWriter;
+
+typedef const JfrSymbolId::SymbolEntry* SymbolEntryPtr;
+
+static int write__artifact__symbol__entry__(JfrCheckpointWriter* writer,
+                                            SymbolEntryPtr entry) {
+  assert(writer != NULL, "invariant");
+  assert(entry != NULL, "invariant");
+  ResourceMark rm;
+  writer->write(CREATE_SYMBOL_ID(entry->id()));
+  writer->write(entry->value()->as_C_string());
+  return 1;
+}
+
+int write__artifact__symbol__entry(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* e) {
+  assert(e != NULL, "invariant");
+  return write__artifact__symbol__entry__(writer, (SymbolEntryPtr)e);
+}
+
+typedef JfrArtifactWriterImplHost<SymbolEntryPtr, write__artifact__symbol__entry> SymbolEntryWriterImpl;
+typedef JfrArtifactWriterHost<SymbolEntryWriterImpl, TYPE_SYMBOL> SymbolEntryWriter;
+
+typedef const JfrSymbolId::CStringEntry* CStringEntryPtr;
+
+static int write__artifact__cstring__entry__(JfrCheckpointWriter* writer, CStringEntryPtr entry) {
+  assert(writer != NULL, "invariant");
+  assert(entry != NULL, "invariant");
+  writer->write(CREATE_SYMBOL_ID(entry->id()));
+  writer->write(entry->value());
+  return 1;
+}
+
+int write__artifact__cstring__entry(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* e) {
+  assert(e != NULL, "invariant");
+  return write__artifact__cstring__entry__(writer, (CStringEntryPtr)e);
+}
+
+typedef JfrArtifactWriterImplHost<CStringEntryPtr, write__artifact__cstring__entry> CStringEntryWriterImpl;
+typedef JfrArtifactWriterHost<CStringEntryWriterImpl, TYPE_SYMBOL> CStringEntryWriter;
+
+int write__artifact__klass__symbol(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* k) {
+  assert(writer != NULL, "invariant");
+  assert(artifacts != NULL, "invaiant");
+  assert(k != NULL, "invariant");
+  const InstanceKlass* const ik = (const InstanceKlass*)k;
+  if (ik->is_anonymous()) {
+    CStringEntryPtr entry =
+      artifacts->map_cstring(JfrSymbolId::anonymous_klass_name_hash_code(ik));
+    assert(entry != NULL, "invariant");
+    return write__artifact__cstring__entry__(writer, entry);
+  }
+
+  SymbolEntryPtr entry = artifacts->map_symbol(JfrSymbolId::regular_klass_name_hash_code(ik));
+  return write__artifact__symbol__entry__(writer, entry);
+}
+
+int _compare_traceid_(const traceid& lhs, const traceid& rhs) {
+  return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0;
+}
+
+template <template <typename> class Predicate>
+class KlassSymbolWriterImpl {
+ private:
+  JfrCheckpointWriter* _writer;
+  JfrArtifactSet* _artifacts;
+  Predicate<KlassPtr> _predicate;
+  MethodUsedPredicate<true> _method_used_predicate;
+  MethodFlagPredicate _method_flag_predicate;
+  UniquePredicate<traceid, _compare_traceid_> _unique_predicate;
+
+  int klass_symbols(KlassPtr klass);
+  int package_symbols(PkgPtr pkg);
+  int module_symbols(ModPtr module);
+  int class_loader_symbols(CldPtr cld);
+  int method_symbols(KlassPtr klass);
+
+ public:
+  typedef KlassPtr Type;
+  KlassSymbolWriterImpl(JfrCheckpointWriter* writer,
+                        JfrArtifactSet* artifacts,
+                        bool class_unload) : _writer(writer),
+                                             _artifacts(artifacts),
+                                             _predicate(class_unload),
+                                             _method_used_predicate(class_unload),
+                                             _method_flag_predicate(class_unload),
+                                             _unique_predicate(class_unload) {}
+
+  int operator()(KlassPtr klass) {
+    assert(klass != NULL, "invariant");
+    int count = 0;
+    if (_predicate(klass)) {
+      count += klass_symbols(klass);
+      PkgPtr pkg = klass->package();
+      if (pkg != NULL) {
+        count += package_symbols(pkg);
+        ModPtr module = pkg->module();
+        if (module != NULL && module->is_named()) {
+          count += module_symbols(module);
+        }
+      }
+      CldPtr cld = klass->class_loader_data();
+      assert(cld != NULL, "invariant");
+      if (!cld->is_anonymous()) {
+        count += class_loader_symbols(cld);
+      }
+      if (_method_used_predicate(klass)) {
+        count += method_symbols(klass);
+      }
+    }
+    return count;
+  }
+};
+
+template <template <typename> class Predicate>
+int KlassSymbolWriterImpl<Predicate>::klass_symbols(KlassPtr klass) {
+  assert(klass != NULL, "invariant");
+  assert(_predicate(klass), "invariant");
+  const InstanceKlass* const ik = (const InstanceKlass*)klass;
+  if (ik->is_anonymous()) {
+    CStringEntryPtr entry =
+      this->_artifacts->map_cstring(JfrSymbolId::anonymous_klass_name_hash_code(ik));
+    assert(entry != NULL, "invariant");
+    return _unique_predicate(entry->id()) ? write__artifact__cstring__entry__(this->_writer, entry) : 0;
+  }
+  SymbolEntryPtr entry = this->_artifacts->map_symbol(ik->name());
+  assert(entry != NULL, "invariant");
+  return _unique_predicate(entry->id()) ? write__artifact__symbol__entry__(this->_writer, entry) : 0;
+}
+
+template <template <typename> class Predicate>
+int KlassSymbolWriterImpl<Predicate>::package_symbols(PkgPtr pkg) {
+  assert(pkg != NULL, "invariant");
+  SymbolPtr pkg_name = pkg->name();
+  assert(pkg_name != NULL, "invariant");
+  SymbolEntryPtr package_symbol = this->_artifacts->map_symbol(pkg_name);
+  assert(package_symbol != NULL, "invariant");
+  return _unique_predicate(package_symbol->id()) ?
+    write__artifact__symbol__entry__(this->_writer, package_symbol) : 0;
+}
+
+template <template <typename> class Predicate>
+int KlassSymbolWriterImpl<Predicate>::module_symbols(ModPtr module) {
+  assert(module != NULL, "invariant");
+  assert(module->is_named(), "invariant");
+  int count = 0;
+  SymbolPtr sym = module->name();
+  SymbolEntryPtr entry = NULL;
+  if (sym != NULL) {
+    entry = this->_artifacts->map_symbol(sym);
+    assert(entry != NULL, "invariant");
+    if (_unique_predicate(entry->id())) {
+      count += write__artifact__symbol__entry__(this->_writer, entry);
+    }
+  }
+  sym = module->version();
+  if (sym != NULL) {
+    entry = this->_artifacts->map_symbol(sym);
+    assert(entry != NULL, "invariant");
+    if (_unique_predicate(entry->id())) {
+      count += write__artifact__symbol__entry__(this->_writer, entry);
+    }
+  }
+  sym = module->location();
+  if (sym != NULL) {
+    entry = this->_artifacts->map_symbol(sym);
+    assert(entry != NULL, "invariant");
+    if (_unique_predicate(entry->id())) {
+      count += write__artifact__symbol__entry__(this->_writer, entry);
+    }
+  }
+  return count;
+}
+
+template <template <typename> class Predicate>
+int KlassSymbolWriterImpl<Predicate>::class_loader_symbols(CldPtr cld) {
+  assert(cld != NULL, "invariant");
+  assert(!cld->is_anonymous(), "invariant");
+  int count = 0;
+  // class loader type
+  const Klass* class_loader_klass = cld->class_loader_klass();
+  if (class_loader_klass == NULL) {
+    // (primordial) boot class loader
+    CStringEntryPtr entry = this->_artifacts->map_cstring(0);
+    assert(entry != NULL, "invariant");
+    assert(strncmp(entry->literal(),
+      boot_class_loader_name,
+      strlen(boot_class_loader_name)) == 0, "invariant");
+    if (_unique_predicate(entry->id())) {
+      count += write__artifact__cstring__entry__(this->_writer, entry);
+    }
+  } else {
+    const Symbol* class_loader_name = cld->class_loader_name();
+    if (class_loader_name != NULL) {
+      SymbolEntryPtr entry = this->_artifacts->map_symbol(class_loader_name);
+      assert(entry != NULL, "invariant");
+      if (_unique_predicate(entry->id())) {
+        count += write__artifact__symbol__entry__(this->_writer, entry);
+      }
+    }
+  }
+  return count;
+}
+
+template <template <typename> class Predicate>
+int KlassSymbolWriterImpl<Predicate>::method_symbols(KlassPtr klass) {
+  assert(_predicate(klass), "invariant");
+  assert(_method_used_predicate(klass), "invariant");
+  assert(METHOD_AND_CLASS_USED_ANY_EPOCH(klass), "invariant");
+  int count = 0;
+  const InstanceKlass* const ik = InstanceKlass::cast(klass);
+  const int len = ik->methods()->length();
+  for (int i = 0; i < len; ++i) {
+    MethodPtr method = ik->methods()->at(i);
+    if (_method_flag_predicate(method)) {
+      SymbolEntryPtr entry = this->_artifacts->map_symbol(method->name());
+      assert(entry != NULL, "invariant");
+      if (_unique_predicate(entry->id())) {
+        count += write__artifact__symbol__entry__(this->_writer, entry);
+      }
+      entry = this->_artifacts->map_symbol(method->signature());
+      assert(entry != NULL, "invariant");
+      if (_unique_predicate(entry->id())) {
+        count += write__artifact__symbol__entry__(this->_writer, entry);
+      }
+    }
+  }
+  return count;
+}
+
+typedef KlassSymbolWriterImpl<LeakPredicate> LeakKlassSymbolWriterImpl;
+typedef JfrArtifactWriterHost<LeakKlassSymbolWriterImpl, TYPE_SYMBOL> LeakKlassSymbolWriter;
+
+class ClearKlassAndMethods {
+ private:
+  ClearArtifact<KlassPtr> _clear_klass_tag_bits;
+  ClearArtifact<MethodPtr> _clear_method_flag;
+  MethodUsedPredicate<false> _method_used_predicate;
+
+ public:
+  ClearKlassAndMethods(bool class_unload) : _clear_klass_tag_bits(class_unload),
+                                            _clear_method_flag(class_unload),
+                                            _method_used_predicate(class_unload) {}
+  bool operator()(KlassPtr klass) {
+    if (_method_used_predicate(klass)) {
+      const InstanceKlass* ik = InstanceKlass::cast(klass);
+      const int len = ik->methods()->length();
+      for (int i = 0; i < len; ++i) {
+        MethodPtr method = ik->methods()->at(i);
+        _clear_method_flag(method);
+      }
+    }
+    _clear_klass_tag_bits(klass);
+    return true;
+  }
+};
+
+typedef CompositeFunctor<KlassPtr,
+                         TagLeakpKlassArtifact,
+                         LeakKlassWriter> LeakpKlassArtifactTagging;
+
+typedef CompositeFunctor<KlassPtr,
+                         LeakpKlassArtifactTagging,
+                         KlassWriter> CompositeKlassWriter;
+
+typedef CompositeFunctor<KlassPtr,
+                         CompositeKlassWriter,
+                         KlassArtifactRegistrator> CompositeKlassWriterRegistration;
+
+typedef CompositeFunctor<KlassPtr,
+                         KlassWriter,
+                         KlassArtifactRegistrator> KlassWriterRegistration;
+
+typedef JfrArtifactCallbackHost<KlassPtr, KlassWriterRegistration> KlassCallback;
+typedef JfrArtifactCallbackHost<KlassPtr, CompositeKlassWriterRegistration> CompositeKlassCallback;
+
+/*
+ * Composite operation
+ *
+ * TagLeakpKlassArtifact ->
+ *   LeakpPredicate ->
+ *     LeakpKlassWriter ->
+ *       KlassPredicate ->
+ *         KlassWriter ->
+ *           KlassWriterRegistration
+ */
+void JfrTypeSet::write_klass_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer) {
+  assert(!_artifacts->has_klass_entries(), "invariant");
+  KlassArtifactRegistrator reg(_artifacts);
+  KlassWriter kw(writer, _artifacts, _class_unload);
+  KlassWriterRegistration kwr(&kw, &reg);
+  if (leakp_writer == NULL) {
+    KlassCallback callback(&kwr);
+    _subsystem_callback = &callback;
+    do_klasses();
+    return;
+  }
+  TagLeakpKlassArtifact tagging(_class_unload);
+  LeakKlassWriter lkw(leakp_writer, _artifacts, _class_unload);
+  LeakpKlassArtifactTagging lpkat(&tagging, &lkw);
+  CompositeKlassWriter ckw(&lpkat, &kw);
+  CompositeKlassWriterRegistration ckwr(&ckw, &reg);
+  CompositeKlassCallback callback(&ckwr);
+  _subsystem_callback = &callback;
+  do_klasses();
+}
+
+typedef CompositeFunctor<PkgPtr,
+                         PackageWriter,
+                         ClearArtifact<PkgPtr> > PackageWriterWithClear;
+
+typedef CompositeFunctor<PkgPtr,
+                         LeakPackageWriter,
+                         PackageWriter> CompositePackageWriter;
+
+typedef CompositeFunctor<PkgPtr,
+                         CompositePackageWriter,
+                         ClearArtifact<PkgPtr> > CompositePackageWriterWithClear;
+
+class PackageFieldSelector {
+ public:
+  typedef PkgPtr TypePtr;
+  static TypePtr select(KlassPtr klass) {
+    assert(klass != NULL, "invariant");
+    return ((InstanceKlass*)klass)->package();
+  }
+};
+
+typedef KlassToFieldEnvelope<PackageFieldSelector,
+                             PackageWriterWithClear> KlassPackageWriterWithClear;
+
+typedef KlassToFieldEnvelope<PackageFieldSelector,
+                             CompositePackageWriterWithClear> KlassCompositePackageWriterWithClear;
+
+typedef JfrArtifactCallbackHost<PkgPtr, PackageWriterWithClear> PackageCallback;
+typedef JfrArtifactCallbackHost<PkgPtr, CompositePackageWriterWithClear> CompositePackageCallback;
+
+/*
+ * Composite operation
+ *
+ * LeakpPackageWriter ->
+ *   PackageWriter ->
+ *     ClearArtifact<PackageEntry>
+ *
+ */
+void JfrTypeSet::write_package_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer) {
+  assert(_artifacts->has_klass_entries(), "invariant");
+  ClearArtifact<PkgPtr> clear(_class_unload);
+  PackageWriter pw(writer, _artifacts, _class_unload);
+  if (leakp_writer == NULL) {
+    PackageWriterWithClear pwwc(&pw, &clear);
+    KlassPackageWriterWithClear kpwwc(&pwwc);
+    _artifacts->iterate_klasses(kpwwc);
+    PackageCallback callback(&pwwc);
+    _subsystem_callback = &callback;
+    do_packages();
+    return;
+  }
+  LeakPackageWriter lpw(leakp_writer, _artifacts, _class_unload);
+  CompositePackageWriter cpw(&lpw, &pw);
+  CompositePackageWriterWithClear cpwwc(&cpw, &clear);
+  KlassCompositePackageWriterWithClear ckpw(&cpwwc);
+  _artifacts->iterate_klasses(ckpw);
+  CompositePackageCallback callback(&cpwwc);
+  _subsystem_callback = &callback;
+  do_packages();
+}
+
+typedef CompositeFunctor<ModPtr,
+                         ModuleWriter,
+                         ClearArtifact<ModPtr> > ModuleWriterWithClear;
+
+typedef CompositeFunctor<ModPtr,
+                         LeakModuleWriter,
+                         ModuleWriter> CompositeModuleWriter;
+
+typedef CompositeFunctor<ModPtr,
+                         CompositeModuleWriter,
+                         ClearArtifact<ModPtr> > CompositeModuleWriterWithClear;
+
+typedef JfrArtifactCallbackHost<ModPtr, ModuleWriterWithClear> ModuleCallback;
+typedef JfrArtifactCallbackHost<ModPtr, CompositeModuleWriterWithClear> CompositeModuleCallback;
+
+class ModuleFieldSelector {
+ public:
+  typedef ModPtr TypePtr;
+  static TypePtr select(KlassPtr klass) {
+    assert(klass != NULL, "invariant");
+    PkgPtr pkg = klass->package();
+    return pkg != NULL ? pkg->module() : NULL;
+  }
+};
+
+typedef KlassToFieldEnvelope<ModuleFieldSelector,
+                             ModuleWriterWithClear> KlassModuleWriterWithClear;
+
+typedef KlassToFieldEnvelope<ModuleFieldSelector,
+                             CompositeModuleWriterWithClear> KlassCompositeModuleWriterWithClear;
+
+/*
+ * Composite operation
+ *
+ * LeakpModuleWriter ->
+ *   ModuleWriter ->
+ *     ClearArtifact<ModuleEntry>
+ */
+void JfrTypeSet::write_module_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer) {
+  assert(_artifacts->has_klass_entries(), "invariant");
+  ClearArtifact<ModPtr> clear(_class_unload);
+  ModuleWriter mw(writer, _artifacts, _class_unload);
+  if (leakp_writer == NULL) {
+    ModuleWriterWithClear mwwc(&mw, &clear);
+    KlassModuleWriterWithClear kmwwc(&mwwc);
+    _artifacts->iterate_klasses(kmwwc);
+    ModuleCallback callback(&mwwc);
+    _subsystem_callback = &callback;
+    do_modules();
+    return;
+  }
+  LeakModuleWriter lmw(leakp_writer, _artifacts, _class_unload);
+  CompositeModuleWriter cmw(&lmw, &mw);
+  CompositeModuleWriterWithClear cmwwc(&cmw, &clear);
+  KlassCompositeModuleWriterWithClear kmwwc(&cmwwc);
+  _artifacts->iterate_klasses(kmwwc);
+  CompositeModuleCallback callback(&cmwwc);
+  _subsystem_callback = &callback;
+  do_modules();
+}
+
+typedef CompositeFunctor<CldPtr, CldWriter, ClearArtifact<CldPtr> > CldWriterWithClear;
+typedef CompositeFunctor<CldPtr, LeakCldWriter, CldWriter> CompositeCldWriter;
+typedef CompositeFunctor<CldPtr, CompositeCldWriter, ClearArtifact<CldPtr> > CompositeCldWriterWithClear;
+typedef JfrArtifactCallbackHost<CldPtr, CldWriterWithClear> CldCallback;
+typedef JfrArtifactCallbackHost<CldPtr, CompositeCldWriterWithClear> CompositeCldCallback;
+
+class CldFieldSelector {
+ public:
+  typedef CldPtr TypePtr;
+  static TypePtr select(KlassPtr klass) {
+    assert(klass != NULL, "invariant");
+    CldPtr cld = klass->class_loader_data();
+    return cld->is_anonymous() ? NULL : cld;
+  }
+};
+
+typedef KlassToFieldEnvelope<CldFieldSelector, CldWriterWithClear> KlassCldWriterWithClear;
+typedef KlassToFieldEnvelope<CldFieldSelector, CompositeCldWriterWithClear> KlassCompositeCldWriterWithClear;
+
+/*
+ * Composite operation
+ *
+ * LeakpClassLoaderWriter ->
+ *   ClassLoaderWriter ->
+ *     ClearArtifact<ClassLoaderData>
+ */
+void JfrTypeSet::write_class_loader_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer) {
+  assert(_artifacts->has_klass_entries(), "invariant");
+  ClearArtifact<CldPtr> clear(_class_unload);
+  CldWriter cldw(writer, _artifacts, _class_unload);
+  if (leakp_writer == NULL) {
+    CldWriterWithClear cldwwc(&cldw, &clear);
+    KlassCldWriterWithClear kcldwwc(&cldwwc);
+    _artifacts->iterate_klasses(kcldwwc);
+    CldCallback callback(&cldwwc);
+    _subsystem_callback = &callback;
+    do_class_loaders();
+    return;
+  }
+  LeakCldWriter lcldw(leakp_writer, _artifacts, _class_unload);
+  CompositeCldWriter ccldw(&lcldw, &cldw);
+  CompositeCldWriterWithClear ccldwwc(&ccldw, &clear);
+  KlassCompositeCldWriterWithClear kcclwwc(&ccldwwc);
+  _artifacts->iterate_klasses(kcclwwc);
+  CompositeCldCallback callback(&ccldwwc);
+  _subsystem_callback = &callback;
+  do_class_loaders();
+}
+
+template <bool predicate_bool, typename MethodFunctor>
+class MethodIteratorHost {
+ private:
+  MethodFunctor _method_functor;
+  MethodUsedPredicate<predicate_bool> _method_used_predicate;
+  MethodFlagPredicate _method_flag_predicate;
+
+ public:
+  MethodIteratorHost(JfrCheckpointWriter* writer,
+                     JfrArtifactSet* artifacts,
+                     bool class_unload,
+                     bool skip_header = false) :
+    _method_functor(writer, artifacts, class_unload, skip_header),
+    _method_used_predicate(class_unload),
+    _method_flag_predicate(class_unload) {}
+
+  bool operator()(KlassPtr klass) {
+    if (_method_used_predicate(klass)) {
+      assert(METHOD_AND_CLASS_USED_ANY_EPOCH(klass), "invariant");
+      const InstanceKlass* ik = InstanceKlass::cast(klass);
+      const int len = ik->methods()->length();
+      for (int i = 0; i < len; ++i) {
+        MethodPtr method = ik->methods()->at(i);
+        if (_method_flag_predicate(method)) {
+          _method_functor(method);
+        }
+      }
+    }
+    return true;
+  }
+
+  int count() const { return _method_functor.count(); }
+  void add(int count) { _method_functor.add(count); }
+};
+
+typedef MethodIteratorHost<true /*leakp */,  MethodWriterImpl> LeakMethodWriter;
+typedef MethodIteratorHost<false, MethodWriterImpl> MethodWriter;
+typedef CompositeFunctor<KlassPtr, LeakMethodWriter, MethodWriter> CompositeMethodWriter;
+
+/*
+ * Composite operation
+ *
+ * LeakpMethodWriter ->
+ *   MethodWriter
+ */
+void JfrTypeSet::write_method_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer) {
+  assert(_artifacts->has_klass_entries(), "invariant");
+  MethodWriter mw(writer, _artifacts, _class_unload);
+  if (leakp_writer == NULL) {
+    _artifacts->iterate_klasses(mw);
+    return;
+  }
+  LeakMethodWriter lpmw(leakp_writer, _artifacts, _class_unload);
+  CompositeMethodWriter cmw(&lpmw, &mw);
+  _artifacts->iterate_klasses(cmw);
+}
+static void write_symbols_leakp(JfrCheckpointWriter* leakp_writer, JfrArtifactSet* artifacts, bool class_unload) {
+  assert(leakp_writer != NULL, "invariant");
+  assert(artifacts != NULL, "invariant");
+  LeakKlassSymbolWriter lpksw(leakp_writer, artifacts, class_unload);
+  artifacts->iterate_klasses(lpksw);
+}
+static void write_symbols(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer, JfrArtifactSet* artifacts, bool class_unload) {
+  assert(writer != NULL, "invariant");
+  assert(artifacts != NULL, "invariant");
+  if (leakp_writer != NULL) {
+    write_symbols_leakp(leakp_writer, artifacts, class_unload);
+  }
+  // iterate all registered symbols
+  SymbolEntryWriter symbol_writer(writer, artifacts, class_unload);
+  artifacts->iterate_symbols(symbol_writer);
+  CStringEntryWriter cstring_writer(writer, artifacts, class_unload, true); // skip header
+  artifacts->iterate_cstrings(cstring_writer);
+  symbol_writer.add(cstring_writer.count());
+}
+
+bool JfrTypeSet::_class_unload = false;
+JfrArtifactSet* JfrTypeSet::_artifacts = NULL;
+JfrArtifactClosure* JfrTypeSet::_subsystem_callback = NULL;
+
+void JfrTypeSet::write_symbol_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer) {
+  assert(writer != NULL, "invariant");
+  assert(_artifacts->has_klass_entries(), "invariant");
+  write_symbols(writer, leakp_writer, _artifacts, _class_unload);
+}
+
+void JfrTypeSet::do_unloaded_klass(Klass* klass) {
+  assert(klass != NULL, "invariant");
+  assert(_subsystem_callback != NULL, "invariant");
+  if (IS_JDK_JFR_EVENT_SUBKLASS(klass)) {
+    JfrEventClasses::increment_unloaded_event_class();
+  }
+  if (USED_THIS_EPOCH(klass)) { // includes leakp subset
+    _subsystem_callback->do_artifact(klass);
+    return;
+  }
+  if (klass->is_subclass_of(SystemDictionary::ClassLoader_klass()) || klass == SystemDictionary::Object_klass()) {
+    SET_LEAKP_USED_THIS_EPOCH(klass); // tag leakp "safe byte" for subset inclusion
+    _subsystem_callback->do_artifact(klass);
+  }
+}
+
+void JfrTypeSet::do_klass(Klass* klass) {
+  assert(klass != NULL, "invariant");
+  assert(_subsystem_callback != NULL, "invariant");
+  if (USED_PREV_EPOCH(klass)) { // includes leakp subset
+    _subsystem_callback->do_artifact(klass);
+    return;
+  }
+  if (klass->is_subclass_of(SystemDictionary::ClassLoader_klass()) || klass == SystemDictionary::Object_klass()) {
+    SET_LEAKP_USED_PREV_EPOCH(klass); // tag leakp "safe byte" for subset inclusion
+    _subsystem_callback->do_artifact(klass);
+  }
+}
+
+void JfrTypeSet::do_klasses() {
+  if (_class_unload) {
+    ClassLoaderDataGraph::classes_unloading_do(&do_unloaded_klass);
+    return;
+  }
+  ClassLoaderDataGraph::classes_do(&do_klass);
+}
+
+void JfrTypeSet::do_unloaded_package(PackageEntry* entry) {
+  assert(entry != NULL, "invariant");
+  assert(_subsystem_callback != NULL, "invariant");
+  if (ANY_USED_THIS_EPOCH(entry)) { // includes leakp subset
+    _subsystem_callback->do_artifact(entry);
+  }
+}
+
+void JfrTypeSet::do_package(PackageEntry* entry) {
+  assert(_subsystem_callback != NULL, "invariant");
+  if (ANY_USED_PREV_EPOCH(entry)) { // includes leakp subset
+    _subsystem_callback->do_artifact(entry);
+  }
+}
+
+void JfrTypeSet::do_packages() {
+  if (_class_unload) {
+    ClassLoaderDataGraph::packages_unloading_do(&do_unloaded_package);
+    return;
+  }
+  ClassLoaderDataGraph::packages_do(&do_package);
+}
+void JfrTypeSet::do_unloaded_module(ModuleEntry* entry) {
+  assert(entry != NULL, "invariant");
+  assert(_subsystem_callback != NULL, "invariant");
+  if (ANY_USED_THIS_EPOCH(entry)) { // includes leakp subset
+    _subsystem_callback->do_artifact(entry);
+  }
+}
+
+void JfrTypeSet::do_module(ModuleEntry* entry) {
+  assert(_subsystem_callback != NULL, "invariant");
+  if (ANY_USED_PREV_EPOCH(entry)) { // includes leakp subset
+    _subsystem_callback->do_artifact(entry);
+  }
+}
+
+void JfrTypeSet::do_modules() {
+  if (_class_unload) {
+    ClassLoaderDataGraph::modules_unloading_do(&do_unloaded_module);
+    return;
+  }
+  ClassLoaderDataGraph::modules_do(&do_module);
+}
+
+void JfrTypeSet::do_unloaded_class_loader_data(ClassLoaderData* cld) {
+  assert(_subsystem_callback != NULL, "invariant");
+  if (ANY_USED_THIS_EPOCH(cld)) { // includes leakp subset
+    _subsystem_callback->do_artifact(cld);
+  }
+}
+
+void JfrTypeSet::do_class_loader_data(ClassLoaderData* cld) {
+  assert(_subsystem_callback != NULL, "invariant");
+  if (ANY_USED_PREV_EPOCH(cld)) { // includes leakp subset
+    _subsystem_callback->do_artifact(cld);
+  }
+}
+
+class CLDCallback : public CLDClosure {
+ private:
+  bool _class_unload;
+ public:
+  CLDCallback(bool class_unload) : _class_unload(class_unload) {}
+  void do_cld(ClassLoaderData* cld) {
+     assert(cld != NULL, "invariant");
+    if (cld->is_anonymous()) {
+      return;
+    }
+    if (_class_unload) {
+      JfrTypeSet::do_unloaded_class_loader_data(cld);
+      return;
+    }
+    JfrTypeSet::do_class_loader_data(cld);
+  }
+};
+
+void JfrTypeSet::do_class_loaders() {
+  CLDCallback cld_cb(_class_unload);
+  if (_class_unload) {
+    ClassLoaderDataGraph::cld_unloading_do(&cld_cb);
+    return;
+  }
+  ClassLoaderDataGraph::cld_do(&cld_cb);
+}
+
+static void clear_artifacts(JfrArtifactSet* artifacts,
+                            bool class_unload) {
+  assert(artifacts != NULL, "invariant");
+  assert(artifacts->has_klass_entries(), "invariant");
+
+  // untag
+  ClearKlassAndMethods clear(class_unload);
+  artifacts->iterate_klasses(clear);
+  artifacts->clear();
+}
+
+/**
+ * Write all "tagged" (in-use) constant artifacts and their dependencies.
+ */
+void JfrTypeSet::serialize(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer, bool class_unload) {
+  assert(writer != NULL, "invariant");
+  ResourceMark rm;
+  // initialization begin
+  _class_unload = class_unload;
+  ++checkpoint_id;
+  if (_artifacts == NULL) {
+    _artifacts = new JfrArtifactSet(class_unload);
+    _subsystem_callback = NULL;
+  } else {
+    _artifacts->initialize(class_unload);
+    _subsystem_callback = NULL;
+  }
+  assert(_artifacts != NULL, "invariant");
+  assert(!_artifacts->has_klass_entries(), "invariant");
+  assert(_subsystem_callback == NULL, "invariant");
+  // initialization complete
+
+  // write order is important because an individual write step
+  // might tag an artifact to be written in a subsequent step
+  write_klass_constants(writer, leakp_writer);
+  if (_artifacts->has_klass_entries()) {
+    write_package_constants(writer, leakp_writer);
+    write_module_constants(writer, leakp_writer);
+    write_class_loader_constants(writer, leakp_writer);
+    write_method_constants(writer, leakp_writer);
+    write_symbol_constants(writer, leakp_writer);
+    clear_artifacts(_artifacts, class_unload);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESET_HPP
+#define SHARE_VM_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESET_HPP
+
+#include "jfr/utilities/jfrAllocation.hpp"
+
+class ClassLoaderData;
+class JfrArtifactClosure;
+class JfrArtifactSet;
+class JfrCheckpointWriter;
+class Klass;
+
+class ModuleEntry;
+class PackageEntry;
+
+class JfrTypeSet : AllStatic {
+  friend class CLDCallback;
+  friend class JfrTypeManager;
+  friend class TypeSetSerialization;
+ private:
+  static JfrArtifactSet* _artifacts;
+  static JfrArtifactClosure* _subsystem_callback;
+  static bool _class_unload;
+
+  static void do_klass(Klass* k);
+  static void do_unloaded_klass(Klass* k);
+  static void do_klasses();
+
+  static void do_package(PackageEntry* entry);
+  static void do_unloaded_package(PackageEntry* entry);
+  static void do_packages();
+
+  static void do_module(ModuleEntry* entry);
+  static void do_unloaded_module(ModuleEntry* entry);
+  static void do_modules();
+
+  static void do_class_loader_data(ClassLoaderData* cld);
+  static void do_unloaded_class_loader_data(ClassLoaderData* cld);
+  static void do_class_loaders();
+
+  static void write_klass_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer);
+  static void write_package_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer);
+  static void write_module_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer);
+  static void write_class_loader_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer);
+  static void write_method_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer);
+  static void write_symbol_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer);
+  static void serialize(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer, bool class_unload);
+};
+
+#endif // SHARE_VM_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESET_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp"
+#include "oops/instanceKlass.hpp"
+#include "oops/oop.inline.hpp"
+#include "oops/symbol.hpp"
+
+JfrSymbolId::JfrSymbolId() : _symbol_id_counter(0), _sym_table(new SymbolTable(this)), _cstring_table(new CStringTable(this)) {
+  assert(_sym_table != NULL, "invariant");
+  assert(_cstring_table != NULL, "invariant");
+  initialize();
+}
+
+void JfrSymbolId::initialize() {
+  clear();
+  assert(_symbol_id_counter == 0, "invariant");
+}
+
+void JfrSymbolId::clear() {
+  assert(_sym_table != NULL, "invariant");
+  if (_sym_table->has_entries()) {
+    _sym_table->clear_entries();
+  }
+  assert(!_sym_table->has_entries(), "invariant");
+
+  assert(_cstring_table != NULL, "invariant");
+  if (_cstring_table->has_entries()) {
+    _cstring_table->clear_entries();
+  }
+  assert(!_cstring_table->has_entries(), "invariant");
+  _symbol_id_counter = 0;
+}
+
+JfrSymbolId::~JfrSymbolId() {
+  delete _sym_table;
+  delete _cstring_table;
+}
+
+traceid JfrSymbolId::mark_anonymous_klass_name(const Klass* k) {
+  assert(k != NULL, "invariant");
+  assert(k->is_instance_klass(), "invariant");
+  assert(is_anonymous_klass(k), "invariant");
+
+  uintptr_t anonymous_symbol_hash_code = 0;
+  const char* const anonymous_symbol =
+    create_anonymous_klass_symbol((const InstanceKlass*)k, anonymous_symbol_hash_code);
+
+  if (anonymous_symbol == NULL) {
+    return 0;
+  }
+
+  assert(anonymous_symbol_hash_code != 0, "invariant");
+  traceid symbol_id = mark(anonymous_symbol, anonymous_symbol_hash_code);
+  assert(mark(anonymous_symbol, anonymous_symbol_hash_code) == symbol_id, "invariant");
+  return symbol_id;
+}
+
+const JfrSymbolId::SymbolEntry* JfrSymbolId::map_symbol(const Symbol* symbol) const {
+  return _sym_table->lookup_only(symbol, (uintptr_t)const_cast<Symbol*>(symbol)->identity_hash());
+}
+
+const JfrSymbolId::SymbolEntry* JfrSymbolId::map_symbol(uintptr_t hash) const {
+  return _sym_table->lookup_only(NULL, hash);
+}
+
+const JfrSymbolId::CStringEntry* JfrSymbolId::map_cstring(uintptr_t hash) const {
+  return _cstring_table->lookup_only(NULL, hash);
+}
+
+void JfrSymbolId::assign_id(SymbolEntry* entry) {
+  assert(entry != NULL, "invariant");
+  assert(entry->id() == 0, "invariant");
+  entry->set_id(++_symbol_id_counter);
+}
+
+bool JfrSymbolId::equals(const Symbol* query, uintptr_t hash, const SymbolEntry* entry) {
+  // query might be NULL
+  assert(entry != NULL, "invariant");
+  assert(entry->hash() == hash, "invariant");
+  return true;
+}
+
+void JfrSymbolId::assign_id(CStringEntry* entry) {
+  assert(entry != NULL, "invariant");
+  assert(entry->id() == 0, "invariant");
+  entry->set_id(++_symbol_id_counter);
+}
+
+bool JfrSymbolId::equals(const char* query, uintptr_t hash, const CStringEntry* entry) {
+  // query might be NULL
+  assert(entry != NULL, "invariant");
+  assert(entry->hash() == hash, "invariant");
+  return true;
+}
+
+traceid JfrSymbolId::mark(const Klass* k) {
+  assert(k != NULL, "invariant");
+  traceid symbol_id = 0;
+  if (is_anonymous_klass(k)) {
+    symbol_id = mark_anonymous_klass_name(k);
+  }
+  if (0 == symbol_id) {
+    const Symbol* const sym = k->name();
+    if (sym != NULL) {
+      symbol_id = mark(sym);
+    }
+  }
+  assert(symbol_id > 0, "a symbol handler must mark the symbol for writing");
+  return symbol_id;
+}
+
+traceid JfrSymbolId::mark(const Symbol* symbol) {
+  assert(symbol != NULL, "invariant");
+  return mark(symbol, (uintptr_t)const_cast<Symbol*>(symbol)->identity_hash());
+}
+
+traceid JfrSymbolId::mark(const Symbol* data, uintptr_t hash) {
+  assert(data != NULL, "invariant");
+  assert(_sym_table != NULL, "invariant");
+  return _sym_table->id(data, hash);
+}
+
+traceid JfrSymbolId::mark(const char* str, uintptr_t hash) {
+  assert(str != NULL, "invariant");
+  return _cstring_table->id(str, hash);
+}
+
+bool JfrSymbolId::is_anonymous_klass(const Klass* k) {
+  assert(k != NULL, "invariant");
+  return k->is_instance_klass() && ((const InstanceKlass*)k)->is_anonymous();
+}
+
+/*
+* jsr292 anonymous classes symbol is the external name +
+* the identity_hashcode slash appended:
+*   java.lang.invoke.LambdaForm$BMH/22626602
+*
+* caller needs ResourceMark
+*/
+
+uintptr_t JfrSymbolId::anonymous_klass_name_hash_code(const InstanceKlass* ik) {
+  assert(ik != NULL, "invariant");
+  assert(ik->is_anonymous(), "invariant");
+  const oop mirror = ik->java_mirror();
+  assert(mirror != NULL, "invariant");
+  return (uintptr_t)mirror->identity_hash();
+}
+
+const char* JfrSymbolId::create_anonymous_klass_symbol(const InstanceKlass* ik, uintptr_t& hashcode) {
+  assert(ik != NULL, "invariant");
+  assert(ik->is_anonymous(), "invariant");
+  assert(0 == hashcode, "invariant");
+  char* anonymous_symbol = NULL;
+  const oop mirror = ik->java_mirror();
+  assert(mirror != NULL, "invariant");
+  char hash_buf[40];
+  hashcode = anonymous_klass_name_hash_code(ik);
+  sprintf(hash_buf, "/" UINTX_FORMAT, hashcode);
+  const size_t hash_len = strlen(hash_buf);
+  const size_t result_len = ik->name()->utf8_length();
+  anonymous_symbol = NEW_RESOURCE_ARRAY(char, result_len + hash_len + 1);
+  ik->name()->as_klass_external_name(anonymous_symbol, (int)result_len + 1);
+  assert(strlen(anonymous_symbol) == result_len, "invariant");
+  strcpy(anonymous_symbol + result_len, hash_buf);
+  assert(strlen(anonymous_symbol) == result_len + hash_len, "invariant");
+  return anonymous_symbol;
+}
+
+uintptr_t JfrSymbolId::regular_klass_name_hash_code(const Klass* k) {
+  assert(k != NULL, "invariant");
+  const Symbol* const sym = k->name();
+  assert(sym != NULL, "invariant");
+  return (uintptr_t)const_cast<Symbol*>(sym)->identity_hash();
+}
+
+JfrArtifactSet::JfrArtifactSet(bool class_unload) : _symbol_id(new JfrSymbolId()),
+                                                    _klass_list(NULL),
+                                                    _class_unload(class_unload) {
+  initialize(class_unload);
+  assert(_klass_list != NULL, "invariant");
+}
+
+static const size_t initial_class_list_size = 200;
+void JfrArtifactSet::initialize(bool class_unload) {
+  assert(_symbol_id != NULL, "invariant");
+  _symbol_id->initialize();
+  assert(!_symbol_id->has_entries(), "invariant");
+  _symbol_id->mark(boot_class_loader_name, 0); // pre-load "boot"
+  _class_unload = class_unload;
+  // resource allocation
+  _klass_list = new GrowableArray<const Klass*>(initial_class_list_size, false, mtTracing);
+}
+
+JfrArtifactSet::~JfrArtifactSet() {
+  clear();
+}
+
+void JfrArtifactSet::clear() {
+  _symbol_id->clear();
+  // _klass_list will be cleared by a ResourceMark
+}
+
+traceid JfrArtifactSet::mark_anonymous_klass_name(const Klass* klass) {
+  return _symbol_id->mark_anonymous_klass_name(klass);
+}
+
+traceid JfrArtifactSet::mark(const Symbol* sym, uintptr_t hash) {
+  return _symbol_id->mark(sym, hash);
+}
+
+traceid JfrArtifactSet::mark(const Klass* klass) {
+  return _symbol_id->mark(klass);
+}
+
+traceid JfrArtifactSet::mark(const Symbol* symbol) {
+  return _symbol_id->mark(symbol);
+}
+
+traceid JfrArtifactSet::mark(const char* const str, uintptr_t hash) {
+  return _symbol_id->mark(str, hash);
+}
+
+const JfrSymbolId::SymbolEntry* JfrArtifactSet::map_symbol(const Symbol* symbol) const {
+  return _symbol_id->map_symbol(symbol);
+}
+
+const JfrSymbolId::SymbolEntry* JfrArtifactSet::map_symbol(uintptr_t hash) const {
+  return _symbol_id->map_symbol(hash);
+}
+
+const JfrSymbolId::CStringEntry* JfrArtifactSet::map_cstring(uintptr_t hash) const {
+  return _symbol_id->map_cstring(hash);
+}
+
+bool JfrArtifactSet::has_klass_entries() const {
+  return _klass_list->is_nonempty();
+}
+
+int JfrArtifactSet::entries() const {
+  return _klass_list->length();
+}
+
+void JfrArtifactSet::register_klass(const Klass* k) {
+  assert(k != NULL, "invariant");
+  assert(_klass_list != NULL, "invariant");
+  assert(_klass_list->find(k) == -1, "invariant");
+  _klass_list->append(k);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESETUTILS_HPP
+#define SHARE_VM_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESETUTILS_HPP
+
+#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
+#include "jfr/utilities/jfrAllocation.hpp"
+#include "jfr/utilities/jfrHashtable.hpp"
+#include "oops/klass.hpp"
+#include "oops/method.hpp"
+#include "utilities/growableArray.hpp"
+
+// Composite callback/functor building block
+template <typename T, typename Func1, typename Func2>
+class CompositeFunctor {
+ private:
+  Func1* _f;
+  Func2* _g;
+ public:
+  CompositeFunctor(Func1* f, Func2* g) : _f(f), _g(g) {
+    assert(f != NULL, "invariant");
+    assert(g != NULL, "invariant");
+  }
+  bool operator()(T const& value) {
+    return (*_f)(value) && (*_g)(value);
+  }
+};
+
+class JfrArtifactClosure {
+ public:
+  virtual void do_artifact(const void* artifact) = 0;
+};
+
+template <typename T, typename Callback>
+class JfrArtifactCallbackHost : public JfrArtifactClosure {
+ private:
+  Callback* _callback;
+ public:
+  JfrArtifactCallbackHost(Callback* callback) : _callback(callback) {}
+  void do_artifact(const void* artifact) {
+    (*_callback)(reinterpret_cast<T const&>(artifact));
+  }
+};
+
+template <typename FieldSelector, typename Letter>
+class KlassToFieldEnvelope {
+  Letter* _letter;
+ public:
+  KlassToFieldEnvelope(Letter* letter) : _letter(letter) {}
+  bool operator()(const Klass* klass) {
+    typename FieldSelector::TypePtr t = FieldSelector::select(klass);
+    return t != NULL ? (*_letter)(t) : true;
+  }
+};
+
+template <typename T>
+void tag_leakp_artifact(T const& value, bool class_unload) {
+  assert(value != NULL, "invariant");
+  if (class_unload) {
+    SET_LEAKP_USED_THIS_EPOCH(value);
+    assert(LEAKP_USED_THIS_EPOCH(value), "invariant");
+  } else {
+    SET_LEAKP_USED_PREV_EPOCH(value);
+    assert(LEAKP_USED_PREV_EPOCH(value), "invariant");
+  }
+}
+
+template <typename T>
+class LeakpClearArtifact {
+  bool _class_unload;
+ public:
+  LeakpClearArtifact(bool class_unload) : _class_unload(class_unload) {}
+  bool operator()(T const& value) {
+    if (_class_unload) {
+      if (LEAKP_USED_THIS_EPOCH(value)) {
+        LEAKP_UNUSE_THIS_EPOCH(value);
+      }
+    } else {
+      if (LEAKP_USED_PREV_EPOCH(value)) {
+        LEAKP_UNUSE_PREV_EPOCH(value);
+      }
+    }
+    return true;
+  }
+};
+
+template <typename T>
+class ClearArtifact {
+  bool _class_unload;
+ public:
+  ClearArtifact(bool class_unload) : _class_unload(class_unload) {}
+  bool operator()(T const& value) {
+    if (_class_unload) {
+      if (LEAKP_USED_THIS_EPOCH(value)) {
+        LEAKP_UNUSE_THIS_EPOCH(value);
+      }
+      if (USED_THIS_EPOCH(value)) {
+        UNUSE_THIS_EPOCH(value);
+      }
+      if (METHOD_USED_THIS_EPOCH(value)) {
+        UNUSE_METHOD_THIS_EPOCH(value);
+      }
+    } else {
+      if (LEAKP_USED_PREV_EPOCH(value)) {
+        LEAKP_UNUSE_PREV_EPOCH(value);
+      }
+      if (USED_PREV_EPOCH(value)) {
+        UNUSE_PREV_EPOCH(value);
+      }
+      if (METHOD_USED_PREV_EPOCH(value)) {
+        UNUSE_METHOD_PREV_EPOCH(value);
+      }
+    }
+    return true;
+  }
+};
+
+template <>
+class ClearArtifact<const Method*> {
+  bool _class_unload;
+ public:
+  ClearArtifact(bool class_unload) : _class_unload(class_unload) {}
+  bool operator()(const Method* method) {
+    if (_class_unload) {
+      if (METHOD_FLAG_USED_THIS_EPOCH(method)) {
+        CLEAR_METHOD_FLAG_USED_THIS_EPOCH(method);
+      }
+    } else {
+      if (METHOD_FLAG_USED_PREV_EPOCH(method)) {
+        CLEAR_METHOD_FLAG_USED_PREV_EPOCH(method);
+      }
+    }
+    return true;
+  }
+};
+
+template <typename T>
+class LeakPredicate {
+  bool _class_unload;
+ public:
+  LeakPredicate(bool class_unload) : _class_unload(class_unload) {}
+  bool operator()(T const& value) {
+    return _class_unload ? LEAKP_USED_THIS_EPOCH(value) : LEAKP_USED_PREV_EPOCH(value);
+  }
+};
+
+template <typename T>
+class UsedPredicate {
+  bool _class_unload;
+ public:
+  UsedPredicate(bool class_unload) : _class_unload(class_unload) {}
+  bool operator()(T const& value) {
+    return _class_unload ? USED_THIS_EPOCH(value) : USED_PREV_EPOCH(value);
+  }
+};
+
+template <typename T, int compare(const T&, const T&)>
+class UniquePredicate {
+ private:
+  GrowableArray<T> _seen;
+ public:
+  UniquePredicate(bool) : _seen() {}
+  bool operator()(T const& value) {
+    bool not_unique;
+    _seen.template find_sorted<T, compare>(value, not_unique);
+    if (not_unique) {
+      return false;
+    }
+    _seen.template insert_sorted<compare>(value);
+    return true;
+  }
+};
+
+class MethodFlagPredicate {
+  bool _class_unload;
+ public:
+  MethodFlagPredicate(bool class_unload) : _class_unload(class_unload) {}
+  bool operator()(const Method* method) {
+    return _class_unload ? METHOD_FLAG_USED_THIS_EPOCH(method) : METHOD_FLAG_USED_PREV_EPOCH(method);
+  }
+};
+
+template <bool leakp>
+class MethodUsedPredicate {
+  bool _class_unload;
+ public:
+  MethodUsedPredicate(bool class_unload) : _class_unload(class_unload) {}
+  bool operator()(const Klass* klass) {
+    assert(ANY_USED(klass), "invariant");
+    if (_class_unload) {
+      return leakp ? LEAKP_METHOD_USED_THIS_EPOCH(klass) : METHOD_USED_THIS_EPOCH(klass);
+    }
+    return leakp ? LEAKP_METHOD_USED_PREV_EPOCH(klass) : METHOD_USED_PREV_EPOCH(klass);
+  }
+};
+
+class JfrSymbolId : public JfrCHeapObj {
+  template <typename, typename, template<typename, typename> class, typename, size_t>
+  friend class HashTableHost;
+  typedef HashTableHost<const Symbol*, traceid, Entry, JfrSymbolId> SymbolTable;
+  typedef HashTableHost<const char*, traceid, Entry, JfrSymbolId> CStringTable;
+ public:
+  typedef SymbolTable::HashEntry SymbolEntry;
+  typedef CStringTable::HashEntry CStringEntry;
+ private:
+  SymbolTable* _sym_table;
+  CStringTable* _cstring_table;
+  traceid _symbol_id_counter;
+
+  // hashtable(s) callbacks
+  void assign_id(SymbolEntry* entry);
+  bool equals(const Symbol* query, uintptr_t hash, const SymbolEntry* entry);
+  void assign_id(CStringEntry* entry);
+  bool equals(const char* query, uintptr_t hash, const CStringEntry* entry);
+
+ public:
+  static bool is_anonymous_klass(const Klass* k);
+  static const char* create_anonymous_klass_symbol(const InstanceKlass* ik, uintptr_t& hashcode);
+  static uintptr_t anonymous_klass_name_hash_code(const InstanceKlass* ik);
+  static uintptr_t regular_klass_name_hash_code(const Klass* k);
+
+  JfrSymbolId();
+  ~JfrSymbolId();
+
+  void initialize();
+  void clear();
+
+  traceid mark_anonymous_klass_name(const Klass* k);
+  traceid mark(const Symbol* sym, uintptr_t hash);
+  traceid mark(const Klass* k);
+  traceid mark(const Symbol* symbol);
+  traceid mark(const char* str, uintptr_t hash);
+
+  const SymbolEntry* map_symbol(const Symbol* symbol) const;
+  const SymbolEntry* map_symbol(uintptr_t hash) const;
+  const CStringEntry* map_cstring(uintptr_t hash) const;
+
+  template <typename T>
+  void symbol(T& functor, const Klass* k) {
+    if (is_anonymous_klass(k)) {
+      return;
+    }
+    functor(map_symbol(regular_klass_name_hash_code(k)));
+  }
+
+  template <typename T>
+  void symbol(T& functor, const Method* method) {
+    assert(method != NULL, "invariant");
+    functor(map_symbol((uintptr_t)method->name()->identity_hash()));
+    functor(map_symbol((uintptr_t)method->signature()->identity_hash()));
+  }
+
+  template <typename T>
+  void cstring(T& functor, const Klass* k) {
+    if (!is_anonymous_klass(k)) {
+      return;
+    }
+    functor(map_cstring(anonymous_klass_name_hash_code((const InstanceKlass*)k)));
+  }
+
+  template <typename T>
+  void iterate_symbols(T& functor) {
+    _sym_table->iterate_entry(functor);
+  }
+
+  template <typename T>
+  void iterate_cstrings(T& functor) {
+    _cstring_table->iterate_entry(functor);
+  }
+
+  bool has_entries() const { return has_symbol_entries() || has_cstring_entries(); }
+  bool has_symbol_entries() const { return _sym_table->has_entries(); }
+  bool has_cstring_entries() const { return _cstring_table->has_entries(); }
+};
+
+// external name (synthetic) for the primordial "boot" class loader instance
+const char* const boot_class_loader_name = "boot";
+
+/**
+ * When processing a set of artifacts, there will be a need
+ * to track transitive dependencies originating with each artifact.
+ * These might or might not be explicitly "tagged" at that point.
+ * With the introduction of "epochs" to allow for concurrent tagging,
+ * we attempt to avoid "tagging" an artifact to indicate its use in a
+ * previous epoch. This is mainly to reduce the risk for data races.
+ * Instead, JfrArtifactSet is used to track transitive dependencies
+ * during the write process itself.
+ *
+ * It can also provide opportunities for caching, as the ideal should
+ * be to reduce the amount of iterations neccessary for locating artifacts
+ * in the respective VM subsystems.
+ */
+class JfrArtifactSet : public JfrCHeapObj {
+ private:
+  JfrSymbolId* _symbol_id;
+  GrowableArray<const Klass*>* _klass_list;
+  bool _class_unload;
+
+ public:
+  JfrArtifactSet(bool class_unload);
+  ~JfrArtifactSet();
+
+  // caller needs ResourceMark
+  void initialize(bool class_unload);
+  void clear();
+
+  traceid mark(const Symbol* sym, uintptr_t hash);
+  traceid mark(const Klass* klass);
+  traceid mark(const Symbol* symbol);
+  traceid mark(const char* const str, uintptr_t hash);
+  traceid mark_anonymous_klass_name(const Klass* klass);
+
+  const JfrSymbolId::SymbolEntry* map_symbol(const Symbol* symbol) const;
+  const JfrSymbolId::SymbolEntry* map_symbol(uintptr_t hash) const;
+  const JfrSymbolId::CStringEntry* map_cstring(uintptr_t hash) const;
+
+  bool has_klass_entries() const;
+  int entries() const;
+  void register_klass(const Klass* k);
+
+  template <typename Functor>
+  void iterate_klasses(Functor& functor) const {
+    for (int i = 0; i < _klass_list->length(); ++i) {
+      if (!functor(_klass_list->at(i))) {
+        break;
+      }
+    }
+  }
+
+  template <typename T>
+  void iterate_symbols(T& functor) {
+    _symbol_id->iterate_symbols(functor);
+  }
+
+  template <typename T>
+  void iterate_cstrings(T& functor) {
+    _symbol_id->iterate_cstrings(functor);
+  }
+};
+
+class KlassArtifactRegistrator {
+ private:
+  JfrArtifactSet* _artifacts;
+ public:
+  KlassArtifactRegistrator(JfrArtifactSet* artifacts) :
+    _artifacts(artifacts) {
+    assert(_artifacts != NULL, "invariant");
+  }
+
+  bool operator()(const Klass* klass) {
+    assert(klass != NULL, "invariant");
+    _artifacts->register_klass(klass);
+    return true;
+  }
+};
+
+#endif // SHARE_VM_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESETUTILS_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetWriter.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_CHECKPOINT_TYPES_JFRTYPESETWRITER_HPP
+#define SHARE_VM_JFR_CHECKPOINT_TYPES_JFRTYPESETWRITER_HPP
+
+#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
+#include "memory/allocation.hpp"
+
+template <typename WriterImpl, u4 ID>
+class JfrArtifactWriterHost : public StackObj {
+ private:
+  WriterImpl _impl;
+  JfrCheckpointWriter* _writer;
+  JfrCheckpointContext _ctx;
+  jlong _count_offset;
+  int _count;
+  bool _skip_header;
+ public:
+  JfrArtifactWriterHost(JfrCheckpointWriter* writer,
+                        JfrArtifactSet* artifacts,
+                        bool class_unload,
+                        bool skip_header = false) : _impl(writer, artifacts, class_unload),
+                                                    _writer(writer),
+                                                    _ctx(writer->context()),
+                                                    _count(0),
+                                                    _skip_header(skip_header) {
+    assert(_writer != NULL, "invariant");
+    if (!_skip_header) {
+      _writer->write_type((JfrTypeId)ID);
+      _count_offset = _writer->reserve(sizeof(u4)); // Don't know how many yet
+    }
+  }
+
+  ~JfrArtifactWriterHost() {
+    if (_count == 0) {
+      // nothing written, restore context for rewind
+      _writer->set_context(_ctx);
+      return;
+    }
+    assert(_count > 0, "invariant");
+    if (!_skip_header) {
+      _writer->write_count(_count, _count_offset);
+    }
+  }
+
+  bool operator()(typename WriterImpl::Type const & value) {
+    this->_count += _impl(value);
+    return true;
+  }
+
+  int count() const   { return _count; }
+  void add(int count) { _count += count; }
+};
+
+typedef int(*artifact_write_operation)(JfrCheckpointWriter*, JfrArtifactSet*, const void*);
+
+template <typename T, artifact_write_operation op>
+class JfrArtifactWriterImplHost {
+ private:
+  JfrCheckpointWriter* _writer;
+  JfrArtifactSet* _artifacts;
+  bool _class_unload;
+ public:
+  typedef T Type;
+  JfrArtifactWriterImplHost(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, bool class_unload) :
+    _writer(writer), _artifacts(artifacts), _class_unload(class_unload) {}
+  int operator()(T const& value) {
+    return op(this->_writer, this->_artifacts, value);
+  }
+};
+
+template <typename T, typename Predicate, artifact_write_operation op>
+class JfrPredicatedArtifactWriterImplHost : public JfrArtifactWriterImplHost<T, op> {
+ private:
+  Predicate _predicate;
+  typedef JfrArtifactWriterImplHost<T, op> Parent;
+ public:
+  JfrPredicatedArtifactWriterImplHost(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, bool class_unload) :
+    Parent(writer, artifacts, class_unload), _predicate(class_unload) {}
+  int operator()(T const& value) {
+    return _predicate(value) ? Parent::operator()(value) : 0;
+  }
+};
+
+#endif // SHARE_VM_JFR_CHECKPOINT_TYPES_JFRTYPESETWRITER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/classLoaderData.inline.hpp"
+#include "classfile/symbolTable.hpp"
+#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
+#include "oops/arrayKlass.inline.hpp"
+#include "oops/klass.inline.hpp"
+#include "oops/instanceKlass.inline.hpp"
+#include "oops/method.hpp"
+#include "oops/oop.inline.hpp"
+#include "runtime/atomic.hpp"
+#include "runtime/orderAccess.inline.hpp"
+#include "runtime/vm_version.hpp"
+#include "runtime/jniHandles.inline.hpp"
+#include "runtime/thread.inline.hpp"
+#include "utilities/debug.hpp"
+
+ // returns updated value
+static traceid atomic_inc(traceid volatile* const dest) {
+  assert(VM_Version::supports_cx8(), "invariant");
+  traceid compare_value;
+  traceid exchange_value;
+  do {
+    compare_value = OrderAccess::load_acquire(dest);
+    exchange_value = compare_value + 1;
+  } while (Atomic::cmpxchg(exchange_value, dest, compare_value) != compare_value);
+  return exchange_value;
+}
+
+static traceid next_class_id() {
+  static volatile traceid class_id_counter = MaxJfrEventId + 100;
+  return atomic_inc(&class_id_counter) << TRACE_ID_SHIFT;
+}
+
+static traceid next_thread_id() {
+  static volatile traceid thread_id_counter = 0;
+  return atomic_inc(&thread_id_counter);
+}
+
+static traceid next_module_id() {
+  static volatile traceid module_id_counter = 1;
+  return atomic_inc(&module_id_counter) << TRACE_ID_SHIFT;
+}
+
+static traceid next_package_id() {
+  static volatile traceid package_id_counter = 1;
+  return atomic_inc(&package_id_counter) << TRACE_ID_SHIFT;
+}
+
+static traceid next_class_loader_data_id() {
+  static volatile traceid cld_id_counter = 1;
+  return atomic_inc(&cld_id_counter) << TRACE_ID_SHIFT;
+}
+
+static bool found_jdk_jfr_event_klass = false;
+
+static void check_klass(const Klass* klass) {
+  assert(klass != NULL, "invariant");
+  if (found_jdk_jfr_event_klass) {
+    return;
+  }
+  static const Symbol* jdk_jfr_event_sym = NULL;
+  if (jdk_jfr_event_sym == NULL) {
+    // setup when loading the first TypeArrayKlass (Universe::genesis) hence single threaded invariant
+    jdk_jfr_event_sym = SymbolTable::new_permanent_symbol("jdk/jfr/Event", Thread::current());
+  }
+  assert(jdk_jfr_event_sym != NULL, "invariant");
+  if (jdk_jfr_event_sym == klass->name() && klass->class_loader() == NULL) {
+    found_jdk_jfr_event_klass = true;
+    JfrTraceId::tag_as_jdk_jfr_event(klass);
+  }
+}
+
+void JfrTraceId::assign(const Klass* klass) {
+  assert(klass != NULL, "invariant");
+  klass->set_trace_id(next_class_id());
+  check_klass(klass);
+  const Klass* const super = klass->super();
+  if (super == NULL) {
+    return;
+  }
+  if (IS_EVENT_KLASS(super)) {
+    tag_as_jdk_jfr_event_sub(klass);
+  }
+}
+
+void JfrTraceId::assign(const ModuleEntry* module) {
+  assert(module != NULL, "invariant");
+  module->set_trace_id(next_module_id());
+}
+
+void JfrTraceId::assign(const PackageEntry* package) {
+  assert(package != NULL, "invariant");
+  package->set_trace_id(next_package_id());
+}
+
+void JfrTraceId::assign(const ClassLoaderData* cld) {
+  assert(cld != NULL, "invariant");
+  if (cld->is_anonymous()) {
+    cld->set_trace_id(0);
+    return;
+  }
+  cld->set_trace_id(next_class_loader_data_id());
+}
+
+traceid JfrTraceId::assign_thread_id() {
+  return next_thread_id();
+}
+
+// used by CDS / APPCDS as part of "remove_unshareable_info"
+void JfrTraceId::remove(const Klass* k) {
+  assert(k != NULL, "invariant");
+  // Mask off and store the event flags.
+  // This mechanism will retain the event specific flags
+  // in the archive, allowing for event flag restoration
+  // when renewing the traceid on klass revival.
+  k->set_trace_id(EVENT_FLAGS_MASK(k));
+}
+
+// used by CDS / APPCDS as part of "restore_unshareable_info"
+void JfrTraceId::restore(const Klass* k) {
+  assert(k != NULL, "invariant");
+  if (IS_JDK_JFR_EVENT_KLASS(k)) {
+    found_jdk_jfr_event_klass = true;
+  }
+  const traceid event_flags = k->trace_id();
+  // get a fresh traceid and restore the original event flags
+  k->set_trace_id(next_class_id() | event_flags);
+}
+
+traceid JfrTraceId::get(jclass jc) {
+  assert(jc != NULL, "invariant");
+  assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_vm, "invariant");
+  const oop my_oop = JNIHandles::resolve(jc);
+  assert(my_oop != NULL, "invariant");
+  return get(java_lang_Class::as_Klass(my_oop));
+}
+
+traceid JfrTraceId::use(jclass jc, bool leakp /* false */) {
+  assert(jc != NULL, "invariant");
+  assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_vm, "invariant");
+  const oop my_oop = JNIHandles::resolve(jc);
+  assert(my_oop != NULL, "invariant");
+  return use(java_lang_Class::as_Klass(my_oop), leakp);
+}
+
+bool JfrTraceId::in_visible_set(const jclass jc) {
+  assert(jc != NULL, "invariant");
+  assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_vm, "invariant");
+  const oop mirror = JNIHandles::resolve(jc);
+  assert(mirror != NULL, "invariant");
+  return in_visible_set(java_lang_Class::as_Klass(mirror));
+}
+
+bool JfrTraceId::in_jdk_jfr_event_hierarchy(const jclass jc) {
+  assert(jc != NULL, "invariant");
+  const oop mirror = JNIHandles::resolve(jc);
+  assert(mirror != NULL, "invariant");
+  return in_jdk_jfr_event_hierarchy(java_lang_Class::as_Klass(mirror));
+}
+
+bool JfrTraceId::is_jdk_jfr_event_sub(const jclass jc) {
+  assert(jc != NULL, "invariant");
+  const oop mirror = JNIHandles::resolve(jc);
+  assert(mirror != NULL, "invariant");
+  return is_jdk_jfr_event_sub(java_lang_Class::as_Klass(mirror));
+}
+
+bool JfrTraceId::is_jdk_jfr_event(const jclass jc) {
+  assert(jc != NULL, "invariant");
+  const oop mirror = JNIHandles::resolve(jc);
+  assert(mirror != NULL, "invariant");
+  return is_jdk_jfr_event(java_lang_Class::as_Klass(mirror));
+}
+
+bool JfrTraceId::is_event_host(const jclass jc) {
+  assert(jc != NULL, "invariant");
+  const oop mirror = JNIHandles::resolve(jc);
+  assert(mirror != NULL, "invariant");
+  return is_event_host(java_lang_Class::as_Klass(mirror));
+}
+
+void JfrTraceId::tag_as_jdk_jfr_event_sub(const jclass jc) {
+  assert(jc != NULL, "invariant");
+  const oop mirror = JNIHandles::resolve(jc);
+  assert(mirror != NULL, "invariant");
+  const Klass* const k = java_lang_Class::as_Klass(mirror);
+  tag_as_jdk_jfr_event_sub(k);
+  assert(IS_JDK_JFR_EVENT_SUBKLASS(k), "invariant");
+}
+
+void JfrTraceId::tag_as_event_host(const jclass jc) {
+  assert(jc != NULL, "invariant");
+  const oop mirror = JNIHandles::resolve(jc);
+  assert(mirror != NULL, "invariant");
+  const Klass* const k = java_lang_Class::as_Klass(mirror);
+  tag_as_event_host(k);
+  assert(IS_EVENT_HOST_KLASS(k), "invariant");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_CHECKPOINT_TYPES_TRACEID_JFRTRACEID_HPP
+#define SHARE_VM_JFR_CHECKPOINT_TYPES_TRACEID_JFRTRACEID_HPP
+
+#include "jni.h"
+#include "jfr/utilities/jfrTypes.hpp"
+#include "memory/allocation.hpp"
+
+class ClassLoaderData;
+class Klass;
+class Method;
+class ModuleEntry;
+class PackageEntry;
+class Thread;
+
+/*
+ * JfrTraceId is a means of tagging, e.g. marking, specific instances as being actively in-use.
+ * The most common situation is a committed event that has a field that is referring to a specific instance.
+ * Now there exist a relation between an event (field) and an artifact of some kind.
+ * We track this relation during runtime using the JfrTraceId mechanism in order to reify it into the chunk
+ * where the event is finally written.
+ *
+ * It is the event commit mechanism that tags instances as in-use. The tag routines return the untagged traceid
+ * as a mapping key, and the commit mechanism writes the key into the event field.
+ * Consequently, the mechanism is opaque and not something a user needs to know about.
+ * Indeed, the API promotes using well-known JVM concepts directly in events, such as having a Klass* as an event field.
+ *
+ * Tagging allows for many-to-one mappings of constants, lazy evaluation / collection of tags during chunk rotation
+ * and concurrency (by using an epoch relative tagging scheme).
+ *
+ * JfrTraceId(s) have been added to support tagging instances of classes such as:
+ *
+ *   Klass (includes Method)
+ *   ClassLoaderData
+ *   ModuleEntry
+ *   PackageEntry
+ *
+ * These classes have been extended to include a _traceid field (64-bits).
+ *
+ * Each instance is uniquely identified by a type-relative monotonic counter that is unique over the VM lifecycle.
+ * "Tagging an instance" essentially means to set contextually determined (by epoch) marker bits in the _traceid field.
+ * The constants associated with a tagged instance is a set of which is determined by a constant type definition,
+ * and these constants are then serialized in an upcoming checkpoint event for the relevant chunk.
+ *
+ * Note that a "tagging" is relative to a chunk. Having serialized the tagged instance, the tag bits are reset (for that epoch).
+ * As mentioned previously, the returned traceid is always the untagged value.
+ *
+ * We also use the _traceid field in Klass to quickly identify (bit check) if a newly loaded klass is of type jdk.jfr.Event.
+ * (see jfr/instrumentation/jfrEventClassTransformer.cpp)
+ *
+ *
+ * _traceid bit layout and description planned to go here
+ *
+ *
+ */
+
+class JfrTraceId : public AllStatic {
+ public:
+  static void assign(const Klass* klass);
+  static void assign(const ModuleEntry* module);
+  static void assign(const PackageEntry* package);
+  static void assign(const ClassLoaderData* cld);
+  static traceid assign_thread_id();
+
+  static traceid get(const Klass* klass);
+  static traceid get(jclass jc);
+  static traceid get(const Thread* thread);
+
+  // tag construct as used, returns pre-tagged traceid
+  static traceid use(const Klass* klass, bool leakp = false);
+  static traceid use(jclass jc, bool leakp = false);
+  static traceid use(const Method* method, bool leakp = false);
+  static traceid use(const ModuleEntry* module, bool leakp = false);
+  static traceid use(const PackageEntry* package, bool leakp = false);
+  static traceid use(const ClassLoaderData* cld, bool leakp = false);
+
+  static void remove(const Klass* klass);
+  static void restore(const Klass* klass);
+
+  // set of event classes made visible to java
+  static bool in_visible_set(const Klass* k);
+  static bool in_visible_set(const jclass jc);
+
+  // jdk.jfr.Event
+  static bool is_jdk_jfr_event(const Klass* k);
+  static bool is_jdk_jfr_event(const jclass jc);
+  static void tag_as_jdk_jfr_event(const Klass* k);
+
+  // jdk.jfr.Event subklasses
+  static bool is_jdk_jfr_event_sub(const Klass* k);
+  static bool is_jdk_jfr_event_sub(const jclass jc);
+  static void tag_as_jdk_jfr_event_sub(const Klass* k);
+  static void tag_as_jdk_jfr_event_sub(const jclass jc);
+
+  static bool in_jdk_jfr_event_hierarchy(const Klass* k);
+  static bool in_jdk_jfr_event_hierarchy(const jclass jc);
+
+  // klasses that host an event
+  static bool is_event_host(const Klass* k);
+  static bool is_event_host(const jclass jc);
+  static void tag_as_event_host(const Klass* k);
+  static void tag_as_event_host(const jclass jc);
+};
+
+#endif // SHARE_VM_JFR_CHECKPOINT_TYPES_TRACEID_JFRTRACEID_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_CHECKPOINT_TYPES_TRACEID_JFRTYPEIDS_INLINE_HPP
+#define SHARE_VM_JFR_CHECKPOINT_TYPES_TRACEID_JFRTYPEIDS_INLINE_HPP
+
+#include "classfile/classLoaderData.hpp"
+#include "classfile/moduleEntry.hpp"
+#include "classfile/packageEntry.hpp"
+#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp"
+#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.hpp"
+#include "oops/arrayKlass.hpp"
+#include "oops/klass.hpp"
+#include "oops/instanceKlass.hpp"
+#include "oops/method.hpp"
+#include "runtime/thread.hpp"
+#include "utilities/debug.hpp"
+
+template <typename T>
+inline traceid set_used_and_get(const T* type, bool leakp) {
+  assert(type != NULL, "invariant");
+  if (leakp) {
+    SET_LEAKP_USED_THIS_EPOCH(type);
+    assert(LEAKP_USED_THIS_EPOCH(type), "invariant");
+  }
+  SET_USED_THIS_EPOCH(type);
+  assert(USED_THIS_EPOCH(type), "invariant");
+  return TRACE_ID_MASKED_PTR(type);
+}
+
+template <typename T>
+inline traceid set_used_and_get_shifted(const T* type, bool leakp) {
+  assert(type != NULL, "invariant");
+  return set_used_and_get(type, leakp) >> TRACE_ID_SHIFT;
+}
+
+inline traceid JfrTraceId::get(const Klass* klass) {
+  assert(klass != NULL, "invariant");
+  return TRACE_ID(klass);
+}
+
+inline traceid JfrTraceId::get(const Thread* t) {
+  assert(t != NULL, "invariant");
+  return TRACE_ID_RAW(t->jfr_thread_local());
+}
+
+inline traceid JfrTraceId::use(const Klass* klass, bool leakp /* false */) {
+  assert(klass != NULL, "invariant");
+  return set_used_and_get_shifted(klass, leakp);
+}
+
+inline traceid JfrTraceId::use(const Method* method, bool leakp /* false */) {
+  assert(method != NULL, "invariant");
+  SET_METHOD_FLAG_USED_THIS_EPOCH(method);
+  const Klass* const klass = method->method_holder();
+  assert(klass != NULL, "invariant");
+  if (leakp) {
+    SET_LEAKP_USED_THIS_EPOCH(klass);
+    assert(LEAKP_USED_THIS_EPOCH(klass), "invariant");
+  }
+  SET_METHOD_AND_CLASS_USED_THIS_EPOCH(klass);
+  assert(METHOD_AND_CLASS_USED_THIS_EPOCH(klass), "invariant");
+  return (METHOD_ID(klass, method));
+}
+
+inline traceid JfrTraceId::use(const ModuleEntry* module, bool leakp /* false */) {
+  assert(module != NULL, "invariant");
+  return set_used_and_get_shifted(module, leakp);
+}
+
+inline traceid JfrTraceId::use(const PackageEntry* package, bool leakp /* false */) {
+  assert(package != NULL, "invariant");
+  return set_used_and_get_shifted(package, leakp);
+}
+
+inline traceid JfrTraceId::use(const ClassLoaderData* cld, bool leakp /* false */) {
+  assert(cld != NULL, "invariant");
+  return cld->is_anonymous() ? 0 : set_used_and_get_shifted(cld, leakp);
+}
+
+inline bool JfrTraceId::in_visible_set(const Klass* klass) {
+  assert(klass != NULL, "invariant");
+  assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_vm, "invariant");
+  return (IS_JDK_JFR_EVENT_SUBKLASS(klass) && !klass->is_abstract()) || IS_EVENT_HOST_KLASS(klass);
+}
+
+inline bool JfrTraceId::is_jdk_jfr_event(const Klass* k) {
+  assert(k != NULL, "invariant");
+  return IS_JDK_JFR_EVENT_KLASS(k);
+}
+
+inline void JfrTraceId::tag_as_jdk_jfr_event(const Klass* klass) {
+  assert(klass != NULL, "invariant");
+  assert(IS_NOT_AN_EVENT_KLASS(klass), "invariant");
+  SET_TAG(klass, JDK_JFR_EVENT_KLASS);
+  assert(IS_JDK_JFR_EVENT_KLASS(klass), "invariant");
+  assert(IS_NOT_AN_EVENT_SUB_KLASS(klass), "invariant");
+}
+
+inline bool JfrTraceId::is_jdk_jfr_event_sub(const Klass* k) {
+  assert(k != NULL, "invariant");
+  return IS_JDK_JFR_EVENT_SUBKLASS(k);
+}
+
+inline void JfrTraceId::tag_as_jdk_jfr_event_sub(const Klass* k) {
+  assert(k != NULL, "invariant");
+  if (IS_NOT_AN_EVENT_KLASS(k)) {
+    SET_TAG(k, JDK_JFR_EVENT_SUBKLASS);
+  }
+  assert(IS_JDK_JFR_EVENT_SUBKLASS(k), "invariant");
+}
+
+inline bool JfrTraceId::in_jdk_jfr_event_hierarchy(const Klass* klass) {
+  assert(klass != NULL, "invariant");
+  if (is_jdk_jfr_event(klass)) {
+    return true;
+  }
+  const Klass* const super = klass->super();
+  return super != NULL ? IS_EVENT_KLASS(super) : false;
+}
+
+inline bool JfrTraceId::is_event_host(const Klass* k) {
+  assert(k != NULL, "invariant");
+  return IS_EVENT_HOST_KLASS(k);
+}
+
+inline void JfrTraceId::tag_as_event_host(const Klass* k) {
+  assert(k != NULL, "invariant");
+  SET_TAG(k, EVENT_HOST_KLASS);
+  assert(IS_EVENT_HOST_KLASS(k), "invariant");
+}
+
+#endif // SHARE_VM_JFR_CHECKPOINT_TYPES_TRACEID_JFRTYPEIDS_INLINE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdBits.inline.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDBITS_INLINE_HPP
+#define SHARE_VM_JFR_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDBITS_INLINE_HPP
+
+#include "jfr/utilities/jfrTypes.hpp"
+#include "runtime/atomic.hpp"
+#include "runtime/orderAccess.inline.hpp"
+#include "utilities/macros.hpp"
+
+#ifdef VM_LITTLE_ENDIAN
+static const int low_offset = 0;
+static const int leakp_offset = low_offset + 1;
+#else
+static const int low_offset = 7;
+static const int leakp_offset = low_offset - 1;
+#endif
+
+inline void set_bits(jbyte bits, jbyte* const dest) {
+  assert(dest != NULL, "invariant");
+  const jbyte current = OrderAccess::load_acquire(dest);
+  if (bits != (current & bits)) {
+    *dest |= bits;
+  }
+}
+
+inline void set_mask(jbyte mask, jbyte* const dest) {
+  assert(dest != NULL, "invariant");
+  const jbyte current = OrderAccess::load_acquire(dest);
+  if (mask != (current & mask)) {
+    *dest &= mask;
+  }
+}
+
+inline void set_bits_cas(jbyte bits, jbyte* const dest) {
+  assert(dest != NULL, "invariant");
+  do {
+    const jbyte current = OrderAccess::load_acquire(dest);
+    if (bits == (current & bits)) {
+      return;
+    }
+    const jbyte new_value = current | bits;
+    if (Atomic::cmpxchg(new_value, dest, current) == current) {
+      return;
+    }
+  } while (true);
+}
+
+inline void clear_bits_cas(jbyte bits, jbyte* const dest) {
+  assert(dest != NULL, "invariant");
+  do {
+    const jbyte current = OrderAccess::load_acquire(dest);
+    if (bits != (current & bits)) {
+      return;
+    }
+    const jbyte new_value = current ^ bits;
+    if (Atomic::cmpxchg(new_value, dest, current) == current) {
+      return;
+    }
+  } while (true);
+}
+
+inline void set_traceid_bits(jbyte bits, traceid* dest) {
+  set_bits(bits, ((jbyte*)dest) + low_offset);
+}
+
+inline void set_traceid_bits_cas(jbyte bits, traceid* dest) {
+  set_bits_cas(bits, ((jbyte*)dest) + low_offset);
+}
+
+inline void set_traceid_mask(jbyte mask, traceid* dest) {
+  set_mask(mask, ((jbyte*)dest) + low_offset);
+}
+
+inline void set_leakp_traceid_bits(jbyte bits, traceid* dest) {
+  set_bits(bits, ((jbyte*)dest) + leakp_offset);
+}
+
+inline void set_leakp_traceid_bits_cas(jbyte bits, traceid* dest) {
+  set_bits_cas(bits, ((jbyte*)dest) + leakp_offset);
+}
+
+inline void set_leakp_traceid_mask(jbyte mask, traceid* dest) {
+  set_mask(mask, ((jbyte*)dest) + leakp_offset);
+}
+
+#endif // SHARE_VM_JFR_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDBITS_INLINE_HPP
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp"
+#include "runtime/safepoint.hpp"
+#include "runtime/orderAccess.inline.hpp"
+
+// Alternating epochs on each rotation allow for concurrent tagging.
+// The regular epoch shift happens only during a safepoint.
+// The fence is there only for the emergency dump case which happens outside of safepoint.
+bool JfrTraceIdEpoch::_epoch_state = false;
+void JfrTraceIdEpoch::shift_epoch() {
+  _epoch_state = !_epoch_state;
+  if (!SafepointSynchronize::is_at_safepoint()) {
+    OrderAccess::fence();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDEPOCH_HPP
+#define SHARE_VM_JFR_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDEPOCH_HPP
+
+#include "memory/allocation.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
+
+#define USED_BIT 1
+#define METHOD_USED_BIT (USED_BIT << 2)
+#define EPOCH_1_SHIFT 0
+#define EPOCH_2_SHIFT 1
+#define LEAKP_SHIFT 8
+
+#define USED_EPOCH_1_BIT (USED_BIT << EPOCH_1_SHIFT)
+#define USED_EPOCH_2_BIT (USED_BIT << EPOCH_2_SHIFT)
+#define LEAKP_USED_EPOCH_1_BIT (USED_EPOCH_1_BIT << LEAKP_SHIFT)
+#define LEAKP_USED_EPOCH_2_BIT (USED_EPOCH_2_BIT << LEAKP_SHIFT)
+#define METHOD_USED_EPOCH_1_BIT (METHOD_USED_BIT << EPOCH_1_SHIFT)
+#define METHOD_USED_EPOCH_2_BIT (METHOD_USED_BIT << EPOCH_2_SHIFT)
+#define METHOD_AND_CLASS_IN_USE_BITS (METHOD_USED_BIT | USED_BIT)
+#define METHOD_AND_CLASS_IN_USE_EPOCH_1_BITS (METHOD_AND_CLASS_IN_USE_BITS << EPOCH_1_SHIFT)
+#define METHOD_AND_CLASS_IN_USE_EPOCH_2_BITS (METHOD_AND_CLASS_IN_USE_BITS << EPOCH_2_SHIFT)
+
+class JfrTraceIdEpoch : AllStatic {
+  friend class JfrCheckpointManager;
+ private:
+  static bool _epoch_state;
+  static void shift_epoch();
+
+ public:
+  static bool epoch() {
+    return _epoch_state;
+  }
+
+  static jlong epoch_address() {
+    return (jlong)&_epoch_state;
+  }
+
+  static u1 current() {
+    return _epoch_state ? (u1)1 : (u1)0;
+  }
+
+  static u1 previous() {
+    return _epoch_state ? (u1)0 : (u1)1;
+  }
+
+  static traceid in_use_this_epoch_bit() {
+    return _epoch_state ? USED_EPOCH_2_BIT : USED_EPOCH_1_BIT;
+  }
+
+  static traceid in_use_prev_epoch_bit() {
+    return _epoch_state ? USED_EPOCH_1_BIT : USED_EPOCH_2_BIT;
+  }
+
+  static traceid leakp_in_use_this_epoch_bit() {
+    return _epoch_state ? LEAKP_USED_EPOCH_2_BIT : LEAKP_USED_EPOCH_1_BIT;
+  }
+
+  static traceid leakp_in_use_prev_epoch_bit() {
+    return _epoch_state ? LEAKP_USED_EPOCH_1_BIT : LEAKP_USED_EPOCH_2_BIT;
+  }
+
+  static traceid method_in_use_this_epoch_bit() {
+    return _epoch_state ? METHOD_USED_EPOCH_2_BIT : METHOD_USED_EPOCH_1_BIT;
+  }
+
+  static traceid method_in_use_prev_epoch_bit() {
+    return _epoch_state ? METHOD_USED_EPOCH_1_BIT : METHOD_USED_EPOCH_2_BIT;
+  }
+
+  static traceid method_and_class_in_use_this_epoch_bits() {
+    return _epoch_state ? METHOD_AND_CLASS_IN_USE_EPOCH_2_BITS : METHOD_AND_CLASS_IN_USE_EPOCH_1_BITS;
+  }
+
+  static traceid method_and_class_in_use_prev_epoch_bits() {
+    return _epoch_state ? METHOD_AND_CLASS_IN_USE_EPOCH_1_BITS :  METHOD_AND_CLASS_IN_USE_EPOCH_2_BITS;
+  }
+};
+
+#endif // SHARE_VM_JFR_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDEPOCH_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDMACROS_HPP
+#define SHARE_VM_JFR_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDMACROS_HPP
+
+#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdBits.inline.hpp"
+#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp"
+#include "jfr/support/jfrKlassExtension.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+/**
+ *
+ * If a traceid is used, depending on epoch, either the first or the second bit is tagged.
+ * If a class member (method) is used, either the third or fourth bit is tagged.
+ * Which bit to set is a function of the epoch. This allows for concurrent tagging.
+ *
+ * LeakProfiler subsystem gets its own byte and uses the same tagging scheme but is shifted up 8.
+ *
+ * We also tag the individual method by using the TraceFlag field,
+ * (see jfr/support/jfrTraceIdExtension.hpp for details)
+ *
+ */
+
+// these are defined in jfr/support/jfrKlassExtension.hpp
+//
+// #define JDK_JFR_EVENT_SUBKLASS  16
+// #define JDK_JFR_EVENT_KLASS     32
+// #define EVENT_HOST_KLASS        64
+
+#define IS_JDK_JFR_EVENT_SUBKLASS(ptr) (((ptr)->trace_id() & (JDK_JFR_EVENT_SUBKLASS)) != 0)
+
+#define ANY_USED_BITS (USED_EPOCH_2_BIT         | \
+                       USED_EPOCH_1_BIT         | \
+                       METHOD_USED_EPOCH_2_BIT  | \
+                       METHOD_USED_EPOCH_1_BIT  | \
+                       LEAKP_USED_EPOCH_2_BIT   | \
+                       LEAKP_USED_EPOCH_1_BIT)
+
+#define TRACE_ID_META_BITS (EVENT_HOST_KLASS | JDK_JFR_EVENT_KLASS | JDK_JFR_EVENT_SUBKLASS | ANY_USED_BITS)
+
+#define ANY_EVENT                       (EVENT_HOST_KLASS | JDK_JFR_EVENT_KLASS | JDK_JFR_EVENT_SUBKLASS)
+#define IS_JDK_JFR_EVENT_KLASS(ptr)     (((ptr)->trace_id() & JDK_JFR_EVENT_KLASS) != 0)
+#define IS_EVENT_HOST_KLASS(ptr)        (((ptr)->trace_id() & EVENT_HOST_KLASS) != 0)
+#define IS_NOT_AN_EVENT_KLASS(ptr)      (!IS_EVENT_KLASS(ptr))
+#define IS_NOT_AN_EVENT_SUB_KLASS(ptr)  (!IS_JDK_JFR_EVENT_SUBKLASS(ptr))
+#define IS_NOT_JDK_JFR_EVENT_KLASS(ptr) (!IS_JDK_JFR_EVENT_KLASS(ptr))
+#define EVENT_FLAGS_MASK(ptr)           (((ptr)->trace_id() & ANY_EVENT) != 0)
+#define UNEVENT(ptr)                    ((ptr)->set_trace_id(((ptr)->trace_id()) & ~ANY_EVENT))
+
+#define TRACE_ID_SHIFT 16
+
+#define TRACE_ID_MASKED(id)             (id & ~TRACE_ID_META_BITS)
+#define TRACE_ID_VALUE(id)              (TRACE_ID_MASKED(id) >> TRACE_ID_SHIFT)
+#define TRACE_ID_MASKED_PTR(ptr)        (TRACE_ID_MASKED((ptr)->trace_id()))
+#define TRACE_ID_RAW(ptr)               ((ptr)->trace_id())
+#define TRACE_ID(ptr)                   (TRACE_ID_MASKED_PTR(ptr) >> TRACE_ID_SHIFT)
+#define METHOD_ID(kls, meth)            (TRACE_ID_MASKED_PTR(kls) | (meth)->method_idnum())
+#define SET_TAG(ptr, tag)               (set_traceid_bits(tag, (ptr)->trace_id_addr()))
+#define SET_LEAKP_TAG(ptr, tag)         (set_leakp_traceid_bits(tag, (ptr)->trace_id_addr()))
+#define SET_TAG_CAS(ptr, tag)           (set_traceid_bits_cas(tag, (ptr)->trace_id_addr()))
+#define SET_LEAKP_TAG_CAS(ptr, tag)     (set_leakp_traceid_bits_cas(tag, (ptr)->trace_id_addr()))
+
+#define IN_USE_THIS_EPOCH_BIT           (JfrTraceIdEpoch::in_use_this_epoch_bit())
+#define IN_USE_PREV_EPOCH_BIT           (JfrTraceIdEpoch::in_use_prev_epoch_bit())
+#define LEAKP_IN_USE_THIS_EPOCH_BIT     (JfrTraceIdEpoch::leakp_in_use_this_epoch_bit())
+#define LEAKP_IN_USE_PREV_EPOCH_BIT     (JfrTraceIdEpoch::leakp_in_use_prev_epoch_bit())
+
+#define METHOD_IN_USE_THIS_EPOCH_BIT    (JfrTraceIdEpoch::method_in_use_this_epoch_bit())
+#define METHOD_IN_USE_PREV_EPOCH_BIT    (JfrTraceIdEpoch::method_in_use_prev_epoch_bit())
+#define METHOD_AND_CLASS_IN_USE_THIS_EPOCH_BITS (JfrTraceIdEpoch::method_and_class_in_use_this_epoch_bits())
+#define METHOD_AND_CLASS_IN_USE_PREV_EPOCH_BITS (JfrTraceIdEpoch::method_and_class_in_use_prev_epoch_bits())
+
+#define UNUSE_THIS_EPOCH_MASK           (~(IN_USE_THIS_EPOCH_BIT))
+#define UNUSE_PREV_EPOCH_MASK           (~(IN_USE_PREV_EPOCH_BIT))
+#define LEAKP_UNUSE_THIS_EPOCH_MASK     UNUSE_THIS_EPOCH_MASK
+#define LEAKP_UNUSE_PREV_EPOCH_MASK     UNUSE_PREV_EPOCH_MASK
+
+#define UNUSE_METHOD_THIS_EPOCH_MASK    (~(METHOD_IN_USE_THIS_EPOCH_BIT))
+#define UNUSE_METHOD_PREV_EPOCH_MASK    (~(METHOD_IN_USE_PREV_EPOCH_BIT))
+#define LEAKP_UNUSE_METHOD_THIS_EPOCH_MASK (~(UNUSE_METHOD_THIS_EPOCH_MASK))
+#define LEAKP_UNUSE_METHOD_PREV_EPOCH_MASK (~UNUSE_METHOD_PREV_EPOCH_MASK))
+
+#define UNUSE_METHOD_AND_CLASS_THIS_EPOCH_MASK (~(METHOD_IN_USE_THIS_EPOCH_BIT | IN_USE_THIS_EPOCH_BIT))
+#define UNUSE_METHOD_AND_CLASS_PREV_EPOCH_MASK (~(METHOD_IN_USE_PREV_EPOCH_BIT | IN_USE_PREV_EPOCH_BIT))
+
+#define SET_USED_THIS_EPOCH(ptr)        (SET_TAG(ptr, IN_USE_THIS_EPOCH_BIT))
+#define SET_USED_PREV_EPOCH(ptr)        (SET_TAG_CAS(ptr, IN_USE_PREV_EPOCH_BIT))
+#define SET_LEAKP_USED_THIS_EPOCH(ptr)  (SET_LEAKP_TAG(ptr, IN_USE_THIS_EPOCH_BIT))
+#define SET_LEAKP_USED_PREV_EPOCH(ptr)  (SET_LEAKP_TAG(ptr, IN_USE_PREV_EPOCH_BIT))
+#define SET_METHOD_AND_CLASS_USED_THIS_EPOCH(kls) (SET_TAG(kls, METHOD_AND_CLASS_IN_USE_THIS_EPOCH_BITS))
+
+#define USED_THIS_EPOCH(ptr)            (((ptr)->trace_id() & IN_USE_THIS_EPOCH_BIT) != 0)
+#define NOT_USED_THIS_EPOCH(ptr)        (!USED_THIS_EPOCH(ptr))
+#define USED_PREV_EPOCH(ptr)            (((ptr)->trace_id() & IN_USE_PREV_EPOCH_BIT) != 0)
+#define NOT_USED_PREV_EPOCH(ptr)        (!USED_PREV_EPOCH(ptr))
+#define USED_ANY_EPOCH(ptr)             (((ptr)->trace_id() & (USED_EPOCH_2_BIT | USED_EPOCH_1_BIT)) != 0)
+#define NOT_USED_ANY_EPOCH(ptr)         (!USED_ANY_EPOCH(ptr))
+
+#define LEAKP_USED_THIS_EPOCH(ptr)      (((ptr)->trace_id() & LEAKP_IN_USE_THIS_EPOCH_BIT) != 0)
+#define LEAKP_NOT_USED_THIS_EPOCH(ptr)  (!LEAKP_USED_THIS_EPOCH(ptr))
+#define LEAKP_USED_PREV_EPOCH(ptr)      (((ptr)->trace_id() & LEAKP_IN_USE_PREV_EPOCH_BIT) != 0)
+#define LEAKP_NOT_USED_PREV_EPOCH(ptr)  (!LEAKP_USED_PREV_EPOCH(ptr))
+#define LEAKP_USED_ANY_EPOCH(ptr)       (((ptr)->trace_id() & (LEAKP_USED_EPOCH_2_BIT | LEAKP_USED_EPOCH_1_BIT)) != 0)
+#define LEAKP_NOT_USED_ANY_EPOCH(ptr)   (!LEAKP_USED_ANY_EPOCH(ptr))
+
+#define ANY_USED_THIS_EPOCH(ptr)        (((ptr)->trace_id() & (LEAKP_IN_USE_THIS_EPOCH_BIT | IN_USE_THIS_EPOCH_BIT)) != 0)
+#define ANY_NOT_USED_THIS_EPOCH(ptr)    (!ANY_USED_THIS_EPOCH(ptr))
+#define ANY_USED_PREV_EPOCH(ptr)        (((ptr)->trace_id() & (LEAKP_IN_USE_PREV_EPOCH_BIT | IN_USE_PREV_EPOCH_BIT)) != 0)
+#define ANY_NOT_USED_PREV_EPOCH(ptr)    (!ANY_USED_PREV_EPOCH(ptr))
+
+#define METHOD_USED_THIS_EPOCH(kls)     (((kls)->trace_id() & METHOD_IN_USE_THIS_EPOCH_BIT) != 0)
+#define METHOD_NOT_USED_THIS_EPOCH(kls) (!METHOD_USED_THIS_EPOCH(kls))
+#define METHOD_USED_PREV_EPOCH(kls)     (((kls)->trace_id() & METHOD_IN_USE_PREV_EPOCH_BIT) != 0)
+#define METHOD_NOT_USED_PREV_EPOCH(kls) (!METHOD_USED_PREV_EPOCH(kls))
+#define METHOD_USED_ANY_EPOCH(kls)      (((kls)->trace_id() & (METHOD_IN_USE_PREV_EPOCH_BIT | METHOD_IN_USE_THIS_EPOCH_BIT)) != 0)
+
+#define METHOD_NOT_USED_ANY_EPOCH(kls)  (!METHOD_USED_ANY_EPOCH(kls))
+
+#define METHOD_AND_CLASS_USED_THIS_EPOCH(kls) ((((kls)->trace_id() & METHOD_AND_CLASS_IN_USE_THIS_EPOCH_BITS) == \
+                                                                     METHOD_AND_CLASS_IN_USE_THIS_EPOCH_BITS) != 0)
+
+#define METHOD_AND_CLASS_USED_PREV_EPOCH(kls) ((((kls)->trace_id() & METHOD_AND_CLASS_IN_USE_PREV_EPOCH_BITS) == \
+                                                                     METHOD_AND_CLASS_IN_USE_PREV_EPOCH_BITS) != 0)
+
+#define METHOD_AND_CLASS_USED_ANY_EPOCH(kls)     ((METHOD_USED_ANY_EPOCH(kls) && USED_ANY_EPOCH(kls)) != 0)
+#define METHOD_AND_CLASS_NOT_USED_ANY_EPOCH(kls) (!METHOD_AND_CLASS_USED_ANY_EPOCH(kls))
+
+#define LEAKP_METHOD_IN_USE_THIS_EPOCH  (LEAKP_IN_USE_THIS_EPOCH_BIT | METHOD_IN_USE_THIS_EPOCH_BIT)
+#define LEAKP_METHOD_IN_USE_PREV_EPOCH  (LEAKP_IN_USE_PREV_EPOCH_BIT | METHOD_IN_USE_PREV_EPOCH_BIT)
+#define LEAKP_METHOD_USED_THIS_EPOCH(ptr)  ((((ptr)->trace_id() & LEAKP_METHOD_IN_USE_THIS_EPOCH) == \
+                                                                  LEAKP_METHOD_IN_USE_THIS_EPOCH) != 0)
+#define LEAKP_METHOD_NOT_USED_THIS_EPOCH(kls) (!LEAKP_METHOD_USED_THIS_EPOCH(kls))
+#define LEAKP_METHOD_USED_PREV_EPOCH(ptr)  ((((ptr)->trace_id() & LEAKP_METHOD_IN_USE_PREV_EPOCH) == \
+                                                                  LEAKP_METHOD_IN_USE_PREV_EPOCH) != 0)
+#define LEAKP_METHOD_NOT_USED_PREV_EPOCH(kls) (!LEAKP_METHOD_USED_PREV_EPOCH(kls))
+
+#define UNUSE_THIS_EPOCH(ptr)           (set_traceid_mask(UNUSE_THIS_EPOCH_MASK, (ptr)->trace_id_addr()))
+#define UNUSE_PREV_EPOCH(ptr)           (set_traceid_mask(UNUSE_PREV_EPOCH_MASK, (ptr)->trace_id_addr()))
+#define UNUSE_METHOD_THIS_EPOCH(kls)    (set_traceid_mask(UNUSE_METHOD_THIS_EPOCH_MASK, (kls)->trace_id_addr()))
+#define UNUSE_METHOD_PREV_EPOCH(kls)    (set_traceid_mask(UNUSE_METHOD_PREV_EPOCH_MASK, (kls)->trace_id_addr()))
+
+#define LEAKP_UNUSE_THIS_EPOCH(ptr)     (set_leakp_traceid_mask(UNUSE_THIS_EPOCH_MASK, (ptr)->trace_id_addr()))
+#define LEAKP_UNUSE_PREV_EPOCH(ptr)     (set_leakp_traceid_mask(UNUSE_PREV_EPOCH_MASK, (ptr)->trace_id_addr()))
+#define LEAKP_UNUSE_METHOD_THIS_EPOCH(kls) (set_leakp_traceid_mask(UNUSE_METHOD_THIS_EPOCH_MASK, (kls)->trace_id_addr()))
+#define LEAKP_UNUSE_METHOD_PREV_EPOCH(kls) (set_leakp_traceid_mask(UNUSE_METHOD_PREV_EPOCH_MASK, (kls)->trace_id_addr()))
+
+#define ANY_USED(ptr)                   (((ptr)->trace_id() & ANY_USED_BITS) != 0)
+#define ANY_NOT_USED(ptr)               (!ANY_USED(ptr))
+
+#define UNUSE_METHOD_AND_CLASS_THIS_EPOCH(kls) (set_traceid_mask(UNUSE_METHOD_AND_CLASS_THIS_EPOCH_MASK, (kls)->trace_id_addr()))
+#define LEAKP_UNUSE_METHOD_AND_CLASS_THIS_EPOCH(kls) (set_leakp_traceid_mask(UNUSE_METHOD_AND_CLASS_THIS_EPOCH_MASK, (kls)->trace_id_addr()))
+#define UNUSE_METHOD_AND_CLASS_PREV_EPOCH(kls) (set_traceid_mask(UNUSE_METHOD_AND_CLASS_PREV_EPOCH_MASK, (kls)->trace_id_addr()))
+#define LEAKP_UNUSE_METHODS_AND_CLASS_PREV_EPOCH(kls) (set_leakp_traceid_mask(UNUSE_METHOD_AND_CLASS_PREV_EPOCH_MASK, (kls)->trace_id_addr()))
+
+#define METHOD_FLAG_USED_THIS_EPOCH(m)       ((m)->is_trace_flag_set((jbyte)JfrTraceIdEpoch::in_use_this_epoch_bit()))
+#define METHOD_FLAG_NOT_USED_THIS_EPOCH(m)   (!METHOD_FLAG_USED_THIS_EPOCH(m))
+#define SET_METHOD_FLAG_USED_THIS_EPOCH(m)   ((m)->set_trace_flag((jbyte)JfrTraceIdEpoch::in_use_this_epoch_bit()))
+#define METHOD_FLAG_USED_PREV_EPOCH(m)       ((m)->is_trace_flag_set((jbyte)JfrTraceIdEpoch::in_use_prev_epoch_bit()))
+#define METHOD_FLAG_NOT_USED_PREV_EPOCH(m)   (!METHOD_FLAG_USED_PREV_EPOCH(m))
+#define METHOD_FLAG_USED_ANY_EPOCH(m)        ((METHOD_FLAG_USED_THIS_EPOCH(m) || METHOD_FLAG_USED_PREV_EPOCH(m)) != 0)
+#define METHOD_FLAG_NOT_USED_ANY_EPOCH(m)    ((METHOD_FLAG_NOT_USED_THIS_EPOCH(m) && METHOD_FLAG_NOT_USED_PREV_EPOCH(m)) != 0)
+#define CLEAR_METHOD_FLAG_USED_THIS_EPOCH(m) (clear_bits_cas((jbyte)JfrTraceIdEpoch::in_use_this_epoch_bit(), (m)->trace_flags_addr()))
+#define CLEAR_METHOD_FLAG_USED_PREV_EPOCH(m) (clear_bits_cas((jbyte)JfrTraceIdEpoch::in_use_prev_epoch_bit(), (m)->trace_flags_addr()))
+
+#endif // SHARE_VM_JFR_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDMACROS_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/jfrEventSetting.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/recorder/jfrEventSetting.inline.hpp"
+
+JfrNativeSettings JfrEventSetting::_jvm_event_settings;
+
+bool JfrEventSetting::set_threshold(jlong id, jlong threshold_ticks) {
+  JfrEventId event_id = (JfrEventId)id;
+  assert(bounds_check_event(event_id), "invariant");
+  setting(event_id).threshold_ticks = threshold_ticks;
+  return true;
+}
+
+bool JfrEventSetting::set_cutoff(jlong id, jlong cutoff_ticks) {
+  JfrEventId event_id = (JfrEventId)id;
+  assert(bounds_check_event(event_id), "invariant");
+  setting(event_id).cutoff_ticks = cutoff_ticks;
+  return true;
+}
+
+void JfrEventSetting::set_stacktrace(jlong id, bool enabled) {
+  JfrEventId event_id = (JfrEventId)id;
+  assert(bounds_check_event(event_id), "invariant");
+  setting(event_id).stacktrace = enabled;
+}
+
+void JfrEventSetting::set_enabled(jlong id, bool enabled) {
+  JfrEventId event_id = (JfrEventId)id;
+  assert(bounds_check_event(event_id), "invariant");
+  setting(event_id).enabled = enabled;
+}
+
+#ifdef ASSERT
+bool JfrEventSetting::bounds_check_event(jlong id) {
+  if ((unsigned)id < NUM_RESERVED_EVENTS || (unsigned)id >= MaxJfrEventId) {
+    return false;
+  }
+  return true;
+}
+#endif // ASSERT
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/jfrEventSetting.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_RECORDER_JFREVENTSETTING_HPP
+#define SHARE_VM_JFR_RECORDER_JFREVENTSETTING_HPP
+
+#include "jni.h"
+#include "jfr/utilities/jfrAllocation.hpp"
+#include "jfrfiles/jfrEventControl.hpp"
+
+//
+// Native event settings as an associative array using the event id as key.
+//
+class JfrEventSetting : AllStatic {
+ private:
+  static JfrNativeSettings _jvm_event_settings;
+  static jfrNativeEventSetting& setting(JfrEventId event_id);
+
+ public:
+  static void set_enabled(jlong event_id, bool enabled);
+  static bool is_enabled(JfrEventId event_id);
+  static void set_stacktrace(jlong event_id, bool enabled);
+  static bool has_stacktrace(JfrEventId event_id);
+  static bool set_threshold(jlong event_id, jlong threshold_ticks);
+  static jlong threshold(JfrEventId event_id);
+  static bool set_cutoff(jlong event_id, jlong cutoff_ticks);
+  static jlong cutoff(JfrEventId event_id);
+  DEBUG_ONLY(static bool bounds_check_event(jlong id);)
+};
+
+#endif //  SHARE_VM_JFR_RECORDER_JFREVENTSETTING_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/jfrEventSetting.inline.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_RECORDER_JFREVENTSETTING_INLINE_HPP
+#define SHARE_VM_JFR_RECORDER_JFREVENTSETTING_INLINE_HPP
+
+#include "jfr/recorder/jfrEventSetting.hpp"
+
+inline jfrNativeEventSetting& JfrEventSetting::setting(JfrEventId event_id) {
+  return _jvm_event_settings.bits[event_id];
+}
+
+inline bool JfrEventSetting::is_enabled(JfrEventId event_id) {
+  return 0 != setting(event_id).enabled;
+}
+
+inline bool JfrEventSetting::has_stacktrace(JfrEventId event_id) {
+  return 0 != setting(event_id).stacktrace;
+}
+
+inline jlong JfrEventSetting::threshold(JfrEventId event_id) {
+  return setting(event_id).threshold_ticks;
+}
+
+inline jlong JfrEventSetting::cutoff(JfrEventId event_id) {
+  return setting(event_id).cutoff_ticks;
+}
+
+#endif // SHARE_VM_JFR_RECORDER_JFREVENTSETTING_INLINE_HPP
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,360 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/dcmd/jfrDcmds.hpp"
+#include "jfr/instrumentation/jfrJvmtiAgent.hpp"
+#include "jfr/jni/jfrJavaSupport.hpp"
+#include "jfr/periodic/jfrOSInterface.hpp"
+#include "jfr/periodic/sampling/jfrThreadSampler.hpp"
+#include "jfr/recorder/jfrRecorder.hpp"
+#include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
+#include "jfr/recorder/repository/jfrRepository.hpp"
+#include "jfr/recorder/service/jfrOptionSet.hpp"
+#include "jfr/recorder/service/jfrPostBox.hpp"
+#include "jfr/recorder/service/jfrRecorderService.hpp"
+#include "jfr/recorder/service/jfrRecorderThread.hpp"
+#include "jfr/recorder/storage/jfrStorage.hpp"
+#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
+#include "jfr/recorder/stringpool/jfrStringPool.hpp"
+#include "jfr/utilities/jfrTime.hpp"
+#include "jfr/writers/jfrJavaEventWriter.hpp"
+#include "logging/log.hpp"
+#include "logging/logStream.hpp"
+#include "memory/resourceArea.inline.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/flags/jvmFlag.hpp"
+#include "runtime/globals.hpp"
+
+static bool is_disabled_on_command_line() {
+  static const size_t length = strlen("FlightRecorder");
+  static JVMFlag* const flight_recorder_flag = JVMFlag::find_flag("FlightRecorder", length);
+  assert(flight_recorder_flag != NULL, "invariant");
+  return flight_recorder_flag->is_command_line() ? !FlightRecorder : false;
+}
+
+bool JfrRecorder::is_disabled() {
+  return is_disabled_on_command_line();
+}
+
+static bool set_flight_recorder_flag(bool flag_value) {
+  JVMFlag::boolAtPut((char*)"FlightRecorder", &flag_value, JVMFlag::MANAGEMENT);
+  return FlightRecorder;
+}
+
+static bool _enabled = false;
+
+static bool enable() {
+  assert(!_enabled, "invariant");
+  _enabled = set_flight_recorder_flag(true);
+  return _enabled;
+}
+
+bool JfrRecorder::is_enabled() {
+  return _enabled;
+}
+
+bool JfrRecorder::on_vm_init() {
+  if (!is_disabled()) {
+    if (FlightRecorder || StartFlightRecording != NULL) {
+      enable();
+    }
+  }
+  // fast time initialization
+  return JfrTime::initialize();
+}
+
+static JfrStartFlightRecordingDCmd* _startup_recording = NULL;
+
+// Parsing options here to detect errors as soon as possible
+static bool parse_startup_recording(TRAPS) {
+  assert(StartFlightRecording != NULL, "invariant");
+  CmdLine cmdline(StartFlightRecording, strlen(StartFlightRecording), true);
+  _startup_recording->parse(&cmdline, ',', THREAD);
+  if (HAS_PENDING_EXCEPTION) {
+    java_lang_Throwable::print(PENDING_EXCEPTION, tty);
+    CLEAR_PENDING_EXCEPTION;
+    return false;
+  }
+  return true;
+}
+
+static bool initialize_startup_recording(TRAPS) {
+  if (StartFlightRecording != NULL) {
+    _startup_recording = new (ResourceObj::C_HEAP, mtTracing) JfrStartFlightRecordingDCmd(tty, true);
+    return _startup_recording != NULL && parse_startup_recording(THREAD);
+  }
+  return true;
+}
+
+static bool startup_recording(TRAPS) {
+  if (_startup_recording == NULL) {
+    return true;
+  }
+  log_trace(jfr, system)("Starting up Jfr startup recording");
+  _startup_recording->execute(DCmd_Source_Internal, Thread::current());
+  delete _startup_recording;
+  _startup_recording = NULL;
+  if (HAS_PENDING_EXCEPTION) {
+    log_debug(jfr, system)("Exception while starting Jfr startup recording");
+    CLEAR_PENDING_EXCEPTION;
+    return false;
+  }
+  log_trace(jfr, system)("Finished starting Jfr startup recording");
+  return true;
+}
+
+static void log_jdk_jfr_module_resolution_error(TRAPS) {
+  LogTarget(Error, jfr, system) lt_error;
+  LogTargetHandle handle(lt_error);
+  LogStream stream(handle);
+  JfrJavaSupport::is_jdk_jfr_module_available(&stream, THREAD);
+}
+
+bool JfrRecorder::on_vm_start() {
+  const bool in_graph = JfrJavaSupport::is_jdk_jfr_module_available();
+  Thread* const thread = Thread::current();
+  if (!JfrOptionSet::initialize(thread)) {
+    return false;
+  }
+  if (!register_jfr_dcmds()) {
+    return false;
+  }
+  if (!initialize_startup_recording(thread)) {
+    return false;
+  }
+  if (in_graph) {
+    if (!JfrJavaEventWriter::initialize()) {
+      return false;
+    }
+    if (!JfrOptionSet::configure(thread)) {
+      return false;
+    }
+  }
+  if (!is_enabled()) {
+    return true;
+  }
+  if (!in_graph) {
+    log_jdk_jfr_module_resolution_error(thread);
+    return false;
+  }
+  return startup_recording(thread);
+}
+
+static bool _created = false;
+
+//
+// Main entry point for starting Jfr functionality.
+// Non-protected initializations assume single-threaded setup.
+//
+bool JfrRecorder::create(bool simulate_failure) {
+  assert(!is_disabled(), "invariant");
+  assert(!is_created(), "invariant");
+  if (!is_enabled()) {
+    enable();
+  }
+  if (!create_components() || simulate_failure) {
+    destroy_components();
+    return false;
+  }
+  if (!create_recorder_thread()) {
+    destroy_components();
+    return false;
+  }
+  _created = true;
+  return true;
+}
+
+bool JfrRecorder::is_created() {
+  return _created;
+}
+
+bool JfrRecorder::create_components() {
+  ResourceMark rm;
+  HandleMark hm;
+
+  if (!create_jvmti_agent()) {
+    return false;
+  }
+  if (!create_post_box()) {
+    return false;
+  }
+  if (!create_chunk_repository()) {
+    return false;
+  }
+  if (!create_storage()) {
+    return false;
+  }
+  if (!create_checkpoint_manager()) {
+    return false;
+  }
+  if (!create_stacktrace_repository()) {
+    return false;
+  }
+  if (!create_os_interface()) {
+    return false;
+  }
+  if (!create_stringpool()) {
+    return false;
+  }
+  if (!create_thread_sampling()) {
+    return false;
+  }
+  return true;
+}
+
+// subsystems
+static JfrJvmtiAgent* _jvmti_agent = NULL;
+static JfrPostBox* _post_box = NULL;
+static JfrStorage* _storage = NULL;
+static JfrCheckpointManager* _checkpoint_manager = NULL;
+static JfrRepository* _repository = NULL;
+static JfrStackTraceRepository* _stack_trace_repository;
+static JfrStringPool* _stringpool = NULL;
+static JfrOSInterface* _os_interface = NULL;
+static JfrThreadSampling* _thread_sampling = NULL;
+
+bool JfrRecorder::create_jvmti_agent() {
+  return JfrOptionSet::allow_retransforms() ? JfrJvmtiAgent::create() : true;
+}
+
+bool JfrRecorder::create_post_box() {
+  assert(_post_box == NULL, "invariant");
+  _post_box = JfrPostBox::create();
+  return _post_box != NULL;
+}
+
+bool JfrRecorder::create_chunk_repository() {
+  assert(_repository == NULL, "invariant");
+  assert(_post_box != NULL, "invariant");
+  _repository = JfrRepository::create(*_post_box);
+  return _repository != NULL && _repository->initialize();
+}
+
+bool JfrRecorder::create_os_interface() {
+  assert(_os_interface == NULL, "invariant");
+  _os_interface = JfrOSInterface::create();
+  return _os_interface != NULL && _os_interface->initialize();
+}
+
+bool JfrRecorder::create_storage() {
+  assert(_repository != NULL, "invariant");
+  assert(_post_box != NULL, "invariant");
+  _storage = JfrStorage::create(_repository->chunkwriter(), *_post_box);
+  return _storage != NULL && _storage->initialize();
+}
+
+bool JfrRecorder::create_checkpoint_manager() {
+  assert(_checkpoint_manager == NULL, "invariant");
+  assert(_repository != NULL, "invariant");
+  _checkpoint_manager = JfrCheckpointManager::create(_repository->chunkwriter());
+  return _checkpoint_manager != NULL && _checkpoint_manager->initialize();
+}
+
+bool JfrRecorder::create_stacktrace_repository() {
+  assert(_stack_trace_repository == NULL, "invariant");
+  _stack_trace_repository = JfrStackTraceRepository::create();
+  return _stack_trace_repository != NULL && _stack_trace_repository->initialize();
+}
+
+bool JfrRecorder::create_stringpool() {
+  assert(_stringpool == NULL, "invariant");
+  assert(_repository != NULL, "invariant");
+  _stringpool = JfrStringPool::create(_repository->chunkwriter());
+  return _stringpool != NULL && _stringpool->initialize();
+}
+
+bool JfrRecorder::create_thread_sampling() {
+  assert(_thread_sampling == NULL, "invariant");
+  _thread_sampling = JfrThreadSampling::create();
+  return _thread_sampling != NULL;
+}
+
+void JfrRecorder::destroy_components() {
+  JfrJvmtiAgent::destroy();
+  if (_post_box != NULL) {
+    JfrPostBox::destroy();
+    _post_box = NULL;
+  }
+  if (_repository != NULL) {
+    JfrRepository::destroy();
+    _repository = NULL;
+  }
+  if (_storage != NULL) {
+    JfrStorage::destroy();
+    _storage = NULL;
+  }
+  if (_checkpoint_manager != NULL) {
+    JfrCheckpointManager::destroy();
+    _checkpoint_manager = NULL;
+  }
+  if (_stack_trace_repository != NULL) {
+    JfrStackTraceRepository::destroy();
+    _stack_trace_repository = NULL;
+  }
+  if (_stringpool != NULL) {
+    JfrStringPool::destroy();
+    _stringpool = NULL;
+  }
+  if (_os_interface != NULL) {
+    JfrOSInterface::destroy();
+    _os_interface = NULL;
+  }
+  if (_thread_sampling != NULL) {
+    JfrThreadSampling::destroy();
+    _thread_sampling = NULL;
+  }
+}
+
+bool JfrRecorder::create_recorder_thread() {
+  return JfrRecorderThread::start(_checkpoint_manager, _post_box, Thread::current());
+}
+
+void JfrRecorder::destroy() {
+  assert(is_created(), "invariant");
+  _post_box->post(MSG_SHUTDOWN);
+  JfrJvmtiAgent::destroy();
+}
+
+void JfrRecorder::on_recorder_thread_exit() {
+  assert(!is_recording(), "invariant");
+  // intent is to destroy the recorder instance and components,
+  // but need sensitive coordination not yet in place
+  //
+  // destroy_components();
+  //
+  log_debug(jfr, system)("Recorder thread STOPPED");
+}
+
+void JfrRecorder::start_recording() {
+  _post_box->post(MSG_START);
+}
+
+bool JfrRecorder::is_recording() {
+  return JfrRecorderService::is_recording();
+}
+
+void JfrRecorder::stop_recording() {
+  _post_box->post(MSG_STOP);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/jfrRecorder.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_RECORDER_JFRRECORDER_HPP
+#define SHARE_VM_JFR_RECORDER_JFRRECORDER_HPP
+
+#include "jfr/utilities/jfrAllocation.hpp"
+
+class JavaThread;
+class Thread;
+
+//
+// Represents the singleton instance of Flight Recorder.
+// Lifecycle management of recorder components.
+//
+class JfrRecorder : public JfrCHeapObj {
+  friend class Jfr;
+  friend void recorderthread_entry(JavaThread*, Thread*);
+ private:
+  static bool create_checkpoint_manager();
+  static bool create_chunk_repository();
+  static bool create_jvmti_agent();
+  static bool create_os_interface();
+  static bool create_post_box();
+  static bool create_recorder_thread();
+  static bool create_stacktrace_repository();
+  static bool create_storage();
+  static bool create_stringpool();
+  static bool create_thread_sampling();
+  static bool create_components();
+  static void destroy_components();
+  static void on_recorder_thread_exit();
+  static bool on_vm_start();
+  static bool on_vm_init();
+
+ public:
+  static bool is_enabled();
+  static bool is_disabled();
+  static bool create(bool simulate_failure);
+  static bool is_created();
+  static void destroy();
+  static void start_recording();
+  static bool is_recording();
+  static void stop_recording();
+};
+
+#endif // SHARE_VM_JFR_RECORDER_JFRRECORDER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/repository/jfrChunkSizeNotifier.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/jni/jfrJavaSupport.hpp"
+#include "jfr/recorder/repository/jfrChunkWriter.hpp"
+#include "jfr/recorder/repository/jfrChunkSizeNotifier.hpp"
+
+size_t JfrChunkSizeNotifier::_chunk_size_threshold = 0;
+
+void JfrChunkSizeNotifier::set_chunk_size_threshold(size_t bytes) {
+  _chunk_size_threshold = bytes;
+}
+
+size_t JfrChunkSizeNotifier::chunk_size_threshold() {
+  return _chunk_size_threshold;
+}
+
+static jobject new_chunk_monitor = NULL;
+
+// lazy install
+static jobject get_new_chunk_monitor(Thread* thread) {
+  static bool initialized = false;
+  if (initialized) {
+    assert(new_chunk_monitor != NULL, "invariant");
+    return new_chunk_monitor;
+  }
+  assert(new_chunk_monitor == NULL, "invariant");
+  // read static field
+  HandleMark hm(thread);
+  static const char klass[] = "jdk/jfr/internal/JVM";
+  static const char field[] = "FILE_DELTA_CHANGE";
+  static const char signature[] = "Ljava/lang/Object;";
+  JavaValue result(T_OBJECT);
+  JfrJavaArguments field_args(&result, klass, field, signature, thread);
+  JfrJavaSupport::get_field_global_ref(&field_args, thread);
+  new_chunk_monitor = result.get_jobject();
+  initialized = new_chunk_monitor != NULL;
+  return new_chunk_monitor;
+}
+
+void JfrChunkSizeNotifier::notify() {
+  Thread* const thread = Thread::current();
+  JfrJavaSupport::notify_all(get_new_chunk_monitor(thread), thread);
+}
+
+void JfrChunkSizeNotifier::release_monitor() {
+  if (new_chunk_monitor != NULL) {
+    JfrJavaSupport::destroy_global_jni_handle(new_chunk_monitor);
+    new_chunk_monitor = NULL;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/repository/jfrChunkSizeNotifier.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_RECORDER_REPOSITORY_JFRRCHUNKSIZENOTIFIER_HPP
+#define SHARE_VM_JFR_RECORDER_REPOSITORY_JFRRCHUNKSIZENOTIFIER_HPP
+
+#include "memory/allocation.hpp"
+
+//
+// Responsible for notifications about current chunk size now exceeding threshold.
+// This is a means to initiate a chunk rotation on the basis of size written.
+//
+class JfrChunkSizeNotifier : AllStatic {
+  friend class JfrRecorder;
+ private:
+  static size_t _chunk_size_threshold;
+  static void release_monitor();
+ public:
+  static void set_chunk_size_threshold(size_t bytes);
+  static size_t chunk_size_threshold();
+  static void notify();
+};
+
+#endif // SHARE_VM_JFR_RECORDER_REPOSITORY_JFRRCHUNKSIZENOTIFIER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/repository/jfrChunkState.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/dcmd/jfrDcmds.hpp"
+#include "jfr/recorder/jfrRecorder.hpp"
+#include "jfr/recorder/repository/jfrChunkState.hpp"
+#include "jfr/recorder/repository/jfrChunkWriter.hpp"
+#include "jfr/utilities/jfrTime.hpp"
+#include "jfr/utilities/jfrTimeConverter.hpp"
+#include "logging/log.hpp"
+#include "runtime/os.inline.hpp"
+#include "runtime/thread.inline.hpp"
+
+JfrChunkState::JfrChunkState() :
+  _path(NULL),
+  _start_ticks(0),
+  _start_nanos(0),
+  _previous_start_ticks(0),
+  _previous_start_nanos(0),
+  _previous_checkpoint_offset(0) {}
+
+JfrChunkState::~JfrChunkState() {
+  reset();
+}
+
+void JfrChunkState::reset() {
+  if (_path != NULL) {
+    JfrCHeapObj::free(_path, strlen(_path) + 1);
+    _path = NULL;
+  }
+  set_previous_checkpoint_offset(0);
+}
+
+void JfrChunkState::set_previous_checkpoint_offset(jlong offset) {
+  _previous_checkpoint_offset = offset;
+}
+
+jlong JfrChunkState::previous_checkpoint_offset() const {
+  return _previous_checkpoint_offset;
+}
+
+jlong JfrChunkState::previous_start_ticks() const {
+  return _previous_start_ticks;
+}
+
+jlong JfrChunkState::previous_start_nanos() const {
+  return _previous_start_nanos;
+}
+
+void JfrChunkState::update_start_ticks() {
+  _start_ticks = JfrTicks::now();
+}
+
+void JfrChunkState::update_start_nanos() {
+  _start_nanos = os::javaTimeMillis() * JfrTimeConverter::NANOS_PER_MILLISEC;
+}
+
+void JfrChunkState::save_current_and_update_start_ticks() {
+  _previous_start_ticks = _start_ticks;
+  update_start_ticks();
+}
+
+void JfrChunkState::save_current_and_update_start_nanos() {
+  _previous_start_nanos = _start_nanos;
+  update_start_nanos();
+}
+
+void JfrChunkState::update_time_to_now() {
+  save_current_and_update_start_nanos();
+  save_current_and_update_start_ticks();
+}
+
+jlong JfrChunkState::last_chunk_duration() const {
+  return _start_nanos - _previous_start_nanos;
+}
+
+static char* copy_path(const char* path) {
+  assert(path != NULL, "invariant");
+  const size_t path_len = strlen(path);
+  char* new_path = JfrCHeapObj::new_array<char>(path_len + 1);
+  strncpy(new_path, path, path_len);
+  new_path[path_len] = '\0';
+  return new_path;
+}
+
+void JfrChunkState::set_path(const char* path) {
+  assert(JfrStream_lock->owned_by_self(), "invariant");
+  if (_path != NULL) {
+    JfrCHeapObj::free(_path, strlen(_path) + 1);
+    _path = NULL;
+  }
+  if (path != NULL) {
+    _path = copy_path(path);
+  }
+}
+
+const char* JfrChunkState::path() const {
+  return _path;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/repository/jfrChunkState.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_RECORDER_REPOSITORY_JFRRCHUNKSTATE_HPP
+#define SHARE_VM_JFR_RECORDER_REPOSITORY_JFRRCHUNKSTATE_HPP
+
+#include "jni.h"
+#include "jfr/utilities/jfrAllocation.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
+
+class JfrChunkState : public JfrCHeapObj {
+  friend class JfrChunkWriter;
+ private:
+  char* _path;
+  jlong _start_ticks;
+  jlong _start_nanos;
+  jlong _previous_start_ticks;
+  jlong _previous_start_nanos;
+  jlong _previous_checkpoint_offset;
+
+  void update_start_ticks();
+  void update_start_nanos();
+  void save_current_and_update_start_ticks();
+  void save_current_and_update_start_nanos();
+
+  JfrChunkState();
+  ~JfrChunkState();
+  void reset();
+  jlong previous_checkpoint_offset() const;
+  void set_previous_checkpoint_offset(jlong offset);
+  jlong previous_start_ticks() const;
+  jlong previous_start_nanos() const;
+  jlong last_chunk_duration() const;
+  void update_time_to_now();
+  void set_path(const char* path);
+  const char* path() const;
+};
+
+#endif // SHARE_VM_JFR_RECORDER_REPOSITORY_JFRRCHUNKSTATE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/repository/jfrChunkWriter.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/recorder/repository/jfrChunkState.hpp"
+#include "jfr/recorder/repository/jfrChunkWriter.hpp"
+#include "jfr/recorder/service/jfrOptionSet.hpp"
+#include "jfr/utilities/jfrTime.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/os.hpp"
+
+const u2 JFR_VERSION_MAJOR = 2;
+const u2 JFR_VERSION_MINOR = 0;
+
+static const size_t MAGIC_LEN = 4;
+static const size_t FILEHEADER_SLOT_SIZE = 8;
+static const size_t CHUNK_SIZE_OFFSET = 8;
+
+JfrChunkWriter::JfrChunkWriter() : JfrChunkWriterBase(NULL), _chunkstate(NULL) {}
+
+bool JfrChunkWriter::initialize() {
+  assert(_chunkstate == NULL, "invariant");
+  _chunkstate = new JfrChunkState();
+  return _chunkstate != NULL;
+}
+
+static fio_fd open_existing(const char* path) {
+  return os::open(path, O_RDWR, S_IREAD | S_IWRITE);
+}
+
+static fio_fd open_chunk(const char* path) {
+  assert(JfrStream_lock->owned_by_self(), "invariant");
+  return path != NULL ? open_existing(path) : invalid_fd;
+}
+
+bool JfrChunkWriter::open() {
+  assert(_chunkstate != NULL, "invariant");
+  JfrChunkWriterBase::reset(open_chunk(_chunkstate->path()));
+  const bool is_open = this->has_valid_fd();
+  if (is_open) {
+    this->bytes("FLR", MAGIC_LEN);
+    this->be_write((u2)JFR_VERSION_MAJOR);
+    this->be_write((u2)JFR_VERSION_MINOR);
+    this->reserve(6 * FILEHEADER_SLOT_SIZE);
+    // u8 chunk_size
+    // u8 initial checkpoint offset
+    // u8 metadata section offset
+    // u8 chunk start nanos
+    // u8 chunk duration nanos
+    // u8 chunk start ticks
+    this->be_write(JfrTime::frequency());
+    // chunk capabilities, CompressedIntegers etc
+    this->be_write((u4)JfrOptionSet::compressed_integers() ? 1 : 0);
+    _chunkstate->reset();
+  }
+  return is_open;
+}
+
+size_t JfrChunkWriter::close(intptr_t metadata_offset) {
+  write_header(metadata_offset);
+  this->flush();
+  this->close_fd();
+  return size_written();
+}
+
+void JfrChunkWriter::write_header(intptr_t metadata_offset) {
+  assert(this->is_valid(), "invariant");
+  // Chunk size
+  this->write_be_at_offset(size_written(), CHUNK_SIZE_OFFSET);
+  // initial checkpoint event offset
+  this->write_be_at_offset(_chunkstate->previous_checkpoint_offset(), CHUNK_SIZE_OFFSET + (1 * FILEHEADER_SLOT_SIZE));
+  // metadata event offset
+  this->write_be_at_offset(metadata_offset, CHUNK_SIZE_OFFSET + (2 * FILEHEADER_SLOT_SIZE));
+  // start of chunk in nanos since epoch
+  this->write_be_at_offset(_chunkstate->previous_start_nanos(), CHUNK_SIZE_OFFSET + (3 * FILEHEADER_SLOT_SIZE));
+  // duration of chunk in nanos
+  this->write_be_at_offset(_chunkstate->last_chunk_duration(), CHUNK_SIZE_OFFSET + (4 * FILEHEADER_SLOT_SIZE));
+  // start of chunk in ticks
+  this->write_be_at_offset(_chunkstate->previous_start_ticks(), CHUNK_SIZE_OFFSET + (5 * FILEHEADER_SLOT_SIZE));
+}
+
+void JfrChunkWriter::set_chunk_path(const char* chunk_path) {
+  _chunkstate->set_path(chunk_path);
+}
+
+intptr_t JfrChunkWriter::size_written() const {
+  return this->is_valid() ? this->current_offset() : 0;
+}
+
+intptr_t JfrChunkWriter::previous_checkpoint_offset() const {
+  return _chunkstate->previous_checkpoint_offset();
+}
+
+void JfrChunkWriter::set_previous_checkpoint_offset(intptr_t offset) {
+  _chunkstate->set_previous_checkpoint_offset(offset);
+}
+
+void JfrChunkWriter::time_stamp_chunk_now() {
+  _chunkstate->update_time_to_now();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/repository/jfrChunkWriter.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_RECORDER_REPOSITORY_JFRCHUNKWRITER_HPP
+#define SHARE_VM_JFR_RECORDER_REPOSITORY_JFRCHUNKWRITER_HPP
+
+#include "jfr/writers/jfrStorageAdapter.hpp"
+#include "jfr/writers/jfrStreamWriterHost.inline.hpp"
+#include "jfr/writers/jfrWriterHost.inline.hpp"
+
+typedef MallocAdapter<M> JfrStreamBuffer; // 1 mb buffered writes
+typedef StreamWriterHost<JfrStreamBuffer, JfrCHeapObj> JfrBufferedStreamWriter;
+typedef WriterHost<BigEndianEncoder, CompressedIntegerEncoder, JfrBufferedStreamWriter> JfrChunkWriterBase;
+
+class JfrChunkState;
+
+class JfrChunkWriter : public JfrChunkWriterBase {
+  friend class JfrRepository;
+ private:
+  JfrChunkState* _chunkstate;
+
+  bool open();
+  size_t close(intptr_t metadata_offset);
+  void write_header(intptr_t metadata_offset);
+  void set_chunk_path(const char* chunk_path);
+
+ public:
+  JfrChunkWriter();
+  bool initialize();
+  intptr_t size_written() const;
+  intptr_t previous_checkpoint_offset() const;
+  void set_previous_checkpoint_offset(intptr_t offset);
+  void time_stamp_chunk_now();
+};
+
+#endif // SHARE_VM_JFR_RECORDER_REPOSITORY_JFRCHUNKWRITER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/jfrEvents.hpp"
+#include "jfr/leakprofiler/leakProfiler.hpp"
+#include "jfr/recorder/repository/jfrEmergencyDump.hpp"
+#include "jfr/recorder/service/jfrPostBox.hpp"
+#include "jfr/recorder/service/jfrRecorderService.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
+#include "memory/resourceArea.hpp"
+#include "runtime/atomic.hpp"
+#include "runtime/handles.hpp"
+#include "runtime/globals.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/thread.hpp"
+
+/*
+* We are just about to exit the VM, so we will be very aggressive
+* at this point in order to increase overall success of dumping jfr data:
+*
+* 1. if the thread state is not "_thread_in_vm", we will quick transition
+*    it to "_thread_in_vm".
+* 2. the nesting state for both resource and handle areas are unknown,
+*    so we allocate new fresh arenas, discarding the old ones.
+* 3. if the thread is the owner of some critical lock(s), unlock them.
+*
+* If we end up deadlocking in the attempt of dumping out jfr data,
+* we rely on the WatcherThread task "is_error_reported()",
+* to exit the VM after a hard-coded timeout.
+* This "safety net" somewhat explains the aggressiveness in this attempt.
+*
+*/
+static void prepare_for_emergency_dump(Thread* thread) {
+  if (thread->is_Java_thread()) {
+    ((JavaThread*)thread)->set_thread_state(_thread_in_vm);
+  }
+
+#ifdef ASSERT
+  Monitor* owned_lock = thread->owned_locks();
+  while (owned_lock != NULL) {
+    Monitor* next = owned_lock->next();
+    owned_lock->unlock();
+    owned_lock = next;
+  }
+#endif // ASSERT
+
+  if (Threads_lock->owned_by_self()) {
+    Threads_lock->unlock();
+  }
+
+  if (Module_lock->owned_by_self()) {
+    Module_lock->unlock();
+  }
+
+  if (Heap_lock->owned_by_self()) {
+    Heap_lock->unlock();
+  }
+
+  if (Safepoint_lock->owned_by_self()) {
+    Safepoint_lock->unlock();
+  }
+
+  if (VMOperationQueue_lock->owned_by_self()) {
+    VMOperationQueue_lock->unlock();
+  }
+
+  if (VMOperationRequest_lock->owned_by_self()) {
+    VMOperationRequest_lock->unlock();
+  }
+
+
+  if (Service_lock->owned_by_self()) {
+    Service_lock->unlock();
+  }
+
+  if (CodeCache_lock->owned_by_self()) {
+    CodeCache_lock->unlock();
+  }
+
+  if (PeriodicTask_lock->owned_by_self()) {
+    PeriodicTask_lock->unlock();
+  }
+
+  if (JfrMsg_lock->owned_by_self()) {
+    JfrMsg_lock->unlock();
+  }
+
+  if (JfrBuffer_lock->owned_by_self()) {
+    JfrBuffer_lock->unlock();
+  }
+
+  if (JfrStream_lock->owned_by_self()) {
+    JfrStream_lock->unlock();
+  }
+
+  if (JfrStacktrace_lock->owned_by_self()) {
+    JfrStacktrace_lock->unlock();
+  }
+}
+
+static volatile int jfr_shutdown_lock = 0;
+
+static bool guard_reentrancy() {
+  return Atomic::cmpxchg(1, &jfr_shutdown_lock, 0) == 0;
+}
+
+void JfrEmergencyDump::on_vm_shutdown(bool exception_handler) {
+  if (!guard_reentrancy()) {
+    return;
+  }
+  // function made non-reentrant
+  Thread* thread = Thread::current();
+  if (exception_handler) {
+    // we are crashing
+    if (thread->is_Watcher_thread()) {
+      // The Watcher thread runs the periodic thread sampling task.
+      // If it has crashed, it is likely that another thread is
+      // left in a suspended state. This would mean the system
+      // will not be able to ever move to a safepoint. We try
+      // to avoid issuing safepoint operations when attempting
+      // an emergency dump, but a safepoint might be already pending.
+      return;
+    }
+    prepare_for_emergency_dump(thread);
+  }
+  EventDumpReason event;
+  if (event.should_commit()) {
+    event.set_reason(exception_handler ? "Crash" : "Out of Memory");
+    event.set_recordingId(-1);
+    event.commit();
+  }
+  if (!exception_handler) {
+    // OOM
+    LeakProfiler::emit_events(max_jlong, false);
+  }
+  const int messages = MSGBIT(MSG_VM_ERROR);
+  ResourceMark rm(thread);
+  HandleMark hm(thread);
+  JfrRecorderService service;
+  service.rotate(messages);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_RECORDER_INTERNAL_JFREMERGENCY_HPP
+#define SHARE_VM_JFR_RECORDER_INTERNAL_JFREMERGENCY_HPP
+
+#include "memory/allocation.hpp"
+
+//
+// Responsible for creating an hs_err<pid>.jfr file in exceptional shutdown situations (crash, OOM)
+//
+class JfrEmergencyDump : AllStatic {
+ public:
+  static void on_vm_shutdown(bool exception_handler);
+};
+
+#endif // SHARE_VM_JFR_RECORDER_INTERNAL_JFREMERGENCY_HPP
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/repository/jfrRepository.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,480 @@
+/*
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/jfr.hpp"
+#include "jfr/jni/jfrJavaSupport.hpp"
+#include "jfr/recorder/jfrRecorder.hpp"
+#include "jfr/recorder/repository/jfrChunkState.hpp"
+#include "jfr/recorder/repository/jfrChunkWriter.hpp"
+#include "jfr/recorder/repository/jfrRepository.hpp"
+#include "jfr/recorder/service/jfrPostBox.hpp"
+#include "logging/log.hpp"
+#include "memory/resourceArea.hpp"
+#include "runtime/mutex.hpp"
+#include "runtime/os.hpp"
+#include "runtime/thread.inline.hpp"
+
+static JfrRepository* _instance = NULL;
+
+JfrRepository& JfrRepository::instance() {
+  return *_instance;
+}
+
+static JfrChunkWriter* _chunkwriter = NULL;
+
+static bool initialize_chunkwriter() {
+  assert(_chunkwriter == NULL, "invariant");
+  _chunkwriter = new JfrChunkWriter();
+  return _chunkwriter != NULL && _chunkwriter->initialize();
+}
+
+JfrChunkWriter& JfrRepository::chunkwriter() {
+  return *_chunkwriter;
+}
+
+JfrRepository::JfrRepository(JfrPostBox& post_box) : _path(NULL), _post_box(post_box) {}
+
+bool JfrRepository::initialize() {
+  return initialize_chunkwriter();
+}
+
+JfrRepository::~JfrRepository() {
+  if (_path != NULL) {
+    JfrCHeapObj::free(_path, strlen(_path) + 1);
+    _path = NULL;
+  }
+
+  if (_chunkwriter != NULL) {
+    delete _chunkwriter;
+    _chunkwriter = NULL;
+  }
+}
+
+JfrRepository* JfrRepository::create(JfrPostBox& post_box) {
+  assert(_instance == NULL, "invariant");
+  _instance = new JfrRepository(post_box);
+  return _instance;
+}
+
+void JfrRepository::destroy() {
+  assert(_instance != NULL, "invariant");
+  delete _instance;
+  _instance = NULL;
+}
+
+static const char vm_error_filename_fmt[] = "hs_err_pid%p.jfr";
+static const char vm_oom_filename_fmt[] = "hs_oom_pid%p.jfr";
+static const char vm_soe_filename_fmt[] = "hs_soe_pid%p.jfr";
+static const char chunk_file_jfr_ext[] = ".jfr";
+static const size_t iso8601_len = 19; // "YYYY-MM-DDTHH:MM:SS"
+
+static fio_fd open_exclusivly(const char* path) {
+  return os::open(path, O_CREAT | O_WRONLY, S_IREAD | S_IWRITE);
+}
+
+static fio_fd open_existing(const char* path) {
+  return os::open(path, O_RDWR, S_IREAD | S_IWRITE);
+}
+
+static int file_sort(const char** const file1, const char** file2) {
+  assert(NULL != *file1 && NULL != *file2, "invariant");
+  int cmp = strncmp(*file1, *file2, iso8601_len);
+  if (0 == cmp) {
+    const char* const dot1 = strchr(*file1, '.');
+    assert(NULL != dot1, "invariant");
+    const char* const dot2 = strchr(*file2, '.');
+    assert(NULL != dot2, "invariant");
+    ptrdiff_t file1_len = dot1 - *file1;
+    ptrdiff_t file2_len = dot2 - *file2;
+    if (file1_len < file2_len) {
+      return -1;
+    }
+    if (file1_len > file2_len) {
+      return 1;
+    }
+    assert(file1_len == file2_len, "invariant");
+    cmp = strncmp(*file1, *file2, file1_len);
+  }
+  assert(cmp != 0, "invariant");
+  return cmp;
+}
+
+static void iso8601_to_date_time(char* iso8601_str) {
+  assert(iso8601_str != NULL, "invariant");
+  assert(strlen(iso8601_str) == iso8601_len, "invariant");
+  // "YYYY-MM-DDTHH:MM:SS"
+  for (size_t i = 0; i < iso8601_len; ++i) {
+    switch(iso8601_str[i]) {
+      case 'T' :
+      case '-' :
+      case ':' :
+        iso8601_str[i] = '_';
+        break;
+    }
+  }
+  // "YYYY_MM_DD_HH_MM_SS"
+}
+
+static void date_time(char* buffer, size_t buffer_len) {
+  assert(buffer != NULL, "invariant");
+  assert(buffer_len >= iso8601_len, "buffer too small");
+  os::iso8601_time(buffer, buffer_len);
+  assert(strlen(buffer) >= iso8601_len + 1, "invariant");
+  // "YYYY-MM-DDTHH:MM:SS"
+  buffer[iso8601_len] = '\0';
+  iso8601_to_date_time(buffer);
+}
+
+static jlong file_size(fio_fd fd) {
+  assert(fd != invalid_fd, "invariant");
+  const jlong current_offset = os::current_file_offset(fd);
+  const jlong size = os::lseek(fd, 0, SEEK_END);
+  os::seek_to_file_offset(fd, current_offset);
+  return size;
+}
+
+class RepositoryIterator : public StackObj {
+ private:
+  const char* const _repo;
+  const size_t _repository_len;
+  GrowableArray<const char*>* _files;
+  const char* const fully_qualified(const char* entry) const;
+  mutable int _iterator;
+
+ public:
+   RepositoryIterator(const char* repository, size_t repository_len);
+   ~RepositoryIterator() {}
+  debug_only(void print_repository_files() const;)
+  const char* const filter(const char* entry) const;
+  bool has_next() const;
+  const char* const next() const;
+};
+
+const char* const RepositoryIterator::fully_qualified(const char* entry) const {
+  assert(NULL != entry, "invariant");
+  char* file_path_entry = NULL;
+   // only use files that have content, not placeholders
+  const char* const file_separator = os::file_separator();
+  if (NULL != file_separator) {
+    const size_t entry_len = strlen(entry);
+    const size_t file_separator_length = strlen(file_separator);
+    const size_t file_path_entry_length = _repository_len + file_separator_length + entry_len;
+    file_path_entry = NEW_RESOURCE_ARRAY_RETURN_NULL(char, file_path_entry_length + 1);
+    if (NULL == file_path_entry) {
+      return NULL;
+    }
+    int position = 0;
+    position += jio_snprintf(&file_path_entry[position], _repository_len + 1, "%s", _repo);
+    position += jio_snprintf(&file_path_entry[position], file_separator_length + 1, "%s", os::file_separator());
+    position += jio_snprintf(&file_path_entry[position], entry_len + 1, "%s", entry);
+    file_path_entry[position] = '\0';
+    assert((size_t)position == file_path_entry_length, "invariant");
+    assert(strlen(file_path_entry) == (size_t)position, "invariant");
+  }
+  return file_path_entry;
+}
+
+const char* const RepositoryIterator::filter(const char* entry) const {
+  if (entry == NULL) {
+    return NULL;
+  }
+  const size_t entry_len = strlen(entry);
+  if (entry_len <= 2) {
+    // for "." and ".."
+    return NULL;
+  }
+  char* entry_name = NEW_RESOURCE_ARRAY_RETURN_NULL(char, entry_len + 1);
+  if (entry_name == NULL) {
+    return NULL;
+  }
+  strncpy(entry_name, entry, entry_len);
+  entry_name[entry_len] = '\0';
+  const char* const fully_qualified_path_entry = fully_qualified(entry_name);
+  if (NULL == fully_qualified_path_entry) {
+    return NULL;
+  }
+  const fio_fd entry_fd = open_existing(fully_qualified_path_entry);
+  if (invalid_fd == entry_fd) {
+    return NULL;
+  }
+  const jlong entry_size = file_size(entry_fd);
+  os::close(entry_fd);
+  if (0 == entry_size) {
+    return NULL;
+  }
+  return entry_name;
+}
+
+RepositoryIterator::RepositoryIterator(const char* repository, size_t repository_len) :
+  _repo(repository),
+  _repository_len(repository_len),
+  _files(NULL),
+  _iterator(0) {
+  if (NULL != _repo) {
+    assert(strlen(_repo) == _repository_len, "invariant");
+    _files = new GrowableArray<const char*>(10);
+    DIR* dirp = os::opendir(_repo);
+    if (dirp == NULL) {
+      log_error(jfr, system)("Unable to open repository %s", _repo);
+      return;
+    }
+    struct dirent* dentry;
+    char* dir_buffer = NEW_RESOURCE_ARRAY_RETURN_NULL(char, os::readdir_buf_size(_repo));
+    if (dir_buffer == NULL) {
+      return;
+    }
+    while ((dentry = os::readdir(dirp, (struct dirent*)dir_buffer)) != NULL) {
+      const char* const entry_path = filter(dentry->d_name);
+      if (NULL != entry_path) {
+        _files->append(entry_path);
+      }
+    }
+    os::closedir(dirp);
+    if (_files->length() > 1) {
+      _files->sort(file_sort);
+    }
+  }
+}
+
+#ifdef ASSERT
+void RepositoryIterator::print_repository_files() const {
+  while (has_next()) {
+    log_error(jfr, system)( "%s", next());
+  }
+}
+#endif
+bool RepositoryIterator::has_next() const {
+  return (_files != NULL && _iterator < _files->length());
+}
+
+const char* const RepositoryIterator::next() const {
+  return _iterator >= _files->length() ? NULL : fully_qualified(_files->at(_iterator++));
+}
+
+static void write_emergency_file(fio_fd emergency_fd, const RepositoryIterator& iterator) {
+  assert(emergency_fd != invalid_fd, "invariant");
+  const size_t size_of_file_copy_block = 1 * M; // 1 mb
+  jbyte* const file_copy_block = NEW_RESOURCE_ARRAY_RETURN_NULL(jbyte, size_of_file_copy_block);
+  if (file_copy_block == NULL) {
+    return;
+  }
+ jlong bytes_written_total = 0;
+  while (iterator.has_next()) {
+    fio_fd current_fd = invalid_fd;
+    const char* const fqn = iterator.next();
+    if (fqn != NULL) {
+      current_fd = open_existing(fqn);
+      if (current_fd != invalid_fd) {
+        const jlong current_filesize = file_size(current_fd);
+        assert(current_filesize > 0, "invariant");
+        jlong bytes_read = 0;
+        jlong bytes_written = 0;
+        while (bytes_read < current_filesize) {
+          bytes_read += (jlong)os::read_at(current_fd, file_copy_block, size_of_file_copy_block, bytes_read);
+          assert(bytes_read - bytes_written <= (jlong)size_of_file_copy_block, "invariant");
+          bytes_written += (jlong)os::write(emergency_fd, file_copy_block, bytes_read - bytes_written);
+          assert(bytes_read == bytes_written, "invariant");
+        }
+        os::close(current_fd);
+        bytes_written_total += bytes_written;
+      }
+    }
+  }
+}
+
+static const char* create_emergency_dump_path() {
+  assert(JfrStream_lock->owned_by_self(), "invariant");
+  char* buffer = NEW_RESOURCE_ARRAY_RETURN_NULL(char, O_BUFLEN);
+  if (NULL == buffer) {
+    return NULL;
+  }
+  const char* const cwd = os::get_current_directory(buffer, O_BUFLEN);
+  if (NULL == cwd) {
+    return NULL;
+  }
+  size_t pos = strlen(cwd);
+  const int fsep_len = jio_snprintf(&buffer[pos], O_BUFLEN - pos, "%s", os::file_separator());
+  const char* filename_fmt = NULL;
+  // fetch specific error cause
+  switch (JfrJavaSupport::cause()) {
+    case JfrJavaSupport::OUT_OF_MEMORY:
+      filename_fmt = vm_oom_filename_fmt;
+      break;
+    case JfrJavaSupport::STACK_OVERFLOW:
+      filename_fmt = vm_soe_filename_fmt;
+      break;
+    default:
+      filename_fmt = vm_error_filename_fmt;
+  }
+  char* emergency_dump_path = NULL;
+  pos += fsep_len;
+  if (Arguments::copy_expand_pid(filename_fmt, strlen(filename_fmt), &buffer[pos], O_BUFLEN - pos)) {
+    const size_t emergency_filename_length = strlen(buffer);
+    emergency_dump_path = NEW_RESOURCE_ARRAY_RETURN_NULL(char, emergency_filename_length + 1);
+    if (NULL == emergency_dump_path) {
+      return NULL;
+    }
+    strncpy(emergency_dump_path, buffer, emergency_filename_length);
+    emergency_dump_path[emergency_filename_length] = '\0';
+  }
+  return emergency_dump_path;
+}
+
+// Caller needs ResourceMark
+static const char* create_emergency_chunk_path(const char* repository_base, size_t repository_len) {
+  assert(repository_base != NULL, "invariant");
+  assert(JfrStream_lock->owned_by_self(), "invariant");
+  // date time
+  char date_time_buffer[32] = {0};
+  date_time(date_time_buffer, sizeof(date_time_buffer));
+  size_t date_time_len = strlen(date_time_buffer);
+  size_t chunkname_max_len = repository_len               // repository_base
+                             + 1                          // "/"
+                             + date_time_len              // date_time
+                             + strlen(chunk_file_jfr_ext) // .jfr
+                             + 1;
+  char* chunk_path = NEW_RESOURCE_ARRAY_RETURN_NULL(char, chunkname_max_len);
+  if (chunk_path == NULL) {
+    return NULL;
+  }
+  // append the individual substrings
+  jio_snprintf(chunk_path, chunkname_max_len, "%s%s%s%s", repository_base, os::file_separator(), date_time_buffer, chunk_file_jfr_ext);
+  return chunk_path;
+}
+
+static fio_fd emergency_dump_file() {
+  assert(JfrStream_lock->owned_by_self(), "invariant");
+  ResourceMark rm;
+  const char* const emergency_dump_path = create_emergency_dump_path();
+  if (emergency_dump_path == NULL) {
+    return invalid_fd;
+  }
+  const fio_fd fd = open_exclusivly(emergency_dump_path);
+  if (fd != invalid_fd) {
+    log_info(jfr)( // For user, should not be "jfr, system"
+      "Attempting to recover JFR data, emergency jfr file: %s", emergency_dump_path);
+  }
+  return fd;
+}
+
+static const char* emergency_path(const char* repository, size_t repository_len) {
+  return repository == NULL ? create_emergency_dump_path() : create_emergency_chunk_path(repository, repository_len);
+}
+
+void JfrRepository::on_vm_error() {
+  assert(!JfrStream_lock->owned_by_self(), "invariant");
+  const char* path = _path;
+  if (path == NULL) {
+    // completed already
+    return;
+  }
+  ResourceMark rm;
+  MutexLockerEx stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag);
+  const fio_fd emergency_fd = emergency_dump_file();
+  if (emergency_fd != invalid_fd) {
+    RepositoryIterator iterator(path, strlen(path));
+    write_emergency_file(emergency_fd, iterator);
+    os::close(emergency_fd);
+  }
+}
+
+bool JfrRepository::set_path(const char* path) {
+  assert(path != NULL, "trying to set the repository path with a NULL string!");
+  if (_path != NULL) {
+    // delete existing
+    JfrCHeapObj::free(_path, strlen(_path) + 1);
+  }
+  const size_t path_len = strlen(path);
+  _path = JfrCHeapObj::new_array<char>(path_len + 1);
+  if (_path == NULL) {
+    return false;
+  }
+  strncpy(_path, path, path_len);
+  _path[path_len] = '\0';
+  return true;
+}
+
+void JfrRepository::set_chunk_path(const char* path) {
+  assert(JfrStream_lock->owned_by_self(), "invariant");
+  chunkwriter().set_chunk_path(path);
+}
+
+void JfrRepository::notify_on_new_chunk_path() {
+  if (Jfr::is_recording()) {
+    instance()._post_box.post(MSG_ROTATE);
+  }
+}
+
+/**
+* Sets the file where data should be written.
+*
+* Recording  Previous  Current  Action
+* ==============================================
+*   true     null      null     Ignore, keep recording in-memory
+*   true     null      file1    Start disk recording
+*   true     file      null     Copy out metadata to disk and continue in-memory recording
+*   true     file1     file2    Copy out metadata and start with new File (file2)
+*   false     *        null     Ignore, but start recording to memory
+*   false     *        file     Ignore, but start recording to disk
+*/
+void JfrRepository::set_chunk_path(jstring path, JavaThread* jt) {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt));
+  ResourceMark rm(jt);
+  const char* const canonical_chunk_path = JfrJavaSupport::c_str(path, jt);
+  {
+    MutexLockerEx stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag);
+    if (NULL == canonical_chunk_path && !_chunkwriter->is_valid()) {
+      // new output is NULL and current output is NULL
+      return;
+    }
+    instance().set_chunk_path(canonical_chunk_path);
+  }
+  notify_on_new_chunk_path();
+}
+
+void JfrRepository::set_path(jstring location, JavaThread* jt) {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt));
+  ResourceMark rm(jt);
+  const char* const path = JfrJavaSupport::c_str(location, jt);
+  if (path != NULL) {
+    instance().set_path(path);
+  }
+}
+
+bool JfrRepository::open_chunk(bool vm_error /* false */) {
+  assert(JfrStream_lock->owned_by_self(), "invariant");
+  if (vm_error) {
+    ResourceMark rm;
+    const char* repository_path = _path;
+    const size_t repository_path_len = repository_path != NULL ? strlen(repository_path) : 0;
+    const char* const path = emergency_path(repository_path, repository_path_len);
+    _chunkwriter->set_chunk_path(path);
+  }
+  return _chunkwriter->open();
+}
+
+size_t JfrRepository::close_chunk(jlong metadata_offset) {
+  return _chunkwriter->close(metadata_offset);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/repository/jfrRepository.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+#ifndef SHARE_VM_JFR_RECORDER_REPOSITORY_JFRREPOSITORY_HPP
+#define SHARE_VM_JFR_RECORDER_REPOSITORY_JFRREPOSITORY_HPP
+
+#include "jni.h"
+#include "jfr/utilities/jfrAllocation.hpp"
+
+class JfrChunkWriter;
+class JfrPostBox;
+
+//
+// Represents the location on disk where internal files, "chunks", are stored.
+//
+// A "chunk" is a self-contained file artifact storing events and metadata that
+// has been moved out of process memory.
+//
+// Chunk files are associated with recordings and are managed at a higher level in Java.
+// Java continously keeps the VM informed about new chunk locations via set_chunk_path().
+//
+// A JfrChunkWriter will open the next chunk file which it maintains as the current chunk.
+// There is a rotation scheme in place for creating new chunks at certain intervals.
+//
+class JfrRepository : public JfrCHeapObj {
+  friend class JfrRecorder;
+  friend class JfrRecorderService;
+ private:
+  char* _path;
+  JfrPostBox& _post_box;
+
+  JfrRepository(JfrPostBox& post_box);
+  ~JfrRepository();
+
+  bool set_path(const char* path);
+  void set_chunk_path(const char* path);
+  bool open_chunk(bool vm_error = false);
+  size_t close_chunk(jlong metadata_offset);
+  void on_vm_error();
+  static void notify_on_new_chunk_path();
+  static JfrChunkWriter& chunkwriter();
+
+  static JfrRepository& instance();
+  static JfrRepository* create(JfrPostBox& post_box);
+  bool initialize();
+  static void destroy();
+
+ public:
+  static void set_path(jstring location, JavaThread* jt);
+  static void set_chunk_path(jstring path, JavaThread* jt);
+};
+
+#endif // SHARE_VM_JFR_RECORDER_REPOSITORY_JFRREPOSITORY_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/service/jfrEvent.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/recorder/service/jfrEvent.hpp"
+#include "utilities/bitMap.inline.hpp"
+#include "utilities/macros.hpp"
+
+#ifdef ASSERT
+JfrEventVerifier::JfrEventVerifier() : _committed(false) {
+  memset(_verification_storage, 0, (sizeof(_verification_storage)));
+  _verification_bit_map = BitMapView(_verification_storage, (BitMap::idx_t)(sizeof(_verification_storage) * BitsPerByte));
+}
+
+void JfrEventVerifier::check(BitMap::idx_t field_idx) const {
+  assert(field_idx < _verification_bit_map.size(), "too many fields to verify, please resize _verification_storage");
+}
+
+void JfrEventVerifier::set_field_bit(size_t field_idx) {
+  check((BitMap::idx_t)field_idx);
+  _verification_bit_map.set_bit((BitMap::idx_t)field_idx);
+}
+
+bool JfrEventVerifier::verify_field_bit(size_t field_idx) const {
+  check((BitMap::idx_t)field_idx);
+  return _verification_bit_map.at((BitMap::idx_t)field_idx);
+}
+
+void JfrEventVerifier::set_committed() {
+  assert(!_committed, "invariant");
+  _committed = true;
+}
+
+void JfrEventVerifier::clear_committed() {
+  _committed = false;
+}
+
+bool JfrEventVerifier::committed() const {
+  return _committed;
+}
+
+#endif // ASSERT
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/service/jfrEvent.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_RECORDER_SERVICE_JFREVENT_HPP
+#define SHARE_VM_JFR_RECORDER_SERVICE_JFREVENT_HPP
+
+#include "jfr/recorder/jfrEventSetting.inline.hpp"
+#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
+#include "jfr/utilities/jfrTime.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
+#include "jfr/writers/jfrNativeEventWriter.hpp"
+#include "runtime/thread.hpp"
+#include "utilities/exceptions.hpp"
+#include "utilities/ticks.hpp"
+#ifdef ASSERT
+#include "utilities/bitMap.hpp"
+#endif
+
+#ifdef ASSERT
+class JfrEventVerifier {
+  template <typename>
+  friend class JfrEvent;
+ private:
+  // verification of event fields
+  BitMap::bm_word_t _verification_storage[1];
+  BitMapView _verification_bit_map;
+  bool _committed;
+
+  JfrEventVerifier();
+  void check(BitMap::idx_t field_idx) const;
+  void set_field_bit(size_t field_idx);
+  bool verify_field_bit(size_t field_idx) const;
+  void set_committed();
+  void clear_committed();
+  bool committed() const;
+};
+#endif // ASSERT
+
+template <typename T>
+class JfrEvent {
+ private:
+  jlong _start_time;
+  jlong _end_time;
+  bool _started;
+
+ protected:
+  JfrEvent(EventStartTime timing=TIMED) : _start_time(0), _end_time(0), _started(false)
+#ifdef ASSERT
+  , _verifier()
+#endif
+  {
+    if (T::is_enabled()) {
+      _started = true;
+      if (TIMED == timing && !T::isInstant) {
+        set_starttime(JfrTicks::now());
+      }
+    }
+  }
+
+  void commit() {
+    if (!should_commit()) {
+      return;
+    }
+    assert(!_verifier.committed(), "event already committed");
+    if (_start_time == 0) {
+      set_starttime(JfrTicks::now());
+    } else if (_end_time == 0) {
+      set_endtime(JfrTicks::now());
+    }
+    if (should_write()) {
+      write_event();
+      DEBUG_ONLY(_verifier.set_committed();)
+    }
+  }
+
+ public:
+  void set_starttime(const JfrTicks& time) {
+    _start_time = time.value();
+  }
+
+  void set_endtime(const JfrTicks& time) {
+    _end_time = time.value();
+  }
+
+  void set_starttime(const Ticks& time) {
+    _start_time = JfrTime::is_ft_enabled() ? time.ft_value() : time.value();
+  }
+
+  void set_endtime(const Ticks& time) {
+    _end_time = JfrTime::is_ft_enabled() ? time.ft_value() : time.value();
+  }
+
+  static bool is_enabled() {
+    return JfrEventSetting::is_enabled(T::eventId);
+  }
+
+  static bool is_stacktrace_enabled() {
+    return JfrEventSetting::has_stacktrace(T::eventId);
+  }
+
+  static JfrEventId id() {
+    return T::eventId;
+  }
+
+  static bool is_instant() {
+    return T::isInstant;
+  }
+
+  static bool is_requestable() {
+    return T::isRequestable;
+  }
+
+  static bool has_thread() {
+    return T::hasThread;
+  }
+
+  static bool has_stacktrace() {
+    return T::hasStackTrace;
+  }
+
+  bool should_commit() {
+    return _started;
+  }
+
+ private:
+  bool should_write() {
+    if (T::isInstant || T::isRequestable || T::hasCutoff) {
+      return true;
+    }
+    return (_end_time - _start_time) >= JfrEventSetting::threshold(T::eventId);
+  }
+
+  void write_event() {
+    DEBUG_ONLY(assert_precondition();)
+    Thread* const event_thread = Thread::current();
+    JfrThreadLocal* const tl = event_thread->jfr_thread_local();
+    JfrBuffer* const buffer = tl->native_buffer();
+    if (buffer == NULL) {
+      // most likely a pending OOM
+      return;
+    }
+    JfrNativeEventWriter writer(buffer, event_thread);
+    writer.write<u8>(T::eventId);
+    assert(_start_time != 0, "invariant");
+    writer.write(_start_time);
+    if (!(T::isInstant || T::isRequestable) || T::hasCutoff) {
+      assert(_end_time != 0, "invariant");
+      writer.write(_end_time - _start_time);
+    }
+    if (T::hasThread) {
+      writer.write(tl->thread_id());
+    }
+    if (T::hasStackTrace) {
+      if (is_stacktrace_enabled()) {
+        if (tl->has_cached_stack_trace()) {
+          writer.write(tl->cached_stack_trace_id());
+        } else {
+          writer.write(JfrStackTraceRepository::record(event_thread));
+        }
+      } else {
+        writer.write<traceid>(0);
+      }
+    }
+    // payload
+    static_cast<T*>(this)->writeData(writer);
+  }
+
+#ifdef ASSERT
+ private:
+  // verification of event fields
+  JfrEventVerifier _verifier;
+
+  void assert_precondition() {
+    assert(T::eventId >= (JfrEventId)NUM_RESERVED_EVENTS, "event id underflow invariant");
+    assert(T::eventId < MaxJfrEventId, "event id overflow invariant");
+    DEBUG_ONLY(static_cast<T*>(this)->verify());
+  }
+
+ protected:
+  void set_field_bit(size_t field_idx) {
+    _verifier.set_field_bit(field_idx);
+    // it is ok to reuse an already committed event
+    // granted you provide new informational content
+    _verifier.clear_committed();
+  }
+
+  bool verify_field_bit(size_t field_idx) const {
+    return _verifier.verify_field_bit(field_idx);
+  }
+#endif // ASSERT
+};
+
+#endif // SHARE_VM_JFR_RECORDER_SERVICE_JFREVENT_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/service/jfrMemorySizer.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,434 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/recorder/service/jfrMemorySizer.hpp"
+#include "logging/log.hpp"
+#include "runtime/os.hpp"
+
+const julong MAX_ADJUSTED_GLOBAL_BUFFER_SIZE = 1 * M;
+const julong MIN_ADJUSTED_GLOBAL_BUFFER_SIZE_CUTOFF = 512 * K;
+const julong MIN_GLOBAL_BUFFER_SIZE = 64 * K;
+// implies at least 2 * MIN_GLOBAL_BUFFER SIZE
+const julong MIN_BUFFER_COUNT = 2;
+// MAX global buffer count open ended
+const julong DEFAULT_BUFFER_COUNT = 20;
+// MAX thread local buffer size == size of a single global buffer (runtime determined)
+// DEFAULT thread local buffer size = 2 * os page size (runtime determined)
+const julong MIN_THREAD_BUFFER_SIZE = 4 * K;
+const julong MIN_MEMORY_SIZE = 1 * M;
+const julong DEFAULT_MEMORY_SIZE = 10 * M;
+
+//
+// In pages:
+//
+// units = total_pages / per_unit_pages
+//
+static julong div_pages(julong& total_pages, julong& per_unit_pages) {
+  assert(total_pages > 0, "invariant");
+  assert(per_unit_pages > 0, "invariant");
+  assert(total_pages >= per_unit_pages, "invariant");
+
+  const julong units = total_pages / per_unit_pages;
+  const julong rem = total_pages % per_unit_pages;
+
+  assert(units > 0, "invariant");
+
+  if (rem > 0) {
+    total_pages -= rem % units;
+    per_unit_pages += rem / units;
+  }
+
+  assert(per_unit_pages > 0, "invariant");
+  assert(total_pages % units == 0, "invariant");
+  assert(units * per_unit_pages == total_pages, "invariant");
+  assert(units == total_pages / per_unit_pages, "invariant");
+
+  return units;
+}
+
+static void page_size_align_up(julong& value) {
+  static const julong alignment = os::vm_page_size() - 1;
+  value = (value + alignment) & ~alignment;
+}
+
+//
+// In bytes:
+// units = total_bytes / per_unit_bytes
+//
+static julong div_total_by_per_unit(julong& total_bytes, julong& per_unit_bytes) {
+  assert(total_bytes > 0, "invariant");
+  assert(per_unit_bytes > 0, "invariant");
+  assert(total_bytes >= per_unit_bytes, "invariant");
+
+  page_size_align_up(total_bytes);
+  assert(total_bytes % os::vm_page_size() == 0, "invariant");
+  julong total_pages = total_bytes / os::vm_page_size();
+
+  page_size_align_up(per_unit_bytes);
+  assert(per_unit_bytes % os::vm_page_size() == 0, "invariant");
+  julong per_unit_pages = per_unit_bytes / os::vm_page_size();
+
+  const julong units = div_pages(total_pages, per_unit_pages);
+  assert(units > 0, "invariant");
+
+  total_bytes = total_pages * os::vm_page_size();
+  per_unit_bytes = per_unit_pages * os::vm_page_size();
+
+  assert(per_unit_bytes > 0, "invariant");
+  assert(total_bytes / per_unit_bytes == units, "invariant");
+
+  return units;
+}
+
+//
+// per_unit_bytes = total_bytes / units
+//
+static julong div_total_by_units(julong& total_bytes, julong& units) {
+  page_size_align_up(total_bytes);
+  assert(total_bytes % os::vm_page_size() == 0, "invariant");
+  julong total_pages = total_bytes / os::vm_page_size();
+  assert(units > 0, "invariant");
+
+  julong per_unit_pages = total_pages <= units ? 1 : total_pages / units;
+  units = div_pages(total_pages, per_unit_pages);
+
+  julong per_unit_bytes = per_unit_pages * os::vm_page_size();
+  assert(per_unit_bytes % os::vm_page_size() == 0, "invariant");
+
+  total_bytes = total_pages * os::vm_page_size();
+  assert(total_bytes % os::vm_page_size() == 0, "invariant");
+
+  assert(total_bytes % units == 0, "invariant");
+  assert(total_bytes / units == per_unit_bytes, "invariant");
+  assert(units * per_unit_bytes == total_bytes, "invariant");
+
+  return per_unit_bytes;
+}
+
+//
+// total_bytes = per_unit_bytes * units;
+//
+static julong multiply(julong& per_unit_bytes, julong& units) {
+  page_size_align_up(per_unit_bytes);
+  assert(per_unit_bytes % os::vm_page_size() == 0, "invariant");
+  assert(units > 0, "invariant");
+
+  julong total_bytes = per_unit_bytes * units;
+  assert(total_bytes % os::vm_page_size() == 0, "invariant");
+
+  assert(total_bytes % units == 0, "invariant");
+  assert(total_bytes / units == per_unit_bytes, "invariant");
+  assert(units * per_unit_bytes == total_bytes, "invariant");
+
+  return total_bytes;
+}
+
+// Total_bytes is explicitly set.
+//
+// Deduce other parameters by delegating to a sizing policy
+template <typename SizingPolicy>
+static julong adjust(JfrMemoryOptions* options) {
+  page_size_align_up(options->memory_size);
+  assert(options->memory_size % os::vm_page_size() == 0, "invariant");
+  julong total_pages = options->memory_size / os::vm_page_size();
+  assert(options->buffer_count > 0, "invariant");
+  julong per_unit_pages = total_pages / options->buffer_count;
+  page_size_align_up(options->thread_buffer_size);
+  assert(options->thread_buffer_size % os::vm_page_size() == 0, "invariant");
+  julong thread_buffer_pages = options->thread_buffer_size / os::vm_page_size();
+
+  SizingPolicy::adjust(total_pages, per_unit_pages, options->buffer_count, thread_buffer_pages, options->thread_buffer_size_configured);
+  assert(options->buffer_count * per_unit_pages == total_pages, "invariant");
+
+  const julong per_unit_bytes = per_unit_pages * os::vm_page_size();
+  options->memory_size = total_pages * os::vm_page_size();
+  options->thread_buffer_size = thread_buffer_pages * os::vm_page_size();
+
+  assert(options->memory_size % options->buffer_count == 0, "invariant");
+  assert(options->memory_size / options->buffer_count == per_unit_bytes, "invariant");
+  assert(options->buffer_count * per_unit_bytes == options->memory_size, "invariant");
+  assert(per_unit_bytes >= options->thread_buffer_size, "invariant");
+  return per_unit_bytes;
+}
+
+static void align_buffer_size(julong& buffer_size_in_pages, julong max_size_pages, julong min_size_pages, bool sizeup = false) {
+  buffer_size_in_pages = MIN2(buffer_size_in_pages, max_size_pages);
+  buffer_size_in_pages = MAX2(buffer_size_in_pages, min_size_pages);
+  size_t multiples = 0;
+  if (buffer_size_in_pages < max_size_pages) {
+    while (buffer_size_in_pages >=
+      (min_size_pages << (multiples + (sizeup ? 0 : 1)))) {
+      ++multiples;
+    }
+    buffer_size_in_pages = min_size_pages << multiples;
+  }
+  assert(buffer_size_in_pages >= min_size_pages && buffer_size_in_pages <= max_size_pages, "invariant");
+}
+
+static void adjust_buffer_size_to_total_memory_size(julong& total_pages, julong& buffer_size_pages) {
+  static const julong max_buffer_size_pages = MAX_ADJUSTED_GLOBAL_BUFFER_SIZE / os::vm_page_size();
+  // If memory size is less than DEFAULT_MEMORY_SIZE,
+  // the adjustment algorithm can decrease the size of the global buffer
+  // all the way down to the MIN_GLOBAL_BUFFER_SIZE (taking embedded use case in account).
+  // If memory size is larger than DEFAULT_MEMORY_SIZE, the lowest size of
+  // a global buffer will be the size of MIN_ADJUSTED_GLOBAL_BUFFER_SIZE_CUTOFF
+  static const julong min_buffer_size_pages =
+    total_pages * os::vm_page_size() < DEFAULT_MEMORY_SIZE ?
+      MIN_GLOBAL_BUFFER_SIZE / os::vm_page_size() :
+      MIN_ADJUSTED_GLOBAL_BUFFER_SIZE_CUTOFF / os::vm_page_size();
+
+  align_buffer_size(buffer_size_pages, max_buffer_size_pages, min_buffer_size_pages);
+  assert(buffer_size_pages % min_buffer_size_pages == 0, "invariant");
+
+  julong remainder = total_pages % buffer_size_pages;
+  while (remainder >= (buffer_size_pages >> 1)) {
+    if (buffer_size_pages <= min_buffer_size_pages) {
+      break;
+    }
+    buffer_size_pages >>= 1;
+    remainder = total_pages % buffer_size_pages;
+  }
+}
+
+// Sizing policy class
+class ScaleOutAdjuster : public AllStatic {
+ public:
+  static void adjust(julong& total_pages,
+                     julong& buffer_size_pages,
+                     julong& buffer_count,
+                     julong& thread_buffer_size_pages,
+                     bool is_thread_buffer_size_set) {
+    assert(buffer_count > 0, "invariant");
+    adjust_buffer_size_to_total_memory_size(total_pages, buffer_size_pages);
+    assert(buffer_size_pages * os::vm_page_size() >= MIN_GLOBAL_BUFFER_SIZE, "invariant");
+    assert((buffer_size_pages * os::vm_page_size()) % MIN_GLOBAL_BUFFER_SIZE == 0, "invariant");
+    if (is_thread_buffer_size_set) {
+      if (thread_buffer_size_pages > buffer_size_pages) {
+        buffer_size_pages = thread_buffer_size_pages;
+      }
+    }
+    // and with this information, calculate what the new buffer count will be
+    buffer_count = div_pages(total_pages, buffer_size_pages);
+  }
+};
+
+static void memory_and_thread_buffer_size(JfrMemoryOptions* options) {
+  assert(options->memory_size_configured, "invariant");
+  assert(!options->buffer_count_configured, "invariant");
+  assert(!options->global_buffer_size_configured, "invariant");
+  // here the only thing specified is the overall total memory size
+  // we can and will apply some sizing heuristics to derive both
+  // the size of an individual global buffer and by implication the number of global
+  // buffers to use. Starting values for buffer count and global_buffer_size
+  // will be the defaults.
+  options->global_buffer_size = adjust<ScaleOutAdjuster>(options);
+}
+
+static void memory_size_and_buffer_count(JfrMemoryOptions* options) {
+  assert(options->memory_size_configured, "invariant");
+  assert(!options->global_buffer_size_configured, "invariant");
+  assert(!options->thread_buffer_size_configured, "invariant");
+  assert(options->buffer_count_configured, "invariant");
+  options->global_buffer_size = div_total_by_units(options->memory_size, options->buffer_count);
+}
+
+static void memory_size_and_global_buffer_size(JfrMemoryOptions* options) {
+  assert(options->memory_size_configured, "invariant");
+  assert(options->global_buffer_size_configured, "invariant");
+  assert(!options->buffer_count_configured, "invariant");
+  page_size_align_up(options->thread_buffer_size);
+  options->buffer_count = div_total_by_per_unit(options->memory_size, options->global_buffer_size);
+  if (options->thread_buffer_size > options->global_buffer_size) {
+    options->global_buffer_size = options->thread_buffer_size;
+    options->buffer_count = div_total_by_per_unit(options->memory_size, options->global_buffer_size);
+  }
+  assert(options->global_buffer_size >= options->thread_buffer_size, "invariant");
+}
+
+static bool is_ambiguous(const JfrMemoryOptions* options) {
+  assert(options->memory_size_configured, "invariant");
+  assert(options->global_buffer_size_configured, "invariant");
+  assert(options->buffer_count_configured, "invariant");
+  assert(options->thread_buffer_size <= options->global_buffer_size, "invariant");
+  // This can cause an ambiguous situation because all three parameters are explicitly set.
+  return options->global_buffer_size * options->buffer_count != options->memory_size;
+}
+
+static void all_options_set(JfrMemoryOptions* options) {
+  options->buffer_count = div_total_by_per_unit(options->memory_size, options->global_buffer_size);
+  page_size_align_up(options->thread_buffer_size);
+  if (options->thread_buffer_size > options->global_buffer_size) {
+    options->global_buffer_size = options->thread_buffer_size;
+    options->buffer_count = div_total_by_per_unit(options->memory_size, options->global_buffer_size);
+  }
+  assert(options->global_buffer_size >= options->thread_buffer_size, "invariant");
+  assert(options->memory_size / options->global_buffer_size == options->buffer_count, "invariant");
+  assert(options->memory_size % options->global_buffer_size == 0, "invariant");
+}
+
+static void global_buffer_size(JfrMemoryOptions* options) {
+  assert(!options->memory_size_configured, "invariant");
+  page_size_align_up(options->thread_buffer_size);
+  if (options->thread_buffer_size > options->global_buffer_size) {
+    options->global_buffer_size = options->thread_buffer_size;
+  }
+  options->memory_size = multiply(options->global_buffer_size, options->buffer_count);
+  assert(options->global_buffer_size >= options->thread_buffer_size, "invariant");
+}
+
+static void thread_buffer_size(JfrMemoryOptions* options) {
+  assert(!options->global_buffer_size_configured, "invariant");
+  assert(options->thread_buffer_size_configured, "invariant");
+  page_size_align_up(options->thread_buffer_size);
+  options->global_buffer_size = div_total_by_units(options->memory_size, options->buffer_count);
+  if (options->thread_buffer_size > options->global_buffer_size) {
+    options->global_buffer_size = options->thread_buffer_size;
+    options->buffer_count = div_total_by_per_unit(options->memory_size, options->global_buffer_size);
+  }
+  assert(options->global_buffer_size >= options->thread_buffer_size, "invariant");
+}
+
+static void default_size(const JfrMemoryOptions* options) {
+  // no memory options explicitly set
+  // default values already statically adjusted
+  assert(!options->thread_buffer_size_configured, "invariant");
+  assert(!options->memory_size_configured, "invariant");
+  assert(!options->buffer_count_configured, "invarinat");
+  assert(!options->global_buffer_size_configured, "invariant");
+}
+
+#ifdef ASSERT
+static void assert_post_condition(const JfrMemoryOptions* options) {
+  assert(options->memory_size % os::vm_page_size() == 0, "invariant");
+  assert(options->global_buffer_size % os::vm_page_size() == 0, "invariant");
+  assert(options->thread_buffer_size % os::vm_page_size() == 0, "invariant");
+  assert(options->buffer_count > 0, "invariant");
+}
+#endif
+
+// MEMORY SIZING ALGORITHM
+
+bool JfrMemorySizer::adjust_options(JfrMemoryOptions* options) {
+  assert(options != NULL, "invariant");
+
+  enum MemoryOptions {
+    MEMORY_SIZE = 1,
+    GLOBAL_BUFFER_SIZE = 2,
+    GLOBAL_BUFFER_COUNT = 4,
+    THREAD_BUFFER_SIZE = 8
+  };
+
+  // LEGEND
+  //
+  // M = "memorysize" option
+  // G = "globalbuffersize" option
+  // C = "numglobalbuffers" option
+  // T = "threadbuffersize" option
+  //
+  // The memory options comprise an n-set (a 4-set) = { M, G, C, T }
+  //
+  // Number of r-subsets = 5 (0, 1, 2, 3, 4) (including null set)
+  //
+  // Unordered selection:
+  //
+  // C(4, 0) = {} = NULL set = 1
+  // C(4, 1) = { (M), (G), (C), (T) } = 4
+  // C(4, 2) = { (M, G), (M, C), (M, T), (G, C), (G, T), (C, T) } = 6
+  // C(4, 3) = { (M, G, C), (M, G, T), (M, C, T), (G, C, T) } = 4
+  // C(4, 4) = { (M, G, C, T) } = 1
+  //
+  // in shorter terms: P({ M, G, C, T}) = 16
+  //
+#define MG   (MEMORY_SIZE | GLOBAL_BUFFER_SIZE)
+#define MC   (MEMORY_SIZE | GLOBAL_BUFFER_COUNT)
+#define MT   (MEMORY_SIZE | THREAD_BUFFER_SIZE)
+#define MGC  (MG | GLOBAL_BUFFER_COUNT)
+#define MGT  (MG | THREAD_BUFFER_SIZE)
+#define MCT  (MC | THREAD_BUFFER_SIZE)
+#define MGCT (MGC | THREAD_BUFFER_SIZE)
+#define GC   (GLOBAL_BUFFER_SIZE | GLOBAL_BUFFER_COUNT)
+#define GT   (GLOBAL_BUFFER_SIZE | THREAD_BUFFER_SIZE)
+#define GCT  (GC | THREAD_BUFFER_SIZE)
+#define CT   (GLOBAL_BUFFER_COUNT | THREAD_BUFFER_SIZE)
+
+  int set_of_options = 0;
+
+  if (options->memory_size_configured) {
+    set_of_options |= MEMORY_SIZE;
+  }
+  if (options->global_buffer_size_configured) {
+    set_of_options |= GLOBAL_BUFFER_SIZE;
+  }
+  if (options->buffer_count_configured) {
+    set_of_options |= GLOBAL_BUFFER_COUNT;
+  }
+  if (options->thread_buffer_size_configured) {
+    set_of_options |= THREAD_BUFFER_SIZE;
+  }
+
+  switch (set_of_options) {
+    case MT:
+    case MEMORY_SIZE:
+      memory_and_thread_buffer_size(options);
+      break;
+    case MC:
+      memory_size_and_buffer_count(options);
+      break;
+    case MGT:
+      assert(options->thread_buffer_size_configured, "invariant");
+    case MG:
+      memory_size_and_global_buffer_size(options);
+      break;
+    case MGC:
+    case MGCT:
+      if (is_ambiguous(options)) {
+        // Let the user resolve the ambiguity by bailing.
+        return false;
+      }
+      all_options_set(options);
+      break;
+    case GCT:
+      assert(options->buffer_count_configured, "invariant");
+      assert(options->thread_buffer_size_configured, "invariant");
+    case GC:
+      assert(options->global_buffer_size_configured, "invariant");
+    case GT:
+    case GLOBAL_BUFFER_COUNT:
+    case GLOBAL_BUFFER_SIZE:
+      global_buffer_size(options);
+      break;
+    case MCT:
+      assert(options->memory_size_configured, "invariant");
+    case CT:
+      assert(options->buffer_count_configured, "invariant");
+    case THREAD_BUFFER_SIZE:
+      thread_buffer_size(options);
+      break;
+    default:
+      default_size(options);
+  }
+  DEBUG_ONLY(assert_post_condition(options);)
+  return true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/service/jfrMemorySizer.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_RECORDER_SERVICE_JFRMEMORYSIZER_HPP
+#define SHARE_VM_JFR_RECORDER_SERVICE_JFRMEMORYSIZER_HPP
+
+#include "memory/allocation.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+extern const julong MIN_BUFFER_COUNT;
+extern const julong MIN_GLOBAL_BUFFER_SIZE;
+extern const julong MIN_MEMORY_SIZE;
+extern const julong MIN_THREAD_BUFFER_SIZE;
+
+struct JfrMemoryOptions {
+  julong memory_size;
+  julong global_buffer_size;
+  julong buffer_count;
+  julong thread_buffer_size;
+  bool memory_size_configured;
+  bool global_buffer_size_configured;
+  bool buffer_count_configured;
+  bool thread_buffer_size_configured;
+};
+
+//
+// Encapsulates sizing of memory options
+// The options parameter is modified with updated values.
+//
+class JfrMemorySizer : AllStatic {
+ public:
+  static bool adjust_options(JfrMemoryOptions* options);
+};
+
+#endif // SHARE_VM_JFR_RECORDER_SERVICE_JFRMEMORYSIZER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/service/jfrOptionSet.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,713 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/dcmd/jfrDcmds.hpp"
+#include "jfr/recorder/service/jfrMemorySizer.hpp"
+#include "jfr/recorder/service/jfrOptionSet.hpp"
+#include "jfr/utilities/jfrAllocation.hpp"
+#include "logging/log.hpp"
+#include "memory/allocation.inline.hpp"
+#include "memory/resourceArea.hpp"
+#include "runtime/java.hpp"
+#include "runtime/thread.inline.hpp"
+#include "services/diagnosticArgument.hpp"
+#include "services/diagnosticFramework.hpp"
+#include "utilities/ostream.hpp"
+
+struct ObsoleteOption {
+  const char* name;
+  const char* message;
+};
+
+static const ObsoleteOption OBSOLETE_OPTIONS[] = {
+  {"checkpointbuffersize", ""},
+  {"maxsize",              "Use -XX:StartFlightRecording=maxsize=... instead."},
+  {"maxage",               "Use -XX:StartFlightRecording=maxage=... instead."},
+  {"settings",             "Use -XX:StartFlightRecording=settings=... instead."},
+  {"defaultrecording",     "Use -XX:StartFlightRecording=disk=false to create an in-memory recording."},
+  {"disk",                 "Use -XX:StartFlightRecording=disk=... instead."},
+  {"dumponexit",           "Use -XX:StartFlightRecording=dumponexit=... instead."},
+  {"dumponexitpath",       "Use -XX:StartFlightRecording=filename=... instead."},
+  {"loglevel",             "Use -Xlog:jfr=... instead."}
+};
+
+jlong JfrOptionSet::max_chunk_size() {
+  return _max_chunk_size;
+}
+
+void JfrOptionSet::set_max_chunk_size(jlong value) {
+  _max_chunk_size = value;
+}
+
+jlong JfrOptionSet::global_buffer_size() {
+  return _global_buffer_size;
+}
+
+void JfrOptionSet::set_global_buffer_size(jlong value) {
+  _global_buffer_size = value;
+}
+
+jlong JfrOptionSet::thread_buffer_size() {
+  return _thread_buffer_size;
+}
+
+void JfrOptionSet::set_thread_buffer_size(jlong value) {
+  _thread_buffer_size = value;
+}
+
+jlong JfrOptionSet::memory_size() {
+  return _memory_size;
+}
+
+void JfrOptionSet::set_memory_size(jlong value) {
+  _memory_size = value;
+}
+
+jlong JfrOptionSet::num_global_buffers() {
+  return _num_global_buffers;
+}
+
+void JfrOptionSet::set_num_global_buffers(jlong value) {
+  _num_global_buffers = value;
+}
+
+jint JfrOptionSet::old_object_queue_size() {
+  return (jint)_old_object_queue_size;
+}
+
+void JfrOptionSet::set_old_object_queue_size(jlong value) {
+  _old_object_queue_size = value;
+}
+
+u4 JfrOptionSet::stackdepth() {
+  return _stack_depth;
+}
+
+static const u4 STACK_DEPTH_DEFAULT = 64;
+static const u4 MIN_STACK_DEPTH = 1;
+static const u4 MAX_STACK_DEPTH = 2048;
+
+void JfrOptionSet::set_stackdepth(u4 depth) {
+  if (depth < MIN_STACK_DEPTH) {
+    _stack_depth = MIN_STACK_DEPTH;
+  } else if (depth > MAX_STACK_DEPTH) {
+    _stack_depth = MAX_STACK_DEPTH;
+  } else {
+    _stack_depth = depth;
+  }
+}
+
+bool JfrOptionSet::sample_threads() {
+  return _sample_threads == JNI_TRUE;
+}
+
+void JfrOptionSet::set_sample_threads(jboolean sample) {
+  _sample_threads = sample;
+}
+
+bool JfrOptionSet::can_retransform() {
+  return _retransform == JNI_TRUE;
+}
+
+void JfrOptionSet::set_retransform(jboolean value) {
+  _retransform = value;
+}
+
+bool JfrOptionSet::sample_protection() {
+  return _sample_protection == JNI_TRUE;
+}
+
+#ifdef ASSERT
+void JfrOptionSet::set_sample_protection(jboolean protection) {
+  _sample_protection = protection;
+}
+#endif
+
+bool JfrOptionSet::compressed_integers() {
+  // Set this to false for debugging purposes.
+  return true;
+}
+
+bool JfrOptionSet::allow_retransforms() {
+#if INCLUDE_JVMTI
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool JfrOptionSet::allow_event_retransforms() {
+  return allow_retransforms() && (DumpSharedSpaces || can_retransform());
+}
+
+// default options for the dcmd parser
+const char* const default_repository = NULL;
+const char* const default_global_buffer_size = "512k";
+const char* const default_num_global_buffers = "20";
+const char* const default_memory_size = "10m";
+const char* const default_thread_buffer_size = "8k";
+const char* const default_max_chunk_size = "12m";
+const char* const default_sample_threads = "true";
+const char* const default_stack_depth = "64";
+const char* const default_retransform = "true";
+const char* const default_old_object_queue_size = "256";
+DEBUG_ONLY(const char* const default_sample_protection = "false";)
+
+// statics
+static DCmdArgument<char*> _dcmd_repository(
+  "repository",
+  "Flight recorder disk repository location",
+  "STRING",
+  false,
+  default_repository);
+
+static DCmdArgument<MemorySizeArgument> _dcmd_threadbuffersize(
+  "threadbuffersize",
+  "Thread buffer size",
+  "MEMORY SIZE",
+  false,
+  default_thread_buffer_size);
+
+static DCmdArgument<MemorySizeArgument> _dcmd_memorysize(
+  "memorysize",
+  "Size of memory to be used by Flight Recorder",
+  "MEMORY SIZE",
+  false,
+  default_memory_size);
+
+static DCmdArgument<MemorySizeArgument> _dcmd_globalbuffersize(
+  "globalbuffersize",
+  "Global buffer size",
+  "MEMORY SIZE",
+  false,
+  default_global_buffer_size);
+
+static DCmdArgument<jlong> _dcmd_numglobalbuffers(
+  "numglobalbuffers",
+  "Number of global buffers",
+  "JULONG",
+  false,
+  default_num_global_buffers);
+
+static DCmdArgument<MemorySizeArgument> _dcmd_maxchunksize(
+  "maxchunksize",
+  "Maximum size of a single repository disk chunk",
+  "MEMORY SIZE",
+  false,
+  default_max_chunk_size);
+
+static DCmdArgument<jlong> _dcmd_old_object_queue_size (
+  "old-object-queue-size",
+  "Maximum number of old objects to track",
+  "JINT",
+  false,
+  default_old_object_queue_size);
+
+static DCmdArgument<bool> _dcmd_sample_threads(
+  "samplethreads",
+  "Thread sampling enable / disable (only sampling when event enabled and sampling enabled)",
+  "BOOLEAN",
+  false,
+  default_sample_threads);
+
+#ifdef ASSERT
+static DCmdArgument<bool> _dcmd_sample_protection(
+  "sampleprotection",
+  "Safeguard for stackwalking while sampling threads (false by default)",
+  "BOOLEAN",
+  false,
+  default_sample_protection);
+#endif
+
+static DCmdArgument<jlong> _dcmd_stackdepth(
+  "stackdepth",
+  "Stack depth for stacktraces (minimum 1, maximum 2048)",
+  "JULONG",
+  false,
+  default_stack_depth);
+
+static DCmdArgument<bool> _dcmd_retransform(
+  "retransform",
+  "If event classes should be instrumented using JVMTI (by default true)",
+  "BOOLEAN",
+  true,
+  default_retransform);
+
+static DCmdParser _parser;
+
+static void register_parser_options() {
+  _parser.add_dcmd_option(&_dcmd_repository);
+  _parser.add_dcmd_option(&_dcmd_threadbuffersize);
+  _parser.add_dcmd_option(&_dcmd_memorysize);
+  _parser.add_dcmd_option(&_dcmd_globalbuffersize);
+  _parser.add_dcmd_option(&_dcmd_numglobalbuffers);
+  _parser.add_dcmd_option(&_dcmd_maxchunksize);
+  _parser.add_dcmd_option(&_dcmd_stackdepth);
+  _parser.add_dcmd_option(&_dcmd_sample_threads);
+  _parser.add_dcmd_option(&_dcmd_retransform);
+  _parser.add_dcmd_option(&_dcmd_old_object_queue_size);
+  DEBUG_ONLY(_parser.add_dcmd_option(&_dcmd_sample_protection);)
+}
+
+static bool parse_flight_recorder_options_internal(TRAPS) {
+  if (FlightRecorderOptions == NULL) {
+    return true;
+  }
+  const size_t length = strlen((const char*)FlightRecorderOptions);
+  CmdLine cmdline((const char*)FlightRecorderOptions, length, true);
+  _parser.parse(&cmdline, ',', THREAD);
+  if (HAS_PENDING_EXCEPTION) {
+    for (int index = 0; index < 9; index++) {
+      ObsoleteOption option = OBSOLETE_OPTIONS[index];
+      const char* p = strstr((const char*)FlightRecorderOptions, option.name);
+      const size_t option_length = strlen(option.name);
+      if (p != NULL && p[option_length] == '=') {
+        log_error(arguments) ("-XX:FlightRecorderOptions=%s=... has been removed. %s", option.name, option.message);
+        return false;
+      }
+    }
+    ResourceMark rm(THREAD);
+    oop message = java_lang_Throwable::message(PENDING_EXCEPTION);
+    if (message != NULL) {
+      const char* msg = java_lang_String::as_utf8_string(message);
+      log_error(arguments) ("%s", msg);
+    }
+    CLEAR_PENDING_EXCEPTION;
+    return false;
+  }
+  return true;
+}
+
+jlong JfrOptionSet::_max_chunk_size = 0;
+jlong JfrOptionSet::_global_buffer_size = 0;
+jlong JfrOptionSet::_thread_buffer_size = 0;
+jlong JfrOptionSet::_memory_size = 0;
+jlong JfrOptionSet::_num_global_buffers = 0;
+jlong JfrOptionSet::_old_object_queue_size = 0;
+u4 JfrOptionSet::_stack_depth = STACK_DEPTH_DEFAULT;
+jboolean JfrOptionSet::_sample_threads = JNI_TRUE;
+jboolean JfrOptionSet::_retransform = JNI_TRUE;
+#ifdef ASSERT
+jboolean JfrOptionSet::_sample_protection = JNI_FALSE;
+#else
+jboolean JfrOptionSet::_sample_protection = JNI_TRUE;
+#endif
+
+bool JfrOptionSet::initialize(Thread* thread) {
+  register_parser_options();
+  if (!parse_flight_recorder_options_internal(thread)) {
+    return false;
+  }
+  if (_dcmd_retransform.is_set()) {
+    set_retransform(_dcmd_retransform.value());
+  }
+  set_old_object_queue_size(_dcmd_old_object_queue_size.value());
+  return adjust_memory_options();
+}
+
+bool JfrOptionSet::configure(TRAPS) {
+  if (FlightRecorderOptions == NULL) {
+    return true;
+  }
+  ResourceMark rm(THREAD);
+  bufferedStream st;
+  // delegate to DCmd execution
+  JfrConfigureFlightRecorderDCmd configure(&st, false);
+  configure._repository_path.set_is_set(_dcmd_repository.is_set());
+  char* repo = _dcmd_repository.value();
+  if (repo != NULL) {
+    const size_t len = strlen(repo);
+    char* repo_copy = JfrCHeapObj::new_array<char>(len + 1);
+    if (NULL == repo_copy) {
+      return false;
+    }
+    strncpy(repo_copy, repo, len + 1);
+    configure._repository_path.set_value(repo_copy);
+  }
+
+  configure._stack_depth.set_is_set(_dcmd_stackdepth.is_set());
+  configure._stack_depth.set_value(_dcmd_stackdepth.value());
+
+  configure._thread_buffer_size.set_is_set(_dcmd_threadbuffersize.is_set());
+  configure._thread_buffer_size.set_value(_dcmd_threadbuffersize.value()._size);
+
+  configure._global_buffer_count.set_is_set(_dcmd_numglobalbuffers.is_set());
+  configure._global_buffer_count.set_value(_dcmd_numglobalbuffers.value());
+
+  configure._global_buffer_size.set_is_set(_dcmd_globalbuffersize.is_set());
+  configure._global_buffer_size.set_value(_dcmd_globalbuffersize.value()._size);
+
+  configure._max_chunk_size.set_is_set(_dcmd_maxchunksize.is_set());
+  configure._max_chunk_size.set_value(_dcmd_maxchunksize.value()._size);
+
+  configure._memory_size.set_is_set(_dcmd_memorysize.is_set());
+  configure._memory_size.set_value(_dcmd_memorysize.value()._size);
+
+  configure._sample_threads.set_is_set(_dcmd_sample_threads.is_set());
+  configure._sample_threads.set_value(_dcmd_sample_threads.value());
+
+  configure.execute(DCmd_Source_Internal, THREAD);
+
+  if (HAS_PENDING_EXCEPTION) {
+    java_lang_Throwable::print(PENDING_EXCEPTION, tty);
+    CLEAR_PENDING_EXCEPTION;
+    return false;
+  }
+  return true;
+}
+
+template <typename Argument>
+static julong divide_with_user_unit(Argument& memory_argument, julong value) {
+  if (memory_argument.value()._size != memory_argument.value()._val) {
+    switch (memory_argument.value()._multiplier) {
+    case 'k': case 'K':
+      return value / K;
+    case 'm': case 'M':
+      return value / M;
+    case 'g': case 'G':
+      return value / G;
+    }
+  }
+  return value;
+}
+
+template <typename Argument>
+static void log_lower_than_min_value(Argument& memory_argument, julong min_value) {
+  if (memory_argument.value()._size != memory_argument.value()._val) {
+    // has multiplier
+    log_error(arguments) (
+      "This value is lower than the minimum size required " JULONG_FORMAT "%c",
+      divide_with_user_unit(memory_argument, min_value),
+      memory_argument.value()._multiplier);
+    return;
+  }
+  log_error(arguments) (
+    "This value is lower than the minimum size required " JULONG_FORMAT,
+    divide_with_user_unit(memory_argument, min_value));
+}
+
+template <typename Argument>
+static void log_set_value(Argument& memory_argument) {
+  if (memory_argument.value()._size != memory_argument.value()._val) {
+    // has multiplier
+    log_error(arguments) (
+      "Value specified for option \"%s\" is " JULONG_FORMAT "%c",
+      memory_argument.name(),
+      memory_argument.value()._val,
+      memory_argument.value()._multiplier);
+    return;
+  }
+  log_error(arguments) (
+    "Value specified for option \"%s\" is " JULONG_FORMAT,
+    memory_argument.name(), memory_argument.value()._val);
+}
+
+template <typename MemoryArg>
+static void log_adjustments(MemoryArg& original_memory_size, julong new_memory_size, const char* msg) {
+  log_trace(arguments) (
+    "%s size (original) " JULONG_FORMAT " B (user defined: %s)",
+    msg,
+    original_memory_size.value()._size,
+    original_memory_size.is_set() ? "true" : "false");
+  log_trace(arguments) (
+    "%s size (adjusted) " JULONG_FORMAT " B (modified: %s)",
+    msg,
+    new_memory_size,
+    original_memory_size.value()._size != new_memory_size ? "true" : "false");
+  log_trace(arguments) (
+    "%s size (adjustment) %s" JULONG_FORMAT " B",
+    msg,
+    new_memory_size < original_memory_size.value()._size ? "-" : "+",
+    new_memory_size < original_memory_size.value()._size ?
+    original_memory_size.value()._size - new_memory_size :
+    new_memory_size - original_memory_size.value()._size);
+}
+
+// All "triangular" options are explicitly set
+// check that they are congruent and not causing
+// an ambiguous situtation
+template <typename MemoryArg, typename NumberArg>
+static bool check_for_ambiguity(MemoryArg& memory_size, MemoryArg& global_buffer_size, NumberArg& num_global_buffers) {
+  assert(memory_size.is_set(), "invariant");
+  assert(global_buffer_size.is_set(), "invariant");
+  assert(num_global_buffers.is_set(), "invariant");
+  const julong calc_size = global_buffer_size.value()._size * (julong)num_global_buffers.value();
+  if (calc_size != memory_size.value()._size) {
+    // ambiguous
+    log_set_value(global_buffer_size);
+    log_error(arguments) (
+      "Value specified for option \"%s\" is " JLONG_FORMAT,
+      num_global_buffers.name(), num_global_buffers.value());
+    log_set_value(memory_size);
+    log_error(arguments) (
+      "These values are causing an ambiguity when trying to determine how much memory to use");
+    log_error(arguments) ("\"%s\" * \"%s\" do not equal \"%s\"",
+      global_buffer_size.name(),
+      num_global_buffers.name(),
+      memory_size.name());
+    log_error(arguments) (
+      "Try to remove one of the involved options or make sure they are unambigous");
+    return false;
+  }
+  return true;
+}
+
+template <typename Argument>
+static bool ensure_minimum_count(Argument& buffer_count_argument, jlong min_count) {
+  if (buffer_count_argument.value() < min_count) {
+    log_error(arguments) (
+      "Value specified for option \"%s\" is " JLONG_FORMAT,
+      buffer_count_argument.name(), buffer_count_argument.value());
+    log_error(arguments) (
+      "This value is lower than the minimum required number " JLONG_FORMAT,
+      min_count);
+    return false;
+  }
+  return true;
+}
+
+// global buffer size and num global buffers specified
+// ensure that particular combination to be ihigher than minimum memory size
+template <typename MemoryArg, typename NumberArg>
+static bool ensure_calculated_gteq(MemoryArg& global_buffer_size, NumberArg& num_global_buffers, julong min_value) {
+  assert(global_buffer_size.is_set(), "invariant");
+  assert(num_global_buffers.is_set(), "invariant");
+  const julong calc_size = global_buffer_size.value()._size * (julong)num_global_buffers.value();
+  if (calc_size < min_value) {
+    log_set_value(global_buffer_size);
+    log_error(arguments) (
+      "Value specified for option \"%s\" is " JLONG_FORMAT,
+      num_global_buffers.name(), num_global_buffers.value());
+    log_error(arguments) ("\"%s\" * \"%s\" (" JULONG_FORMAT
+      ") is lower than minimum memory size required " JULONG_FORMAT,
+      global_buffer_size.name(),
+      num_global_buffers.name(),
+      calc_size,
+      min_value);
+    return false;
+  }
+  return true;
+}
+
+template <typename Argument>
+static bool ensure_first_gteq_second(Argument& first_argument, Argument& second_argument) {
+  if (second_argument.value()._size > first_argument.value()._size) {
+    log_set_value(first_argument);
+    log_set_value(second_argument);
+    log_error(arguments) (
+      "The value for option \"%s\" should not be larger than the value specified for option \"%s\"",
+      second_argument.name(), first_argument.name());
+    return false;
+  }
+  return true;
+}
+
+static bool valid_memory_relations(const JfrMemoryOptions& options) {
+  if (options.global_buffer_size_configured) {
+    if (options.memory_size_configured) {
+      if (!ensure_first_gteq_second(_dcmd_memorysize, _dcmd_globalbuffersize)) {
+        return false;
+      }
+    }
+    if (options.thread_buffer_size_configured) {
+      if (!ensure_first_gteq_second(_dcmd_globalbuffersize, _dcmd_threadbuffersize)) {
+        return false;
+      }
+    }
+    if (options.buffer_count_configured) {
+      if (!ensure_calculated_gteq(_dcmd_globalbuffersize, _dcmd_numglobalbuffers, MIN_MEMORY_SIZE)) {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+static void post_process_adjusted_memory_options(const JfrMemoryOptions& options) {
+  assert(options.memory_size >= MIN_MEMORY_SIZE, "invariant");
+  assert(options.global_buffer_size >= MIN_GLOBAL_BUFFER_SIZE, "invariant");
+  assert(options.buffer_count >= MIN_BUFFER_COUNT, "invariant");
+  assert(options.thread_buffer_size >= MIN_THREAD_BUFFER_SIZE, "invariant");
+  log_adjustments(_dcmd_memorysize, options.memory_size, "Memory");
+  log_adjustments(_dcmd_globalbuffersize, options.global_buffer_size, "Global buffer");
+  log_adjustments(_dcmd_threadbuffersize, options.thread_buffer_size, "Thread local buffer");
+  log_trace(arguments) ("Number of global buffers (original) " JLONG_FORMAT " (user defined: %s)",
+    _dcmd_numglobalbuffers.value(),
+    _dcmd_numglobalbuffers.is_set() ? "true" : "false");
+  log_trace(arguments) ( "Number of global buffers (adjusted) " JULONG_FORMAT " (modified: %s)",
+    options.buffer_count,
+    _dcmd_numglobalbuffers.value() != (jlong)options.buffer_count ? "true" : "false");
+  log_trace(arguments) ("Number of global buffers (adjustment) %s" JLONG_FORMAT,
+    (jlong)options.buffer_count < _dcmd_numglobalbuffers.value() ? "" : "+",
+    (jlong)options.buffer_count - _dcmd_numglobalbuffers.value());
+
+  MemorySizeArgument adjusted_memory_size;
+  adjusted_memory_size._val = divide_with_user_unit(_dcmd_memorysize, options.memory_size);
+  adjusted_memory_size._multiplier = _dcmd_memorysize.value()._multiplier;
+  adjusted_memory_size._size = options.memory_size;
+
+  MemorySizeArgument adjusted_global_buffer_size;
+  adjusted_global_buffer_size._val = divide_with_user_unit(_dcmd_globalbuffersize, options.global_buffer_size);
+  adjusted_global_buffer_size._multiplier = _dcmd_globalbuffersize.value()._multiplier;
+  adjusted_global_buffer_size._size = options.global_buffer_size;
+
+  MemorySizeArgument adjusted_thread_buffer_size;
+  adjusted_thread_buffer_size._val = divide_with_user_unit(_dcmd_threadbuffersize, options.thread_buffer_size);
+  adjusted_thread_buffer_size._multiplier = _dcmd_threadbuffersize.value()._multiplier;
+  adjusted_thread_buffer_size._size = options.thread_buffer_size;
+
+  // store back to dcmd
+  _dcmd_memorysize.set_value(adjusted_memory_size);
+  _dcmd_memorysize.set_is_set(true);
+  _dcmd_globalbuffersize.set_value(adjusted_global_buffer_size);
+  _dcmd_globalbuffersize.set_is_set(true);
+  _dcmd_numglobalbuffers.set_value((jlong)options.buffer_count);
+  _dcmd_numglobalbuffers.set_is_set(true);
+  _dcmd_threadbuffersize.set_value(adjusted_thread_buffer_size);
+  _dcmd_threadbuffersize.set_is_set(true);
+}
+
+static void initialize_memory_options_from_dcmd(JfrMemoryOptions& options) {
+  options.memory_size = _dcmd_memorysize.value()._size;
+  options.global_buffer_size = MAX2<julong>(_dcmd_globalbuffersize.value()._size, (julong)os::vm_page_size());
+  options.buffer_count = (julong)_dcmd_numglobalbuffers.value();
+  options.thread_buffer_size = MAX2<julong>(_dcmd_threadbuffersize.value()._size, (julong)os::vm_page_size());
+  // determine which options have been explicitly set
+  options.memory_size_configured = _dcmd_memorysize.is_set();
+  options.global_buffer_size_configured = _dcmd_globalbuffersize.is_set();
+  options.buffer_count_configured = _dcmd_numglobalbuffers.is_set();
+  options.thread_buffer_size_configured = _dcmd_threadbuffersize.is_set();
+  assert(options.memory_size >= MIN_MEMORY_SIZE, "invariant");
+  assert(options.global_buffer_size >= MIN_GLOBAL_BUFFER_SIZE, "invariant");
+  assert(options.buffer_count >= MIN_BUFFER_COUNT, "invariant");
+  assert(options.thread_buffer_size >= MIN_THREAD_BUFFER_SIZE, "invariant");
+}
+
+template <typename Argument>
+static bool ensure_gteq(Argument& memory_argument, const jlong value) {
+  if ((jlong)memory_argument.value()._size < value) {
+    log_set_value(memory_argument);
+    log_lower_than_min_value(memory_argument, value);
+    return false;
+  }
+  return true;
+}
+
+static bool ensure_valid_minimum_sizes() {
+  // ensure valid minimum memory sizes
+  if (_dcmd_memorysize.is_set()) {
+    if (!ensure_gteq(_dcmd_memorysize, MIN_MEMORY_SIZE)) {
+      return false;
+    }
+  }
+  if (_dcmd_globalbuffersize.is_set()) {
+    if (!ensure_gteq(_dcmd_globalbuffersize, MIN_GLOBAL_BUFFER_SIZE)) {
+      return false;
+    }
+  }
+  if (_dcmd_numglobalbuffers.is_set()) {
+    if (!ensure_minimum_count(_dcmd_numglobalbuffers, MIN_BUFFER_COUNT)) {
+      return false;
+    }
+  }
+  if (_dcmd_threadbuffersize.is_set()) {
+    if (!ensure_gteq(_dcmd_threadbuffersize, MIN_THREAD_BUFFER_SIZE)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+/**
+ * Starting with the initial set of memory values from the user,
+ * sanitize, enforce min/max rules and adjust to a set of consistent options.
+ *
+ * Adjusted memory sizes will be page aligned.
+ */
+bool JfrOptionSet::adjust_memory_options() {
+  if (!ensure_valid_minimum_sizes()) {
+    return false;
+  }
+  JfrMemoryOptions options;
+  initialize_memory_options_from_dcmd(options);
+  if (!valid_memory_relations(options)) {
+    return false;
+  }
+  if (!JfrMemorySizer::adjust_options(&options)) {
+    if (!check_for_ambiguity(_dcmd_memorysize, _dcmd_globalbuffersize, _dcmd_numglobalbuffers)) {
+      return false;
+    }
+  }
+  post_process_adjusted_memory_options(options);
+  return true;
+}
+
+/*
+
+to support starting multiple startup recordings
+
+static const char* start_flight_recording_option_original = NULL;
+static const char* flight_recorder_option_original = NULL;
+
+static void copy_option_string(const JavaVMOption* option, const char** addr) {
+  assert(option != NULL, "invariant");
+  assert(option->optionString != NULL, "invariant");
+  const size_t length = strlen(option->optionString);
+  *addr = JfrCHeapObj::new_array<char>(length + 1);
+  assert(*addr != NULL, "invarinat");
+  strncpy((char*)*addr, option->optionString, length + 1);
+  assert(strncmp(*addr, option->optionString, length + 1) == 0, "invariant");
+}
+
+copy_option_string(*option, &start_flight_recording_option_original);
+copy_option_string(*option, &flight_recorder_option_original);
+*/
+
+bool JfrOptionSet::parse_start_flight_recording_option(const JavaVMOption** option, char* tail) {
+  assert(option != NULL, "invariant");
+  assert(tail != NULL, "invariant");
+  assert((*option)->optionString != NULL, "invariant");
+  assert(strncmp((*option)->optionString, "-XX:StartFlightRecording", 24) == 0, "invariant");
+  if (*tail == '\0') {
+    // Add dummy dumponexit=false so -XX:StartFlightRecording can be used without a parameter.
+    // The existing option->optionString points to stack memory so no need to deallocate.
+    const_cast<JavaVMOption*>(*option)->optionString = (char*)"-XX:StartFlightRecording=dumponexit=false";
+  } else {
+    *tail = '='; // ":" -> "="
+  }
+  return false;
+}
+
+bool JfrOptionSet::parse_flight_recorder_option(const JavaVMOption** option, char* tail) {
+  assert(option != NULL, "invariant");
+  assert(tail != NULL, "invariant");
+  assert((*option)->optionString != NULL, "invariant");
+  assert(strncmp((*option)->optionString, "-XX:FlightRecorderOptions", 25) == 0, "invariant");
+  if (tail != NULL) {
+    *tail = '='; // ":" -> "="
+  }
+  return false;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/service/jfrOptionSet.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_RECORDER_SERVICE_JFROPTIONSET_HPP
+#define SHARE_VM_JFR_RECORDER_SERVICE_JFROPTIONSET_HPP
+
+#include "jni.h"
+#include "memory/allocation.hpp"
+#include "utilities/exceptions.hpp"
+
+//
+// Command-line options and defaults
+//
+class JfrOptionSet : public AllStatic {
+  friend class JfrRecorder;
+ private:
+  static jlong _max_chunk_size;
+  static jlong _global_buffer_size;
+  static jlong _thread_buffer_size;
+  static jlong _memory_size;
+  static jlong _num_global_buffers;
+  static jlong _old_object_queue_size;
+  static u4 _stack_depth;
+  static jboolean _sample_threads;
+  static jboolean _retransform;
+  static jboolean _sample_protection;
+
+  static bool initialize(Thread* thread);
+  static bool configure(TRAPS);
+  static bool adjust_memory_options();
+
+ public:
+  static jlong max_chunk_size();
+  static void set_max_chunk_size(jlong value);
+  static jlong global_buffer_size();
+  static void set_global_buffer_size(jlong value);
+  static jlong thread_buffer_size();
+  static void set_thread_buffer_size(jlong value);
+  static jlong memory_size();
+  static void set_memory_size(jlong value);
+  static jlong num_global_buffers();
+  static void set_num_global_buffers(jlong value);
+  static jint old_object_queue_size();
+  static void set_old_object_queue_size(jlong value);
+  static u4 stackdepth();
+  static void set_stackdepth(u4 depth);
+  static bool sample_threads();
+  static void set_sample_threads(jboolean sample);
+  static bool can_retransform();
+  static void set_retransform(jboolean value);
+  static bool compressed_integers();
+  static bool allow_retransforms();
+  static bool allow_event_retransforms();
+  static bool sample_protection();
+  DEBUG_ONLY(static void set_sample_protection(jboolean protection);)
+
+  static bool parse_start_flight_recording_option(const JavaVMOption** option, char* tail);
+  static bool parse_flight_recorder_option(const JavaVMOption** option, char* tail);
+
+};
+
+#endif // SHARE_VM_JFR_RECORDER_SERVICE_JFROPTIONSET_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/service/jfrPostBox.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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 "jfr/recorder/service/jfrPostBox.hpp"
+#include "jfr/utilities/jfrTryLock.hpp"
+#include "runtime/atomic.hpp"
+#include "runtime/orderAccess.inline.hpp"
+#include "runtime/thread.inline.hpp"
+
+#define MSG_IS_SYNCHRONOUS ( (MSGBIT(MSG_ROTATE)) |          \
+                             (MSGBIT(MSG_STOP))   |          \
+                             (MSGBIT(MSG_START))  |          \
+                             (MSGBIT(MSG_CLONE_IN_MEMORY)) | \
+                             (MSGBIT(MSG_VM_ERROR))          \
+                           )
+
+static JfrPostBox* _instance = NULL;
+
+JfrPostBox& JfrPostBox::instance() {
+  return *_instance;
+}
+
+JfrPostBox* JfrPostBox::create() {
+  assert(_instance == NULL, "invariant");
+  _instance = new JfrPostBox();
+  return _instance;
+}
+
+void JfrPostBox::destroy() {
+  assert(_instance != NULL, "invariant");
+  delete _instance;
+  _instance = NULL;
+}
+
+JfrPostBox::JfrPostBox() :
+  _msg_read_serial(0),
+  _msg_handled_serial(0),
+  _messages(0),
+  _has_waiters(false) {}
+
+static bool is_thread_lock_aversive() {
+  Thread* const thread = Thread::current();
+  return (thread->is_Java_thread() && ((JavaThread*)thread)->thread_state() != _thread_in_vm) || thread->is_VM_thread();
+}
+
+static bool is_synchronous(int messages) {
+  return ((messages & MSG_IS_SYNCHRONOUS) != 0);
+}
+
+void JfrPostBox::post(JFR_Msg msg) {
+  const int the_message = MSGBIT(msg);
+  if (is_thread_lock_aversive()) {
+    deposit(the_message);
+    return;
+  }
+  if (!is_synchronous(the_message)) {
+    asynchronous_post(the_message);
+    return;
+  }
+  synchronous_post(the_message);
+}
+
+void JfrPostBox::deposit(int new_messages) {
+  while (true) {
+    const int current_msgs = OrderAccess::load_acquire(&_messages);
+    // OR the new message
+    const int exchange_value = current_msgs | new_messages;
+    const int result = Atomic::cmpxchg(exchange_value, &_messages, current_msgs);
+    if (result == current_msgs) {
+      return;
+    }
+    /* Some other thread just set exactly what this thread wanted */
+    if ((result & new_messages) == new_messages) {
+      return;
+    }
+  }
+}
+
+void JfrPostBox::asynchronous_post(int msg) {
+  assert(!is_synchronous(msg), "invariant");
+  deposit(msg);
+  JfrMonitorTryLock try_msg_lock(JfrMsg_lock);
+  if (try_msg_lock.acquired()) {
+    JfrMsg_lock->notify_all();
+  }
+}
+
+void JfrPostBox::synchronous_post(int msg) {
+  assert(is_synchronous(msg), "invariant");
+  assert(!JfrMsg_lock->owned_by_self(), "should not hold JfrMsg_lock here!");
+  MutexLockerEx msg_lock(JfrMsg_lock);
+  deposit(msg);
+  // serial_id is used to check when what we send in has been processed.
+  // _msg_read_serial is read under JfrMsg_lock protection.
+  const uintptr_t serial_id = OrderAccess::load_acquire(&_msg_read_serial) + 1;
+  JfrMsg_lock->notify_all();
+  while (!is_message_processed(serial_id)) {
+    JfrMsg_lock->wait();
+  }
+}
+
+/*
+ * Check if a synchronous message has been processed.
+ * We avoid racing on _msg_handled_serial by ensuring
+ * that we are holding the JfrMsg_lock when checking
+ * completion status.
+ */
+bool JfrPostBox::is_message_processed(uintptr_t serial_id) const {
+  assert(JfrMsg_lock->owned_by_self(), "_msg_handled_serial must be read under JfrMsg_lock protection");
+  return serial_id <= OrderAccess::load_acquire(&_msg_handled_serial);
+}
+
+bool JfrPostBox::is_empty() const {
+  assert(JfrMsg_lock->owned_by_self(), "not holding JfrMsg_lock!");
+  return OrderAccess::load_acquire(&_messages) == 0;
+}
+
+int JfrPostBox::collect() {
+  // get pending and reset to 0
+  const int messages = Atomic::xchg(0, &_messages);
+  if (check_waiters(messages)) {
+    _has_waiters = true;
+    assert(JfrMsg_lock->owned_by_self(), "incrementing _msg_read_serial is protected by JfrMsg_lock");
+    // Update made visible on release of JfrMsg_lock via fence instruction in Monitor::IUnlock.
+    ++_msg_read_serial;
+  }
+  return messages;
+}
+
+bool JfrPostBox::check_waiters(int messages) const {
+  assert(JfrMsg_lock->owned_by_self(), "not holding JfrMsg_lock!");
+  assert(!_has_waiters, "invariant");
+  return is_synchronous(messages);
+}
+
+void JfrPostBox::notify_waiters() {
+  if (!_has_waiters) {
+    return;
+  }
+  _has_waiters = false;
+  assert(JfrMsg_lock->owned_by_self(), "incrementing _msg_handled_serial is protected by JfrMsg_lock.");
+  // Update made visible on release of JfrMsg_lock via fence instruction in Monitor::IUnlock.
+  ++_msg_handled_serial;
+  JfrMsg_lock->notify();
+}
+
+// safeguard to ensure no threads are left waiting
+void JfrPostBox::notify_collection_stop() {
+  MutexLockerEx msg_lock(JfrMsg_lock);
+  JfrMsg_lock->notify_all();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/service/jfrPostBox.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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 SHARE_VM_JFR_RECORDER_SERVICE_JFRPOSTBOX_HPP
+#define SHARE_VM_JFR_RECORDER_SERVICE_JFRPOSTBOX_HPP
+
+#include "jfr/utilities/jfrAllocation.hpp"
+
+#define MSGBIT(e) (1<<(e))
+
+enum JFR_Msg {
+  MSG_ALL_MSGS = -1,
+  MSG_CLONE_IN_MEMORY = 0,
+  MSG_START,
+  MSG_STOP,
+  MSG_ROTATE,
+  MSG_FULLBUFFER,
+  MSG_CHECKPOINT,
+  MSG_WAKEUP,
+  MSG_SHUTDOWN,
+  MSG_VM_ERROR,
+  MSG_DEADBUFFER,
+  MSG_NO_OF_MSGS
+};
+
+/**
+ *  Jfr messaging.
+ *
+ *  Synchronous messages (posting thread waits for message completion):
+ *
+ *  MSG_CLONE_IN_MEMORY (0) ; MSGBIT(MSG_CLONE_IN_MEMORY) == (1 << 0) == 0x1
+ *  MSG_START(1)            ; MSGBIT(MSG_START) == (1 << 0x1) == 0x2
+ *  MSG_STOP (2)            ; MSGBIT(MSG_STOP) == (1 << 0x2) == 0x4
+ *  MSG_ROTATE (3)          ; MSGBIT(MSG_ROTATE) == (1 << 0x3) == 0x8
+ *  MSG_VM_ERROR (8)        ; MSGBIT(MSG_VM_ERROR) == (1 << 8) == 0x100
+ *
+ *  Asynchronous messages (posting thread returns immediately upon deposit):
+ *
+ *  MSG_FULLBUFFER (4)      ; MSGBIT(MSG_FULLBUFFER) == (1 << 0x4) == 0x10
+ *  MSG_CHECKPOINT (5)      ; MSGBIT(CHECKPOINT) == (1 << 5) == 0x20
+ *  MSG_WAKEUP (6)          ; MSGBIT(WAKEUP) == (1 << 6) == 0x40
+ *  MSG_SHUTDOWN (7)        ; MSGBIT(MSG_SHUTDOWN) == (1 << 7) == 0x80
+ *  MSG_DEADBUFFER (9)      ; MSGBIT(MSG_DEADBUFFER) == (1 << 9) == 0x200
+ */
+
+class JfrPostBox : public JfrCHeapObj {
+  friend class JfrRecorder;
+ public:
+  void post(JFR_Msg msg);
+
+ private:
+  uintptr_t _msg_read_serial;
+  uintptr_t _msg_handled_serial;
+  volatile int _messages;
+  bool _has_waiters;
+
+  JfrPostBox();
+  static JfrPostBox& instance();
+  static JfrPostBox* create();
+  static void destroy();
+
+  void asynchronous_post(int msg);
+  void synchronous_post(int msg);
+  void deposit(int new_messages);
+  bool is_message_processed(uintptr_t serial_id) const;
+
+  friend void recorderthread_entry(JavaThread*, Thread*);
+  // for the friend declaration above
+  bool is_empty() const;
+  int collect();
+  bool check_waiters(int messages) const;
+  void notify_waiters();
+  void notify_collection_stop();
+};
+
+#endif // SHARE_VM_JFR_RECORDER_SERVICE_JFRPOSTBOX_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,542 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/jni/jfrJavaSupport.hpp"
+#include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp"
+#include "jfr/recorder/jfrRecorder.hpp"
+#include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
+#include "jfr/recorder/checkpoint/jfrMetadataEvent.hpp"
+#include "jfr/recorder/repository/jfrChunkSizeNotifier.hpp"
+#include "jfr/recorder/repository/jfrChunkWriter.hpp"
+#include "jfr/recorder/repository/jfrRepository.hpp"
+#include "jfr/recorder/service/jfrPostBox.hpp"
+#include "jfr/recorder/service/jfrRecorderService.hpp"
+#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
+#include "jfr/recorder/storage/jfrStorage.hpp"
+#include "jfr/recorder/storage/jfrStorageControl.hpp"
+#include "jfr/recorder/stringpool/jfrStringPool.hpp"
+#include "jfr/utilities/jfrAllocation.hpp"
+#include "jfr/utilities/jfrTime.hpp"
+#include "jfr/writers/jfrJavaEventWriter.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
+#include "logging/log.hpp"
+#include "memory/resourceArea.hpp"
+#include "runtime/atomic.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/orderAccess.inline.hpp"
+#include "runtime/os.hpp"
+#include "runtime/safepoint.hpp"
+#include "runtime/thread.inline.hpp"
+#include "runtime/vm_operations.hpp"
+#include "runtime/vmThread.hpp"
+
+// set data iff *dest == NULL
+static bool try_set(void* const data, void** dest, bool clear) {
+  assert(data != NULL, "invariant");
+  const void* const current = OrderAccess::load_acquire(dest);
+  if (current != NULL) {
+    if (current != data) {
+      // already set
+      return false;
+    }
+    assert(current == data, "invariant");
+    if (!clear) {
+      // recursion disallowed
+      return false;
+    }
+  }
+  return Atomic::cmpxchg(clear ? NULL : data, dest, current) == current;
+}
+
+static void* rotation_thread = NULL;
+static const int rotation_try_limit = 1000;
+static const int rotation_retry_sleep_millis = 10;
+
+class RotationLock : public StackObj {
+ private:
+  Thread* const _thread;
+  bool _acquired;
+
+  void log(bool recursion) {
+    assert(!_acquired, "invariant");
+    const char* error_msg = NULL;
+    if (recursion) {
+      error_msg = "Unable to issue rotation due to recursive calls.";
+    }
+    else {
+      error_msg = "Unable to issue rotation due to wait timeout.";
+    }
+    log_info(jfr)( // For user, should not be "jfr, system"
+      "%s", error_msg);
+  }
+ public:
+  RotationLock(Thread* thread) : _thread(thread), _acquired(false) {
+    assert(_thread != NULL, "invariant");
+    if (_thread == rotation_thread) {
+      // recursion not supported
+      log(true);
+      return;
+    }
+
+    // limited to not spin indefinitely
+    for (int i = 0; i < rotation_try_limit; ++i) {
+      if (try_set(_thread, &rotation_thread, false)) {
+        _acquired = true;
+        assert(_thread == rotation_thread, "invariant");
+        return;
+      }
+      if (_thread->is_Java_thread()) {
+        // in order to allow the system to move to a safepoint
+        MutexLockerEx msg_lock(JfrMsg_lock);
+        JfrMsg_lock->wait(false, rotation_retry_sleep_millis);
+      }
+      else {
+        os::naked_short_sleep(rotation_retry_sleep_millis);
+      }
+    }
+    log(false);
+  }
+
+  ~RotationLock() {
+    assert(_thread != NULL, "invariant");
+    if (_acquired) {
+      assert(_thread == rotation_thread, "invariant");
+      while (!try_set(_thread, &rotation_thread, true));
+    }
+  }
+  bool not_acquired() const { return !_acquired; }
+};
+
+static intptr_t write_checkpoint_event_prologue(JfrChunkWriter& cw, u8 type_id) {
+  const intptr_t prev_cp_offset = cw.previous_checkpoint_offset();
+  const intptr_t prev_cp_relative_offset = 0 == prev_cp_offset ? 0 : prev_cp_offset - cw.current_offset();
+  cw.reserve(sizeof(u4));
+  cw.write<u8>(EVENT_CHECKPOINT);
+  cw.write(JfrTicks::now());
+  cw.write<jlong>((jlong)0);
+  cw.write(prev_cp_relative_offset); // write previous checkpoint offset delta
+  cw.write<bool>(false); // flushpoint
+  cw.write<u4>((u4)1); // nof types in this checkpoint
+  cw.write<u8>(type_id);
+  const intptr_t number_of_elements_offset = cw.current_offset();
+  cw.reserve(sizeof(u4));
+  return number_of_elements_offset;
+}
+
+template <typename ContentFunctor>
+class WriteCheckpointEvent : public StackObj {
+ private:
+  JfrChunkWriter& _cw;
+  u8 _type_id;
+  ContentFunctor& _content_functor;
+ public:
+  WriteCheckpointEvent(JfrChunkWriter& cw, u8 type_id, ContentFunctor& functor) :
+    _cw(cw),
+    _type_id(type_id),
+    _content_functor(functor) {
+    assert(_cw.is_valid(), "invariant");
+  }
+  bool process() {
+    // current_cp_offset is also offset for the event size header field
+    const intptr_t current_cp_offset = _cw.current_offset();
+    const intptr_t num_elements_offset = write_checkpoint_event_prologue(_cw, _type_id);
+    // invocation
+    _content_functor.process();
+    const u4 number_of_elements = (u4)_content_functor.processed();
+    if (number_of_elements == 0) {
+      // nothing to do, rewind writer to start
+      _cw.seek(current_cp_offset);
+      return true;
+    }
+    assert(number_of_elements > 0, "invariant");
+    assert(_cw.current_offset() > num_elements_offset, "invariant");
+    _cw.write_padded_at_offset<u4>(number_of_elements, num_elements_offset);
+    _cw.write_padded_at_offset<u4>((u4)_cw.current_offset() - current_cp_offset, current_cp_offset);
+    // update writer with last checkpoint position
+    _cw.set_previous_checkpoint_offset(current_cp_offset);
+    return true;
+  }
+};
+
+template <typename Instance, size_t(Instance::*func)()>
+class ServiceFunctor {
+ private:
+  Instance& _instance;
+  size_t _processed;
+ public:
+  ServiceFunctor(Instance& instance) : _instance(instance), _processed(0) {}
+  bool process() {
+    _processed = (_instance.*func)();
+    return true;
+  }
+  size_t processed() const { return _processed; }
+};
+
+template <typename Instance, void(Instance::*func)()>
+class JfrVMOperation : public VM_Operation {
+ private:
+  Instance& _instance;
+ public:
+  JfrVMOperation(Instance& instance) : _instance(instance) {}
+  void doit() { (_instance.*func)(); }
+  VMOp_Type type() const { return VMOp_JFRCheckpoint; }
+  Mode evaluation_mode() const { return _safepoint; } // default
+};
+
+class WriteStackTraceRepository : public StackObj {
+ private:
+  JfrStackTraceRepository& _repo;
+  JfrChunkWriter& _cw;
+  size_t _elements_processed;
+  bool _clear;
+
+ public:
+  WriteStackTraceRepository(JfrStackTraceRepository& repo, JfrChunkWriter& cw, bool clear) :
+    _repo(repo), _cw(cw), _elements_processed(0), _clear(clear) {}
+  bool process() {
+    _elements_processed = _repo.write(_cw, _clear);
+    return true;
+  }
+  size_t processed() const { return _elements_processed; }
+  void reset() { _elements_processed = 0; }
+};
+
+static bool recording = false;
+
+static void set_recording_state(bool is_recording) {
+  OrderAccess::storestore();
+  recording = is_recording;
+}
+
+bool JfrRecorderService::is_recording() {
+  return recording;
+}
+
+JfrRecorderService::JfrRecorderService() :
+  _checkpoint_manager(JfrCheckpointManager::instance()),
+  _chunkwriter(JfrRepository::chunkwriter()),
+  _repository(JfrRepository::instance()),
+  _storage(JfrStorage::instance()),
+  _stack_trace_repository(JfrStackTraceRepository::instance()),
+  _string_pool(JfrStringPool::instance()) {}
+
+void JfrRecorderService::start() {
+  RotationLock rl(Thread::current());
+  if (rl.not_acquired()) {
+    return;
+  }
+  log_debug(jfr, system)("Request to START recording");
+  assert(!is_recording(), "invariant");
+  clear();
+  set_recording_state(true);
+  assert(is_recording(), "invariant");
+  open_new_chunk();
+  log_debug(jfr, system)("Recording STARTED");
+}
+
+void JfrRecorderService::clear() {
+  ResourceMark rm;
+  HandleMark hm;
+  pre_safepoint_clear();
+  invoke_safepoint_clear();
+  post_safepoint_clear();
+}
+
+void JfrRecorderService::pre_safepoint_clear() {
+  _stack_trace_repository.clear();
+  _string_pool.clear();
+  _storage.clear();
+}
+
+void JfrRecorderService::invoke_safepoint_clear() {
+  JfrVMOperation<JfrRecorderService, &JfrRecorderService::safepoint_clear> safepoint_task(*this);
+  VMThread::execute(&safepoint_task);
+}
+
+//
+// safepoint clear sequence
+//
+//  clear stacktrace repository ->
+//    clear string pool ->
+//      clear storage ->
+//        shift epoch ->
+//          update time
+//
+void JfrRecorderService::safepoint_clear() {
+  assert(SafepointSynchronize::is_at_safepoint(), "invariant");
+  _stack_trace_repository.clear();
+  _string_pool.clear();
+  _storage.clear();
+  _checkpoint_manager.shift_epoch();
+  _chunkwriter.time_stamp_chunk_now();
+}
+
+void JfrRecorderService::post_safepoint_clear() {
+  _checkpoint_manager.clear();
+}
+
+static void stop() {
+  assert(JfrRecorderService::is_recording(), "invariant");
+  log_debug(jfr, system)("Recording STOPPED");
+  set_recording_state(false);
+  assert(!JfrRecorderService::is_recording(), "invariant");
+}
+
+void JfrRecorderService::rotate(int msgs) {
+  RotationLock rl(Thread::current());
+  if (rl.not_acquired()) {
+    return;
+  }
+  static bool vm_error = false;
+  if (msgs & MSGBIT(MSG_VM_ERROR)) {
+    vm_error = true;
+    prepare_for_vm_error_rotation();
+  }
+  if (msgs & (MSGBIT(MSG_STOP))) {
+    stop();
+  }
+  // action determined by chunkwriter state
+  if (!_chunkwriter.is_valid()) {
+    in_memory_rotation();
+    return;
+  }
+  if (vm_error) {
+    vm_error_rotation();
+    return;
+  }
+  chunk_rotation();
+}
+
+void JfrRecorderService::prepare_for_vm_error_rotation() {
+  if (!_chunkwriter.is_valid()) {
+    open_new_chunk(true);
+  }
+  _checkpoint_manager.register_service_thread(Thread::current());
+}
+
+void JfrRecorderService::open_new_chunk(bool vm_error) {
+  assert(!_chunkwriter.is_valid(), "invariant");
+  assert(!JfrStream_lock->owned_by_self(), "invariant");
+  MutexLockerEx stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag);
+  if (!_repository.open_chunk(vm_error)) {
+    assert(!_chunkwriter.is_valid(), "invariant");
+    _storage.control().set_to_disk(false);
+    return;
+  }
+  assert(_chunkwriter.is_valid(), "invariant");
+  _storage.control().set_to_disk(true);
+}
+
+void JfrRecorderService::in_memory_rotation() {
+  assert(!_chunkwriter.is_valid(), "invariant");
+  // currently running an in-memory recording
+  open_new_chunk();
+  if (_chunkwriter.is_valid()) {
+    // dump all in-memory buffer data to the newly created chunk
+    serialize_storage_from_in_memory_recording();
+  }
+}
+
+void JfrRecorderService::serialize_storage_from_in_memory_recording() {
+  assert(!JfrStream_lock->owned_by_self(), "not holding stream lock!");
+  MutexLockerEx stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag);
+  _storage.write();
+}
+
+void JfrRecorderService::chunk_rotation() {
+  finalize_current_chunk();
+  open_new_chunk();
+}
+
+void JfrRecorderService::finalize_current_chunk() {
+  assert(_chunkwriter.is_valid(), "invariant");
+  write();
+  assert(!_chunkwriter.is_valid(), "invariant");
+}
+
+void JfrRecorderService::write() {
+  ResourceMark rm;
+  HandleMark hm;
+  pre_safepoint_write();
+  invoke_safepoint_write();
+  post_safepoint_write();
+}
+
+typedef ServiceFunctor<JfrStringPool, &JfrStringPool::write> WriteStringPool;
+typedef ServiceFunctor<JfrStringPool, &JfrStringPool::write_at_safepoint> WriteStringPoolSafepoint;
+typedef WriteCheckpointEvent<WriteStackTraceRepository> WriteStackTraceCheckpoint;
+typedef WriteCheckpointEvent<WriteStringPool> WriteStringPoolCheckpoint;
+typedef WriteCheckpointEvent<WriteStringPoolSafepoint> WriteStringPoolCheckpointSafepoint;
+
+static void write_stacktrace_checkpoint(JfrStackTraceRepository& stack_trace_repo, JfrChunkWriter& chunkwriter, bool clear) {
+  WriteStackTraceRepository write_stacktrace_repo(stack_trace_repo, chunkwriter, clear);
+  WriteStackTraceCheckpoint write_stack_trace_checkpoint(chunkwriter, TYPE_STACKTRACE, write_stacktrace_repo);
+  write_stack_trace_checkpoint.process();
+}
+
+static void write_stringpool_checkpoint(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) {
+  WriteStringPool write_string_pool(string_pool);
+  WriteStringPoolCheckpoint write_string_pool_checkpoint(chunkwriter, TYPE_STRING, write_string_pool);
+  write_string_pool_checkpoint.process();
+}
+
+static void write_stringpool_checkpoint_safepoint(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) {
+  WriteStringPoolSafepoint write_string_pool(string_pool);
+  WriteStringPoolCheckpointSafepoint write_string_pool_checkpoint(chunkwriter, TYPE_STRING, write_string_pool);
+  write_string_pool_checkpoint.process();
+}
+
+//
+// pre-safepoint write sequence
+//
+//  lock stream lock ->
+//    write non-safepoint dependent types ->
+//      write checkpoint epoch transition list->
+//        write stack trace checkpoint ->
+//          write string pool checkpoint ->
+//            write storage ->
+//              release stream lock
+//
+void JfrRecorderService::pre_safepoint_write() {
+  MutexLockerEx stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag);
+  assert(_chunkwriter.is_valid(), "invariant");
+  _checkpoint_manager.write_types();
+  _checkpoint_manager.write_epoch_transition_mspace();
+  write_stacktrace_checkpoint(_stack_trace_repository, _chunkwriter, false);
+  write_stringpool_checkpoint(_string_pool, _chunkwriter);
+  _storage.write();
+}
+
+void JfrRecorderService::invoke_safepoint_write() {
+  JfrVMOperation<JfrRecorderService, &JfrRecorderService::safepoint_write> safepoint_task(*this);
+  VMThread::execute(&safepoint_task);
+}
+
+static void write_object_sample_stacktrace(JfrStackTraceRepository& stack_trace_repository) {
+  WriteObjectSampleStacktrace object_sample_stacktrace(stack_trace_repository);
+  object_sample_stacktrace.process();
+}
+
+//
+// safepoint write sequence
+//
+//   lock stream lock ->
+//     write object sample stacktraces ->
+//       write stacktrace repository ->
+//         write string pool ->
+//           write safepoint dependent types ->
+//             write storage ->
+//                 shift_epoch ->
+//                   update time ->
+//                     lock metadata descriptor ->
+//                       release stream lock
+//
+void JfrRecorderService::safepoint_write() {
+  assert(SafepointSynchronize::is_at_safepoint(), "invariant");
+  MutexLockerEx stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag);
+  write_object_sample_stacktrace(_stack_trace_repository);
+  write_stacktrace_checkpoint(_stack_trace_repository, _chunkwriter, true);
+  write_stringpool_checkpoint_safepoint(_string_pool, _chunkwriter);
+  _checkpoint_manager.write_safepoint_types();
+  _storage.write_at_safepoint();
+  _checkpoint_manager.shift_epoch();
+  _chunkwriter.time_stamp_chunk_now();
+  JfrMetadataEvent::lock();
+}
+
+static jlong write_metadata_event(JfrChunkWriter& chunkwriter) {
+  assert(chunkwriter.is_valid(), "invariant");
+  const jlong metadata_offset = chunkwriter.current_offset();
+  JfrMetadataEvent::write(chunkwriter, metadata_offset);
+  return metadata_offset;
+}
+
+//
+// post-safepoint write sequence
+//
+//  lock stream lock ->
+//    write type set ->
+//      write checkpoints ->
+//        write metadata event ->
+//          write chunk header ->
+//            close chunk fd ->
+//              release stream lock
+//
+void JfrRecorderService::post_safepoint_write() {
+  assert(_chunkwriter.is_valid(), "invariant");
+  // During the safepoint tasks just completed, the system transitioned to a new epoch.
+  // Type tagging is epoch relative which entails we are able to write out the
+  // already tagged artifacts for the previous epoch. We can accomplish this concurrently
+  // with threads now tagging artifacts in relation to the new, now updated, epoch and remain outside of a safepoint.
+  _checkpoint_manager.write_type_set();
+  MutexLockerEx stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag);
+  // serialize any outstanding checkpoint memory
+  _checkpoint_manager.write();
+  // serialize the metadata descriptor event and close out the chunk
+  _repository.close_chunk(write_metadata_event(_chunkwriter));
+  assert(!_chunkwriter.is_valid(), "invariant");
+}
+
+void JfrRecorderService::vm_error_rotation() {
+  if (_chunkwriter.is_valid()) {
+    finalize_current_chunk_on_vm_error();
+    assert(!_chunkwriter.is_valid(), "invariant");
+    _repository.on_vm_error();
+  }
+}
+
+void JfrRecorderService::finalize_current_chunk_on_vm_error() {
+  assert(_chunkwriter.is_valid(), "invariant");
+  pre_safepoint_write();
+  JfrMetadataEvent::lock();
+  // Do not attempt safepoint dependent operations during emergency dump.
+  // Optimistically write tagged artifacts.
+  _checkpoint_manager.shift_epoch();
+  _checkpoint_manager.write_type_set();
+  // update time
+  _chunkwriter.time_stamp_chunk_now();
+  post_safepoint_write();
+  assert(!_chunkwriter.is_valid(), "invariant");
+}
+
+void JfrRecorderService::process_full_buffers() {
+  if (_chunkwriter.is_valid()) {
+    assert(!JfrStream_lock->owned_by_self(), "invariant");
+    MutexLockerEx stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag);
+    _storage.write_full();
+  }
+}
+
+void JfrRecorderService::scavenge() {
+  _storage.scavenge();
+}
+
+void JfrRecorderService::evaluate_chunk_size_for_rotation() {
+  const size_t size_written = _chunkwriter.size_written();
+  if (size_written > JfrChunkSizeNotifier::chunk_size_threshold()) {
+    JfrChunkSizeNotifier::notify();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_RECORDER_SERVICE_JFRRECORDERSERVICE_HPP
+#define SHARE_VM_JFR_RECORDER_SERVICE_JFRRECORDERSERVICE_HPP
+
+#include "jfr/utilities/jfrAllocation.hpp"
+
+class JfrCheckpointManager;
+class JfrChunkWriter;
+class JfrRepository;
+class JfrStackTraceRepository;
+class JfrStorage;
+class JfrStringPool;
+
+class JfrRecorderService : public StackObj {
+ private:
+  JfrCheckpointManager& _checkpoint_manager;
+  JfrChunkWriter& _chunkwriter;
+  JfrRepository& _repository;
+  JfrStackTraceRepository& _stack_trace_repository;
+  JfrStorage& _storage;
+  JfrStringPool& _string_pool;
+
+  void open_new_chunk(bool vm_error = false);
+  void chunk_rotation();
+  void in_memory_rotation();
+  void serialize_storage_from_in_memory_recording();
+  void finalize_current_chunk();
+  void finalize_current_chunk_on_vm_error();
+  void prepare_for_vm_error_rotation();
+  void vm_error_rotation();
+
+  void clear();
+  void pre_safepoint_clear();
+  void safepoint_clear();
+  void invoke_safepoint_clear();
+  void post_safepoint_clear();
+
+  void write();
+  void pre_safepoint_write();
+  void safepoint_write();
+  void invoke_safepoint_write();
+  void post_safepoint_write();
+
+ public:
+  JfrRecorderService();
+  void start();
+  void rotate(int msgs);
+  void process_full_buffers();
+  void scavenge();
+  void evaluate_chunk_size_for_rotation();
+  static bool is_recording();
+};
+
+#endif // SHARE_VM_JFR_RECORDER_SERVICE_JFRRECORDERSERVICE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderThread.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jni.h"
+#include "classfile/javaClasses.hpp"
+#include "classfile/symbolTable.hpp"
+#include "classfile/systemDictionary.hpp"
+#include "jfr/jni/jfrJavaSupport.hpp"
+#include "jfr/recorder/jfrRecorder.hpp"
+#include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
+#include "jfr/recorder/service/jfrRecorderThread.hpp"
+#include "memory/resourceArea.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/thread.inline.hpp"
+#include "utilities/preserveException.hpp"
+#include "utilities/macros.hpp"
+
+static Thread* start_thread(instanceHandle thread_oop, ThreadFunction proc, TRAPS) {
+  assert(thread_oop.not_null(), "invariant");
+  assert(proc != NULL, "invariant");
+
+  bool allocation_failed = false;
+  JavaThread* new_thread = NULL;
+  {
+    MutexLocker mu(Threads_lock);
+    new_thread = new JavaThread(proc);
+    // At this point it may be possible that no
+    // osthread was created for the JavaThread due to lack of memory.
+    if (new_thread == NULL || new_thread->osthread() == NULL) {
+      delete new_thread;
+      allocation_failed = true;
+    } else {
+      java_lang_Thread::set_thread(thread_oop(), new_thread);
+      java_lang_Thread::set_priority(thread_oop(), NormPriority);
+      java_lang_Thread::set_daemon(thread_oop());
+      new_thread->set_threadObj(thread_oop());
+      Threads::add(new_thread);
+    }
+  }
+  if (allocation_failed) {
+    JfrJavaSupport::throw_out_of_memory_error("Unable to create native recording thread for JFR", CHECK_NULL);
+  }
+
+  Thread::start(new_thread);
+  return new_thread;
+}
+
+JfrPostBox* JfrRecorderThread::_post_box = NULL;
+
+JfrPostBox& JfrRecorderThread::post_box() {
+  return *_post_box;
+}
+
+// defined in JfrRecorderThreadLoop.cpp
+void recorderthread_entry(JavaThread*, Thread*);
+
+bool JfrRecorderThread::start(JfrCheckpointManager* cp_manager, JfrPostBox* post_box, TRAPS) {
+  assert(cp_manager != NULL, "invariant");
+  assert(post_box != NULL, "invariant");
+  _post_box = post_box;
+
+  static const char klass[] = "jdk/jfr/internal/JVMUpcalls";
+  static const char method[] = "createRecorderThread";
+  static const char signature[] = "(Ljava/lang/ThreadGroup;Ljava/lang/ClassLoader;)Ljava/lang/Thread;";
+
+  JavaValue result(T_OBJECT);
+  JfrJavaArguments create_thread_args(&result, klass, method, signature, CHECK_false);
+
+  // arguments
+  create_thread_args.push_oop(Universe::system_thread_group());
+  create_thread_args.push_oop(SystemDictionary::java_system_loader());
+
+  JfrJavaSupport::call_static(&create_thread_args, CHECK_false);
+  instanceHandle h_thread_oop(THREAD, (instanceOop)result.get_jobject());
+  assert(h_thread_oop.not_null(), "invariant");
+  // attempt thread start
+  const Thread* const t = start_thread(h_thread_oop, recorderthread_entry,THREAD);
+  if (!HAS_PENDING_EXCEPTION) {
+    cp_manager->register_service_thread(t);
+    return true;
+  }
+  assert(HAS_PENDING_EXCEPTION, "invariant");
+  // Start failed, remove the thread from the system thread group
+  JavaValue void_result(T_VOID);
+  JfrJavaArguments remove_thread_args(&void_result);
+  remove_thread_args.set_klass(SystemDictionary::ThreadGroup_klass());
+  remove_thread_args.set_name(vmSymbols::remove_method_name());
+  remove_thread_args.set_signature(vmSymbols::thread_void_signature());
+  remove_thread_args.set_receiver(Universe::system_thread_group());
+  remove_thread_args.push_oop(h_thread_oop());
+  CautiouslyPreserveExceptionMark cpe(THREAD);
+  JfrJavaSupport::call_special(&remove_thread_args, THREAD);
+  return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderThread.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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 SHARE_VM_JFR_RECORDER_SERVICE_JFRRECORDERTHREAD_HPP
+#define SHARE_VM_JFR_RECORDER_SERVICE_JFRRECORDERTHREAD_HPP
+
+#include "memory/allocation.hpp"
+#include "utilities/debug.hpp"
+
+class JavaThread;
+class JfrCheckpointManager;
+class JfrPostBox;
+class Thread;
+
+class JfrRecorderThread : AllStatic {
+ private:
+  static JfrPostBox* _post_box;
+
+ public:
+  static JfrPostBox& post_box();
+  static bool start(JfrCheckpointManager* cp_manager, JfrPostBox* post_box, TRAPS);
+};
+
+#endif // SHARE_VM_JFR_RECORDER_SERVICE_JFRRECORDERTHREAD_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/recorder/jfrRecorder.hpp"
+#include "jfr/recorder/service/jfrPostBox.hpp"
+#include "jfr/recorder/service/jfrRecorderService.hpp"
+#include "jfr/recorder/service/jfrRecorderThread.hpp"
+#include "logging/log.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/thread.inline.hpp"
+
+//
+// Entry point for "JFR Recorder Thread" message loop.
+// The recorder thread executes service requests collected from the message system.
+//
+void recorderthread_entry(JavaThread* thread, Thread* unused) {
+  assert(thread != NULL, "invariant");
+  #define START (msgs & (MSGBIT(MSG_START)))
+  #define SHUTDOWN (msgs & MSGBIT(MSG_SHUTDOWN))
+  #define ROTATE (msgs & (MSGBIT(MSG_ROTATE)|MSGBIT(MSG_STOP)))
+  #define PROCESS_FULL_BUFFERS (msgs & (MSGBIT(MSG_ROTATE)|MSGBIT(MSG_STOP)|MSGBIT(MSG_FULLBUFFER)))
+  #define SCAVENGE (msgs & (MSGBIT(MSG_DEADBUFFER)))
+
+  JfrPostBox& post_box = JfrRecorderThread::post_box();
+  log_debug(jfr, system)("Recorder thread STARTED");
+
+  {
+    bool done = false;
+    int msgs = 0;
+    JfrRecorderService service;
+    MutexLockerEx msg_lock(JfrMsg_lock);
+
+    // JFR MESSAGE LOOP PROCESSING - BEGIN
+    while (!done) {
+      if (post_box.is_empty()) {
+        JfrMsg_lock->wait(false);
+      }
+      msgs = post_box.collect();
+      JfrMsg_lock->unlock();
+      if (PROCESS_FULL_BUFFERS) {
+        service.process_full_buffers();
+      }
+      if (SCAVENGE) {
+        service.scavenge();
+      }
+      // Check amount of data written to chunk already
+      // if it warrants asking for a new chunk
+      service.evaluate_chunk_size_for_rotation();
+      if (START) {
+        service.start();
+      } else if (ROTATE) {
+        service.rotate(msgs);
+      }
+      JfrMsg_lock->lock();
+      post_box.notify_waiters();
+      if (SHUTDOWN) {
+        log_debug(jfr, system)("Request to STOP recorder");
+        done = true;
+      }
+    } // JFR MESSAGE LOOP PROCESSING - END
+
+  } // JfrMsg_lock scope
+
+  assert(!JfrMsg_lock->owned_by_self(), "invariant");
+  post_box.notify_collection_stop();
+  JfrRecorder::on_recorder_thread_exit();
+
+  #undef START
+  #undef SHUTDOWN
+  #undef ROTATE
+  #undef PROCESS_FULL_BUFFERS
+  #undef SCAVENGE
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,463 @@
+/*
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/metadata/jfrSerializer.hpp"
+#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
+#include "jfr/recorder/repository/jfrChunkWriter.hpp"
+#include "jfr/recorder/service/jfrOptionSet.hpp"
+#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
+#include "memory/allocation.inline.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/safepoint.hpp"
+#include "runtime/task.hpp"
+#include "runtime/vframe.inline.hpp"
+
+class vframeStreamSamples : public vframeStreamCommon {
+ public:
+  // constructor that starts with sender of frame fr (top_frame)
+  vframeStreamSamples(JavaThread *jt, frame fr, bool stop_at_java_call_stub);
+  void samples_next();
+  void stop() {}
+};
+
+vframeStreamSamples::vframeStreamSamples(JavaThread *jt, frame fr, bool stop_at_java_call_stub) : vframeStreamCommon(jt) {
+  _stop_at_java_call_stub = stop_at_java_call_stub;
+  _frame = fr;
+
+  // We must always have a valid frame to start filling
+  bool filled_in = fill_from_frame();
+  assert(filled_in, "invariant");
+}
+
+// Solaris SPARC Compiler1 needs an additional check on the grandparent
+// of the top_frame when the parent of the top_frame is interpreted and
+// the grandparent is compiled. However, in this method we do not know
+// the relationship of the current _frame relative to the top_frame so
+// we implement a more broad sanity check. When the previous callee is
+// interpreted and the current sender is compiled, we verify that the
+// current sender is also walkable. If it is not walkable, then we mark
+// the current vframeStream as at the end.
+void vframeStreamSamples::samples_next() {
+  // handle frames with inlining
+  if (_mode == compiled_mode &&
+      vframeStreamCommon::fill_in_compiled_inlined_sender()) {
+    return;
+  }
+
+  // handle general case
+  int loop_count = 0;
+  int loop_max = MaxJavaStackTraceDepth * 2;
+  do {
+    loop_count++;
+    // By the time we get here we should never see unsafe but better safe then segv'd
+    if (loop_count > loop_max || !_frame.safe_for_sender(_thread)) {
+      _mode = at_end_mode;
+      return;
+    }
+    _frame = _frame.sender(&_reg_map);
+  } while (!fill_from_frame());
+}
+
+static JfrStackTraceRepository* _instance = NULL;
+
+JfrStackTraceRepository& JfrStackTraceRepository::instance() {
+  return *_instance;
+}
+
+JfrStackTraceRepository* JfrStackTraceRepository::create() {
+  assert(_instance == NULL, "invariant");
+  _instance = new JfrStackTraceRepository();
+  return _instance;
+}
+
+void JfrStackTraceRepository::destroy() {
+  assert(_instance != NULL, "invarinat");
+  delete _instance;
+  _instance = NULL;
+}
+
+JfrStackTraceRepository::JfrStackTraceRepository() : _next_id(0), _entries(0) {
+  memset(_table, 0, sizeof(_table));
+}
+class JfrFrameType : public JfrSerializer {
+ public:
+  void serialize(JfrCheckpointWriter& writer) {
+    writer.write_count(JfrStackFrame::NUM_FRAME_TYPES);
+    writer.write_key(JfrStackFrame::FRAME_INTERPRETER);
+    writer.write("Interpreted");
+    writer.write_key(JfrStackFrame::FRAME_JIT);
+    writer.write("JIT compiled");
+    writer.write_key(JfrStackFrame::FRAME_INLINE);
+    writer.write("Inlined");
+    writer.write_key(JfrStackFrame::FRAME_NATIVE);
+    writer.write("Native");
+  }
+};
+
+bool JfrStackTraceRepository::initialize() {
+  return JfrSerializer::register_serializer(TYPE_FRAMETYPE, false, true, new JfrFrameType());
+}
+
+size_t JfrStackTraceRepository::clear() {
+  MutexLockerEx lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag);
+  if (_entries == 0) {
+    return 0;
+  }
+  for (u4 i = 0; i < TABLE_SIZE; ++i) {
+    JfrStackTraceRepository::StackTrace* stacktrace = _table[i];
+    while (stacktrace != NULL) {
+      JfrStackTraceRepository::StackTrace* next = stacktrace->next();
+      delete stacktrace;
+      stacktrace = next;
+    }
+  }
+  memset(_table, 0, sizeof(_table));
+  const size_t processed = _entries;
+  _entries = 0;
+  return processed;
+}
+
+traceid JfrStackTraceRepository::add_trace(const JfrStackTrace& stacktrace) {
+  MutexLockerEx lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag);
+  const size_t index = stacktrace._hash % TABLE_SIZE;
+  const StackTrace* table_entry = _table[index];
+
+  while (table_entry != NULL) {
+    if (table_entry->equals(stacktrace)) {
+      return table_entry->id();
+    }
+    table_entry = table_entry->next();
+  }
+
+  if (!stacktrace.have_lineno()) {
+    return 0;
+  }
+
+  traceid id = ++_next_id;
+  _table[index] = new StackTrace(id, stacktrace, _table[index]);
+  ++_entries;
+  return id;
+}
+
+traceid JfrStackTraceRepository::add(const JfrStackTrace& stacktrace) {
+  return instance().add_trace(stacktrace);
+}
+
+traceid JfrStackTraceRepository::record(Thread* thread, int skip /* 0 */) {
+  assert(thread == Thread::current(), "invariant");
+  JfrThreadLocal* const tl = thread->jfr_thread_local();
+  assert(tl != NULL, "invariant");
+  if (tl->has_cached_stack_trace()) {
+    return tl->cached_stack_trace_id();
+  }
+  if (!thread->is_Java_thread() || thread->is_hidden_from_external_view()) {
+    return 0;
+  }
+  JfrStackFrame* frames = tl->stackframes();
+  if (frames == NULL) {
+    // pending oom
+    return 0;
+  }
+  assert(frames != NULL, "invariant");
+  assert(tl->stackframes() == frames, "invariant");
+  return instance().record_for((JavaThread*)thread, skip,frames, tl->stackdepth());
+}
+
+traceid JfrStackTraceRepository::record(Thread* thread, int skip, unsigned int* hash) {
+  assert(thread == Thread::current(), "invariant");
+  JfrThreadLocal* const tl = thread->jfr_thread_local();
+  assert(tl != NULL, "invariant");
+
+  if (tl->has_cached_stack_trace()) {
+    *hash = tl->cached_stack_trace_hash();
+    return tl->cached_stack_trace_id();
+  }
+  if (!thread->is_Java_thread() || thread->is_hidden_from_external_view()) {
+    return 0;
+  }
+  JfrStackFrame* frames = tl->stackframes();
+  if (frames == NULL) {
+    // pending oom
+    return 0;
+  }
+  assert(frames != NULL, "invariant");
+  assert(tl->stackframes() == frames, "invariant");
+  return instance().record_for((JavaThread*)thread, skip, frames, tl->stackdepth(), hash);
+}
+
+traceid JfrStackTraceRepository::record_for(JavaThread* thread, int skip, JfrStackFrame *frames, u4 max_frames) {
+  JfrStackTrace stacktrace(frames, max_frames);
+  if (!stacktrace.record_safe(thread, skip)) {
+    return 0;
+  }
+  traceid tid = add(stacktrace);
+  if (tid == 0) {
+    stacktrace.resolve_linenos();
+    tid = add(stacktrace);
+  }
+  return tid;
+}
+
+traceid JfrStackTraceRepository::record_for(JavaThread* thread, int skip, JfrStackFrame *frames, u4 max_frames, unsigned int* hash) {
+  assert(hash != NULL && *hash == 0, "invariant");
+  JfrStackTrace stacktrace(frames, max_frames);
+  if (!stacktrace.record_safe(thread, skip, true)) {
+    return 0;
+  }
+  traceid tid = add(stacktrace);
+  if (tid == 0) {
+    stacktrace.resolve_linenos();
+    tid = add(stacktrace);
+  }
+  *hash = stacktrace._hash;
+  return tid;
+}
+
+size_t JfrStackTraceRepository::write_impl(JfrChunkWriter& sw, bool clear) {
+  MutexLockerEx lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag);
+  assert(_entries > 0, "invariant");
+  int count = 0;
+  for (u4 i = 0; i < TABLE_SIZE; ++i) {
+    JfrStackTraceRepository::StackTrace* stacktrace = _table[i];
+    while (stacktrace != NULL) {
+      JfrStackTraceRepository::StackTrace* next = stacktrace->next();
+      if (stacktrace->should_write()) {
+        stacktrace->write(sw);
+        ++count;
+      }
+      if (clear) {
+        delete stacktrace;
+      }
+      stacktrace = next;
+    }
+  }
+  if (clear) {
+    memset(_table, 0, sizeof(_table));
+    _entries = 0;
+  }
+  return count;
+}
+
+size_t JfrStackTraceRepository::write(JfrChunkWriter& sw, bool clear) {
+  return _entries > 0 ? write_impl(sw, clear) : 0;
+}
+
+traceid JfrStackTraceRepository::write(JfrCheckpointWriter& writer, traceid id, unsigned int hash) {
+  assert(JfrStacktrace_lock->owned_by_self(), "invariant");
+  const StackTrace* const trace = resolve_entry(hash, id);
+  assert(trace != NULL, "invariant");
+  assert(trace->hash() == hash, "invariant");
+  assert(trace->id() == id, "invariant");
+  trace->write(writer);
+  return id;
+}
+
+JfrStackTraceRepository::StackTrace::StackTrace(traceid id, const JfrStackTrace& trace, JfrStackTraceRepository::StackTrace* next) :
+  _next(next),
+  _frames(NULL),
+  _id(id),
+  _nr_of_frames(trace._nr_of_frames),
+  _hash(trace._hash),
+  _reached_root(trace._reached_root),
+  _written(false) {
+  if (_nr_of_frames > 0) {
+    _frames = NEW_C_HEAP_ARRAY(JfrStackFrame, _nr_of_frames, mtTracing);
+    memcpy(_frames, trace._frames, _nr_of_frames * sizeof(JfrStackFrame));
+  }
+}
+
+JfrStackTraceRepository::StackTrace::~StackTrace() {
+  if (_frames != NULL) {
+    FREE_C_HEAP_ARRAY(JfrStackFrame, _frames);
+  }
+}
+
+bool JfrStackTraceRepository::StackTrace::equals(const JfrStackTrace& rhs) const {
+  if (_reached_root != rhs._reached_root || _nr_of_frames != rhs._nr_of_frames || _hash != rhs._hash) {
+    return false;
+  }
+  for (u4 i = 0; i < _nr_of_frames; ++i) {
+    if (!_frames[i].equals(rhs._frames[i])) {
+      return false;
+    }
+  }
+  return true;
+}
+
+template <typename Writer>
+static void write_stacktrace(Writer& w, traceid id, bool reached_root, u4 nr_of_frames, const JfrStackFrame* frames) {
+  w.write((u8)id);
+  w.write((u1)!reached_root);
+  w.write(nr_of_frames);
+  for (u4 i = 0; i < nr_of_frames; ++i) {
+    frames[i].write(w);
+  }
+}
+
+void JfrStackTraceRepository::StackTrace::write(JfrChunkWriter& sw) const {
+  assert(!_written, "invariant");
+  write_stacktrace(sw, _id, _reached_root, _nr_of_frames, _frames);
+  _written = true;
+}
+
+void JfrStackTraceRepository::StackTrace::write(JfrCheckpointWriter& cpw) const {
+  write_stacktrace(cpw, _id, _reached_root, _nr_of_frames, _frames);
+}
+
+// JfrStackFrame
+
+bool JfrStackFrame::equals(const JfrStackFrame& rhs) const {
+  return _methodid == rhs._methodid && _bci == rhs._bci && _type == rhs._type;
+}
+
+template <typename Writer>
+static void write_frame(Writer& w, traceid methodid, int line, int bci, u1 type) {
+  w.write((u8)methodid);
+  w.write((u4)line);
+  w.write((u4)bci);
+  w.write((u8)type);
+}
+
+void JfrStackFrame::write(JfrChunkWriter& cw) const {
+  write_frame(cw, _methodid, _line, _bci, _type);
+}
+
+void JfrStackFrame::write(JfrCheckpointWriter& cpw) const {
+  write_frame(cpw, _methodid, _line, _bci, _type);
+}
+
+// invariant is that the entry to be resolved actually exists in the table
+const JfrStackTraceRepository::StackTrace* JfrStackTraceRepository::resolve_entry(unsigned int hash, traceid id) const {
+  const size_t index = (hash % TABLE_SIZE);
+  const StackTrace* trace = _table[index];
+  while (trace != NULL && trace->id() != id) {
+    trace = trace->next();
+  }
+  assert(trace != NULL, "invariant");
+  assert(trace->hash() == hash, "invariant");
+  assert(trace->id() == id, "invariant");
+  return trace;
+}
+
+void JfrStackFrame::resolve_lineno() {
+  assert(_method, "no method pointer");
+  assert(_line == 0, "already have linenumber");
+  _line = _method->line_number_from_bci(_bci);
+  _method = NULL;
+}
+
+void JfrStackTrace::set_frame(u4 frame_pos, JfrStackFrame& frame) {
+  assert(frame_pos < _max_frames, "illegal frame_pos");
+  _frames[frame_pos] = frame;
+}
+
+void JfrStackTrace::resolve_linenos() {
+  for(unsigned int i = 0; i < _nr_of_frames; i++) {
+    _frames[i].resolve_lineno();
+  }
+  _lineno = true;
+}
+
+bool JfrStackTrace::record_safe(JavaThread* thread, int skip, bool leakp /* false */) {
+  assert(SafepointSynchronize::safepoint_safe(thread, thread->thread_state())
+         || thread == Thread::current(), "Thread stack needs to be walkable");
+  vframeStream vfs(thread);
+  u4 count = 0;
+  _reached_root = true;
+  for(int i = 0; i < skip; i++) {
+    if (vfs.at_end()) {
+      break;
+    }
+    vfs.next();
+  }
+
+  while (!vfs.at_end()) {
+    if (count >= _max_frames) {
+      _reached_root = false;
+      break;
+    }
+    const Method* method = vfs.method();
+    const traceid mid = JfrTraceId::use(method, leakp);
+    int type = vfs.is_interpreted_frame() ? JfrStackFrame::FRAME_INTERPRETER : JfrStackFrame::FRAME_JIT;
+    int bci = 0;
+    if (method->is_native()) {
+      type = JfrStackFrame::FRAME_NATIVE;
+    } else {
+      bci = vfs.bci();
+    }
+    // Can we determine if it's inlined?
+    _hash = (_hash << 2) + (unsigned int)(((size_t)mid >> 2) + (bci << 4) + type);
+    _frames[count] = JfrStackFrame(mid, bci, type, method);
+    vfs.next();
+    count++;
+  }
+
+  _nr_of_frames = count;
+  return true;
+}
+
+bool JfrStackTrace::record_thread(JavaThread& thread, frame& frame) {
+  vframeStreamSamples st(&thread, frame, false);
+  u4 count = 0;
+  _reached_root = true;
+
+  while (!st.at_end()) {
+    if (count >= _max_frames) {
+      _reached_root = false;
+      break;
+    }
+    const Method* method = st.method();
+    if (!method->is_valid_method()) {
+      // we throw away everything we've gathered in this sample since
+      // none of it is safe
+      return false;
+    }
+    const traceid mid = JfrTraceId::use(method);
+    int type = st.is_interpreted_frame() ? JfrStackFrame::FRAME_INTERPRETER : JfrStackFrame::FRAME_JIT;
+    int bci = 0;
+    if (method->is_native()) {
+      type = JfrStackFrame::FRAME_NATIVE;
+    } else {
+      bci = st.bci();
+    }
+    const int lineno = method->line_number_from_bci(bci);
+    // Can we determine if it's inlined?
+    _hash = (_hash << 2) + (unsigned int)(((size_t)mid >> 2) + (bci << 4) + type);
+    _frames[count] = JfrStackFrame(mid, bci, type, lineno);
+    st.samples_next();
+    count++;
+  }
+
+  _lineno = true;
+  _nr_of_frames = count;
+  return true;
+}
+
+void JfrStackTraceRepository::write_metadata(JfrCheckpointWriter& writer) {
+  JfrFrameType fct;
+  writer.write_type(TYPE_FRAMETYPE);
+  fct.serialize(writer);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_RECORDER_STACKTRACE_JFRSTACKTRACEREPOSITORY_HPP
+#define SHARE_VM_JFR_RECORDER_STACKTRACE_JFRSTACKTRACEREPOSITORY_HPP
+
+#include "jfr/utilities/jfrAllocation.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
+
+class frame;
+class JavaThread;
+class JfrCheckpointSystem;
+class JfrCheckpointWriter;
+class JfrChunkWriter;
+class Method;
+
+class JfrStackFrame {
+ private:
+  const Method* _method;
+  traceid _methodid;
+  int _line;
+  int _bci;
+  u1 _type;
+
+ public:
+  enum {
+    FRAME_INTERPRETER = 0,
+    FRAME_JIT,
+    FRAME_INLINE,
+    FRAME_NATIVE,
+    NUM_FRAME_TYPES
+  };
+
+  JfrStackFrame(const traceid& id, int bci, int type, const Method* method) :
+    _method(method), _methodid(id), _line(0), _bci(bci), _type(type) {}
+  JfrStackFrame(const traceid& id, int bci, int type, int lineno) :
+    _method(NULL), _methodid(id), _line(0), _bci(bci), _type(type) {}
+  bool equals(const JfrStackFrame& rhs) const;
+  void write(JfrChunkWriter& cw) const;
+  void write(JfrCheckpointWriter& cpw) const;
+  void resolve_lineno();
+};
+
+class JfrStackTrace : public StackObj {
+  friend class JfrStackTraceRepository;
+ private:
+  JfrStackFrame* _frames;
+  traceid _id;
+  u4 _nr_of_frames;
+  unsigned int _hash;
+  const u4 _max_frames;
+  bool _reached_root;
+  bool _lineno;
+
+ public:
+  JfrStackTrace(JfrStackFrame* frames, u4 max_frames) : _frames(frames),
+                                                        _id(0),
+                                                        _nr_of_frames(0),
+                                                        _hash(0),
+                                                        _reached_root(false),
+                                                        _max_frames(max_frames),
+                                                        _lineno(false) {}
+  bool record_thread(JavaThread& thread, frame& frame);
+  bool record_safe(JavaThread* thread, int skip, bool leakp = false);
+  void resolve_linenos();
+  void set_nr_of_frames(u4 nr_of_frames) { _nr_of_frames = nr_of_frames; }
+  void set_hash(unsigned int hash) { _hash = hash; }
+  void set_frame(u4 frame_pos, JfrStackFrame& frame);
+  void set_reached_root(bool reached_root) { _reached_root = reached_root; }
+  bool full_stacktrace() const { return _reached_root; }
+  bool have_lineno() const { return _lineno; }
+};
+
+class JfrStackTraceRepository : public JfrCHeapObj {
+  friend class JfrRecorder;
+  friend class JfrRecorderService;
+  friend class ObjectSampler;
+  friend class WriteObjectSampleStacktrace;
+
+  class StackTrace : public JfrCHeapObj {
+    friend class JfrStackTrace;
+    friend class JfrStackTraceRepository;
+   private:
+    StackTrace* _next;
+    JfrStackFrame* _frames;
+    const traceid _id;
+    u4 _nr_of_frames;
+    unsigned int _hash;
+    bool _reached_root;
+    mutable bool _written;
+
+    unsigned int hash() const { return _hash; }
+    bool should_write() const { return !_written; }
+
+   public:
+    StackTrace(traceid id, const JfrStackTrace& trace, StackTrace* next);
+    ~StackTrace();
+    traceid id() const { return _id; }
+    StackTrace* next() const { return _next; }
+    void write(JfrChunkWriter& cw) const;
+    void write(JfrCheckpointWriter& cpw) const;
+    bool equals(const JfrStackTrace& rhs) const;
+  };
+
+ private:
+  static const u4 TABLE_SIZE = 2053;
+  StackTrace* _table[TABLE_SIZE];
+  traceid _next_id;
+  u4 _entries;
+
+  size_t write_impl(JfrChunkWriter& cw, bool clear);
+  traceid record_for(JavaThread* thread, int skip, JfrStackFrame* frames, u4 max_frames);
+  traceid record_for(JavaThread* thread, int skip, JfrStackFrame* frames, u4 max_frames, unsigned int* hash);
+  traceid add_trace(const JfrStackTrace& stacktrace);
+  const StackTrace* resolve_entry(unsigned int hash, traceid id) const;
+
+  static void write_metadata(JfrCheckpointWriter& cpw);
+
+  JfrStackTraceRepository();
+  static JfrStackTraceRepository& instance();
+ public:
+  static JfrStackTraceRepository* create();
+  bool initialize();
+  static void destroy();
+  static traceid add(const JfrStackTrace& stacktrace);
+  static traceid record(Thread* thread, int skip = 0);
+  static traceid record(Thread* thread, int skip, unsigned int* hash);
+  traceid write(JfrCheckpointWriter& cpw, traceid id, unsigned int hash);
+  size_t write(JfrChunkWriter& cw, bool clear);
+  size_t clear();
+};
+
+#endif // SHARE_VM_JFR_RECORDER_STACKTRACE_JFRSTACKTRACEREPOSITORY_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/storage/jfrBuffer.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/recorder/storage/jfrBuffer.hpp"
+#include "runtime/atomic.hpp"
+#include "runtime/orderAccess.inline.hpp"
+#include "runtime/thread.inline.hpp"
+
+static const u1* const MUTEX_CLAIM = NULL;
+
+JfrBuffer::JfrBuffer() : _next(NULL),
+                         _prev(NULL),
+                         _identity(NULL),
+                         _pos(NULL),
+                         _top(NULL),
+                         _flags(0),
+                         _header_size(0),
+                         _size(0) {}
+
+bool JfrBuffer::initialize(size_t header_size, size_t size, const void* id /* NULL */) {
+  _header_size = (u2)header_size;
+  _size = (u4)(size / BytesPerWord);
+  assert(_identity == NULL, "invariant");
+  _identity = id;
+  set_pos(start());
+  set_top(start());
+  assert(_next == NULL, "invariant");
+  assert(free_size() == size, "invariant");
+  assert(!transient(), "invariant");
+  assert(!lease(), "invariant");
+  assert(!retired(), "invariant");
+  return true;
+}
+
+void JfrBuffer::reinitialize() {
+  assert(!lease(), "invariant");
+  assert(!transient(), "invariant");
+  set_pos(start());
+  clear_retired();
+  set_top(start());
+}
+
+void JfrBuffer::concurrent_reinitialization() {
+  concurrent_top();
+  assert(!lease(), "invariant");
+  assert(!transient(), "invariant");
+  set_pos(start());
+  set_concurrent_top(start());
+  clear_retired();
+}
+
+size_t JfrBuffer::discard() {
+  size_t discard_size = unflushed_size();
+  set_top(pos());
+  return discard_size;
+}
+
+const u1* JfrBuffer::stable_top() const {
+  const u1* current_top;
+  do {
+    current_top = OrderAccess::load_acquire(&_top);
+  } while (MUTEX_CLAIM == current_top);
+  return current_top;
+}
+
+const u1* JfrBuffer::top() const {
+  return _top;
+}
+
+void JfrBuffer::set_top(const u1* new_top) {
+  _top = new_top;
+}
+
+const u1* JfrBuffer::concurrent_top() const {
+  do {
+    const u1* current_top = stable_top();
+    if (Atomic::cmpxchg(MUTEX_CLAIM, &_top, current_top) == current_top) {
+      return current_top;
+    }
+  } while (true);
+}
+
+void JfrBuffer::set_concurrent_top(const u1* new_top) {
+  assert(new_top != MUTEX_CLAIM, "invariant");
+  assert(new_top <= end(), "invariant");
+  assert(new_top >= start(), "invariant");
+  assert(top() == MUTEX_CLAIM, "invariant");
+  OrderAccess::release_store(&_top, new_top);
+}
+
+size_t JfrBuffer::unflushed_size() const {
+  return pos() - stable_top();
+}
+
+void JfrBuffer::acquire(const void* id) {
+  assert(id != NULL, "invariant");
+  const void* current_id;
+  do {
+    current_id = OrderAccess::load_acquire(&_identity);
+  } while (current_id != NULL || Atomic::cmpxchg(id, &_identity, current_id) != current_id);
+}
+
+bool JfrBuffer::try_acquire(const void* id) {
+  assert(id != NULL, "invariant");
+  const void* const current_id = OrderAccess::load_acquire(&_identity);
+  return current_id == NULL && Atomic::cmpxchg(id, &_identity, current_id) == current_id;
+}
+
+void JfrBuffer::release() {
+  OrderAccess::release_store(&_identity, (const void*)NULL);
+}
+
+void JfrBuffer::clear_identity() {
+  _identity = NULL;
+}
+
+#ifdef ASSERT
+static bool validate_to(const JfrBuffer* const to, size_t size) {
+  assert(to != NULL, "invariant");
+  assert(to->acquired_by_self(), "invariant");
+  assert(to->free_size() >= size, "invariant");
+  return true;
+}
+
+static bool validate_concurrent_this(const JfrBuffer* const t, size_t size) {
+  assert(t->top() == MUTEX_CLAIM, "invariant");
+  return true;
+}
+
+static bool validate_this(const JfrBuffer* const t, size_t size) {
+  assert(t->top() + size <= t->pos(), "invariant");
+  return true;
+}
+
+bool JfrBuffer::acquired_by_self() const {
+  return identity() == Thread::current();
+}
+#endif // ASSERT
+
+void JfrBuffer::move(JfrBuffer* const to, size_t size) {
+  assert(validate_to(to, size), "invariant");
+  assert(validate_this(this, size), "invariant");
+  const u1* current_top = top();
+  assert(current_top != NULL, "invariant");
+  memcpy(to->pos(), current_top, size);
+  to->set_pos(size);
+  to->release();
+  set_top(current_top + size);
+}
+
+void JfrBuffer::concurrent_move_and_reinitialize(JfrBuffer* const to, size_t size) {
+  assert(validate_to(to, size), "invariant");
+  const u1* current_top = concurrent_top();
+  assert(validate_concurrent_this(this, size), "invariant");
+  const size_t actual_size = MIN2(size, (size_t)(pos() - current_top));
+  assert(actual_size <= size, "invariant");
+  memcpy(to->pos(), current_top, actual_size);
+  to->set_pos(actual_size);
+  set_pos(start());
+  to->release();
+  set_concurrent_top(start());
+}
+
+// flags
+enum FLAG {
+  RETIRED = 1,
+  TRANSIENT = 2,
+  LEASE = 4
+};
+
+bool JfrBuffer::transient() const {
+  return (u1)TRANSIENT == (_flags & (u1)TRANSIENT);
+}
+
+void JfrBuffer::set_transient() {
+  _flags |= (u1)TRANSIENT;
+  assert(transient(), "invariant");
+}
+
+void JfrBuffer::clear_transient() {
+  if (transient()) {
+    _flags ^= (u1)TRANSIENT;
+  }
+  assert(!transient(), "invariant");
+}
+
+bool JfrBuffer::lease() const {
+  return (u1)LEASE == (_flags & (u1)LEASE);
+}
+
+void JfrBuffer::set_lease() {
+  _flags |= (u1)LEASE;
+  assert(lease(), "invariant");
+}
+
+void JfrBuffer::clear_lease() {
+  if (lease()) {
+    _flags ^= (u1)LEASE;
+  }
+  assert(!lease(), "invariant");
+}
+
+static u2 load_acquire_flags(const u2* const flags) {
+  return OrderAccess::load_acquire(flags);
+}
+
+static void release_store_flags(u2* const flags, u2 new_flags) {
+  OrderAccess::release_store(flags, new_flags);
+}
+
+bool JfrBuffer::retired() const {
+  return (u1)RETIRED == (load_acquire_flags(&_flags) & (u1)RETIRED);
+}
+
+void JfrBuffer::set_retired() {
+  const u2 new_flags = load_acquire_flags(&_flags) | (u1)RETIRED;
+  release_store_flags(&_flags, new_flags);
+}
+
+void JfrBuffer::clear_retired() {
+  u2 new_flags = load_acquire_flags(&_flags);
+  if ((u1)RETIRED == (new_flags & (u1)RETIRED)) {
+    new_flags ^= (u1)RETIRED;
+    release_store_flags(&_flags, new_flags);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/storage/jfrBuffer.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_RECORDER_STORAGE_JFRBUFFER_HPP
+#define SHARE_VM_JFR_RECORDER_STORAGE_JFRBUFFER_HPP
+
+#include "jni.h"
+#include "memory/allocation.hpp"
+
+//
+// Represents a piece of committed memory.
+//
+// u1* _pos <-- next store position
+// u1* _top <-- next unflushed position
+//
+// const void* _identity <<-- acquired by
+//
+// Must be the owner before attempting stores.
+// Use acquire() and/or try_acquire() for exclusive access
+// to the (entire) buffer (cas identity).
+//
+// Stores to the buffer should uphold transactional semantics.
+// A new _pos must be updated only after all intended stores have completed.
+// The relation between _pos and _top must hold atomically,
+// e.g. the delta must always be fully parsable.
+// _top can move concurrently by other threads but is always <= _pos.
+//
+class JfrBuffer {
+ private:
+  JfrBuffer* _next;
+  JfrBuffer* _prev;
+  const void* volatile _identity;
+  u1* _pos;
+  mutable const u1* volatile _top;
+  u2 _flags;
+  u2 _header_size;
+  u4 _size;
+
+  const u1* stable_top() const;
+  void clear_flags();
+
+ public:
+  JfrBuffer();
+  bool initialize(size_t header_size, size_t size, const void* id = NULL);
+  void reinitialize();
+  void concurrent_reinitialization();
+  size_t discard();
+  JfrBuffer* next() const {
+    return _next;
+  }
+
+  JfrBuffer* prev() const {
+    return _prev;
+  }
+
+  void set_next(JfrBuffer* next) {
+    _next = next;
+  }
+
+  void set_prev(JfrBuffer* prev) {
+    _prev = prev;
+  }
+
+  const u1* start() const {
+    return ((const u1*)this) + _header_size;
+  }
+
+  u1* start() {
+    return ((u1*)this) + _header_size;
+  }
+
+  const u1* end() const {
+    return start() + size();
+  }
+
+  const u1* pos() const {
+    return _pos;
+  }
+
+  u1* pos() {
+    return _pos;
+  }
+
+  u1** pos_address() {
+    return (u1**)&_pos;
+  }
+
+  void set_pos(u1* new_pos) {
+    assert(new_pos <= end(), "invariant");
+    _pos = new_pos;
+  }
+
+  void set_pos(size_t size) {
+    assert(_pos + size <= end(), "invariant");
+    _pos += size;
+  }
+
+  const u1* top() const;
+  void set_top(const u1* new_top);
+  const u1* concurrent_top() const;
+  void set_concurrent_top(const u1* new_top);
+
+  size_t header_size() const {
+    return _header_size;
+  }
+
+  size_t size() const {
+    return _size * BytesPerWord;
+  }
+
+  size_t total_size() const {
+    return header_size() + size();
+  }
+
+  size_t free_size() const {
+    return end() - pos();
+  }
+
+  size_t unflushed_size() const;
+
+  bool empty() const {
+    return pos() == start();
+  }
+
+  const void* identity() const {
+    return _identity;
+  }
+
+  void clear_identity();
+
+  void acquire(const void* id);
+  bool try_acquire(const void* id);
+  void release();
+
+  void move(JfrBuffer* const to, size_t size);
+  void concurrent_move_and_reinitialize(JfrBuffer* const to, size_t size);
+
+  bool transient() const;
+  void set_transient();
+  void clear_transient();
+
+  bool lease() const;
+  void set_lease();
+  void clear_lease();
+
+  bool retired() const;
+  void set_retired();
+  void clear_retired();
+
+  debug_only(bool acquired_by_self() const;)
+};
+
+class JfrAgeNode : public JfrBuffer {
+ private:
+  JfrBuffer* _retired;
+
+ public:
+  JfrAgeNode() : _retired(NULL) {}
+  void set_retired_buffer(JfrBuffer* retired) {
+    _retired = retired;
+  }
+  JfrBuffer* retired_buffer() const {
+    return _retired;
+  }
+};
+
+#endif // SHARE_VM_JFR_RECORDER_STORAGE_JFRBUFFER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+#ifndef SHARE_VM_JFR_RECORDER_STORAGE_JFRMEMORYSPACE_HPP
+#define SHARE_VM_JFR_RECORDER_STORAGE_JFRMEMORYSPACE_HPP
+
+#include "jfr/utilities/jfrAllocation.hpp"
+#include "jfr/utilities/jfrDoublyLinkedList.hpp"
+#include "jfr/utilities/jfrIterator.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
+#include "runtime/os.hpp"
+#include "utilities/globalDefinitions.hpp"
+#include "utilities/macros.hpp"
+
+template <typename T, template <typename> class RetrievalType, typename Callback>
+class JfrMemorySpace : public JfrCHeapObj {
+ public:
+  typedef T Type;
+  typedef RetrievalType<JfrMemorySpace<T, RetrievalType, Callback> > Retrieval;
+  typedef JfrDoublyLinkedList<Type> List;
+  typedef StopOnNullIterator<List> Iterator;
+ private:
+  List _free;
+  List _full;
+  size_t _min_elem_size;
+  size_t _limit_size;
+  size_t _cache_count;
+  Callback* _callback;
+
+  bool should_populate_cache() const { return _free.count() < _cache_count; }
+
+ public:
+  JfrMemorySpace(size_t min_elem_size, size_t limit_size, size_t cache_count, Callback* callback);
+  ~JfrMemorySpace();
+  bool initialize();
+
+  size_t min_elem_size() const { return _min_elem_size; }
+  size_t limit_size() const { return _limit_size; }
+
+  bool has_full() const { return _full.head() != NULL; }
+  bool has_free() const { return _free.head() != NULL; }
+  bool is_full_empty() const { return !has_full(); }
+  bool is_free_empty() const { return !has_free(); }
+
+  size_t full_count() const { return _full.count(); }
+  size_t free_count() const { return _free.count(); }
+
+  List& full() { return _full; }
+  const List& full() const { return _full; }
+  List& free() { return _free; }
+  const List& free() const { return _free; }
+
+  Type* full_head() { return _full.head(); }
+  Type* full_tail() { return _full.tail(); }
+  Type* free_head() { return _free.head(); }
+  Type* free_tail() { return _free.tail(); }
+
+  void insert_free_head(Type* t) { _free.prepend(t); }
+  void insert_free_tail(Type* t) { _free.append(t); }
+  void insert_free_tail(Type* t, Type* tail, size_t count) { _free.append_list(t, tail, count); }
+  void insert_full_head(Type* t) { _full.prepend(t); }
+  void insert_full_tail(Type* t) { _full.append(t); }
+  void insert_full_tail(Type* t, Type* tail, size_t count) { _full.append_list(t, tail, count); }
+
+  Type* remove_free(Type* t) { return _free.remove(t); }
+  Type* remove_full(Type* t) { return _full.remove(t); }
+  Type* remove_free_tail() { _free.remove(_free.tail()); }
+  Type* remove_full_tail() { return _full.remove(_full.tail()); }
+  Type* clear_full(bool return_tail = false) { return _full.clear(return_tail); }
+  Type* clear_free(bool return_tail = false) { return _free.clear(return_tail); }
+  void release_full(Type* t);
+  void release_free(Type* t);
+
+  void register_full(Type* t, Thread* thread) { _callback->register_full(t, thread); }
+  void lock() { _callback->lock(); }
+  void unlock() { _callback->unlock(); }
+  DEBUG_ONLY(bool is_locked() const { return _callback->is_locked(); })
+
+  Type* allocate(size_t size);
+  void deallocate(Type* t);
+  Type* get(size_t size, Thread* thread) { return Retrieval::get(size, this, thread); }
+
+  template <typename IteratorCallback, typename IteratorType>
+  void iterate(IteratorCallback& callback, bool full = true, jfr_iter_direction direction = forward);
+
+  debug_only(bool in_full_list(const Type* t) const { return _full.in_list(t); })
+  debug_only(bool in_free_list(const Type* t) const { return _free.in_list(t); })
+};
+
+// allocations are even multiples of the mspace min size
+inline u8 align_allocation_size(u8 requested_size, size_t min_elem_size) {
+  assert((int)min_elem_size % os::vm_page_size() == 0, "invariant");
+  u8 alloc_size_bytes = min_elem_size;
+  while (requested_size > alloc_size_bytes) {
+    alloc_size_bytes <<= 1;
+  }
+  assert((int)alloc_size_bytes % os::vm_page_size() == 0, "invariant");
+  return alloc_size_bytes;
+}
+
+template <typename T, template <typename> class RetrievalType, typename Callback>
+T* JfrMemorySpace<T, RetrievalType, Callback>::allocate(size_t size) {
+  const u8 aligned_size_bytes = align_allocation_size(size, _min_elem_size);
+  void* const allocation = JfrCHeapObj::new_array<u1>(aligned_size_bytes + sizeof(T));
+  if (allocation == NULL) {
+    return NULL;
+  }
+  T* const t = new (allocation) T;
+  assert(t != NULL, "invariant");
+  if (!t->initialize(sizeof(T), aligned_size_bytes)) {
+    JfrCHeapObj::free(t, aligned_size_bytes + sizeof(T));
+    return NULL;
+  }
+  return t;
+}
+
+template <typename T, template <typename> class RetrievalType, typename Callback>
+void JfrMemorySpace<T, RetrievalType, Callback>::deallocate(T* t) {
+  assert(t != NULL, "invariant");
+  assert(!_free.in_list(t), "invariant");
+  assert(!_full.in_list(t), "invariant");
+  assert(t != NULL, "invariant");
+  JfrCHeapObj::free(t, t->total_size());
+}
+
+template <typename Mspace>
+class MspaceLock {
+ private:
+  Mspace* _mspace;
+ public:
+  MspaceLock(Mspace* mspace) : _mspace(mspace) { _mspace->lock(); }
+  ~MspaceLock() { _mspace->unlock(); }
+};
+
+template <typename Mspace>
+class ReleaseOp : public StackObj {
+ private:
+  Mspace* _mspace;
+  Thread* _thread;
+  bool _release_full;
+ public:
+  typedef typename Mspace::Type Type;
+  ReleaseOp(Mspace* mspace, Thread* thread, bool release_full = true) : _mspace(mspace), _thread(thread), _release_full(release_full) {}
+  bool process(Type* t);
+  size_t processed() const { return 0; }
+};
+
+#endif // SHARE_VM_JFR_RECORDER_STORAGE_JFRMEMORYSPACE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.inline.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,385 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_RECORDER_STORAGE_JFRMEMORYSPACE_INLINE_HPP
+#define SHARE_VM_JFR_RECORDER_STORAGE_JFRMEMORYSPACE_INLINE_HPP
+
+#include "jfr/recorder/storage/jfrMemorySpace.hpp"
+
+template <typename T, template <typename> class RetrievalType, typename Callback>
+JfrMemorySpace<T, RetrievalType, Callback>::
+JfrMemorySpace(size_t min_elem_size, size_t limit_size, size_t cache_count, Callback* callback) :
+  _free(),
+  _full(),
+  _min_elem_size(min_elem_size),
+  _limit_size(limit_size),
+  _cache_count(cache_count),
+  _callback(callback) {}
+
+template <typename T, template <typename> class RetrievalType, typename Callback>
+JfrMemorySpace<T, RetrievalType, Callback>::~JfrMemorySpace() {
+  Iterator full_iter(_full);
+  while (full_iter.has_next()) {
+    Type* t = full_iter.next();
+    _full.remove(t);
+    deallocate(t);
+  }
+  Iterator free_iter(_free);
+  while (free_iter.has_next()) {
+    Type* t = free_iter.next();
+    _free.remove(t);
+    deallocate(t);
+  }
+}
+
+template <typename T, template <typename> class RetrievalType, typename Callback>
+bool JfrMemorySpace<T, RetrievalType, Callback>::initialize() {
+  assert(_min_elem_size % os::vm_page_size() == 0, "invariant");
+  assert(_limit_size % os::vm_page_size() == 0, "invariant");
+  // pre-allocate cache elements
+  for (size_t i = 0; i < _cache_count; ++i) {
+    Type* const t = allocate(_min_elem_size);
+    if (t == NULL) {
+      return false;
+    }
+    insert_free_head(t);
+  }
+  assert(_free.count() == _cache_count, "invariant");
+  return true;
+}
+
+template <typename T, template <typename> class RetrievalType, typename Callback>
+inline void JfrMemorySpace<T, RetrievalType, Callback>::release_full(T* t) {
+  assert(is_locked(), "invariant");
+  assert(t != NULL, "invariant");
+  assert(_full.in_list(t), "invariant");
+  remove_full(t);
+  assert(!_full.in_list(t), "invariant");
+  if (t->transient()) {
+    deallocate(t);
+    return;
+  }
+  assert(t->empty(), "invariant");
+  assert(!t->retired(), "invariant");
+  assert(t->identity() == NULL, "invariant");
+  if (should_populate_cache()) {
+    assert(!_free.in_list(t), "invariant");
+    insert_free_head(t);
+  } else {
+    deallocate(t);
+  }
+}
+
+template <typename T, template <typename> class RetrievalType, typename Callback>
+inline void JfrMemorySpace<T, RetrievalType, Callback>::release_free(T* t) {
+  assert(is_locked(), "invariant");
+  assert(t != NULL, "invariant");
+  assert(_free.in_list(t), "invariant");
+  if (t->transient()) {
+    remove_free(t);
+    assert(!_free.in_list(t), "invariant");
+    deallocate(t);
+    return;
+  }
+  assert(t->empty(), "invariant");
+  assert(!t->retired(), "invariant");
+  assert(t->identity() == NULL, "invariant");
+  if (!should_populate_cache()) {
+    remove_free(t);
+    assert(!_free.in_list(t), "invariant");
+    deallocate(t);
+  }
+}
+
+template <typename T, template <typename> class RetrievalType, typename Callback>
+template <typename IteratorCallback, typename IteratorType>
+inline void JfrMemorySpace<T, RetrievalType, Callback>
+::iterate(IteratorCallback& callback, bool full, jfr_iter_direction direction) {
+  IteratorType iterator(full ? _full : _free, direction);
+  while (iterator.has_next()) {
+    callback.process(iterator.next());
+  }
+}
+
+template <typename Mspace>
+inline size_t size_adjustment(size_t size, Mspace* mspace) {
+  assert(mspace != NULL, "invariant");
+  static const size_t min_elem_size = mspace->min_elem_size();
+  if (size < min_elem_size) {
+    size = min_elem_size;
+  }
+  return size;
+}
+
+template <typename Mspace>
+inline typename Mspace::Type* mspace_allocate(size_t size, Mspace* mspace) {
+  return mspace->allocate(size_adjustment(size, mspace));
+}
+
+template <typename Mspace>
+inline typename Mspace::Type* mspace_allocate_acquired(size_t size, Mspace* mspace, Thread* thread) {
+  typename Mspace::Type* const t = mspace_allocate(size, mspace);
+  if (t == NULL) return NULL;
+  t->acquire(thread);
+  return t;
+}
+
+template <typename Mspace>
+inline typename Mspace::Type* mspace_allocate_transient(size_t size, Mspace* mspace, Thread* thread) {
+  typename Mspace::Type* const t = mspace_allocate_acquired(size, mspace, thread);
+  if (t == NULL) return NULL;
+  assert(t->acquired_by_self(), "invariant");
+  t->set_transient();
+  return t;
+}
+
+template <typename Mspace>
+inline typename Mspace::Type* mspace_allocate_transient_lease(size_t size, Mspace* mspace, Thread* thread) {
+  typename Mspace::Type* const t = mspace_allocate_transient(size, mspace, thread);
+  if (t == NULL) return NULL;
+  assert(t->acquired_by_self(), "invariant");
+  assert(t->transient(), "invaiant");
+  t->set_lease();
+  return t;
+}
+
+template <typename Mspace>
+inline typename Mspace::Type* mspace_allocate_to_full(size_t size, Mspace* mspace, Thread* thread) {
+  assert(mspace->is_locked(), "invariant");
+  typename Mspace::Type* const t = mspace_allocate_acquired(size, mspace, thread);
+  if (t == NULL) return NULL;
+  mspace->insert_full_head(t);
+  return t;
+}
+
+template <typename Mspace>
+inline typename Mspace::Type* mspace_allocate_transient_to_full(size_t size, Mspace* mspace, Thread* thread) {
+  typename Mspace::Type* const t = mspace_allocate_transient(size, mspace, thread);
+  if (t == NULL) return NULL;
+  MspaceLock<Mspace> lock(mspace);
+  mspace->insert_full_head(t);
+  return t;
+}
+
+template <typename Mspace>
+inline typename Mspace::Type* mspace_allocate_transient_lease_to_full(size_t size, Mspace* mspace, Thread* thread) {
+  typename Mspace::Type* const t = mspace_allocate_transient_lease(size, mspace, thread);
+  if (t == NULL) return NULL;
+  assert(t->acquired_by_self(), "invariant");
+  assert(t->transient(), "invaiant");
+  assert(t->lease(), "invariant");
+  MspaceLock<Mspace> lock(mspace);
+  mspace->insert_full_head(t);
+  return t;
+}
+
+template <typename Mspace>
+inline typename Mspace::Type* mspace_allocate_transient_lease_to_free(size_t size, Mspace* mspace, Thread* thread) {
+  typename Mspace::Type* const t = mspace_allocate_transient_lease(size, mspace, thread);
+  if (t == NULL) return NULL;
+  assert(t->acquired_by_self(), "invariant");
+  assert(t->transient(), "invaiant");
+  assert(t->lease(), "invariant");
+  MspaceLock<Mspace> lock(mspace);
+  mspace->insert_free_head(t);
+  return t;
+}
+
+template <typename Mspace>
+inline typename Mspace::Type* mspace_get_free(size_t size, Mspace* mspace, Thread* thread) {
+  return mspace->get(size, thread);
+}
+
+template <typename Mspace>
+inline typename Mspace::Type* mspace_get_free_with_retry(size_t size, Mspace* mspace, size_t retry_count, Thread* thread) {
+  assert(size <= mspace->min_elem_size(), "invariant");
+  for (size_t i = 0; i < retry_count; ++i) {
+    typename Mspace::Type* const t = mspace_get_free(size, mspace, thread);
+    if (t != NULL) {
+      return t;
+    }
+  }
+  return NULL;
+}
+
+template <typename Mspace>
+inline typename Mspace::Type* mspace_get_free_with_detach(size_t size, Mspace* mspace, Thread* thread) {
+  typename Mspace::Type* t = mspace_get_free(size, mspace, thread);
+  if (t != NULL) {
+    mspace->remove_free(t);
+  }
+  return t;
+}
+
+template <typename Mspace>
+inline typename Mspace::Type* mspace_get_free_to_full(size_t size, Mspace* mspace, Thread* thread) {
+  assert(size <= mspace->min_elem_size(), "invariant");
+  assert(mspace->is_locked(), "invariant");
+  typename Mspace::Type* t = mspace_get_free(size, mspace, thread);
+  if (t == NULL) {
+    return NULL;
+  }
+  assert(t->acquired_by_self(), "invariant");
+  move_to_head(t, mspace->free(), mspace->full());
+  return t;
+}
+
+template <typename Mspace>
+inline typename Mspace::Type* mspace_get_to_full(size_t size, Mspace* mspace, Thread* thread) {
+  size = size_adjustment(size, mspace);
+  MspaceLock<Mspace> lock(mspace);
+  if (size <= mspace->min_elem_size()) {
+    typename Mspace::Type* const t = mspace_get_free_to_full(size, mspace, thread);
+    if (t != NULL) {
+      return t;
+    }
+  }
+  return mspace_allocate_to_full(size, mspace, thread);
+}
+
+template <typename Mspace>
+inline typename Mspace::Type* mspace_get_free_lease_with_retry(size_t size, Mspace* mspace, size_t retry_count, Thread* thread) {
+  typename Mspace::Type* t = mspace_get_free_with_retry(size, mspace, retry_count, thread);
+  if (t != NULL) {
+    t->set_lease();
+  }
+  return t;
+}
+
+template <typename Mspace>
+inline typename Mspace::Type* mspace_get_lease(size_t size, Mspace* mspace, Thread* thread) {
+  typename Mspace::Type* t;
+  t = mspace_get_free_lease(size, mspace, thread);
+  if (t != NULL) {
+    assert(t->acquired_by_self(), "invariant");
+    assert(t->lease(), "invariant");
+    return t;
+  }
+  t = mspace_allocate_transient_to_full(size, mspace, thread);
+  if (t != NULL) {
+    t->set_lease();
+  }
+  return t;
+}
+
+template <typename Mspace>
+inline void mspace_release_full(typename Mspace::Type* t, Mspace* mspace) {
+  assert(t != NULL, "invariant");
+  assert(t->unflushed_size() == 0, "invariant");
+  assert(mspace != NULL, "invariant");
+  assert(mspace->is_locked(), "invariant");
+  mspace->release_full(t);
+}
+
+template <typename Mspace>
+inline void mspace_release_free(typename Mspace::Type* t, Mspace* mspace) {
+  assert(t != NULL, "invariant");
+  assert(t->unflushed_size() == 0, "invariant");
+  assert(mspace != NULL, "invariant");
+  assert(mspace->is_locked(), "invariant");
+  mspace->release_free(t);
+}
+
+template <typename Mspace>
+inline void mspace_release_full_critical(typename Mspace::Type* t, Mspace* mspace) {
+  MspaceLock<Mspace> lock(mspace);
+  mspace_release_full(t, mspace);
+}
+
+template <typename Mspace>
+inline void mspace_release_free_critical(typename Mspace::Type* t, Mspace* mspace) {
+  MspaceLock<Mspace> lock(mspace);
+  mspace_release_free(t, mspace);
+}
+
+template <typename List>
+inline void move_to_head(typename List::Node* t, List& from, List& to) {
+  assert(from.in_list(t), "invariant");
+  to.prepend(from.remove(t));
+}
+
+template <typename Processor, typename Mspace, typename Iterator>
+inline void process_free_list_iterator_control(Processor& processor, Mspace* mspace, jfr_iter_direction direction = forward) {
+  mspace->template iterate<Processor, Iterator>(processor, false, direction);
+}
+
+template <typename Processor, typename Mspace, typename Iterator>
+inline void process_full_list_iterator_control(Processor& processor, Mspace* mspace, jfr_iter_direction direction = forward) {
+  mspace->template iterate<Processor, Iterator>(processor, true, direction);
+}
+
+template <typename Processor, typename Mspace>
+inline void process_full_list(Processor& processor, Mspace* mspace, jfr_iter_direction direction = forward) {
+  assert(mspace != NULL, "invariant");
+  if (mspace->is_full_empty()) return;
+  process_full_list_iterator_control<Processor, Mspace, typename Mspace::Iterator>(processor, mspace, direction);
+}
+
+template <typename Processor, typename Mspace>
+inline void process_free_list(Processor& processor, Mspace* mspace, jfr_iter_direction direction = forward) {
+  assert(mspace != NULL, "invariant");
+  assert(mspace->has_free(), "invariant");
+  process_free_list_iterator_control<Processor, Mspace, typename Mspace::Iterator>(processor, mspace, direction);
+}
+
+template <typename Mspace>
+inline bool ReleaseOp<Mspace>::process(typename Mspace::Type* t) {
+  assert(t != NULL, "invariant");
+  if (t->retired() || t->try_acquire(_thread)) {
+    if (t->transient()) {
+      if (_release_full) {
+        mspace_release_full_critical(t, _mspace);
+      } else {
+        mspace_release_free_critical(t, _mspace);
+      }
+      return true;
+    }
+    t->reinitialize();
+    assert(t->empty(), "invariant");
+    t->release(); // publish
+  }
+  return true;
+}
+
+#ifdef ASSERT
+template <typename T>
+inline void assert_migration_state(const T* old, const T* new_buffer, size_t used, size_t requested) {
+  assert(old != NULL, "invariant");
+  assert(new_buffer != NULL, "invariant");
+  assert(old->pos() >= old->start(), "invariant");
+  assert(old->pos() + used <= old->end(), "invariant");
+  assert(new_buffer->free_size() >= (used + requested), "invariant");
+}
+#endif // ASSERT
+
+template <typename T>
+inline void migrate_outstanding_writes(const T* old, T* new_buffer, size_t used, size_t requested) {
+  DEBUG_ONLY(assert_migration_state(old, new_buffer, used, requested);)
+  if (used > 0) {
+    memcpy(new_buffer->pos(), old->pos(), used);
+  }
+}
+
+#endif // SHARE_VM_JFR_RECORDER_STORAGE_JFRMEMORYSPACE_INLINE_HPP
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/storage/jfrMemorySpaceRetrieval.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_RECORDER_STORAGE_JFRMEMORYSPACERETRIEVAL_HPP
+#define SHARE_VM_JFR_RECORDER_STORAGE_JFRMEMORYSPACERETRIEVAL_HPP
+
+#include "memory/allocation.hpp"
+#include "jfr/recorder/repository/jfrChunkWriter.hpp"
+#include "jfr/recorder/storage/jfrBuffer.hpp"
+#include "jfr/utilities/jfrAllocation.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
+
+/*
+* Some policy classes for getting mspace memory
+*/
+
+template <typename Mspace>
+class JfrMspaceRetrieval : AllStatic {
+ public:
+  typedef typename Mspace::Type Type;
+  static Type* get(size_t size, Mspace* mspace, typename Mspace::Iterator& iterator, Thread* thread) {
+    while (iterator.has_next()) {
+      Type* const t = iterator.next();
+      if (t->retired()) continue;
+      if (t->try_acquire(thread)) {
+        assert(!t->retired(), "invariant");
+        if (t->free_size() >= size) {
+          return t;
+        }
+        t->set_retired();
+        mspace->register_full(t, thread);
+      }
+    }
+    return NULL;
+  }
+};
+
+template <typename Mspace>
+class JfrMspaceAlternatingRetrieval {
+ private:
+   // provides stochastic distribution over "deque" endpoints; racy is ok here
+  static bool _last_access;
+ public:
+  typedef typename Mspace::Type Type;
+  static Type* get(size_t size, Mspace* mspace, Thread* thread) {
+    typename Mspace::Iterator iterator(mspace->free(), (_last_access = !_last_access) ? forward : backward);
+    return JfrMspaceRetrieval<Mspace>::get(size, mspace, iterator, thread);
+  }
+};
+
+template <typename Mspace>
+bool JfrMspaceAlternatingRetrieval<Mspace>::_last_access = false;
+
+template <typename Mspace>
+class JfrMspaceSequentialRetrieval {
+ public:
+  typedef typename Mspace::Type Type;
+  static Type* get(size_t size, Mspace* mspace, Thread* thread) {
+    typename Mspace::Iterator iterator(mspace->free());
+    return JfrMspaceRetrieval<Mspace>::get(size, mspace, iterator, thread);
+  }
+};
+
+template <typename Mspace>
+class JfrExclusiveRetrieval : AllStatic {
+public:
+  typedef typename Mspace::Type Type;
+  static Type* get(size_t size, Mspace* mspace, typename Mspace::Iterator& iterator, Thread* thread) {
+    assert(mspace->is_locked(), "invariant");
+    if (iterator.has_next()) {
+      Type* const t = iterator.next();
+      assert(!t->retired(), "invariant");
+      assert(t->identity() == NULL, "invariant");
+      assert(t->free_size() >= size, "invariant");
+      t->acquire(thread);
+      return t;
+    }
+    return NULL;
+  }
+};
+
+template <typename Mspace>
+class JfrThreadLocalRetrieval {
+public:
+  typedef typename Mspace::Type Type;
+  static Type* get(size_t size, Mspace* mspace, Thread* thread) {
+    typename Mspace::Iterator iterator(mspace->free(), forward);
+    return JfrExclusiveRetrieval<Mspace>::get(size, mspace, iterator, thread);
+  }
+};
+
+#endif // SHARE_VM_JFR_RECORDER_STORAGE_JFRMEMORYSPACERETRIEVAL_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,762 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/jfrEvents.hpp"
+#include "jfr/jni/jfrJavaSupport.hpp"
+#include "jfr/recorder/jfrRecorder.hpp"
+#include "jfr/recorder/repository/jfrChunkWriter.hpp"
+#include "jfr/recorder/service/jfrOptionSet.hpp"
+#include "jfr/recorder/service/jfrPostBox.hpp"
+#include "jfr/recorder/storage/jfrMemorySpace.inline.hpp"
+#include "jfr/recorder/storage/jfrStorage.hpp"
+#include "jfr/recorder/storage/jfrStorageControl.hpp"
+#include "jfr/recorder/storage/jfrStorageUtils.inline.hpp"
+#include "jfr/utilities/jfrIterator.hpp"
+#include "jfr/utilities/jfrTime.hpp"
+#include "jfr/writers/jfrNativeEventWriter.hpp"
+#include "logging/log.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/orderAccess.inline.hpp"
+#include "runtime/safepoint.hpp"
+#include "runtime/thread.hpp"
+
+typedef JfrStorage::Buffer* BufferPtr;
+
+static JfrStorage* _instance = NULL;
+static JfrStorageControl* _control;
+
+JfrStorage& JfrStorage::instance() {
+  return *_instance;
+}
+
+JfrStorage* JfrStorage::create(JfrChunkWriter& chunkwriter, JfrPostBox& post_box) {
+  assert(_instance == NULL, "invariant");
+  _instance = new JfrStorage(chunkwriter, post_box);
+  return _instance;
+}
+
+void JfrStorage::destroy() {
+  if (_instance != NULL) {
+    delete _instance;
+    _instance = NULL;
+  }
+}
+
+JfrStorage::JfrStorage(JfrChunkWriter& chunkwriter, JfrPostBox& post_box) :
+  _control(NULL),
+  _global_mspace(NULL),
+  _thread_local_mspace(NULL),
+  _transient_mspace(NULL),
+  _age_mspace(NULL),
+  _chunkwriter(chunkwriter),
+  _post_box(post_box) {}
+
+JfrStorage::~JfrStorage() {
+  if (_control != NULL) {
+    delete _control;
+  }
+  if (_global_mspace != NULL) {
+    delete _global_mspace;
+  }
+  if (_thread_local_mspace != NULL) {
+    delete _thread_local_mspace;
+  }
+  if (_transient_mspace != NULL) {
+    delete _transient_mspace;
+  }
+  if (_age_mspace != NULL) {
+    delete _age_mspace;
+  }
+  _instance = NULL;
+}
+
+static const size_t in_memory_discard_threshold_delta = 2; // start to discard data when the only this number of free buffers are left
+static const size_t unlimited_mspace_size = 0;
+static const size_t thread_local_cache_count = 8;
+static const size_t thread_local_scavenge_threshold = thread_local_cache_count / 2;
+static const size_t transient_buffer_size_multiplier = 8; // against thread local buffer size
+
+template <typename Mspace>
+static Mspace* create_mspace(size_t buffer_size, size_t limit, size_t cache_count, JfrStorage* storage_instance) {
+  Mspace* mspace = new Mspace(buffer_size, limit, cache_count, storage_instance);
+  if (mspace != NULL) {
+    mspace->initialize();
+  }
+  return mspace;
+}
+
+bool JfrStorage::initialize() {
+  assert(_control == NULL, "invariant");
+  assert(_global_mspace == NULL, "invariant");
+  assert(_thread_local_mspace == NULL, "invariant");
+  assert(_transient_mspace == NULL, "invariant");
+  assert(_age_mspace == NULL, "invariant");
+
+  const size_t num_global_buffers = (size_t)JfrOptionSet::num_global_buffers();
+  assert(num_global_buffers >= in_memory_discard_threshold_delta, "invariant");
+  const size_t memory_size = (size_t)JfrOptionSet::memory_size();
+  const size_t global_buffer_size = (size_t)JfrOptionSet::global_buffer_size();
+  const size_t thread_buffer_size = (size_t)JfrOptionSet::thread_buffer_size();
+
+  _control = new JfrStorageControl(num_global_buffers, num_global_buffers - in_memory_discard_threshold_delta);
+  if (_control == NULL) {
+    return false;
+  }
+  _global_mspace = create_mspace<JfrStorageMspace>(global_buffer_size, memory_size, num_global_buffers, this);
+  if (_global_mspace == NULL) {
+    return false;
+  }
+  _thread_local_mspace = create_mspace<JfrThreadLocalMspace>(thread_buffer_size, unlimited_mspace_size, thread_local_cache_count, this);
+  if (_thread_local_mspace == NULL) {
+    return false;
+  }
+  _transient_mspace = create_mspace<JfrStorageMspace>(thread_buffer_size * transient_buffer_size_multiplier, unlimited_mspace_size, 0, this);
+  if (_transient_mspace == NULL) {
+    return false;
+  }
+  _age_mspace = create_mspace<JfrStorageAgeMspace>(0 /* no extra size except header */, unlimited_mspace_size, num_global_buffers, this);
+  if (_age_mspace == NULL) {
+    return false;
+  }
+  control().set_scavenge_threshold(thread_local_scavenge_threshold);
+  return true;
+}
+
+JfrStorageControl& JfrStorage::control() {
+  return *instance()._control;
+}
+
+static void log_allocation_failure(const char* msg, size_t size) {
+  log_warning(jfr)("Unable to allocate " SIZE_FORMAT " bytes of %s.", size, msg);
+}
+
+BufferPtr JfrStorage::acquire_thread_local(Thread* thread, size_t size /* 0 */) {
+  BufferPtr buffer = mspace_get_to_full(size, instance()._thread_local_mspace, thread);
+  if (buffer == NULL) {
+    log_allocation_failure("thread local_memory", size);
+    return NULL;
+  }
+  assert(buffer->acquired_by_self(), "invariant");
+  return buffer;
+}
+
+BufferPtr JfrStorage::acquire_transient(size_t size, Thread* thread) {
+  BufferPtr buffer = mspace_allocate_transient_lease_to_full(size, instance()._transient_mspace, thread);
+  if (buffer == NULL) {
+    log_allocation_failure("transient memory", size);
+    return NULL;
+  }
+  assert(buffer->acquired_by_self(), "invariant");
+  assert(buffer->transient(), "invariant");
+  assert(buffer->lease(), "invariant");
+  return buffer;
+}
+
+static BufferPtr get_lease(size_t size, JfrStorageMspace* mspace, JfrStorage& storage_instance, size_t retry_count, Thread* thread) {
+  assert(size <= mspace->min_elem_size(), "invariant");
+  while (true) {
+    BufferPtr t = mspace_get_free_lease_with_retry(size, mspace, retry_count, thread);
+    if (t == NULL && storage_instance.control().should_discard()) {
+      storage_instance.discard_oldest(thread);
+      continue;
+    }
+    return t;
+  }
+}
+
+static BufferPtr get_promotion_buffer(size_t size, JfrStorageMspace* mspace, JfrStorage& storage_instance, size_t retry_count, Thread* thread) {
+  assert(size <= mspace->min_elem_size(), "invariant");
+  while (true) {
+    BufferPtr t = mspace_get_free_with_retry(size, mspace, retry_count, thread);
+    if (t == NULL && storage_instance.control().should_discard()) {
+      storage_instance.discard_oldest(thread);
+      continue;
+    }
+    return t;
+  }
+}
+
+static const size_t lease_retry = 10;
+
+BufferPtr JfrStorage::acquire_large(size_t size, Thread* thread) {
+  JfrStorage& storage_instance = instance();
+  const size_t max_elem_size = storage_instance._global_mspace->min_elem_size(); // min is also max
+  // if not too large and capacity is still available, ask for a lease from the global system
+  if (size < max_elem_size && storage_instance.control().is_global_lease_allowed()) {
+    BufferPtr const buffer = get_lease(size, storage_instance._global_mspace, storage_instance, lease_retry, thread);
+    if (buffer != NULL) {
+      assert(buffer->acquired_by_self(), "invariant");
+      assert(!buffer->transient(), "invariant");
+      assert(buffer->lease(), "invariant");
+      storage_instance.control().increment_leased();
+      return buffer;
+    }
+  }
+  return acquire_transient(size, thread);
+}
+
+static void write_data_loss_event(JfrBuffer* buffer, u8 unflushed_size, Thread* thread) {
+  assert(buffer != NULL, "invariant");
+  assert(buffer->empty(), "invariant");
+  const u8 total_data_loss = thread->jfr_thread_local()->add_data_lost(unflushed_size);
+  if (EventDataLoss::is_enabled()) {
+    JfrNativeEventWriter writer(buffer, thread);
+    writer.write<u8>(EventDataLoss::eventId);
+    writer.write(JfrTicks::now());
+    writer.write(unflushed_size);
+    writer.write(total_data_loss);
+  }
+}
+
+static void write_data_loss(BufferPtr buffer, Thread* thread) {
+  assert(buffer != NULL, "invariant");
+  const size_t unflushed_size = buffer->unflushed_size();
+  buffer->concurrent_reinitialization();
+  if (unflushed_size == 0) {
+    return;
+  }
+  write_data_loss_event(buffer, unflushed_size, thread);
+}
+
+static const size_t promotion_retry = 100;
+
+bool JfrStorage::flush_regular_buffer(BufferPtr buffer, Thread* thread) {
+  assert(buffer != NULL, "invariant");
+  assert(!buffer->lease(), "invariant");
+  assert(!buffer->transient(), "invariant");
+  const size_t unflushed_size = buffer->unflushed_size();
+  if (unflushed_size == 0) {
+    buffer->concurrent_reinitialization();
+    assert(buffer->empty(), "invariant");
+    return true;
+  }
+  BufferPtr const promotion_buffer = get_promotion_buffer(unflushed_size, _global_mspace, *this, promotion_retry, thread);
+  if (promotion_buffer == NULL) {
+    write_data_loss(buffer, thread);
+    return false;
+  }
+  assert(promotion_buffer->acquired_by_self(), "invariant");
+  assert(promotion_buffer->free_size() >= unflushed_size, "invariant");
+  buffer->concurrent_move_and_reinitialize(promotion_buffer, unflushed_size);
+  assert(buffer->empty(), "invariant");
+  return true;
+}
+
+/*
+* 1. If the buffer was a "lease" from the global system, release back.
+* 2. If the buffer is transient (temporal dynamically allocated), retire and register full.
+*
+* The buffer is effectively invalidated for the thread post-return,
+* and the caller should take means to ensure that it is not referenced any longer.
+*/
+void JfrStorage::release_large(BufferPtr buffer, Thread* thread) {
+  assert(buffer != NULL, "invariant");
+  assert(buffer->lease(), "invariant");
+  assert(buffer->acquired_by_self(), "invariant");
+  buffer->clear_lease();
+  if (buffer->transient()) {
+    buffer->set_retired();
+    register_full(buffer, thread);
+  } else {
+    buffer->release();
+    control().decrement_leased();
+  }
+}
+
+static JfrAgeNode* new_age_node(BufferPtr buffer, JfrStorageAgeMspace* age_mspace, Thread* thread) {
+  assert(buffer != NULL, "invariant");
+  assert(age_mspace != NULL, "invariant");
+  return mspace_allocate_transient(0, age_mspace, thread);
+}
+
+static void log_registration_failure(size_t unflushed_size) {
+  log_warning(jfr)("Unable to register a full buffer of " SIZE_FORMAT " bytes.", unflushed_size);
+  log_debug(jfr, system)("Cleared 1 full buffer of " SIZE_FORMAT " bytes.", unflushed_size);
+}
+
+static void handle_registration_failure(BufferPtr buffer) {
+  assert(buffer != NULL, "invariant");
+  assert(buffer->retired(), "invariant");
+  const size_t unflushed_size = buffer->unflushed_size();
+  buffer->reinitialize();
+  log_registration_failure(unflushed_size);
+}
+
+static JfrAgeNode* get_free_age_node(JfrStorageAgeMspace* age_mspace, Thread* thread) {
+  assert(JfrBuffer_lock->owned_by_self(), "invariant");
+  return mspace_get_free_with_detach(0, age_mspace, thread);
+}
+
+static bool insert_full_age_node(JfrAgeNode* age_node, JfrStorageAgeMspace* age_mspace, Thread* thread) {
+  assert(JfrBuffer_lock->owned_by_self(), "invariant");
+  assert(age_node->retired_buffer()->retired(), "invariant");
+  age_mspace->insert_full_head(age_node);
+  return true;
+}
+
+static bool full_buffer_registration(BufferPtr buffer, JfrStorageAgeMspace* age_mspace, JfrStorageControl& control, Thread* thread) {
+  assert(buffer != NULL, "invariant");
+  assert(buffer->retired(), "invariant");
+  assert(age_mspace != NULL, "invariant");
+  MutexLockerEx lock(JfrBuffer_lock, Mutex::_no_safepoint_check_flag);
+  JfrAgeNode* age_node = get_free_age_node(age_mspace, thread);
+  if (age_node == NULL) {
+    age_node = new_age_node(buffer, age_mspace, thread);
+    if (age_node == NULL) {
+      return false;
+    }
+  }
+  assert(age_node->acquired_by_self(), "invariant");
+  assert(age_node != NULL, "invariant");
+  age_node->set_retired_buffer(buffer);
+  return insert_full_age_node(age_node, age_mspace, thread);
+}
+
+void JfrStorage::register_full(BufferPtr buffer, Thread* thread) {
+  assert(buffer != NULL, "invariant");
+  assert(buffer->retired(), "invariant");
+  if (!full_buffer_registration(buffer, _age_mspace, control(), thread)) {
+    handle_registration_failure(buffer);
+    buffer->release();
+  }
+  if (control().should_post_buffer_full_message()) {
+    _post_box.post(MSG_FULLBUFFER);
+  }
+}
+
+void JfrStorage::lock() {
+  assert(!JfrBuffer_lock->owned_by_self(), "invariant");
+  JfrBuffer_lock->lock_without_safepoint_check();
+}
+
+void JfrStorage::unlock() {
+  assert(JfrBuffer_lock->owned_by_self(), "invariant");
+  JfrBuffer_lock->unlock();
+}
+
+#ifdef ASSERT
+bool JfrStorage::is_locked() const {
+  return JfrBuffer_lock->owned_by_self();
+}
+#endif
+
+// don't use buffer on return, it is gone
+void JfrStorage::release(BufferPtr buffer, Thread* thread) {
+  assert(buffer != NULL, "invariant");
+  assert(!buffer->lease(), "invariant");
+  assert(!buffer->transient(), "invariant");
+  assert(!buffer->retired(), "invariant");
+  if (!buffer->empty()) {
+    if (!flush_regular_buffer(buffer, thread)) {
+      buffer->concurrent_reinitialization();
+    }
+  }
+  assert(buffer->empty(), "invariant");
+  control().increment_dead();
+  buffer->release();
+  buffer->set_retired();
+}
+
+void JfrStorage::release_thread_local(BufferPtr buffer, Thread* thread) {
+  assert(buffer != NULL, "invariant");
+  JfrStorage& storage_instance = instance();
+  storage_instance.release(buffer, thread);
+  if (storage_instance.control().should_scavenge()) {
+    storage_instance._post_box.post(MSG_DEADBUFFER);
+  }
+}
+
+static void log_discard(size_t count, size_t amount, size_t current) {
+  if (log_is_enabled(Debug, jfr, system)) {
+    assert(count > 0, "invariant");
+    log_debug(jfr, system)("Cleared " SIZE_FORMAT " full buffer(s) of " SIZE_FORMAT" bytes.", count, amount);
+    log_debug(jfr, system)("Current number of full buffers " SIZE_FORMAT "", current);
+  }
+}
+
+void JfrStorage::discard_oldest(Thread* thread) {
+  if (JfrBuffer_lock->try_lock()) {
+    if (!control().should_discard()) {
+      // another thread handled it
+      return;
+    }
+    const size_t num_full_pre_discard = control().full_count();
+    size_t num_full_post_discard = 0;
+    size_t discarded_size = 0;
+    while (true) {
+      JfrAgeNode* const oldest_age_node = _age_mspace->full_tail();
+      if (oldest_age_node == NULL) {
+        break;
+      }
+      BufferPtr const buffer = oldest_age_node->retired_buffer();
+      assert(buffer->retired(), "invariant");
+      discarded_size += buffer->unflushed_size();
+      num_full_post_discard = control().decrement_full();
+      if (buffer->transient()) {
+        mspace_release_full(buffer, _transient_mspace);
+        mspace_release_full(oldest_age_node, _age_mspace);
+        continue;
+      } else {
+        mspace_release_full(oldest_age_node, _age_mspace);
+        buffer->reinitialize();
+        buffer->release(); // pusb
+        break;
+      }
+    }
+    JfrBuffer_lock->unlock();
+    const size_t number_of_discards = num_full_pre_discard - num_full_post_discard;
+    if (number_of_discards > 0) {
+      log_discard(number_of_discards, discarded_size, num_full_post_discard);
+    }
+  }
+}
+
+#ifdef ASSERT
+typedef const BufferPtr ConstBufferPtr;
+
+static void assert_flush_precondition(ConstBufferPtr cur, size_t used, bool native, const Thread* t) {
+  assert(t != NULL, "invariant");
+  assert(cur != NULL, "invariant");
+  assert(cur->pos() + used <= cur->end(), "invariant");
+  assert(native ? t->jfr_thread_local()->native_buffer() == cur : t->jfr_thread_local()->java_buffer() == cur, "invariant");
+}
+
+static void assert_flush_regular_precondition(ConstBufferPtr cur, const u1* const cur_pos, size_t used, size_t req, const Thread* t) {
+  assert(t != NULL, "invariant");
+  assert(t->jfr_thread_local()->shelved_buffer() == NULL, "invariant");
+  assert(cur != NULL, "invariant");
+  assert(!cur->lease(), "invariant");
+  assert(cur_pos != NULL, "invariant");
+  assert(req >= used, "invariant");
+}
+
+static void assert_provision_large_precondition(ConstBufferPtr cur, size_t used, size_t req, const Thread* t) {
+  assert(cur != NULL, "invariant");
+  assert(t != NULL, "invariant");
+  assert(t->jfr_thread_local()->shelved_buffer() != NULL, "invariant");
+  assert(req >= used, "invariant");
+}
+
+static void assert_flush_large_precondition(ConstBufferPtr cur, const u1* const cur_pos, size_t used, size_t req, bool native, Thread* t) {
+  assert(t != NULL, "invariant");
+  assert(cur != NULL, "invariant");
+  assert(cur->lease(), "invariant");
+  assert(cur_pos != NULL, "invariant");
+  assert(native ? t->jfr_thread_local()->native_buffer() == cur : t->jfr_thread_local()->java_buffer() == cur, "invariant");
+  assert(t->jfr_thread_local()->shelved_buffer() != NULL, "invariant");
+  assert(req >= used, "invariant");
+  assert(cur != t->jfr_thread_local()->shelved_buffer(), "invariant");
+}
+#endif // ASSERT
+
+BufferPtr JfrStorage::flush(BufferPtr cur, size_t used, size_t req, bool native, Thread* t) {
+  debug_only(assert_flush_precondition(cur, used, native, t);)
+  const u1* const cur_pos = cur->pos();
+  req += used;
+  // requested size now encompass the outstanding used size
+  return cur->lease() ? instance().flush_large(cur, cur_pos, used, req, native, t) :
+                          instance().flush_regular(cur, cur_pos, used, req, native, t);
+}
+
+BufferPtr JfrStorage::flush_regular(BufferPtr cur, const u1* const cur_pos, size_t used, size_t req, bool native, Thread* t) {
+  debug_only(assert_flush_regular_precondition(cur, cur_pos, used, req, t);)
+  // A flush is needed before memcpy since a non-large buffer is thread stable
+  // (thread local). The flush will not modify memory in addresses above pos()
+  // which is where the "used / uncommitted" data resides. It is therefore both
+  // possible and valid to migrate data after the flush. This is however only
+  // the case for stable thread local buffers; it is not the case for large buffers.
+  if (!cur->empty()) {
+    flush_regular_buffer(cur, t);
+  }
+  assert(t->jfr_thread_local()->shelved_buffer() == NULL, "invariant");
+  if (cur->free_size() >= req) {
+    // simplest case, no switching of buffers
+    if (used > 0) {
+      memcpy(cur->pos(), (void*)cur_pos, used);
+    }
+    assert(native ? t->jfr_thread_local()->native_buffer() == cur : t->jfr_thread_local()->java_buffer() == cur, "invariant");
+    return cur;
+  }
+  // Going for a "larger-than-regular" buffer.
+  // Shelve the current buffer to make room for a temporary lease.
+  t->jfr_thread_local()->shelve_buffer(cur);
+  return provision_large(cur, cur_pos, used, req, native, t);
+}
+
+static BufferPtr store_buffer_to_thread_local(BufferPtr buffer, JfrThreadLocal* jfr_thread_local, bool native) {
+  assert(buffer != NULL, "invariant");
+  if (native) {
+    jfr_thread_local->set_native_buffer(buffer);
+  } else {
+    jfr_thread_local->set_java_buffer(buffer);
+  }
+  return buffer;
+}
+
+static BufferPtr restore_shelved_buffer(bool native, Thread* t) {
+  JfrThreadLocal* const tl = t->jfr_thread_local();
+  BufferPtr shelved = tl->shelved_buffer();
+  assert(shelved != NULL, "invariant");
+  tl->shelve_buffer(NULL);
+  // restore shelved buffer back as primary
+  return store_buffer_to_thread_local(shelved, tl, native);
+}
+
+BufferPtr JfrStorage::flush_large(BufferPtr cur, const u1* const cur_pos, size_t used, size_t req, bool native, Thread* t) {
+  debug_only(assert_flush_large_precondition(cur, cur_pos, used, req, native, t);)
+  // Can the "regular" buffer (now shelved) accommodate the requested size?
+  BufferPtr shelved = t->jfr_thread_local()->shelved_buffer();
+  assert(shelved != NULL, "invariant");
+  if (shelved->free_size() >= req) {
+    if (req > 0) {
+      memcpy(shelved->pos(), (void*)cur_pos, (size_t)used);
+    }
+    // release and invalidate
+    release_large(cur, t);
+    return restore_shelved_buffer(native, t);
+  }
+  // regular too small
+  return provision_large(cur, cur_pos,  used, req, native, t);
+}
+
+static BufferPtr large_fail(BufferPtr cur, bool native, JfrStorage& storage_instance, Thread* t) {
+  assert(cur != NULL, "invariant");
+  assert(t != NULL, "invariant");
+  if (cur->lease()) {
+    storage_instance.release_large(cur, t);
+  }
+  return restore_shelved_buffer(native, t);
+}
+
+// Always returns a non-null buffer.
+// If accommodating the large request fails, the shelved buffer is returned
+// even though it might be smaller than the requested size.
+// Caller needs to ensure if the size was successfully accommodated.
+BufferPtr JfrStorage::provision_large(BufferPtr cur, const u1* const cur_pos, size_t used, size_t req, bool native, Thread* t) {
+  debug_only(assert_provision_large_precondition(cur, used, req, t);)
+  assert(t->jfr_thread_local()->shelved_buffer() != NULL, "invariant");
+  BufferPtr const buffer = acquire_large(req, t);
+  if (buffer == NULL) {
+    // unable to allocate and serve the request
+    return large_fail(cur, native, *this, t);
+  }
+  // ok managed to acquire a "large" buffer for the requested size
+  assert(buffer->free_size() >= req, "invariant");
+  assert(buffer->lease(), "invariant");
+  // transfer outstanding data
+  memcpy(buffer->pos(), (void*)cur_pos, used);
+  if (cur->lease()) {
+    release_large(cur, t);
+    // don't use current anymore, it is gone
+  }
+  return store_buffer_to_thread_local(buffer, t->jfr_thread_local(), native);
+}
+
+typedef UnBufferedWriteToChunk<JfrBuffer> WriteOperation;
+typedef MutexedWriteOp<WriteOperation> MutexedWriteOperation;
+typedef ConcurrentWriteOp<WriteOperation> ConcurrentWriteOperation;
+typedef ConcurrentWriteOpExcludeRetired<WriteOperation> ThreadLocalConcurrentWriteOperation;
+
+size_t JfrStorage::write() {
+  const size_t full_size_processed = write_full();
+  WriteOperation wo(_chunkwriter);
+  ThreadLocalConcurrentWriteOperation tlwo(wo);
+  process_full_list(tlwo, _thread_local_mspace);
+  ConcurrentWriteOperation cwo(wo);
+  process_free_list(cwo, _global_mspace);
+  return full_size_processed + wo.processed();
+}
+
+size_t JfrStorage::write_at_safepoint() {
+  assert(SafepointSynchronize::is_at_safepoint(), "invariant");
+  WriteOperation wo(_chunkwriter);
+  MutexedWriteOperation writer(wo); // mutexed write mode
+  process_full_list(writer, _thread_local_mspace);
+  assert(_transient_mspace->is_free_empty(), "invariant");
+  process_full_list(writer, _transient_mspace);
+  assert(_global_mspace->is_full_empty(), "invariant");
+  process_free_list(writer, _global_mspace);
+  return wo.processed();
+}
+
+typedef DiscardOp<DefaultDiscarder<JfrStorage::Buffer> > DiscardOperation;
+typedef ReleaseOp<JfrStorageMspace> ReleaseOperation;
+typedef CompositeOperation<MutexedWriteOperation, ReleaseOperation> FullOperation;
+
+size_t JfrStorage::clear() {
+  const size_t full_size_processed = clear_full();
+  DiscardOperation discarder(concurrent); // concurrent discard mode
+  process_full_list(discarder, _thread_local_mspace);
+  assert(_transient_mspace->is_free_empty(), "invariant");
+  process_full_list(discarder, _transient_mspace);
+  assert(_global_mspace->is_full_empty(), "invariant");
+  process_free_list(discarder, _global_mspace);
+  return full_size_processed + discarder.processed();
+}
+
+static void insert_free_age_nodes(JfrStorageAgeMspace* age_mspace, JfrAgeNode* head, JfrAgeNode* tail, size_t count) {
+  if (tail != NULL) {
+    assert(tail->next() == NULL, "invariant");
+    assert(head != NULL, "invariant");
+    assert(head->prev() == NULL, "invariant");
+    MutexLockerEx buffer_lock(JfrBuffer_lock, Mutex::_no_safepoint_check_flag);
+    age_mspace->insert_free_tail(head, tail, count);
+  }
+}
+
+template <typename Processor>
+static void process_age_list(Processor& processor, JfrStorageAgeMspace* age_mspace, JfrAgeNode* head, size_t count) {
+  assert(age_mspace != NULL, "invariant");
+  assert(head != NULL, "invariant");
+  JfrAgeNode* node = head;
+  JfrAgeNode* last = NULL;
+  while (node != NULL) {
+    last = node;
+    BufferPtr const buffer = node->retired_buffer();
+    assert(buffer != NULL, "invariant");
+    assert(buffer->retired(), "invariant");
+    processor.process(buffer);
+    // at this point, buffer is already live or destroyed
+    node->clear_identity();
+    JfrAgeNode* const next = (JfrAgeNode*)node->next();
+    if (node->transient()) {
+      // detach
+      last = (JfrAgeNode*)last->prev();
+      if (last != NULL) {
+        last->set_next(next);
+      } else {
+        head = next;
+      }
+      if (next != NULL) {
+        next->set_prev(last);
+      }
+      --count;
+      age_mspace->deallocate(node);
+    }
+    node = next;
+  }
+  insert_free_age_nodes(age_mspace, head, last, count);
+}
+
+template <typename Processor>
+static size_t process_full(Processor& processor, JfrStorageControl& control, JfrStorageAgeMspace* age_mspace) {
+  assert(age_mspace != NULL, "invariant");
+  if (age_mspace->is_full_empty()) {
+    // nothing to do
+    return 0;
+  }
+  size_t count;
+  JfrAgeNode* head;;
+  {
+    // fetch age list
+    MutexLockerEx buffer_lock(JfrBuffer_lock, Mutex::_no_safepoint_check_flag);
+    count = age_mspace->full_count();
+    head = age_mspace->clear_full();
+    control.reset_full();
+  }
+  assert(head != NULL, "invariant");
+  process_age_list(processor, age_mspace, head, count);
+  return count;
+}
+
+static void log(size_t count, size_t amount, bool clear = false) {
+  if (log_is_enabled(Debug, jfr, system)) {
+    if (count > 0) {
+      log_debug(jfr, system)("%s " SIZE_FORMAT " full buffer(s) of " SIZE_FORMAT" B of data%s",
+        clear ? "Discarded" : "Wrote", count, amount, clear ? "." : " to chunk.");
+    }
+  }
+}
+
+// full writer
+// Assumption is retired only; exclusive access
+// MutexedWriter -> ReleaseOp
+//
+size_t JfrStorage::write_full() {
+  assert(_chunkwriter.is_valid(), "invariant");
+  Thread* const thread = Thread::current();
+  WriteOperation wo(_chunkwriter);
+  MutexedWriteOperation writer(wo); // a retired buffer implies mutexed access
+  ReleaseOperation ro(_transient_mspace, thread);
+  FullOperation cmd(&writer, &ro);
+  const size_t count = process_full(cmd, control(), _age_mspace);
+  log(count, writer.processed());
+  return writer.processed();
+}
+
+size_t JfrStorage::clear_full() {
+  DiscardOperation discarder(mutexed); // a retired buffer implies mutexed access
+  const size_t count = process_full(discarder, control(), _age_mspace);
+  log(count, discarder.processed(), true);
+  return discarder.processed();
+}
+
+static void scavenge_log(size_t count, size_t amount, size_t current) {
+  if (count > 0) {
+    if (log_is_enabled(Debug, jfr, system)) {
+      log_debug(jfr, system)("Released " SIZE_FORMAT " dead buffer(s) of " SIZE_FORMAT" B of data.", count, amount);
+      log_debug(jfr, system)("Current number of dead buffers " SIZE_FORMAT "", current);
+    }
+  }
+}
+
+template <typename Mspace>
+class Scavenger {
+private:
+  JfrStorageControl& _control;
+  Mspace* _mspace;
+  size_t _count;
+  size_t _amount;
+public:
+  typedef typename Mspace::Type Type;
+  Scavenger(JfrStorageControl& control, Mspace* mspace) : _control(control), _mspace(mspace), _count(0), _amount(0) {}
+  bool process(Type* t) {
+    if (t->retired()) {
+      assert(!t->transient(), "invariant");
+      assert(!t->lease(), "invariant");
+      assert(t->empty(), "invariant");
+      assert(t->identity() == NULL, "invariant");
+      ++_count;
+      _amount += t->total_size();
+      t->clear_retired();
+      _control.decrement_dead();
+      mspace_release_full_critical(t, _mspace);
+    }
+    return true;
+  }
+  size_t processed() const { return _count; }
+  size_t amount() const { return _amount; }
+};
+
+size_t JfrStorage::scavenge() {
+  JfrStorageControl& ctrl = control();
+  if (ctrl.dead_count() == 0) {
+    return 0;
+  }
+  Scavenger<JfrThreadLocalMspace> scavenger(ctrl, _thread_local_mspace);
+  process_full_list(scavenger, _thread_local_mspace);
+  scavenge_log(scavenger.processed(), scavenger.amount(), ctrl.dead_count());
+  return scavenger.processed();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/storage/jfrStorage.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+#ifndef SHARE_VM_JFR_RECORDER_STORAGE_JFRSTORAGE_HPP
+#define SHARE_VM_JFR_RECORDER_STORAGE_JFRSTORAGE_HPP
+
+#include "jfr/recorder/storage/jfrBuffer.hpp"
+#include "jfr/recorder/storage/jfrMemorySpace.hpp"
+#include "jfr/recorder/storage/jfrMemorySpaceRetrieval.hpp"
+
+class JfrChunkWriter;
+class JfrPostBox;
+class JfrStorage;
+class JfrStorageControl;
+
+typedef JfrMemorySpace<JfrBuffer, JfrMspaceAlternatingRetrieval, JfrStorage> JfrStorageMspace;
+typedef JfrMemorySpace<JfrBuffer, JfrThreadLocalRetrieval, JfrStorage> JfrThreadLocalMspace;
+typedef JfrMemorySpace<JfrAgeNode, JfrMspaceSequentialRetrieval, JfrStorage> JfrStorageAgeMspace;
+
+//
+// Responsible for providing backing storage for writing events.
+//
+class JfrStorage : public JfrCHeapObj {
+ public:
+  typedef JfrStorageMspace::Type Buffer;
+ private:
+  JfrStorageControl* _control;
+  JfrStorageMspace* _global_mspace;
+  JfrThreadLocalMspace* _thread_local_mspace;
+  JfrStorageMspace* _transient_mspace;
+  JfrStorageAgeMspace* _age_mspace;
+  JfrChunkWriter& _chunkwriter;
+  JfrPostBox& _post_box;
+
+  // mspace callbacks
+  void register_full(Buffer* t, Thread* thread);
+  void lock();
+  void unlock();
+  DEBUG_ONLY(bool is_locked() const;)
+
+  Buffer* acquire_large(size_t size, Thread* t);
+  Buffer* acquire_transient(size_t size, Thread* thread);
+  bool flush_regular_buffer(Buffer* const buffer, Thread* t);
+  Buffer* flush_regular(Buffer* cur, const u1* cur_pos, size_t used, size_t req, bool native, Thread* t);
+  Buffer* flush_large(Buffer* cur, const u1* cur_pos, size_t used, size_t req, bool native, Thread* t);
+  Buffer* provision_large(Buffer* cur, const u1* cur_pos, size_t used, size_t req, bool native, Thread* t);
+  void release(Buffer* buffer, Thread* t);
+
+  size_t clear();
+  size_t clear_full();
+  size_t write();
+  size_t write_full();
+  size_t write_at_safepoint();
+  size_t scavenge();
+
+  JfrStorage(JfrChunkWriter& cw, JfrPostBox& post_box);
+  ~JfrStorage();
+
+  static JfrStorage& instance();
+  static JfrStorage* create(JfrChunkWriter& chunkwriter, JfrPostBox& post_box);
+  bool initialize();
+  static void destroy();
+
+ public:
+  static Buffer* acquire_thread_local(Thread* t, size_t size = 0);
+  static void release_thread_local(Buffer* buffer, Thread* t);
+  void release_large(Buffer* const buffer, Thread* t);
+  static Buffer* flush(Buffer* cur, size_t used, size_t req, bool native, Thread* t);
+  void discard_oldest(Thread* t);
+  static JfrStorageControl& control();
+
+  friend class JfrRecorder;
+  friend class JfrRecorderService;
+  template <typename, template <typename> class, typename>
+  friend class JfrMemorySpace;
+};
+
+#endif // SHARE_VM_JFR_RECORDER_STORAGE_JFRSTORAGE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/storage/jfrStorageControl.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/recorder/storage/jfrStorageControl.hpp"
+#include "runtime/atomic.hpp"
+#include "runtime/orderAccess.inline.hpp"
+
+// returns the updated value
+static jlong atomic_add(size_t value, size_t volatile* const dest) {
+  size_t compare_value;
+  size_t exchange_value;
+  do {
+    compare_value = OrderAccess::load_acquire(dest);
+    exchange_value = compare_value + value;
+  } while (Atomic::cmpxchg(exchange_value, dest, compare_value) != compare_value);
+  return exchange_value;
+}
+
+static jlong atomic_dec(size_t volatile* const dest) {
+  size_t compare_value;
+  size_t exchange_value;
+  do {
+    compare_value = OrderAccess::load_acquire(dest);
+    assert(compare_value >= 1, "invariant");
+    exchange_value = compare_value - 1;
+  } while (Atomic::cmpxchg(exchange_value, dest, compare_value) != compare_value);
+  return exchange_value;
+}
+
+const size_t max_lease_factor = 2;
+JfrStorageControl::JfrStorageControl(size_t global_count_total, size_t in_memory_discard_threshold) :
+  _global_count_total(global_count_total),
+  _full_count(0),
+  _global_lease_count(0),
+  _dead_count(0),
+  _to_disk_threshold(0),
+  _in_memory_discard_threshold(in_memory_discard_threshold),
+  _global_lease_threshold(global_count_total / max_lease_factor),
+  _scavenge_threshold(0),
+  _to_disk(false) {}
+
+bool JfrStorageControl::to_disk() const {
+  return _to_disk;
+}
+
+void JfrStorageControl::set_to_disk(bool enable) {
+  _to_disk = enable;
+}
+
+// concurrent with lax requirement
+
+size_t JfrStorageControl::full_count() const {
+  return _full_count;
+}
+
+size_t JfrStorageControl::increment_full() {
+  return atomic_add(1, &_full_count);
+}
+
+size_t JfrStorageControl::decrement_full() {
+  return atomic_dec(&_full_count);
+}
+
+void JfrStorageControl::reset_full() {
+  Atomic::store((size_t)0, &_full_count);
+}
+
+bool JfrStorageControl::should_post_buffer_full_message() const {
+  return to_disk() && (full_count() > _to_disk_threshold);
+}
+
+bool JfrStorageControl::should_discard() const {
+  return !to_disk() && full_count() >= _in_memory_discard_threshold;
+}
+
+// concurrent with accuracy requirement
+
+size_t JfrStorageControl::global_lease_count() const {
+  return OrderAccess::load_acquire(&_global_lease_count);
+}
+
+size_t JfrStorageControl::increment_leased() {
+  return atomic_add(1, &_global_lease_count);
+}
+
+size_t JfrStorageControl::decrement_leased() {
+  return atomic_dec(&_global_lease_count);
+}
+
+bool JfrStorageControl::is_global_lease_allowed() const {
+  return global_lease_count() <= _global_lease_threshold;
+}
+
+// concurrent with lax requirement
+
+size_t JfrStorageControl::dead_count() const {
+  return _dead_count;
+}
+
+size_t JfrStorageControl::increment_dead() {
+  return atomic_add(1, &_dead_count);
+}
+
+size_t JfrStorageControl::decrement_dead() {
+  return atomic_dec(&_dead_count);
+}
+
+bool JfrStorageControl::should_scavenge() const {
+  return dead_count() >= _scavenge_threshold;
+}
+
+void JfrStorageControl::set_scavenge_threshold(size_t number_of_dead_buffers) {
+  _scavenge_threshold = number_of_dead_buffers;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/storage/jfrStorageControl.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_RECORDER_STORAGE_JFRSTORAGECONTROL_HPP
+#define SHARE_VM_JFR_RECORDER_STORAGE_JFRSTORAGECONTROL_HPP
+
+#include "jfr/utilities/jfrAllocation.hpp"
+
+class JfrStorageControl : public JfrCHeapObj {
+ private:
+  size_t _global_count_total;
+  size_t _full_count;
+  volatile size_t _global_lease_count;
+  volatile size_t _dead_count;
+  size_t _to_disk_threshold;
+  size_t _in_memory_discard_threshold;
+  size_t _global_lease_threshold;
+  size_t _scavenge_threshold;
+  bool _to_disk;
+
+ public:
+  JfrStorageControl(size_t global_count_total, size_t in_memory_discard_threshold);
+
+  void set_to_disk(bool enable);
+  bool to_disk() const;
+
+  size_t full_count() const;
+  size_t increment_full();
+  size_t decrement_full();
+  void   reset_full();
+  bool should_post_buffer_full_message() const;
+  bool should_discard() const;
+
+  size_t global_lease_count() const;
+  size_t increment_leased();
+  size_t decrement_leased();
+  bool is_global_lease_allowed() const;
+
+  size_t dead_count() const;
+  size_t increment_dead();
+  size_t decrement_dead();
+
+  void set_scavenge_threshold(size_t number_of_dead_buffers);
+  bool should_scavenge() const;
+};
+
+#endif // SHARE_VM_JFR_RECORDER_STORAGE_JFRSTORAGECONTROL_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_RECORDER_STORAGE_JFRSTORAGEUTILS_HPP
+#define SHARE_VM_JFR_RECORDER_STORAGE_JFRSTORAGEUTILS_HPP
+
+#include "jfr/recorder/storage/jfrBuffer.hpp"
+#include "jfr/recorder/repository/jfrChunkWriter.hpp"
+#include "jfr/utilities/jfrAllocation.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
+#include "runtime/thread.hpp"
+
+template <typename Operation, typename NextOperation>
+class CompositeOperation {
+ private:
+  Operation* _op;
+  NextOperation* _next;
+ public:
+  CompositeOperation(Operation* op, NextOperation* next) : _op(op), _next(next) {
+    assert(_op != NULL, "invariant");
+  }
+  typedef typename Operation::Type Type;
+  bool process(Type* t = NULL) {
+    return _next == NULL ? _op->process(t) : _op->process(t) && _next->process(t);
+  }
+  size_t processed() const {
+    return _next == NULL ? _op->processed() : _op->processed() + _next->processed();
+  }
+};
+
+template <typename T>
+class UnBufferedWriteToChunk {
+ private:
+  JfrChunkWriter& _writer;
+  size_t _processed;
+ public:
+  typedef T Type;
+  UnBufferedWriteToChunk(JfrChunkWriter& writer) : _writer(writer), _processed(0) {}
+  bool write(Type* t, const u1* data, size_t size);
+  size_t processed() { return _processed; }
+};
+
+template <typename T>
+class DefaultDiscarder {
+ private:
+  size_t _processed;
+ public:
+  typedef T Type;
+  DefaultDiscarder() : _processed() {}
+  bool discard(Type* t, const u1* data, size_t size);
+  size_t processed() const { return _processed; }
+};
+
+template <typename Operation>
+class ConcurrentWriteOp {
+ private:
+  Operation& _operation;
+ public:
+  typedef typename Operation::Type Type;
+  ConcurrentWriteOp(Operation& operation) : _operation(operation) {}
+  bool process(Type* t);
+  size_t processed() const { return _operation.processed(); }
+};
+
+template <typename Operation>
+class ConcurrentWriteOpExcludeRetired : private ConcurrentWriteOp<Operation> {
+ public:
+  typedef typename Operation::Type Type;
+  ConcurrentWriteOpExcludeRetired(Operation& operation) : ConcurrentWriteOp<Operation>(operation) {}
+  bool process(Type* t);
+  size_t processed() const { return ConcurrentWriteOp<Operation>::processed(); }
+};
+
+
+template <typename Operation>
+class MutexedWriteOp {
+ private:
+  Operation& _operation;
+ public:
+  typedef typename Operation::Type Type;
+  MutexedWriteOp(Operation& operation) : _operation(operation) {}
+  bool process(Type* t);
+  size_t processed() const { return _operation.processed(); }
+};
+
+enum jfr_operation_mode {
+  mutexed = 1,
+  concurrent
+};
+
+template <typename Operation>
+class DiscardOp {
+ private:
+  Operation _operation;
+  jfr_operation_mode _mode;
+ public:
+  typedef typename Operation::Type Type;
+  DiscardOp(jfr_operation_mode mode = concurrent) : _operation(), _mode(mode) {}
+  bool process(Type* t);
+  size_t processed() const { return _operation.processed(); }
+};
+
+#endif // SHARE_VM_JFR_RECORDER_STORAGE_JFRSTORAGEUTILS_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.inline.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_RECORDER_STORAGE_JFRSTORAGEUTILS_INLINE_HPP
+#define SHARE_VM_JFR_RECORDER_STORAGE_JFRSTORAGEUTILS_INLINE_HPP
+
+#include "jfr/recorder/storage/jfrStorageUtils.hpp"
+
+template <typename T>
+inline bool UnBufferedWriteToChunk<T>::write(T* t, const u1* data, size_t size) {
+  _writer.write_unbuffered(data, size);
+  _processed += size;
+  return true;
+}
+
+template <typename T>
+inline bool DefaultDiscarder<T>::discard(T* t, const u1* data, size_t size) {
+  _processed += size;
+  return true;
+}
+
+template <typename Operation>
+inline bool ConcurrentWriteOp<Operation>::process(typename Operation::Type* t) {
+  const u1* const current_top = t->concurrent_top();
+  const size_t unflushed_size = t->pos() - current_top;
+  if (unflushed_size == 0) {
+    t->set_concurrent_top(current_top);
+    return true;
+  }
+  const bool result = _operation.write(t, current_top, unflushed_size);
+  t->set_concurrent_top(current_top + unflushed_size);
+  return result;
+}
+
+template <typename Operation>
+inline bool ConcurrentWriteOpExcludeRetired<Operation>::process(typename Operation::Type* t) {
+  if (t->retired()) {
+    assert(t->empty(), "invariant");
+    return true;
+  }
+  return ConcurrentWriteOp<Operation>::process(t);
+}
+
+template <typename Operation>
+inline bool MutexedWriteOp<Operation>::process(typename Operation::Type* t) {
+  assert(t != NULL, "invariant");
+  const u1* const current_top = t->top();
+  const size_t unflushed_size = t->pos() - current_top;
+  if (unflushed_size == 0) {
+    return true;
+  }
+  const bool result = _operation.write(t, current_top, unflushed_size);
+  t->set_top(current_top + unflushed_size);
+  return result;
+}
+
+template <typename Operation>
+inline bool DiscardOp<Operation>::process(typename Operation::Type* t) {
+  assert(t != NULL, "invariant");
+  const u1* const current_top = _mode == concurrent ? t->concurrent_top() : t->top();
+  const size_t unflushed_size = t->pos() - current_top;
+  if (unflushed_size == 0) {
+    if (_mode == concurrent) {
+      t->set_concurrent_top(current_top);
+    }
+    return true;
+  }
+  const bool result = _operation.discard(t, current_top, unflushed_size);
+  if (_mode == concurrent) {
+    t->set_concurrent_top(current_top + unflushed_size);
+  } else {
+    t->set_top(current_top + unflushed_size);
+  }
+  return result;
+}
+
+#endif // SHARE_VM_JFR_RECORDER_STORAGE_JFRSTORAGEUTILS_INLINE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/storage/jfrVirtualMemory.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,533 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/recorder/storage/jfrVirtualMemory.hpp"
+#include "memory/virtualspace.hpp"
+#include "runtime/orderAccess.inline.hpp"
+#include "runtime/os.hpp"
+#include "services/memTracker.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+/*
+ * A memory segment represents a virtual memory reservation.
+ * It provides ways to commit and decommit physical storage
+ * onto its virtual memory reservation.
+ */
+
+class JfrVirtualMemorySegment : public JfrCHeapObj {
+  friend class JfrVirtualMemoryManager;
+ private:
+  JfrVirtualMemorySegment* _next;
+  char* _top;
+  ReservedSpace _rs;
+  VirtualSpace  _virtual_memory;
+
+  // Convenience functions to access the underlying virtual space metadata
+  const u1* committed_low()  const { return (const u1*)_virtual_memory.low(); }
+  const u1* committed_high() const { return (const u1*)_virtual_memory.high(); }
+  const u1* reserved_low() const { return (const u1*)_virtual_memory.low_boundary(); }
+  const u1* reserved_high() const { return (const u1*)_virtual_memory.high_boundary(); }
+  size_t reserved_words() const  { return _virtual_memory.reserved_size() / BytesPerWord; }
+  size_t committed_words() const { return _virtual_memory.actual_committed_size() / BytesPerWord; }
+  bool is_pre_committed() const { return _virtual_memory.special(); }
+  VirtualSpace& virtual_space() { return _virtual_memory; }
+
+  JfrVirtualMemorySegment();
+  ~JfrVirtualMemorySegment();
+
+  JfrVirtualMemorySegment* next() const { return _next; }
+  void set_next(JfrVirtualMemorySegment* v) { _next = v; }
+
+  // Returns true if requested size is available in the committed area
+  bool is_available(size_t block_size_request_words) {
+    return block_size_request_words <= pointer_delta(committed_high(), _top, sizeof(char*));
+  }
+
+  // allocation pointer committed memory
+  char* top() const { return _top; }
+  void inc_top(size_t size_in_words) {
+    assert(is_available(size_in_words), "invariant");
+    _top += size_in_words * BytesPerWord;
+    assert(_top <= _virtual_memory.high(), "invariant");
+  }
+
+  // initialization is the virtual memory reservation
+  bool initialize(size_t reservation_size_request_bytes);
+  void* take_from_committed(size_t block_size_request_words);
+
+  // Returns committed memory
+  void* commit(size_t block_size_request_words) {
+    return take_from_committed(block_size_request_words);
+  }
+
+  // Commit more memory in a reservation
+  bool expand_by(size_t block_size_request_words);
+
+  // Decommits all committed memory in this reservation segment.
+  void decommit();
+};
+
+JfrVirtualMemorySegment::JfrVirtualMemorySegment() :
+  _next(NULL),
+  _top(NULL),
+  _rs(),
+  _virtual_memory() {}
+
+JfrVirtualMemorySegment::~JfrVirtualMemorySegment() {
+  decommit();
+  _rs.release();
+}
+
+bool JfrVirtualMemorySegment::initialize(size_t reservation_size_request_bytes) {
+  assert(is_aligned(reservation_size_request_bytes, os::vm_allocation_granularity()), "invariant");
+  _rs = ReservedSpace(reservation_size_request_bytes,
+                      os::vm_allocation_granularity(),
+                      UseLargePages && os::can_commit_large_page_memory(),
+                      false);
+  if (!_rs.is_reserved()) {
+    return false;
+  }
+  assert(_rs.base() != NULL, "invariant");
+  assert(_rs.size() != 0, "invariant");
+  assert(is_aligned(_rs.base(), os::vm_allocation_granularity()), "invariant");
+  assert(is_aligned(_rs.size(), os::vm_allocation_granularity()), "invariant");
+  os::trace_page_sizes("Jfr", reservation_size_request_bytes,
+                              reservation_size_request_bytes,
+                              os::vm_page_size(),
+                              _rs.base(),
+                              _rs.size());
+  MemTracker::record_virtual_memory_type((address)_rs.base(), mtTracing);
+  assert(is_aligned(_rs.base(), os::vm_page_size()), "invariant");
+  assert(is_aligned(_rs.size(), os::vm_page_size()), "invariant");
+
+  // ReservedSpaces marked as special will have the entire memory
+  // pre-committed. Setting a committed size will make sure that
+  // committed_size and actual_committed_size agrees.
+  const size_t pre_committed_size = _rs.special() ? _rs.size() : 0;
+  const bool result = virtual_space().initialize_with_granularity(_rs, pre_committed_size, os::vm_page_size());
+
+  if (result) {
+    assert(virtual_space().committed_size() == virtual_space().actual_committed_size(),
+      "Checking that the pre-committed memory was registered by the VirtualSpace");
+    _top = virtual_space().low();
+  }
+  return result;
+}
+
+bool JfrVirtualMemorySegment::expand_by(size_t block_size_request_words) {
+  size_t block_size_request_bytes = block_size_request_words * BytesPerWord;
+  const size_t uncommitted = virtual_space().reserved_size() - virtual_space().actual_committed_size();
+  if (uncommitted < block_size_request_bytes) {
+    // commit whatever is left in the reservation
+    block_size_request_bytes = uncommitted;
+  }
+  assert(is_aligned(block_size_request_bytes, os::vm_allocation_granularity()), "invariant");
+  // commit block in reserved memory
+  bool result = virtual_space().expand_by(block_size_request_bytes, false);
+  assert(result, "Failed to commit memory");
+  return result;
+}
+
+void JfrVirtualMemorySegment::decommit() {
+  assert(_virtual_memory.committed_size() == _virtual_memory.actual_committed_size(),
+    "The committed memory doesn't match the expanded memory.");
+
+  const size_t committed_size = virtual_space().actual_committed_size();
+  if (committed_size > 0) {
+    virtual_space().shrink_by(committed_size);
+  }
+
+  assert(_virtual_memory.actual_committed_size() == 0, "invariant");
+}
+
+// Attempt to get a committed block
+void* JfrVirtualMemorySegment::take_from_committed(size_t block_size_request_words) {
+  // The virtual spaces are always expanded by the
+  // commit granularity to enforce the following condition.
+  // Without this the is_available check will not work correctly.
+  assert(_virtual_memory.committed_size() == _virtual_memory.actual_committed_size(),
+    "The committed memory doesn't match the expanded memory.");
+  if (!is_available(block_size_request_words)) {
+    return NULL;
+  }
+  void* const block = top();
+  assert(block != NULL, "invariant");
+  inc_top(block_size_request_words);
+  return block;
+}
+
+class JfrVirtualMemoryManager : public JfrCHeapObj {
+ typedef JfrVirtualMemorySegment Segment;
+ private:
+  Segment* _segments;
+  Segment* _current_segment;
+  size_t _reservation_size_request_words;
+  size_t _reservation_size_request_limit_words; // total reservation limit
+
+  // Sum of reserved and committed memory in the segments
+  size_t _current_reserved_words;
+  size_t _current_committed_words;
+
+  void link(Segment* segment);
+  Segment* current();
+
+  void inc_reserved_words(size_t words);
+  void inc_committed_words(size_t words);
+
+  bool new_segment(size_t reservation_size_request_words);
+
+  bool expand_segment_by(Segment* segment, size_t block_size_request_words);
+
+  bool expand_by(size_t block_size_request_words, size_t reservation_size_request_words);
+  bool can_reserve() const;
+
+ public:
+  JfrVirtualMemoryManager();
+  ~JfrVirtualMemoryManager();
+
+  bool initialize(size_t reservation_size_request_words, size_t segment_count = 1);
+  void* commit(size_t requested_block_size_words);
+
+  bool is_full() const {
+    return reserved_high() == committed_high();
+  }
+
+  const u1* committed_low() const { return _current_segment->committed_low(); }
+  const u1* committed_high() const { return _current_segment->committed_high(); }
+  const u1* reserved_low() const { return _current_segment->reserved_low(); }
+  const u1* reserved_high() const { return _current_segment->reserved_high(); }
+};
+
+JfrVirtualMemoryManager::JfrVirtualMemoryManager() :
+  _segments(NULL),
+  _current_segment(NULL),
+  _reservation_size_request_words(0),
+  _reservation_size_request_limit_words(0),
+  _current_reserved_words(0),
+  _current_committed_words(0) {}
+
+JfrVirtualMemoryManager::~JfrVirtualMemoryManager() {
+  JfrVirtualMemorySegment* segment = _segments;
+  while (segment != NULL) {
+    JfrVirtualMemorySegment* next_segment = segment->next();
+    delete segment;
+    segment = next_segment;
+  }
+}
+
+// for now only allow a singleton segment per virtual memory client
+bool JfrVirtualMemoryManager::initialize(size_t reservation_size_request_words, size_t segment_count /* 1 */) {
+  assert(is_aligned(reservation_size_request_words * BytesPerWord, os::vm_allocation_granularity()), "invariant");
+  _reservation_size_request_words = reservation_size_request_words;
+  assert(segment_count > 0, "invariant");
+  _reservation_size_request_limit_words = reservation_size_request_words * segment_count;
+  assert(is_aligned(_reservation_size_request_limit_words * BytesPerWord, os::vm_allocation_granularity()), "invariant");
+  return new_segment(_reservation_size_request_words);
+}
+
+bool JfrVirtualMemoryManager::can_reserve() const  {
+  return _reservation_size_request_limit_words == 0 ? true : _current_reserved_words < _reservation_size_request_limit_words;
+}
+
+// Allocate another segment and add it to the list.
+bool JfrVirtualMemoryManager::new_segment(size_t reservation_size_request_words) {
+  assert(reservation_size_request_words > 0, "invariant");
+  assert(is_aligned(reservation_size_request_words * BytesPerWord, os::vm_allocation_granularity()), "invariant");
+  Segment* segment = new Segment();
+  if (NULL == segment) {
+    return false;
+  }
+  if (!segment->initialize(reservation_size_request_words * BytesPerWord)) {
+    delete segment;
+    return false;
+  }
+  assert(segment->reserved_words() == reservation_size_request_words,
+    "Actual reserved memory size differs from requested reservation memory size");
+  link(segment);
+  return true;
+}
+
+bool JfrVirtualMemoryManager::expand_segment_by(JfrVirtualMemorySegment* segment, size_t block_size_request_words) {
+  assert(segment != NULL, "invariant");
+  const size_t before = segment->committed_words();
+  const bool result = segment->expand_by(block_size_request_words);
+  const size_t after = segment->committed_words();
+  // after and before can be the same if the memory was pre-committed.
+  assert(after >= before, "Inconsistency");
+  inc_committed_words(after - before);
+  return result;
+}
+
+void JfrVirtualMemoryManager::inc_reserved_words(size_t words) {
+  _current_reserved_words += words;
+}
+
+JfrVirtualMemorySegment* JfrVirtualMemoryManager::current() {
+  return _current_segment;
+}
+
+void JfrVirtualMemoryManager::inc_committed_words(size_t words) {
+  _current_committed_words += words;
+}
+
+bool JfrVirtualMemoryManager::expand_by(size_t block_size_request_words, size_t reservation_size_request_words) {
+  assert(is_aligned(block_size_request_words * BytesPerWord, os::vm_page_size()), "invariant");
+  assert(is_aligned(block_size_request_words * BytesPerWord, os::vm_allocation_granularity()), "invariant");
+  assert(is_aligned(reservation_size_request_words * BytesPerWord, os::vm_page_size()), "invariant");
+  assert(is_aligned(reservation_size_request_words * BytesPerWord, os::vm_allocation_granularity()), "invariant");
+  assert(block_size_request_words <= reservation_size_request_words, "invariant");
+  // Attempt to commit more memory from the the current virtual space reservation.
+  if (expand_segment_by(current(), block_size_request_words)) {
+    return true;
+  }
+
+  // reached limit of what is allowed to be reserved?
+  if (!can_reserve()) {
+    return false;
+  }
+
+  // Get another segment.
+  if (!new_segment(reservation_size_request_words)) {
+    return false;
+  }
+
+  if (current()->is_pre_committed()) {
+    // The memory was pre-committed, so we are done here.
+    assert(block_size_request_words <= current()->committed_words(),
+           "The new VirtualSpace was pre-committed, so it"
+           "should be large enough to fit the alloc request.");
+    return true;
+  }
+  return expand_segment_by(current(), block_size_request_words);
+}
+
+void JfrVirtualMemoryManager::link(JfrVirtualMemorySegment* segment) {
+  assert(segment != NULL, "invariant");
+  if (_segments == NULL) {
+    _segments = segment;
+  } else {
+    assert(_current_segment != NULL, "invariant");
+    assert(_segments == _current_segment, "invariant");
+    _current_segment->set_next(segment);
+  }
+  _current_segment = segment;
+  inc_reserved_words(segment->reserved_words());
+  inc_committed_words(segment->committed_words());
+}
+
+void* JfrVirtualMemoryManager::commit(size_t block_size_request_words) {
+  assert(is_aligned(block_size_request_words * BytesPerWord, os::vm_allocation_granularity()), "invariant");
+  void* block = current()->commit(block_size_request_words);
+  if (block != NULL) {
+    return block;
+  }
+  assert(block == NULL, "invariant");
+  if (is_full()) {
+    return NULL;
+  }
+  assert(block_size_request_words <= _reservation_size_request_words, "invariant");
+  if (expand_by(block_size_request_words, _reservation_size_request_words)) {
+    block = current()->commit(block_size_request_words);
+    assert(block != NULL, "The allocation was expected to succeed after the expansion");
+  }
+  return block;
+}
+
+JfrVirtualMemory::JfrVirtualMemory() :
+  _vmm(NULL),
+  _reserved_low(),
+  _reserved_high(),
+  _top(NULL),
+  _commit_point(NULL),
+  _physical_commit_size_request_words(0),
+  _aligned_datum_size_bytes(0) {}
+
+JfrVirtualMemory::~JfrVirtualMemory() {
+  assert(_vmm != NULL, "invariant");
+  delete _vmm;
+}
+
+size_t JfrVirtualMemory::aligned_datum_size_bytes() const {
+  return _aligned_datum_size_bytes;
+}
+
+static void adjust_allocation_ratio(size_t* const reservation_size_bytes, size_t* const commit_size_bytes) {
+  assert(reservation_size_bytes != NULL, "invariant");
+  assert(*reservation_size_bytes > 0, "invariant");
+  assert(commit_size_bytes != NULL, "invariant");
+  assert(*commit_size_bytes > 0, "invariant");
+  assert(*reservation_size_bytes >= *commit_size_bytes, "invariant");
+  assert(is_aligned(*reservation_size_bytes, os::vm_allocation_granularity()), "invariant");
+  assert(is_aligned(*commit_size_bytes, os::vm_allocation_granularity()), "invariant");
+
+  size_t reservation_size_units = *reservation_size_bytes / os::vm_allocation_granularity();
+  size_t commit_size_units = *commit_size_bytes / os::vm_allocation_granularity();
+  assert(reservation_size_units > 0, "invariant");
+  assert(commit_size_units > 0, "invariant");
+
+  size_t original_ratio_units = reservation_size_units / commit_size_units;
+  size_t rem = reservation_size_units % commit_size_units;
+  assert(original_ratio_units > 0, "invariant");
+
+  if (rem > 0) {
+    reservation_size_units -= rem % original_ratio_units;
+    commit_size_units += rem / original_ratio_units;
+  }
+
+  assert(commit_size_units > 0, "invariant");
+  assert(reservation_size_units % original_ratio_units == 0, "invariant");
+  assert(original_ratio_units * commit_size_units == reservation_size_units , "invariant");
+  assert(original_ratio_units == reservation_size_units / commit_size_units, "invariant");
+  *reservation_size_bytes = reservation_size_units * os::vm_allocation_granularity();
+  *commit_size_bytes = commit_size_units * os::vm_allocation_granularity();
+  assert((*reservation_size_bytes % *commit_size_bytes) == 0, "invariant");
+}
+
+
+void* JfrVirtualMemory::initialize(size_t reservation_size_request_bytes,
+                                   size_t block_size_request_bytes,
+                                   size_t datum_size_bytes /* 1 */) {
+  assert(_vmm == NULL, "invariant");
+  _vmm = new JfrVirtualMemoryManager();
+
+  if (_vmm == NULL) {
+    return NULL;
+  }
+
+  assert(reservation_size_request_bytes > 0, "invariant");
+  _aligned_datum_size_bytes = align_up(datum_size_bytes, BytesPerWord);
+  assert(is_aligned(_aligned_datum_size_bytes, BytesPerWord), "invariant");
+
+  reservation_size_request_bytes = ReservedSpace::allocation_align_size_up(reservation_size_request_bytes);
+  assert(is_aligned(reservation_size_request_bytes, os::vm_allocation_granularity()), "invariant");
+  assert(is_aligned(reservation_size_request_bytes, _aligned_datum_size_bytes), "invariant");
+  block_size_request_bytes = MAX2(block_size_request_bytes, (size_t)os::vm_allocation_granularity());
+  block_size_request_bytes = ReservedSpace::allocation_align_size_up(block_size_request_bytes);
+  assert(is_aligned(block_size_request_bytes, os::vm_allocation_granularity()), "invariant");
+  assert(is_aligned(block_size_request_bytes, _aligned_datum_size_bytes), "invariant");
+  // adjustment to valid ratio in units of vm_allocation_granularity
+  adjust_allocation_ratio(&reservation_size_request_bytes, &block_size_request_bytes);
+  assert(is_aligned(reservation_size_request_bytes, os::vm_allocation_granularity()), "invariant");
+  assert(is_aligned(reservation_size_request_bytes, _aligned_datum_size_bytes), "invariant");
+  assert(is_aligned(block_size_request_bytes, os::vm_allocation_granularity()), "invariant");
+  assert(is_aligned(block_size_request_bytes, _aligned_datum_size_bytes), "invariant");
+  assert((reservation_size_request_bytes % block_size_request_bytes) == 0, "invariant");
+  const size_t reservation_size_request_words = reservation_size_request_bytes / BytesPerWord;
+  _physical_commit_size_request_words = block_size_request_bytes / BytesPerWord;
+  // virtual memory reservation
+  if (!_vmm->initialize(reservation_size_request_words)) {
+    // is implicitly "full" if reservation fails
+    assert(is_full(), "invariant");
+    return NULL;
+  }
+  _reserved_low = (const u1*)_vmm->reserved_low();
+  _reserved_high = (const u1*)_vmm->reserved_high();
+  // reservation complete
+  _top = (u1*)_vmm->committed_high();
+  _commit_point = _top;
+  assert(_reserved_low == _top, "invariant"); // initial empty state
+  assert((size_t)(_reserved_high - _reserved_low) == reservation_size_request_bytes, "invariant");
+  // initial commit
+  commit_memory_block();
+  return _top;
+}
+
+void* JfrVirtualMemory::commit(size_t block_size_request_words) {
+  assert(_vmm != NULL, "invariant");
+  assert(is_aligned(block_size_request_words * BytesPerWord, os::vm_allocation_granularity()), "invariant");
+  return _vmm->commit(block_size_request_words);
+}
+
+bool JfrVirtualMemory::is_full() const {
+  return _top == _reserved_high;
+}
+
+bool JfrVirtualMemory::is_empty() const {
+  return _top == _reserved_low;
+}
+
+bool JfrVirtualMemory::commit_memory_block() {
+  assert(_vmm != NULL, "invariant");
+  assert(!is_full(), "invariant");
+  assert(_top == _commit_point, "invariant");
+
+  void* const block = _vmm->commit(_physical_commit_size_request_words);
+  if (block != NULL) {
+    _commit_point = _vmm->committed_high();
+    return true;
+  }
+  // all reserved virtual memory is committed
+  assert(block == NULL, "invariant");
+  assert(_vmm->reserved_high() == _vmm->committed_high(), "invariant");
+  return false;
+}
+
+void* JfrVirtualMemory::new_datum() {
+  assert(_vmm != NULL, "invariant");
+  assert(!is_full(), "invariant");
+  if (_top == _commit_point) {
+    if (!commit_memory_block()) {
+      assert(is_full(), "invariant");
+      return NULL;
+    }
+  }
+  assert(_top + _aligned_datum_size_bytes <= _commit_point, "invariant");
+  u1* allocation = _top;
+  _top += _aligned_datum_size_bytes;
+  assert(is_aligned(allocation, _aligned_datum_size_bytes), "invariant");
+  return allocation;
+}
+
+void* JfrVirtualMemory::index_ptr(size_t index) {
+  assert((index * _aligned_datum_size_bytes) + _reserved_low < _commit_point, "invariant");
+  return (void*)((index * _aligned_datum_size_bytes) + _reserved_low);
+}
+
+void* JfrVirtualMemory::get(size_t index) {
+  return index_ptr(index);
+}
+
+size_t JfrVirtualMemory::count() const {
+  return (_top - _reserved_low) / _aligned_datum_size_bytes;
+}
+
+size_t JfrVirtualMemory::live_set() const {
+  return _top - _reserved_low;
+}
+
+size_t JfrVirtualMemory::reserved_size() const {
+  return _reserved_high - _reserved_low;
+}
+
+bool JfrVirtualMemory::compact(size_t index) {
+  assert(index > 0, "invariant");
+  assert(index <= reserved_size(), "invariant");
+  const u1* low = static_cast<u1*>(index_ptr(index));
+  const size_t block_size = _top - low;
+  memcpy(const_cast<u1*>(_reserved_low), low, block_size);
+  _top = const_cast<u1*>(_reserved_low) + block_size;
+  assert(live_set() == block_size, "invariant");
+  return true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/storage/jfrVirtualMemory.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_RECORDER_STORAGE_JFRVIRTUALMEMORY_HPP
+#define SHARE_VM_JFR_RECORDER_STORAGE_JFRVIRTUALMEMORY_HPP
+
+#include "jfr/utilities/jfrAllocation.hpp"
+
+class JfrVirtualMemoryManager;
+
+class JfrVirtualMemory : public JfrCHeapObj {
+ private:
+  JfrVirtualMemoryManager* _vmm;
+  const u1* _reserved_low; // lowest address of reservation
+  const u1* _reserved_high; // highest address of reservation
+  u1* _top; // current allocation address
+  const u1* _commit_point; // synch points for committing new memory
+  size_t _physical_commit_size_request_words; // aligned to os::vm_allocation_granularity()
+  size_t _aligned_datum_size_bytes; // datum alignment
+
+  bool commit_memory_block();
+  void* commit(size_t block_size_request_words);
+  void* index_ptr(size_t index); // index to address map
+
+ public:
+  JfrVirtualMemory();
+  ~JfrVirtualMemory();
+
+  // initialization will do the reservation and return it
+  void* initialize(size_t reservation_size_request_bytes, size_t block_size_request_bytes, size_t datum_size_bytes = 1);
+
+  void* new_datum(); // datum oriented allocation
+  void* get(size_t index); // direct access retrieval
+  size_t aligned_datum_size_bytes() const;
+
+  bool is_full() const; // limit of reservation committed and in use
+  bool is_empty() const;
+
+  size_t count() const; // how many
+  size_t live_set() const; // how much resident memory (actually in use)
+  size_t reserved_size() const; // size of reservation
+  bool compact(size_t index);
+};
+
+#endif // SHARE_VM_JFR_RECORDER_STORAGE_JFRVIRTUALMEMORY_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/javaClasses.inline.hpp"
+#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp"
+#include "jfr/recorder/service/jfrOptionSet.hpp"
+#include "jfr/recorder/storage/jfrMemorySpace.inline.hpp"
+#include "jfr/recorder/repository/jfrChunkWriter.hpp"
+#include "jfr/recorder/storage/jfrStorageUtils.inline.hpp"
+#include "jfr/recorder/stringpool/jfrStringPool.hpp"
+#include "jfr/recorder/stringpool/jfrStringPoolWriter.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
+#include "logging/log.hpp"
+#include "runtime/atomic.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/orderAccess.inline.hpp"
+#include "runtime/safepoint.hpp"
+#include "runtime/thread.inline.hpp"
+
+typedef JfrStringPool::Buffer* BufferPtr;
+
+static JfrStringPool* _instance = NULL;
+
+JfrStringPool& JfrStringPool::instance() {
+  return *_instance;
+}
+
+JfrStringPool* JfrStringPool::create(JfrChunkWriter& cw) {
+  assert(_instance == NULL, "invariant");
+  _instance = new JfrStringPool(cw);
+  return _instance;
+}
+
+void JfrStringPool::destroy() {
+  assert(_instance != NULL, "invariant");
+  delete _instance;
+  _instance = NULL;
+}
+
+JfrStringPool::JfrStringPool(JfrChunkWriter& cw) : _free_list_mspace(NULL), _lock(NULL), _chunkwriter(cw) {}
+
+JfrStringPool::~JfrStringPool() {
+  if (_free_list_mspace != NULL) {
+    delete _free_list_mspace;
+  }
+  if (_lock != NULL) {
+    delete _lock;
+  }
+}
+
+static const size_t unlimited_mspace_size = 0;
+static const size_t string_pool_cache_count = 2;
+static const size_t string_pool_buffer_size = 512 * K;
+
+bool JfrStringPool::initialize() {
+  assert(_free_list_mspace == NULL, "invariant");
+  _free_list_mspace = new JfrStringPoolMspace(string_pool_buffer_size, unlimited_mspace_size, string_pool_cache_count, this);
+  if (_free_list_mspace == NULL || !_free_list_mspace->initialize()) {
+    return false;
+  }
+  assert(_lock == NULL, "invariant");
+  _lock = new Mutex(Monitor::leaf - 1, "Checkpoint mutex", Mutex::_allow_vm_block_flag, Monitor::_safepoint_check_never);
+  return _lock != NULL;
+}
+
+/*
+* If the buffer was a "lease" from the global system, release back.
+*
+* The buffer is effectively invalidated for the thread post-return,
+* and the caller should take means to ensure that it is not referenced any longer.
+*/
+static void release(BufferPtr buffer, Thread* thread) {
+  assert(buffer != NULL, "invariant");
+  assert(buffer->lease(), "invariant");
+  assert(buffer->acquired_by_self(), "invariant");
+  buffer->clear_lease();
+  buffer->release();
+}
+
+BufferPtr JfrStringPool::flush(BufferPtr old, size_t used, size_t requested, Thread* thread) {
+  assert(old != NULL, "invariant");
+  assert(old->lease(), "invariant");
+  if (0 == requested) {
+    // indicates a lease is being returned
+    release(old, thread);
+    return NULL;
+  }
+  // migration of in-flight information
+  BufferPtr const new_buffer = lease_buffer(thread, used + requested);
+  if (new_buffer != NULL) {
+    migrate_outstanding_writes(old, new_buffer, used, requested);
+  }
+  release(old, thread);
+  return new_buffer; // might be NULL
+}
+
+static const size_t lease_retry = 10;
+
+BufferPtr JfrStringPool::lease_buffer(Thread* thread, size_t size /* 0 */) {
+  BufferPtr buffer = mspace_get_free_lease_with_retry(size, instance()._free_list_mspace, lease_retry, thread);
+  if (buffer == NULL) {
+    buffer = mspace_allocate_transient_lease_to_free(size,  instance()._free_list_mspace, thread);
+  }
+  assert(buffer->acquired_by_self(), "invariant");
+  assert(buffer->lease(), "invariant");
+  return buffer;
+}
+
+bool JfrStringPool::add(bool epoch, jlong id, jstring string, JavaThread* jt) {
+  assert(jt != NULL, "invariant");
+  const bool current_epoch = JfrTraceIdEpoch::epoch();
+  if (current_epoch == epoch) {
+    JfrStringPoolWriter writer(jt);
+    writer.write(id);
+    writer.write(string);
+    writer.inc_nof_strings();
+  }
+  return current_epoch;
+}
+
+class StringPoolWriteOp  {
+ public:
+  typedef JfrStringPoolBuffer Type;
+ private:
+  UnBufferedWriteToChunk<Type> _writer;
+  Thread* _thread;
+  size_t _strings_processed;
+ public:
+  StringPoolWriteOp(JfrChunkWriter& writer, Thread* thread) : _writer(writer), _thread(thread), _strings_processed(0) {}
+  bool write(Type* buffer, const u1* data, size_t size) {
+    buffer->acquire(_thread); // blocking
+    const u4 nof_strings_used = (const u4)buffer->string_count();
+    assert(nof_strings_used > 0, "invariant");
+    buffer->set_string_top(buffer->string_top() + nof_strings_used);
+    // "size processed" for string pool buffers is the number of processed string elements
+    _strings_processed += nof_strings_used;
+    const bool ret = _writer.write(buffer, data, size);
+    buffer->release();
+    return ret;
+  }
+  size_t processed() { return _strings_processed; }
+};
+
+typedef StringPoolWriteOp WriteOperation;
+typedef ConcurrentWriteOp<WriteOperation> ConcurrentWriteOperation;
+
+size_t JfrStringPool::write() {
+  Thread* const thread = Thread::current();
+  WriteOperation wo(_chunkwriter, thread);
+  ConcurrentWriteOperation cwo(wo);
+  assert(_free_list_mspace->is_full_empty(), "invariant");
+  process_free_list(cwo, _free_list_mspace);
+  return wo.processed();
+}
+
+typedef MutexedWriteOp<WriteOperation> MutexedWriteOperation;
+typedef ReleaseOp<JfrStringPoolMspace> StringPoolReleaseOperation;
+typedef CompositeOperation<MutexedWriteOperation, StringPoolReleaseOperation> StringPoolWriteOperation;
+
+size_t JfrStringPool::write_at_safepoint() {
+  assert(SafepointSynchronize::is_at_safepoint(), "invariant");
+  Thread* const thread = Thread::current();
+  WriteOperation wo(_chunkwriter, thread);
+  MutexedWriteOperation mwo(wo);
+  StringPoolReleaseOperation spro(_free_list_mspace, thread, false);
+  StringPoolWriteOperation spwo(&mwo, &spro);
+  assert(_free_list_mspace->is_full_empty(), "invariant");
+  process_free_list(spwo, _free_list_mspace);
+  return wo.processed();
+}
+
+class StringPoolBufferDiscarder {
+ private:
+  Thread* _thread;
+  size_t _processed;
+ public:
+  typedef JfrStringPoolBuffer Type;
+  StringPoolBufferDiscarder() : _thread(Thread::current()), _processed(0) {}
+  bool process(Type* buffer) {
+    buffer->acquire(_thread); // serialized access
+    const u1* const current_top = buffer->top();
+    const size_t unflushed_size = buffer->pos() - current_top;
+    if (unflushed_size == 0) {
+      assert(buffer->string_count() == 0, "invariant");
+      buffer->release();
+      return true;
+    }
+    buffer->set_top(current_top + unflushed_size);
+    const u4 nof_strings_used = buffer->string_count();
+    buffer->set_string_top(buffer->string_top() + nof_strings_used);
+    // "size processed" for string pool buffers is the number of string elements
+    _processed += nof_strings_used;
+    buffer->release();
+    return true;
+  }
+  size_t processed() const { return _processed; }
+};
+
+size_t JfrStringPool::clear() {
+  StringPoolBufferDiscarder discard_operation;
+  assert(_free_list_mspace->is_full_empty(), "invariant");
+  process_free_list(discard_operation, _free_list_mspace);
+  return discard_operation.processed();
+}
+
+void JfrStringPool::register_full(BufferPtr t, Thread* thread) {
+  // nothing here at the moment
+  assert(t->retired(), "invariant");
+}
+
+void JfrStringPool::lock() {
+  assert(!_lock->owned_by_self(), "invariant");
+  _lock->lock_without_safepoint_check();
+}
+
+void JfrStringPool::unlock() {
+  _lock->unlock();
+}
+
+#ifdef ASSERT
+bool JfrStringPool::is_locked() const {
+  return _lock->owned_by_self();
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_RECORDER_STRINGPOOL_JFRSTRINGPOOL_HPP
+#define SHARE_VM_JFR_RECORDER_STRINGPOOL_JFRSTRINGPOOL_HPP
+
+#include "jni.h"
+#include "jfr/recorder/storage/jfrMemorySpace.hpp"
+#include "jfr/recorder/storage/jfrMemorySpaceRetrieval.hpp"
+#include "jfr/recorder/stringpool/jfrStringPoolBuffer.hpp"
+
+class JfrChunkWriter;
+class JfrStringPool;
+class Mutex;
+
+typedef JfrMemorySpace<JfrStringPoolBuffer, JfrMspaceSequentialRetrieval, JfrStringPool> JfrStringPoolMspace;
+
+//
+// Although called JfrStringPool, a more succinct description would be
+// "backing storage for the string pool located in Java"
+//
+// There are no lookups in native, only the encoding of string constants to the stream.
+//
+class JfrStringPool : public JfrCHeapObj {
+ public:
+  static bool add(bool epoch, jlong id, jstring string, JavaThread* jt);
+  size_t write();
+  size_t write_at_safepoint();
+  size_t clear();
+
+  typedef JfrStringPoolMspace::Type Buffer;
+ private:
+  JfrStringPoolMspace* _free_list_mspace;
+  Mutex* _lock;
+  JfrChunkWriter& _chunkwriter;
+
+  // mspace callback
+  void register_full(Buffer* t, Thread* thread);
+  void lock();
+  void unlock();
+  DEBUG_ONLY(bool is_locked() const;)
+
+  static Buffer* lease_buffer(Thread* thread, size_t size = 0);
+  static Buffer* flush(Buffer* old, size_t used, size_t requested, Thread* t);
+
+  JfrStringPool(JfrChunkWriter& cw);
+  ~JfrStringPool();
+
+  static JfrStringPool& instance();
+  static JfrStringPool* create(JfrChunkWriter& cw);
+  bool initialize();
+  static void destroy();
+
+  friend class JfrRecorder;
+  friend class JfrRecorderService;
+  friend class JfrStringPoolFlush;
+  friend class JfrStringPoolWriter;
+  template <typename, template <typename> class, typename>
+  friend class JfrMemorySpace;
+};
+
+#endif // SHARE_VM_JFR_RECORDER_STRINGPOOL_JFRSTRINGPOOL_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/stringpool/jfrStringPoolBuffer.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/recorder/stringpool/jfrStringPoolBuffer.hpp"
+#include "runtime/atomic.hpp"
+#include "runtime/orderAccess.inline.hpp"
+#include "runtime/thread.inline.hpp"
+
+JfrStringPoolBuffer::JfrStringPoolBuffer() : JfrBuffer(), _string_count_pos(0), _string_count_top(0) {}
+
+void JfrStringPoolBuffer::reinitialize() {
+  concurrent_top();
+  set_pos((start()));
+  set_string_pos(0);
+  set_string_top(0);
+  set_concurrent_top(start());
+}
+
+uint64_t JfrStringPoolBuffer::string_pos() const {
+  return OrderAccess::load_acquire(&_string_count_pos);
+}
+
+uint64_t JfrStringPoolBuffer::string_top() const {
+  return OrderAccess::load_acquire(&_string_count_top);
+}
+
+uint64_t JfrStringPoolBuffer::string_count() const {
+  return string_pos() - string_top();
+}
+
+void JfrStringPoolBuffer::set_string_pos(uint64_t value) {
+  Atomic::store(value, &_string_count_pos);
+}
+
+void JfrStringPoolBuffer::increment(uint64_t value) {
+  Atomic::add(value, &_string_count_pos);
+}
+
+void JfrStringPoolBuffer::set_string_top(uint64_t value) {
+  Atomic::store(value, &_string_count_top);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/stringpool/jfrStringPoolBuffer.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_RECORDER_STRINGPOOL_JFRSTRINGPOOLBUFFER_HPP
+#define SHARE_VM_JFR_RECORDER_STRINGPOOL_JFRSTRINGPOOLBUFFER_HPP
+
+#include "jfr/recorder/storage/jfrBuffer.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+class JfrStringPoolBuffer : public JfrBuffer {
+ private:
+  uint64_t _string_count_pos;
+  uint64_t _string_count_top;
+
+ public:
+  JfrStringPoolBuffer();
+  void reinitialize();
+  uint64_t string_pos() const;
+  uint64_t string_top() const;
+  uint64_t string_count() const;
+  void increment(uint64_t value);
+  void set_string_pos(uint64_t value);
+  void set_string_top(uint64_t value);
+};
+
+#endif // SHARE_VM_JFR_RECORDER_STRINGPOOL_JFRSTRINGPOOLBUFFER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/stringpool/jfrStringPoolWriter.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/recorder/stringpool/jfrStringPool.hpp"
+#include "jfr/recorder/stringpool/jfrStringPoolWriter.hpp"
+#include "jfr/writers/jfrEventWriterHost.inline.hpp"
+#include "jfr/writers/jfrMemoryWriterHost.inline.hpp"
+
+JfrStringPoolFlush::JfrStringPoolFlush(Type* old, size_t used, size_t requested, Thread* t) :
+  _result(JfrStringPool::flush(old, used, requested, t)) {}
+
+JfrStringPoolWriter::JfrStringPoolWriter(Thread* thread) :
+  JfrStringPoolWriterBase(JfrStringPool::lease_buffer(thread), thread), _nof_strings(0) {}
+
+JfrStringPoolWriter::~JfrStringPoolWriter() {
+  assert(this->is_acquired(), "invariant");
+  if (!this->is_valid() || this->used_size() == 0) {
+    return;
+  }
+  assert(this->used_size() > 0, "invariant");
+  this->storage()->increment(_nof_strings);
+  this->commit();
+  assert(0 == this->current_offset(), "invariant");
+}
+
+void JfrStringPoolWriter::inc_nof_strings() {
+  ++_nof_strings;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/stringpool/jfrStringPoolWriter.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_RECORDER_STRINGPOOL_JFRSTRINGPOOLWRITER_HPP
+#define SHARE_VM_JFR_RECORDER_STRINGPOOL_JFRSTRINGPOOLWRITER_HPP
+
+#include "memory/allocation.hpp"
+#include "jfr/recorder/stringpool/jfrStringPoolBuffer.hpp"
+#include "jfr/writers/jfrEventWriterHost.hpp"
+#include "jfr/writers/jfrMemoryWriterHost.hpp"
+#include "jfr/writers/jfrStorageAdapter.hpp"
+
+class Thread;
+
+class JfrStringPoolFlush : public StackObj {
+ public:
+  typedef JfrStringPoolBuffer Type;
+  JfrStringPoolFlush(Type* old, size_t used, size_t requested, Thread* t);
+  Type* result() { return _result; }
+ private:
+  Type* _result;
+};
+
+typedef Adapter<JfrStringPoolFlush> JfrStringPoolAdapter;
+typedef AcquireReleaseMemoryWriterHost<JfrStringPoolAdapter, StackObj> JfrTransactionalStringPoolWriter;
+typedef EventWriterHost<BigEndianEncoder, CompressedIntegerEncoder, JfrTransactionalStringPoolWriter> JfrStringPoolWriterBase;
+
+class JfrStringPoolWriter : public JfrStringPoolWriterBase {
+ private:
+  size_t _nof_strings;
+ public:
+  JfrStringPoolWriter(Thread* thread);
+  ~JfrStringPoolWriter();
+  void inc_nof_strings();
+};
+
+#endif // SHARE_VM_JFR_RECORDER_STRINGPOOL_JFRSTRINGPOOLWRITER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/support/jfrAllocationTracer.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,43 @@
+/*
+* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* This code is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License version 2 only, as
+* published by the Free Software Foundation.
+*
+* This code is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* version 2 for more details (a copy is included in the LICENSE file that
+* accompanied this code).
+*
+* You should have received a copy of the GNU General Public License version
+* 2 along with this work; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+* or visit www.oracle.com if you need additional information or have any
+* questions.
+*
+*/
+
+#include "precompiled.hpp"
+#include "jfr/leakprofiler/leakProfiler.hpp"
+#include "jfr/support/jfrAllocationTracer.hpp"
+#include "jfr/support/jfrThreadLocal.hpp"
+#include "runtime/thread.hpp"
+
+JfrAllocationTracer::JfrAllocationTracer(HeapWord* obj, size_t alloc_size, Thread* thread) : _tl(NULL) {
+  if (LeakProfiler::is_running()) {
+    assert(thread->is_Java_thread(), "invariant");
+    _tl = thread->jfr_thread_local();
+    LeakProfiler::sample(obj, alloc_size, (JavaThread*)thread);
+  }
+}
+
+JfrAllocationTracer::~JfrAllocationTracer() {
+  if (_tl != NULL) {
+    _tl->clear_cached_stack_trace();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/support/jfrAllocationTracer.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,40 @@
+/*
+* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* This code is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License version 2 only, as
+* published by the Free Software Foundation.
+*
+* This code is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* version 2 for more details (a copy is included in the LICENSE file that
+* accompanied this code).
+*
+* You should have received a copy of the GNU General Public License version
+* 2 along with this work; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+* or visit www.oracle.com if you need additional information or have any
+* questions.
+*
+*/
+
+#ifndef SHARE_VM_JFR_SUPPORT_JFRALLOCATIONTRACER_HPP
+#define SHARE_VM_JFR_SUPPORT_JFRALLOCATIONTRACER_HPP
+
+#include "memory/allocation.hpp"
+
+class JfrThreadLocal;
+
+class JfrAllocationTracer : public StackObj {
+ private:
+  JfrThreadLocal* _tl;
+ public:
+  JfrAllocationTracer(HeapWord* obj, size_t alloc_size, Thread* thread);
+  ~JfrAllocationTracer();
+};
+
+#endif // SHARE_VM_JFR_SUPPORT_JFRALLOCATIONTRACER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/support/jfrEventClass.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
+#include "jfr/support/jfrEventClass.hpp"
+
+bool JdkJfrEvent::is(const Klass* k) {
+  return JfrTraceId::is_jdk_jfr_event(k);
+}
+
+bool JdkJfrEvent::is(const jclass jc) {
+  return JfrTraceId::is_jdk_jfr_event(jc);
+}
+
+void JdkJfrEvent::tag_as(const Klass* k) {
+  JfrTraceId::tag_as_jdk_jfr_event(k);
+}
+
+bool JdkJfrEvent::is_subklass(const Klass* k) {
+  return JfrTraceId::is_jdk_jfr_event_sub(k);
+}
+
+bool JdkJfrEvent::is_subklass(const jclass jc) {
+  return JfrTraceId::is_jdk_jfr_event_sub(jc);
+}
+
+void JdkJfrEvent::tag_as_subklass(const Klass* k) {
+  JfrTraceId::tag_as_jdk_jfr_event_sub(k);
+}
+
+void JdkJfrEvent::tag_as_subklass(const jclass jc) {
+  JfrTraceId::tag_as_jdk_jfr_event_sub(jc);
+}
+
+bool JdkJfrEvent::is_a(const Klass* k) {
+  return JfrTraceId::in_jdk_jfr_event_hierarchy(k);
+}
+
+bool JdkJfrEvent::is_a(const jclass jc) {
+  return JfrTraceId::in_jdk_jfr_event_hierarchy(jc);
+}
+
+bool JdkJfrEvent::is_host(const Klass* k) {
+  return JfrTraceId::is_event_host(k);
+}
+
+bool JdkJfrEvent::is_host(const jclass jc) {
+  return JfrTraceId::is_event_host(jc);
+}
+
+void JdkJfrEvent::tag_as_host(const Klass* k) {
+  JfrTraceId::tag_as_event_host(k);
+}
+
+void JdkJfrEvent::tag_as_host(const jclass jc) {
+  JfrTraceId::tag_as_event_host(jc);
+}
+
+bool JdkJfrEvent::is_visible(const Klass* k) {
+  return JfrTraceId::in_visible_set(k);
+}
+
+bool JdkJfrEvent::is_visible(const jclass jc) {
+  return JfrTraceId::in_visible_set(jc);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/support/jfrEventClass.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_SUPPORT_JFREVENTCLASS_HPP
+#define SHARE_VM_JFR_SUPPORT_JFREVENTCLASS_HPP
+
+#include "jni.h"
+#include "memory/allocation.hpp"
+
+class Klass;
+
+//
+// For convenient access to the jdk.jfr.Event klass hierarchy.
+//
+class JdkJfrEvent : AllStatic {
+ public:
+  // jdk.jfr.Event
+  static bool is(const Klass* k);
+  static bool is(const jclass jc);
+  static void tag_as(const Klass* k);
+
+  // jdk.jfr.Event subklasses
+  static bool is_subklass(const Klass* k);
+  static bool is_subklass(const jclass jc);
+  static void tag_as_subklass(const Klass* k);
+  static void tag_as_subklass(const jclass jc);
+
+  // jdk.jfr.Event hierarchy
+  static bool is_a(const Klass* k);
+  static bool is_a(const jclass jc);
+
+  // klasses that host a jdk.jfr.Event
+  static bool is_host(const Klass* k);
+  static bool is_host(const jclass jc);
+  static void tag_as_host(const Klass* k);
+  static void tag_as_host(const jclass jc);
+
+  // in the set of classes made visible to java
+  static bool is_visible(const Klass* k);
+  static bool is_visible(const jclass jc);
+};
+
+#endif // SHARE_VM_JFR_SUPPORT_JFREVENTCLASS_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/support/jfrFlush.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/recorder/jfrEventSetting.inline.hpp"
+#include "jfr/recorder/storage/jfrStorage.hpp"
+#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
+#include "jfr/support/jfrFlush.hpp"
+#include "jfr/support/jfrThreadLocal.hpp"
+#include "runtime/thread.inline.hpp"
+#include "utilities/debug.hpp"
+
+JfrFlush::JfrFlush(JfrStorage::Buffer* old, size_t used, size_t requested, Thread* t) :
+  _result(JfrStorage::flush(old, used, requested, true, t)) {
+}
+
+template <typename T>
+class LessThanHalfBufferSize : AllStatic {
+public:
+  static bool evaluate(T* t) {
+    assert(t != NULL, "invariant");
+    return t->free_size() < t->size() / 2;
+  }
+};
+
+template <typename T>
+class LessThanSize : AllStatic {
+ public:
+  static bool evaluate(T* t, size_t size) {
+    assert(t != NULL, "invariant");
+    return t->free_size() < size;
+  }
+};
+
+bool jfr_is_event_enabled(JfrEventId id) {
+  return JfrEventSetting::is_enabled(id);
+}
+
+bool jfr_has_stacktrace_enabled(JfrEventId id) {
+  return JfrEventSetting::has_stacktrace(id);
+}
+
+void jfr_conditional_flush(JfrEventId id, size_t size, Thread* t) {
+  assert(jfr_is_event_enabled(id), "invariant");
+  if (t->jfr_thread_local()->has_native_buffer()) {
+    JfrStorage::Buffer* const buffer = t->jfr_thread_local()->native_buffer();
+    if (LessThanSize<JfrStorage::Buffer>::evaluate(buffer, size)) {
+      JfrFlush f(buffer, 0, 0, t);
+    }
+  }
+}
+
+bool jfr_save_stacktrace(Thread* t) {
+  JfrThreadLocal* const tl = t->jfr_thread_local();
+  if (tl->has_cached_stack_trace()) {
+    return false; // no ownership
+  }
+  tl->set_cached_stack_trace_id(JfrStackTraceRepository::record(t));
+  return true;
+}
+
+void jfr_clear_stacktrace(Thread* t) {
+  t->jfr_thread_local()->clear_cached_stack_trace();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/support/jfrFlush.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_SUPPORT_JFRFLUSH_HPP
+#define SHARE_VM_JFR_SUPPORT_JFRFLUSH_HPP
+
+#include "jfr/recorder/storage/jfrBuffer.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
+#include "memory/allocation.hpp"
+
+class Thread;
+
+class JfrFlush : public StackObj {
+ public:
+  typedef JfrBuffer Type;
+  JfrFlush(Type* old, size_t used, size_t requested, Thread* t);
+  Type* result() const { return _result; }
+ private:
+  Type* _result;
+};
+
+void jfr_conditional_flush(JfrEventId id, size_t size, Thread* t);
+bool jfr_is_event_enabled(JfrEventId id);
+bool jfr_has_stacktrace_enabled(JfrEventId id);
+bool jfr_save_stacktrace(Thread* t);
+void jfr_clear_stacktrace(Thread* t);
+
+template <typename Event>
+class JfrConditionalFlush {
+ public:
+  typedef JfrBuffer Type;
+  JfrConditionalFlush(Thread* t) {
+    if (jfr_is_event_enabled(Event::eventId)) {
+      jfr_conditional_flush(Event::eventId, sizeof(Event), t);
+    }
+  }
+};
+
+template <typename Event>
+class JfrConditionalFlushWithStacktrace : public JfrConditionalFlush<Event> {
+  Thread* _t;
+  bool _owner;
+ public:
+  JfrConditionalFlushWithStacktrace(Thread* t) : JfrConditionalFlush<Event>(t), _t(t), _owner(false) {
+    if (Event::has_stacktrace() && jfr_has_stacktrace_enabled(Event::eventId)) {
+      _owner = jfr_save_stacktrace(t);
+    }
+  }
+  ~JfrConditionalFlushWithStacktrace() {
+    if (_owner) {
+      jfr_clear_stacktrace(_t);
+    }
+  }
+};
+
+#endif // SHARE_VM_JFR_SUPPORT_JFRFLUSH_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/support/jfrIntrinsics.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,56 @@
+/*
+* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* This code is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License version 2 only, as
+* published by the Free Software Foundation.
+*
+* This code is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* version 2 for more details (a copy is included in the LICENSE file that
+* accompanied this code).
+*
+* You should have received a copy of the GNU General Public License version
+* 2 along with this work; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+* or visit www.oracle.com if you need additional information or have any
+* questions.
+*
+*/
+
+#ifndef SHARE_VM_JFR_SUPPORT_JFRINTRINSICS_HPP
+#define SHARE_VM_JFR_SUPPORT_JFRINTRINSICS_HPP
+
+#include "utilities/macros.hpp"
+
+#if INCLUDE_JFR
+#include "jfr/support/jfrKlassExtension.hpp"
+#include "jfr/support/jfrThreadExtension.hpp"
+#include "jfr/utilities/jfrTime.hpp"
+#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp"
+
+#define JFR_TEMPLATES(template) \
+  template(jdk_jfr_internal_JVM,          "jdk/jfr/internal/JVM")
+
+#define JFR_INTRINSICS(do_intrinsic, do_class, do_name, do_signature, do_alias)                              \
+  do_intrinsic(_counterTime,        jdk_jfr_internal_JVM, counterTime_name, void_long_signature, F_SN)       \
+    do_name(     counterTime_name,                             "counterTime")                                \
+  do_intrinsic(_getClassId,         jdk_jfr_internal_JVM, getClassId_name, class_long_signature, F_SN)       \
+    do_name(     getClassId_name,                              "getClassId")                                 \
+  do_intrinsic(_getEventWriter,   jdk_jfr_internal_JVM, getEventWriter_name, void_object_signature, F_SN)    \
+    do_name(     getEventWriter_name,                          "getEventWriter")                             \
+
+#define JFR_HAVE_INTRINSICS
+#define JFR_TIME_FUNCTION JfrTime::time_function()
+
+#else // !INCLUDE_JFR
+
+#define JFR_TEMPLATES(template)
+#define JFR_INTRINSICS(do_intrinsic, do_class, do_name, do_signature, do_alias)
+
+#endif // INCLUDE_JFR
+#endif // SHARE_VM_JFR_SUPPORT_JFRINTRINSICS_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/support/jfrKlassExtension.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,42 @@
+/*
+* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* This code is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License version 2 only, as
+* published by the Free Software Foundation.
+*
+* This code is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* version 2 for more details (a copy is included in the LICENSE file that
+* accompanied this code).
+*
+* You should have received a copy of the GNU General Public License version
+* 2 along with this work; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+* or visit www.oracle.com if you need additional information or have any
+* questions.
+*
+*/
+
+#ifndef SHARE_VM_JFR_SUPPORT_JFRKLASSEXTENSION_HPP
+#define SHARE_VM_JFR_SUPPORT_JFRKLASSEXTENSION_HPP
+
+#include "jfr/instrumentation/jfrEventClassTransformer.hpp"
+#include "jfr/support/jfrTraceIdExtension.hpp"
+
+#define DEFINE_KLASS_TRACE_ID_OFFSET \
+  static ByteSize trace_id_offset() { return in_ByteSize(offset_of(InstanceKlass, _trace_id)); }
+
+#define KLASS_TRACE_ID_OFFSET InstanceKlass::trace_id_offset()
+
+#define JDK_JFR_EVENT_SUBKLASS 16
+#define JDK_JFR_EVENT_KLASS    32
+#define EVENT_HOST_KLASS       64
+#define IS_EVENT_KLASS(ptr) (((ptr)->trace_id() & (JDK_JFR_EVENT_KLASS | JDK_JFR_EVENT_SUBKLASS)) != 0)
+#define ON_KLASS_CREATION(k, p, t) if (IS_EVENT_KLASS(k)) JfrEventClassTransformer::on_klass_creation(k, p, t)
+
+#endif // SHARE_VM_JFR_SUPPORT_JFRKLASSEXTENSION_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/support/jfrStackTraceMark.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/recorder/jfrEventSetting.inline.hpp"
+#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
+#include "jfr/support/jfrStackTraceMark.hpp"
+#include "jfr/support/jfrThreadLocal.hpp"
+#include "runtime/thread.inline.hpp"
+
+JfrStackTraceMark::JfrStackTraceMark() : _t(Thread::current()), _previous_id(0), _previous_hash(0) {
+  JfrThreadLocal* const tl = _t->jfr_thread_local();
+  if (tl->has_cached_stack_trace()) {
+    _previous_id = tl->cached_stack_trace_id();
+    _previous_hash = tl->cached_stack_trace_hash();
+  }
+  tl->set_cached_stack_trace_id(JfrStackTraceRepository::record(Thread::current()));
+}
+
+JfrStackTraceMark::JfrStackTraceMark(Thread* t) : _t(t), _previous_id(0), _previous_hash(0) {
+  JfrThreadLocal* const tl = _t->jfr_thread_local();
+  if (tl->has_cached_stack_trace()) {
+    _previous_id = tl->cached_stack_trace_id();
+    _previous_hash = tl->cached_stack_trace_hash();
+  }
+  tl->set_cached_stack_trace_id(JfrStackTraceRepository::record(t));
+}
+
+JfrStackTraceMark::JfrStackTraceMark(JfrEventId eventId) : _t(NULL), _previous_id(0), _previous_hash(0) {
+  if (JfrEventSetting::has_stacktrace(eventId)) {
+    _t = Thread::current();
+    JfrThreadLocal* const tl = _t->jfr_thread_local();
+    if (tl->has_cached_stack_trace()) {
+      _previous_id = tl->cached_stack_trace_id();
+      _previous_hash = tl->cached_stack_trace_hash();
+    }
+    tl->set_cached_stack_trace_id(JfrStackTraceRepository::record(_t));
+  }
+}
+
+JfrStackTraceMark::JfrStackTraceMark(JfrEventId eventId, Thread* t) : _t(NULL), _previous_id(0), _previous_hash(0) {
+  if (JfrEventSetting::has_stacktrace(eventId)) {
+    _t = t;
+    JfrThreadLocal* const tl = _t->jfr_thread_local();
+    if (tl->has_cached_stack_trace()) {
+      _previous_id = tl->cached_stack_trace_id();
+      _previous_hash = tl->cached_stack_trace_hash();
+    }
+    tl->set_cached_stack_trace_id(JfrStackTraceRepository::record(_t));
+  }
+}
+
+JfrStackTraceMark::~JfrStackTraceMark() {
+  if (_previous_id != 0) {
+    _t->jfr_thread_local()->set_cached_stack_trace_id(_previous_id, _previous_hash);
+  } else {
+    if (_t != NULL) {
+      _t->jfr_thread_local()->clear_cached_stack_trace();
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/support/jfrStackTraceMark.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_SUPPORT_JFRSTACKTRACEMARK_HPP
+#define SHARE_VM_JFR_SUPPORT_JFRSTACKTRACEMARK_HPP
+
+#include "memory/allocation.hpp"
+#include "jfrfiles/jfrEventIds.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
+
+class Thread;
+
+class JfrStackTraceMark {
+ private:
+  Thread* _t;
+  traceid _previous_id;
+  unsigned int _previous_hash;
+ public:
+  JfrStackTraceMark();
+  JfrStackTraceMark(Thread* t);
+  JfrStackTraceMark(JfrEventId eventId);
+  JfrStackTraceMark(JfrEventId eventId, Thread* t);
+  ~JfrStackTraceMark();
+};
+
+#endif // SHARE_VM_JFR_SUPPORT_JFRSTACKTRACEMARK_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/support/jfrThreadExtension.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,51 @@
+/*
+* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* This code is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License version 2 only, as
+* published by the Free Software Foundation.
+*
+* This code is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* version 2 for more details (a copy is included in the LICENSE file that
+* accompanied this code).
+*
+* You should have received a copy of the GNU General Public License version
+* 2 along with this work; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+* or visit www.oracle.com if you need additional information or have any
+* questions.
+*
+*/
+
+#ifndef SHARE_VM_JFR_SUPPORT_JFRTHREADEXTENSION_HPP
+#define SHARE_VM_JFR_SUPPORT_JFRTHREADEXTENSION_HPP
+
+#include "jfr/periodic/sampling/jfrThreadSampler.hpp"
+#include "jfr/support/jfrThreadLocal.hpp"
+
+#define DEFINE_THREAD_LOCAL_FIELD_JFR mutable JfrThreadLocal _jfr_thread_local
+
+#define DEFINE_THREAD_LOCAL_OFFSET_JFR \
+  static ByteSize jfr_thread_local_offset() { return in_ByteSize(offset_of(Thread, _jfr_thread_local)); }
+
+#define THREAD_LOCAL_OFFSET_JFR Thread::jfr_thread_local_offset()
+
+#define DEFINE_THREAD_LOCAL_TRACE_ID_OFFSET_JFR \
+  static ByteSize trace_id_offset() { return in_ByteSize(offset_of(JfrThreadLocal, _trace_id)); }
+
+#define DEFINE_THREAD_LOCAL_ACCESSOR_JFR \
+  JfrThreadLocal* jfr_thread_local() const { return &_jfr_thread_local; }
+
+#define THREAD_ID_OFFSET_JFR JfrThreadLocal::trace_id_offset()
+
+#define THREAD_LOCAL_WRITER_OFFSET_JFR \
+  JfrThreadLocal::java_event_writer_offset() + THREAD_LOCAL_OFFSET_JFR
+
+#define SUSPEND_THREAD_CONDITIONAL(thread) if ((thread)->is_trace_suspend()) JfrThreadSampling::on_javathread_suspend(thread)
+
+#endif // SHARE_VM_JFR_SUPPORT_JFRTHREADEXTENSION_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/support/jfrThreadId.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,40 @@
+/*
+* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* This code is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License version 2 only, as
+* published by the Free Software Foundation.
+*
+* This code is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* version 2 for more details (a copy is included in the LICENSE file that
+* accompanied this code).
+*
+* You should have received a copy of the GNU General Public License version
+* 2 along with this work; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+* or visit www.oracle.com if you need additional information or have any
+* questions.
+*
+*/
+
+#ifndef SHARE_VM_JFR_SUPPORT_JFRTHREADID_HPP
+#define SHARE_VM_JFR_SUPPORT_JFRTHREADID_HPP
+
+#include "utilities/macros.hpp"
+
+#if INCLUDE_JFR
+#include "jfr/support/jfrThreadLocal.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
+#define JFR_THREAD_ID(thread) ((thread)->jfr_thread_local()->thread_id())
+#else
+typedef u8 traceid;
+#define JFR_THREAD_ID(thread) ((traceid)(thread)->osthread()->thread_id())
+#endif
+
+#endif // SHARE_VM_JFR_SUPPORT_JFRTHREADID_HPP
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/support/jfrThreadLocal.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/periodic/jfrThreadCPULoadEvent.hpp"
+#include "jfr/jni/jfrJavaSupport.hpp"
+#include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
+#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
+#include "jfr/recorder/service/jfrOptionSet.hpp"
+#include "jfr/recorder/storage/jfrStorage.hpp"
+#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
+#include "jfr/support/jfrThreadLocal.hpp"
+#include "memory/allocation.inline.hpp"
+#include "runtime/os.hpp"
+#include "runtime/thread.inline.hpp"
+
+/* This data structure is per thread and only accessed by the thread itself, no locking required */
+JfrThreadLocal::JfrThreadLocal() :
+  _java_event_writer(NULL),
+  _java_buffer(NULL),
+  _native_buffer(NULL),
+  _shelved_buffer(NULL),
+  _stackframes(NULL),
+  _trace_id(JfrTraceId::assign_thread_id()),
+  _thread_cp(),
+  _data_lost(0),
+  _stack_trace_id(max_julong),
+  _user_time(0),
+  _cpu_time(0),
+  _wallclock_time(os::javaTimeNanos()),
+  _stack_trace_hash(0),
+  _stackdepth(0),
+  _entering_suspend_flag(0) {}
+
+u8 JfrThreadLocal::add_data_lost(u8 value) {
+  _data_lost += value;
+  return _data_lost;
+}
+
+bool JfrThreadLocal::has_thread_checkpoint() const {
+  return _thread_cp.valid();
+}
+
+void JfrThreadLocal::set_thread_checkpoint(const JfrCheckpointBlobHandle& ref) {
+  assert(!_thread_cp.valid(), "invariant");
+  _thread_cp = ref;
+}
+
+const JfrCheckpointBlobHandle& JfrThreadLocal::thread_checkpoint() const {
+  return _thread_cp;
+}
+
+void JfrThreadLocal::on_exit(JavaThread* thread) {
+  JfrCheckpointManager::write_thread_checkpoint(thread);
+  JfrThreadCPULoadEvent::send_event_for_thread(thread);
+}
+
+void JfrThreadLocal::on_destruct(Thread* thread) {
+  JfrThreadLocal* const tl = thread->jfr_thread_local();
+  if (tl->has_native_buffer()) {
+    release(tl->native_buffer(), thread);
+  }
+  if (tl->has_java_buffer()) {
+    release(tl->java_buffer(), thread);
+  }
+  assert(tl->shelved_buffer() == NULL, "invariant");
+  if (thread->jfr_thread_local()->has_java_event_writer()) {
+    JfrJavaSupport::destroy_global_jni_handle(tl->java_event_writer());
+  }
+  destroy_stackframes(thread);
+}
+
+JfrBuffer* JfrThreadLocal::acquire(Thread* thread, size_t size) {
+  return JfrStorage::acquire_thread_local(thread, size);
+}
+
+void JfrThreadLocal::release(JfrBuffer* buffer, Thread* thread) {
+  assert(buffer != NULL, "invariant");
+  JfrStorage::release_thread_local(buffer, thread);
+}
+
+JfrBuffer* JfrThreadLocal::install_native_buffer() const {
+  assert(!has_native_buffer(), "invariant");
+  _native_buffer = acquire(Thread::current());
+  return _native_buffer;
+}
+
+JfrBuffer* JfrThreadLocal::install_java_buffer() const {
+  assert(!has_java_buffer(), "invariant");
+  assert(!has_java_event_writer(), "invariant");
+  _java_buffer = acquire(Thread::current());
+  return _java_buffer;
+}
+
+JfrStackFrame* JfrThreadLocal::install_stackframes() const {
+  assert(_stackframes == NULL, "invariant");
+  _stackdepth = (u4)JfrOptionSet::stackdepth();
+  guarantee(_stackdepth > 0, "Stackdepth must be > 0");
+  _stackframes = NEW_C_HEAP_ARRAY(JfrStackFrame, _stackdepth, mtTracing);
+  return _stackframes;
+}
+
+void JfrThreadLocal::destroy_stackframes(Thread* thread) {
+  assert(thread != NULL, "invariant");
+  JfrStackFrame* frames = thread->jfr_thread_local()->stackframes();
+  if (frames != NULL) {
+    FREE_C_HEAP_ARRAY(JfrStackFrame, frames);
+    thread->jfr_thread_local()->set_stackframes(NULL);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/support/jfrThreadLocal.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_SUPPORT_JFRTHREADLOCAL_HPP
+#define SHARE_VM_JFR_SUPPORT_JFRTHREADLOCAL_HPP
+
+#include "jfr/recorder/checkpoint/jfrCheckpointBlob.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
+#include "utilities/sizes.hpp"
+
+class JavaThread;
+class JfrBuffer;
+class JfrStackFrame;
+
+class JfrThreadLocal {
+ private:
+  jobject _java_event_writer;
+  mutable JfrBuffer* _java_buffer;
+  mutable JfrBuffer* _native_buffer;
+  JfrBuffer* _shelved_buffer;
+  mutable JfrStackFrame* _stackframes;
+  mutable traceid _trace_id;
+  JfrCheckpointBlobHandle _thread_cp;
+  u8 _data_lost;
+  traceid _stack_trace_id;
+  jlong _user_time;
+  jlong _cpu_time;
+  jlong _wallclock_time;
+  unsigned int _stack_trace_hash;
+  mutable u4 _stackdepth;
+  volatile jint _entering_suspend_flag;
+
+  JfrBuffer* install_native_buffer() const;
+  JfrBuffer* install_java_buffer() const;
+  JfrStackFrame* install_stackframes() const;
+
+ public:
+  JfrThreadLocal();
+
+  JfrBuffer* native_buffer() const {
+    return _native_buffer != NULL ? _native_buffer : install_native_buffer();
+  }
+
+  bool has_native_buffer() const {
+    return _native_buffer != NULL;
+  }
+
+  void set_native_buffer(JfrBuffer* buffer) {
+    _native_buffer = buffer;
+  }
+
+  JfrBuffer* java_buffer() const {
+    return _java_buffer != NULL ? _java_buffer : install_java_buffer();
+  }
+
+  bool has_java_buffer() const {
+    return _java_buffer != NULL;
+  }
+
+  void set_java_buffer(JfrBuffer* buffer) {
+    _java_buffer = buffer;
+  }
+
+  JfrBuffer* shelved_buffer() const {
+    return _shelved_buffer;
+  }
+
+  void shelve_buffer(JfrBuffer* buffer) {
+    _shelved_buffer = buffer;
+  }
+
+  bool has_java_event_writer() const {
+    return _java_event_writer != NULL;
+  }
+
+  jobject java_event_writer() {
+    return _java_event_writer;
+  }
+
+  void set_java_event_writer(jobject java_event_writer) {
+    _java_event_writer = java_event_writer;
+  }
+
+  JfrStackFrame* stackframes() const {
+    return _stackframes != NULL ? _stackframes : install_stackframes();
+  }
+
+  void set_stackframes(JfrStackFrame* frames) {
+    _stackframes = frames;
+  }
+
+  u4 stackdepth() const {
+    return _stackdepth;
+  }
+
+  void set_stackdepth(u4 depth) {
+    _stackdepth = depth;
+  }
+
+  traceid thread_id() const {
+    return _trace_id;
+  }
+
+  void set_thread_id(traceid thread_id) {
+    _trace_id = thread_id;
+  }
+
+  void set_cached_stack_trace_id(traceid id, unsigned int hash = 0) {
+    _stack_trace_id = id;
+    _stack_trace_hash = hash;
+  }
+
+  bool has_cached_stack_trace() const {
+    return _stack_trace_id != max_julong;
+  }
+
+  void clear_cached_stack_trace() {
+    _stack_trace_id = max_julong;
+    _stack_trace_hash = 0;
+  }
+
+  traceid cached_stack_trace_id() const {
+    return _stack_trace_id;
+  }
+
+  unsigned int cached_stack_trace_hash() const {
+    return _stack_trace_hash;
+  }
+
+  void set_trace_block() {
+    _entering_suspend_flag = 1;
+  }
+
+  void clear_trace_block() {
+    _entering_suspend_flag = 0;
+  }
+
+  bool is_trace_block() const {
+    return _entering_suspend_flag != 0;
+  }
+
+  u8 data_lost() const {
+    return _data_lost;
+  }
+
+  u8 add_data_lost(u8 value);
+
+  jlong get_user_time() const {
+    return _user_time;
+  }
+
+  void set_user_time(jlong user_time) {
+    _user_time = user_time;
+  }
+
+  jlong get_cpu_time() const {
+    return _cpu_time;
+  }
+
+  void set_cpu_time(jlong cpu_time) {
+    _cpu_time = cpu_time;
+  }
+
+  jlong get_wallclock_time() const {
+    return _wallclock_time;
+  }
+
+  void set_wallclock_time(jlong wallclock_time) {
+    _wallclock_time = wallclock_time;
+  }
+
+  traceid trace_id() const {
+    return _trace_id;
+  }
+
+  traceid* const trace_id_addr() const {
+    return &_trace_id;
+  }
+
+  void set_trace_id(traceid id) const {
+    _trace_id = id;
+  }
+
+  bool has_thread_checkpoint() const;
+  void set_thread_checkpoint(const JfrCheckpointBlobHandle& handle);
+  const JfrCheckpointBlobHandle& thread_checkpoint() const;
+
+  static JfrBuffer* acquire(Thread* t, size_t size = 0);
+  static void release(JfrBuffer* buffer, Thread* t);
+  static void destroy_stackframes(Thread* t);
+  static void on_exit(JavaThread* t);
+  static void on_destruct(Thread* t);
+
+  // Code generation
+  static ByteSize trace_id_offset() {
+    return in_ByteSize(offset_of(JfrThreadLocal, _trace_id));
+  }
+
+  static ByteSize java_event_writer_offset() {
+    return in_ByteSize(offset_of(JfrThreadLocal, _java_event_writer));
+  }
+};
+
+#endif // SHARE_VM_JFR_SUPPORT_JFRTHREADLOCAL_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/support/jfrTraceIdExtension.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,81 @@
+/*
+* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* This code is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License version 2 only, as
+* published by the Free Software Foundation.
+*
+* This code is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* version 2 for more details (a copy is included in the LICENSE file that
+* accompanied this code).
+*
+* You should have received a copy of the GNU General Public License version
+* 2 along with this work; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+* or visit www.oracle.com if you need additional information or have any
+* questions.
+*
+*/
+
+#ifndef SHARE_VM_JFR_SUPPORT_JFRTRACEIDEXTENSION_HPP
+#define SHARE_VM_JFR_SUPPORT_JFRTRACEIDEXTENSION_HPP
+
+#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.hpp"
+
+#define DEFINE_TRACE_ID_FIELD mutable traceid _trace_id
+
+#define DEFINE_TRACE_ID_METHODS \
+  traceid trace_id() const { return _trace_id; } \
+  traceid* const trace_id_addr() const { return &_trace_id; } \
+  void set_trace_id(traceid id) const { _trace_id = id; }
+
+#define DEFINE_TRACE_ID_SIZE \
+  static size_t trace_id_size() { return sizeof(traceid); }
+
+#define INIT_ID(data) JfrTraceId::assign(data)
+#define REMOVE_ID(k) JfrTraceId::remove(k);
+#define RESTORE_ID(k) JfrTraceId::restore(k);
+
+class JfrTraceFlag {
+ private:
+  mutable jbyte _flags;
+ public:
+  JfrTraceFlag() : _flags(0) {}
+  explicit JfrTraceFlag(jbyte flags) : _flags(flags) {}
+  void set_flag(jbyte flag) const {
+    _flags |= flag;
+  }
+  void clear_flag(jbyte flag) const {
+    _flags &= (~flag);
+  }
+  jbyte flags() const { return _flags; }
+  bool is_set(jbyte flag) const {
+    return (_flags & flag) != 0;
+  }
+  jbyte* const flags_addr() const {
+    return &_flags;
+  }
+};
+
+#define DEFINE_TRACE_FLAG mutable JfrTraceFlag _trace_flags
+
+#define DEFINE_TRACE_FLAG_ACCESSOR                 \
+  void set_trace_flag(jbyte flag) const {          \
+    _trace_flags.set_flag(flag);                   \
+  }                                                \
+  jbyte trace_flags() const {                      \
+    return _trace_flags.flags();                   \
+  }                                                \
+  bool is_trace_flag_set(jbyte flag) const {       \
+    return _trace_flags.is_set(flag);              \
+  }                                                \
+  jbyte* const trace_flags_addr() const {          \
+    return _trace_flags.flags_addr();              \
+  }
+
+#endif // SHARE_VM_JFR_SUPPORT_JFRTRACEIDEXTENSION_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/utilities/jfrAllocation.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/recorder/jfrRecorder.hpp"
+#include "jfr/utilities/jfrAllocation.hpp"
+#include "logging/log.hpp"
+#include "memory/allocation.inline.hpp"
+#include "runtime/atomic.hpp"
+#include "runtime/orderAccess.inline.hpp"
+#include "runtime/vm_version.hpp"
+#include "utilities/debug.hpp"
+#include "utilities/macros.hpp"
+#include "utilities/nativeCallStack.hpp"
+
+#ifdef ASSERT
+static jlong atomic_add_jlong(jlong value, jlong volatile* const dest) {
+  assert(VM_Version::supports_cx8(), "unsupported");
+  jlong compare_value;
+  jlong exchange_value;
+  do {
+    compare_value = OrderAccess::load_acquire(dest);
+    exchange_value = compare_value + value;
+  } while (Atomic::cmpxchg(exchange_value, dest, compare_value) != compare_value);
+  return exchange_value;
+}
+
+// debug statistics
+static volatile jlong _allocated_bytes = 0;
+static volatile jlong _deallocated_bytes = 0;
+static volatile jlong _live_set_bytes = 0;
+
+static void add(size_t alloc_size) {
+  if (!JfrRecorder::is_created()) {
+    const jlong total_allocated = atomic_add_jlong(alloc_size, &_allocated_bytes);
+    const jlong current_live_set = atomic_add_jlong(alloc_size, &_live_set_bytes);
+    log_trace(jfr, system)("Allocation: [" SIZE_FORMAT "] bytes", alloc_size);
+    log_trace(jfr, system)("Total alloc [" JLONG_FORMAT "] bytes", total_allocated);
+    log_trace(jfr, system)("Liveset:    [" JLONG_FORMAT "] bytes", current_live_set);
+  }
+}
+
+static void subtract(size_t dealloc_size) {
+  if (!JfrRecorder::is_created()) {
+    const size_t total_deallocated = atomic_add_jlong(dealloc_size, &_deallocated_bytes);
+    const size_t current_live_set = atomic_add_jlong(dealloc_size * -1, &_live_set_bytes);
+    log_trace(jfr, system)("Deallocation: [" SIZE_FORMAT "] bytes", dealloc_size);
+    log_trace(jfr, system)("Total dealloc [" JLONG_FORMAT "] bytes", total_deallocated);
+    log_trace(jfr, system)("Liveset:      [" JLONG_FORMAT "] bytes", current_live_set);
+  }
+}
+
+static void hook_memory_deallocation(size_t dealloc_size) {
+  subtract(dealloc_size);
+}
+#endif // ASSERT
+
+static void hook_memory_allocation(const char* allocation, size_t alloc_size) {
+  if (NULL == allocation) {
+    if (!JfrRecorder::is_created()) {
+      log_warning(jfr, system)("Memory allocation failed for size [" SIZE_FORMAT "] bytes", alloc_size);
+      return;
+    } else {
+      // after critical startup, fail as by default
+      vm_exit_out_of_memory(alloc_size, OOM_MALLOC_ERROR, "AllocateHeap");
+    }
+  }
+  debug_only(add(alloc_size));
+}
+
+void JfrCHeapObj::on_memory_allocation(const void* allocation, size_t size) {
+  hook_memory_allocation((const char*)allocation, size);
+}
+
+void* JfrCHeapObj::operator new(size_t size) throw() {
+  return operator new(size, std::nothrow);
+}
+
+void* JfrCHeapObj::operator new (size_t size, const std::nothrow_t&  nothrow_constant) throw() {
+  void* const memory = CHeapObj<mtTracing>::operator new(size, nothrow_constant, CALLER_PC);
+  hook_memory_allocation((const char*)memory, size);
+  return memory;
+}
+
+void* JfrCHeapObj::operator new [](size_t size) throw() {
+  return operator new[](size, std::nothrow);
+}
+
+void* JfrCHeapObj::operator new [](size_t size, const std::nothrow_t&  nothrow_constant) throw() {
+  void* const memory = CHeapObj<mtTracing>::operator new[](size, nothrow_constant, CALLER_PC);
+  hook_memory_allocation((const char*)memory, size);
+  return memory;
+}
+
+void JfrCHeapObj::operator delete(void* p, size_t size) {
+  debug_only(hook_memory_deallocation(size);)
+  CHeapObj<mtTracing>::operator delete(p);
+}
+
+void JfrCHeapObj::operator delete[](void* p, size_t size) {
+  debug_only(hook_memory_deallocation(size);)
+  CHeapObj<mtTracing>::operator delete[](p);
+}
+
+char* JfrCHeapObj::realloc_array(char* old, size_t size) {
+  char* const memory = ReallocateHeap(old, size, mtTracing, AllocFailStrategy::RETURN_NULL);
+  hook_memory_allocation(memory, size);
+  return memory;
+}
+
+void JfrCHeapObj::free(void* p, size_t size) {
+  debug_only(hook_memory_deallocation(size);)
+  FreeHeap(p);
+}
+
+char* JfrCHeapObj::allocate_array_noinline(size_t elements, size_t element_size) {
+  return AllocateHeap(elements * element_size, mtTracing, CALLER_PC, AllocFailStrategy::RETURN_NULL);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/utilities/jfrAllocation.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_UTILITIES_JFRALLOCATION_HPP
+#define SHARE_VM_JFR_UTILITIES_JFRALLOCATION_HPP
+
+#include "memory/allocation.hpp"
+#include "services/memTracker.hpp"
+#include "utilities/exceptions.hpp"
+
+/*
+ * A subclass to the CHeapObj<mtTracing> allocator, useful for critical
+ * Jfr subsystems. Critical in this context means subsystems for which
+ * allocations are crucial to the bootstrap and initialization of Jfr.
+ * The default behaviour by a CHeapObj is to call vm_exit_out_of_memory()
+ * on allocation failure and this is problematic in combination with the
+ * Jfr on-demand, dynamic start at runtime, capability.
+ * We would not like a user dynamically starting Jfr to
+ * tear down the VM she is about to inspect as a side effect.
+ *
+ * This allocator uses the RETURN_NULL capabilities
+ * instead of calling vm_exit_out_of_memory() until Jfr is properly started.
+ * This allows for controlled behaviour on allocation failures during startup,
+ * which means we can take actions on failure, such as transactional rollback
+ * (deallocations and restorations).
+ * In addition, this allocator allows for easy hooking of memory
+ * allocations / deallocations for debugging purposes.
+ */
+
+class JfrCHeapObj : public CHeapObj<mtTracing> {
+ private:
+  static void on_memory_allocation(const void* allocation, size_t size);
+  static char* allocate_array_noinline(size_t elements, size_t element_size);
+
+ public:
+  NOINLINE void* operator new(size_t size) throw();
+  NOINLINE void* operator new (size_t size, const std::nothrow_t&  nothrow_constant) throw();
+  NOINLINE void* operator new [](size_t size) throw();
+  NOINLINE void* operator new [](size_t size, const std::nothrow_t&  nothrow_constant) throw();
+  void  operator delete(void* p, size_t size);
+  void  operator delete [] (void* p, size_t size);
+  static char* realloc_array(char* old, size_t size);
+  static void free(void* p, size_t size = 0);
+
+  template <class T>
+  static T* new_array(size_t size) {
+    T* const memory = (T*)allocate_array_noinline(size, sizeof(T));
+    on_memory_allocation(memory, sizeof(T) * size);
+    return memory;
+  }
+};
+
+#endif // SHARE_VM_JFR_UTILITIES_JFRALLOCATION_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/utilities/jfrBigEndian.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_UTILITIES_JFRBIGENDIAN_HPP
+#define SHARE_VM_JFR_UTILITIES_JFRBIGENDIAN_HPP
+
+#include "memory/allocation.hpp"
+#include "utilities/bytes.hpp"
+#include "utilities/macros.hpp"
+
+#ifndef VM_LITTLE_ENDIAN
+# define bigendian_16(x) (x)
+# define bigendian_32(x) (x)
+# define bigendian_64(x) (x)
+#else
+# define bigendian_16(x) Bytes::swap_u2(x)
+# define bigendian_32(x) Bytes::swap_u4(x)
+# define bigendian_64(x) Bytes::swap_u8(x)
+#endif
+
+class JfrBigEndian : AllStatic {
+ private:
+  template <typename T>
+  static T read_bytes(const address location);
+  template <typename T>
+  static T read_unaligned(const address location);
+ public:
+  static bool platform_supports_unaligned_reads(void);
+  static bool is_aligned(const void* location, size_t size);
+  template <typename T>
+  static T read(const void* location);
+};
+
+inline bool JfrBigEndian::is_aligned(const void* location, size_t size) {
+  assert(size <= sizeof(u8), "just checking");
+  if (size == sizeof(u1)) {
+    return true;
+  }
+  // check address alignment for datum access
+  return (((uintptr_t)location & (size -1)) == 0);
+}
+
+template <>
+inline u1 JfrBigEndian::read_bytes(const address location) {
+  return (*location & 0xFF);
+}
+
+template <>
+inline u2 JfrBigEndian::read_bytes(const address location) {
+  return Bytes::get_Java_u2(location);
+}
+
+template <>
+inline u4 JfrBigEndian::read_bytes(const address location) {
+  return Bytes::get_Java_u4(location);
+}
+
+template <>
+inline u8 JfrBigEndian::read_bytes(const address location) {
+  return Bytes::get_Java_u8(location);
+}
+
+template <typename T>
+inline T JfrBigEndian::read_unaligned(const address location) {
+  assert(location != NULL, "just checking");
+  switch (sizeof(T)) {
+    case sizeof(u1) :
+      return read_bytes<u1>(location);
+    case sizeof(u2):
+      return read_bytes<u2>(location);
+    case sizeof(u4):
+      return read_bytes<u4>(location);
+    case sizeof(u8):
+      return read_bytes<u8>(location);
+    default:
+      assert(false, "not reach");
+  }
+  return 0;
+}
+
+inline bool JfrBigEndian::platform_supports_unaligned_reads(void) {
+#if defined(IA32) || defined(AMD64)
+  return true;
+#elif defined(SPARC) || defined(ARM) || defined(AARCH64)
+  return false;
+#else
+  #warning "Unconfigured platform"
+  return false;
+#endif
+}
+
+template<typename T>
+inline T JfrBigEndian::read(const void* location) {
+  assert(location != NULL, "just checking");
+  assert(sizeof(T) <= sizeof(u8), "no support for arbitrary sizes");
+  if (sizeof(T) == sizeof(u1)) {
+    return *(T*)location;
+  }
+  if (is_aligned(location, sizeof(T)) || platform_supports_unaligned_reads()) {
+    // fastest case
+    switch (sizeof(T)) {
+      case sizeof(u1):
+        return *(T*)location;
+      case sizeof(u2):
+        return bigendian_16(*(T*)(location));
+      case sizeof(u4):
+        return bigendian_32(*(T*)(location));
+      case sizeof(u8):
+        return bigendian_64(*(T*)(location));
+    }
+  }
+  return read_unaligned<T>((const address)location);
+}
+
+#endif // SHARE_VM_JFR_UTILITIES_JFRBIGENDIAN_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/utilities/jfrDoublyLinkedList.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_UTILITIES_JFRDOUBLYLINKEDLIST_HPP
+#define SHARE_VM_JFR_UTILITIES_JFRDOUBLYLINKEDLIST_HPP
+
+#include "memory/allocation.hpp"
+
+template <typename T>
+class JfrDoublyLinkedList {
+ private:
+  T* _head;
+  T* _tail;
+  size_t _count;
+
+  T** list_head() { return &_head; }
+  T** list_tail() { return &_tail; }
+
+ public:
+  typedef T Node;
+  JfrDoublyLinkedList() : _head(NULL), _tail(NULL), _count(0) {}
+  T* head() const { return _head; }
+  T* tail() const { return _tail; }
+  size_t count() const { return _count; }
+  T* clear(bool return_tail = false);
+  T* remove(T* const node);
+  void prepend(T* const node);
+  void append(T* const node);
+  void append_list(T* const head_node, T* const tail_node, size_t count);
+  debug_only(bool in_list(const T* const target_node) const;)
+  debug_only(bool locate(const T* start_node, const T* const target_node) const;)
+};
+
+template <typename T>
+inline void JfrDoublyLinkedList<T>::prepend(T* const node) {
+  assert(node != NULL, "invariant");
+  node->set_prev(NULL);
+  assert(!in_list(node), "already in list error");
+  T** lh = list_head();
+  if (*lh != NULL) {
+    (*lh)->set_prev(node);
+    node->set_next(*lh);
+  } else {
+    T** lt = list_tail();
+    assert(*lt == NULL, "invariant");
+    *lt = node;
+    node->set_next(NULL);
+    assert(tail() == node, "invariant");
+    assert(node->next() == NULL, "invariant");
+  }
+  *lh = node;
+  ++_count;
+  assert(head() == node, "head error");
+  assert(in_list(node), "not in list error");
+  assert(node->prev() == NULL, "invariant");
+}
+
+template <typename T>
+void JfrDoublyLinkedList<T>::append(T* const node) {
+  assert(node != NULL, "invariant");
+  node->set_next(NULL);
+  assert(!in_list(node), "already in list error");
+  T** lt = list_tail();
+  if (*lt != NULL) {
+    // already an existing tail
+    node->set_prev(*lt);
+    (*lt)->set_next(node);
+  } else {
+    // if no tail, also update head
+    assert(*lt == NULL, "invariant");
+    T** lh = list_head();
+    assert(*lh == NULL, "invariant");
+    node->set_prev(NULL);
+    *lh = node;
+    assert(head() == node, "invariant");
+  }
+  *lt = node;
+  ++_count;
+  assert(tail() == node, "invariant");
+  assert(in_list(node), "not in list error");
+  assert(node->next() == NULL, "invariant");
+}
+
+template <typename T>
+T* JfrDoublyLinkedList<T>::remove(T* const node) {
+  assert(node != NULL, "invariant");
+  assert(in_list(node), "invariant");
+  T* const prev = (T*)node->prev();
+  T* const next = (T*)node->next();
+  if (prev == NULL) {
+    assert(head() == node, "head error");
+    if (next != NULL) {
+      next->set_prev(NULL);
+    } else {
+      assert(next == NULL, "invariant");
+      assert(tail() == node, "tail error");
+      T** lt = list_tail();
+      *lt = NULL;
+      assert(tail() == NULL, "invariant");
+    }
+    T** lh = list_head();
+    *lh = next;
+    assert(head() == next, "invariant");
+  } else {
+    assert(prev != NULL, "invariant");
+    if (next == NULL) {
+      assert(tail() == node, "tail error");
+      T** lt = list_tail();
+      *lt = prev;
+      assert(tail() == prev, "invariant");
+    } else {
+       next->set_prev(prev);
+    }
+    prev->set_next(next);
+  }
+  --_count;
+  assert(_count >= 0, "invariant");
+  assert(!in_list(node), "still in list error");
+  return node;
+}
+
+template <typename T>
+T* JfrDoublyLinkedList<T>::clear(bool return_tail /* false */) {
+  T* const node = return_tail ? tail() : head();
+  T** l = list_head();
+  *l = NULL;
+  l = list_tail();
+  *l = NULL;
+  _count = 0;
+  assert(head() == NULL, "invariant");
+  assert(tail() == NULL, "invariant");
+  return node;
+}
+
+#ifdef ASSERT
+template <typename T>
+bool JfrDoublyLinkedList<T>::locate(const T* node, const T* const target) const {
+  assert(target != NULL, "invariant");
+  while (node != NULL) {
+    if (node == target) {
+      return true;
+    }
+    node = (T*)node->next();
+  }
+  return false;
+}
+
+template <typename T>
+bool JfrDoublyLinkedList<T>::in_list(const T* const target) const {
+  assert(target != NULL, "invariant");
+  return locate(head(), target);
+}
+
+template <typename T>
+inline void validate_count_param(T* node, size_t count_param) {
+  assert(node != NULL, "invariant");
+  size_t count = 0;
+  while (node) {
+    ++count;
+    node = (T*)node->next();
+  }
+  assert(count_param == count, "invariant");
+}
+#endif // ASSERT
+
+template <typename T>
+void JfrDoublyLinkedList<T>::append_list(T* const head_node, T* const tail_node, size_t count) {
+  assert(head_node != NULL, "invariant");
+  assert(!in_list(head_node), "already in list error");
+  assert(tail_node != NULL, "invariant");
+  assert(!in_list(tail_node), "already in list error");
+  assert(tail_node->next() == NULL, "invariant");
+  // ensure passed in list nodes are connected
+  assert(locate(head_node, tail_node), "invariant");
+  T** lt = list_tail();
+  if (*lt != NULL) {
+    head_node->set_prev(*lt);
+    (*lt)->set_next(head_node);
+  } else {
+    // no head
+    assert(*lt == NULL, "invariant");
+    T** lh = list_head();
+    assert(*lh == NULL, "invariant");
+    head_node->set_prev(NULL);
+    *lh = head_node;
+    assert(head() == head_node, "invariant");
+  }
+  *lt = tail_node;
+  const T* node = head_node;
+  debug_only(validate_count_param(node, count);)
+    _count += count;
+  assert(tail() == tail_node, "invariant");
+  assert(in_list(tail_node), "not in list error");
+  assert(in_list(head_node), "not in list error");
+}
+
+#endif // SHARE_VM_JFR_UTILITIES_JFRDOUBLYLINKEDLIST_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/utilities/jfrHashtable.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_UTILITIES_JFRHASHTABLE_HPP
+#define SHARE_VM_JFR_UTILITIES_JFRHASHTABLE_HPP
+
+#include "memory/allocation.inline.hpp"
+#include "runtime/orderAccess.inline.hpp"
+#include "utilities/debug.hpp"
+#include "utilities/macros.hpp"
+
+template <typename T>
+class JfrBasicHashtableEntry {
+ private:
+  typedef JfrBasicHashtableEntry<T> Entry;
+  Entry* _next;
+  T _literal;          // ref to item in table.
+  uintptr_t _hash;
+
+ public:
+  uintptr_t hash() const { return _hash; }
+  void set_hash(uintptr_t hash) { _hash = hash; }
+  T literal() const { return _literal; }
+  T* literal_addr() { return &_literal; }
+  void set_literal(T s) { _literal = s; }
+  void set_next(Entry* next) { _next = next; }
+  Entry* next() const { return _next; }
+  Entry** next_addr() { return &_next; }
+};
+
+template <typename T>
+class JfrHashtableBucket : public CHeapObj<mtTracing> {
+  template <typename>
+  friend class JfrBasicHashtable;
+ private:
+  typedef JfrBasicHashtableEntry<T> TableEntry;
+  TableEntry* _entry;
+
+  TableEntry* get_entry() const {
+    return (TableEntry*)OrderAccess::load_acquire(&_entry);
+  }
+  void set_entry(TableEntry* entry) { OrderAccess::release_store(&_entry, entry);}
+  TableEntry** entry_addr() { return &_entry; }
+};
+
+template <typename T>
+class JfrBasicHashtable : public CHeapObj<mtTracing> {
+ private:
+  typedef JfrHashtableBucket<T> Bucket;
+  typedef JfrBasicHashtableEntry<T> TableEntry;
+  Bucket* _buckets;
+  uintptr_t _table_size;
+  const size_t _entry_size;
+  size_t _number_of_entries;
+
+ protected:
+  JfrBasicHashtable(uintptr_t table_size, size_t entry_size) :
+    _buckets(NULL), _table_size(table_size), _entry_size(entry_size), _number_of_entries(0) {
+    _buckets = NEW_C_HEAP_ARRAY2(Bucket, table_size, mtTracing, CURRENT_PC);
+    memset((void*)_buckets, 0, table_size * sizeof(Bucket));
+  }
+
+  size_t hash_to_index(uintptr_t full_hash) const {
+    const uintptr_t h = full_hash % _table_size;
+    assert(h >= 0 && h < _table_size, "Illegal hash value");
+    return (size_t)h;
+  }
+  size_t entry_size() const { return _entry_size; }
+  void unlink_entry(TableEntry* entry) {
+    entry->set_next(NULL);
+    --_number_of_entries;
+  }
+  void free_buckets() {
+    if (NULL != _buckets) {
+      FREE_C_HEAP_ARRAY(Bucket, _buckets);
+      _buckets = NULL;
+    }
+  }
+  TableEntry* bucket(size_t i) { return _buckets[i].get_entry();}
+  TableEntry** bucket_addr(size_t i) { return _buckets[i].entry_addr(); }
+  uintptr_t table_size() const { return _table_size; }
+  size_t number_of_entries() const { return _number_of_entries; }
+  void add_entry(size_t index, TableEntry* entry) {
+    assert(entry != NULL, "invariant");
+    entry->set_next(bucket(index));
+    _buckets[index].set_entry(entry);
+    ++_number_of_entries;
+  }
+};
+
+template <typename IdType, typename Entry, typename T>
+class AscendingId : public CHeapObj<mtTracing>  {
+ private:
+  IdType _id;
+ public:
+  AscendingId() : _id(0) {}
+  // callbacks
+  void assign_id(Entry* entry) {
+    assert(entry != NULL, "invariant");
+    assert(entry->id() == 0, "invariant");
+    entry->set_id(++_id);
+  }
+  bool equals(const T& data, uintptr_t hash, const Entry* entry) {
+    assert(entry->hash() == hash, "invariant");
+    return true;
+  }
+};
+
+// IdType must be scalar
+template <typename T, typename IdType>
+class Entry : public JfrBasicHashtableEntry<T> {
+ public:
+  typedef IdType ID;
+  void init() { _id = 0; }
+  ID id() const { return _id; }
+  void set_id(ID id) { _id = id; }
+  void set_value(const T& value) { this->set_literal(value); }
+  T& value() const { return *const_cast<Entry*>(this)->literal_addr();}
+  const T* value_addr() const { return const_cast<Entry*>(this)->literal_addr(); }
+
+ private:
+  ID _id;
+};
+
+template <typename T, typename IdType, template <typename, typename> class Entry,
+          typename Callback = AscendingId<IdType, Entry<T, IdType>, T> ,
+          size_t TABLE_SIZE = 1009>
+class HashTableHost : public JfrBasicHashtable<T> {
+ public:
+  typedef Entry<T, IdType> HashEntry;
+  HashTableHost() : _callback(new Callback()) {}
+  HashTableHost(Callback* cb) : JfrBasicHashtable<T>(TABLE_SIZE, sizeof(HashEntry)), _callback(cb) {}
+  ~HashTableHost() {
+    this->clear_entries();
+    this->free_buckets();
+  }
+
+  // direct insert assumes non-existing entry
+  HashEntry& put(const T& data, uintptr_t hash);
+
+  // lookup entry, will put if not found
+  HashEntry& lookup_put(const T& data, uintptr_t hash) {
+    HashEntry* entry = lookup_only(data, hash);
+    return entry == NULL ? put(data, hash) : *entry;
+  }
+
+  // read-only lookup
+  HashEntry* lookup_only(const T& query, uintptr_t hash);
+
+  // id retrieval
+  IdType id(const T& data, uintptr_t hash) {
+    assert(data != NULL, "invariant");
+    const HashEntry& entry = lookup_put(data, hash);
+    assert(entry.id() > 0, "invariant");
+    return entry.id();
+  }
+
+  template <typename Functor>
+  void iterate_value(Functor& f);
+
+  template <typename Functor>
+  void iterate_entry(Functor& f);
+
+  size_t cardinality() const { return this->number_of_entries(); }
+  bool has_entries() const { return this->cardinality() > 0; }
+  void clear_entries();
+
+  // removal and deallocation
+  void free_entry(HashEntry* entry) {
+    assert(entry != NULL, "invariant");
+    JfrBasicHashtable<T>::unlink_entry(entry);
+    FREE_C_HEAP_ARRAY(char, entry);
+  }
+
+ private:
+  Callback* _callback;
+  size_t index_for(uintptr_t hash) { return this->hash_to_index(hash); }
+  HashEntry* new_entry(const T& data, uintptr_t hash);
+  void add_entry(size_t index, HashEntry* new_entry) {
+    assert(new_entry != NULL, "invariant");
+    _callback->assign_id(new_entry);
+    assert(new_entry->id() > 0, "invariant");
+    JfrBasicHashtable<T>::add_entry(index, new_entry);
+  }
+};
+
+template <typename T, typename IdType, template <typename, typename> class Entry, typename Callback, size_t TABLE_SIZE>
+Entry<T, IdType>& HashTableHost<T, IdType, Entry, Callback, TABLE_SIZE>::put(const T& data, uintptr_t hash) {
+  assert(lookup_only(data, hash) == NULL, "use lookup_put()");
+  HashEntry* const entry = new_entry(data, hash);
+  add_entry(index_for(hash), entry);
+  return *entry;
+}
+
+template <typename T, typename IdType, template <typename, typename> class Entry, typename Callback, size_t TABLE_SIZE>
+Entry<T, IdType>* HashTableHost<T, IdType, Entry, Callback, TABLE_SIZE>::lookup_only(const T& query, uintptr_t hash) {
+  HashEntry* entry = (HashEntry*)this->bucket(index_for(hash));
+  while (entry != NULL) {
+    if (entry->hash() == hash && _callback->equals(query, hash, entry)) {
+      return entry;
+    }
+    entry = (HashEntry*)entry->next();
+  }
+  return NULL;
+}
+
+template <typename T, typename IdType, template <typename, typename> class Entry, typename Callback, size_t TABLE_SIZE>
+template <typename Functor>
+void HashTableHost<T, IdType, Entry, Callback, TABLE_SIZE>::iterate_value(Functor& f) {
+  for (size_t i = 0; i < this->table_size(); ++i) {
+    const HashEntry* entry = (const HashEntry*)this->bucket(i);
+    while (entry != NULL) {
+      if (!f(entry->value())) {
+        break;
+      }
+      entry = (HashEntry*)entry->next();
+    }
+  }
+}
+
+template <typename T, typename IdType, template <typename, typename> class Entry, typename Callback, size_t TABLE_SIZE>
+template <typename Functor>
+void HashTableHost<T, IdType, Entry, Callback, TABLE_SIZE>::iterate_entry(Functor& f) {
+  for (size_t i = 0; i < this->table_size(); ++i) {
+    const HashEntry* entry = (const HashEntry*)this->bucket(i);
+    while (entry != NULL) {
+      if (!f(entry)) {
+        break;
+      }
+      entry = (const HashEntry*)entry->next();
+    }
+  }
+}
+
+template <typename T, typename IdType, template <typename, typename> class Entry, typename Callback, size_t TABLE_SIZE>
+void HashTableHost<T, IdType, Entry, Callback, TABLE_SIZE>::clear_entries() {
+  for (size_t i = 0; i < this->table_size(); ++i) {
+    HashEntry** bucket = (HashEntry**)this->bucket_addr(i);
+    HashEntry* entry = *bucket;
+    while (entry != NULL) {
+      HashEntry* entry_to_remove = entry;
+      entry = (HashEntry*)entry->next();
+      this->free_entry(entry_to_remove);
+    }
+    *bucket = NULL;
+  }
+  assert(this->number_of_entries() == 0, "should have removed all entries");
+}
+
+template <typename T, typename IdType, template <typename, typename> class Entry, typename Callback, size_t TABLE_SIZE>
+Entry<T, IdType>* HashTableHost<T, IdType, Entry, Callback, TABLE_SIZE>::new_entry(const T& data, uintptr_t hash) {
+  assert(sizeof(HashEntry) == this->entry_size(), "invariant");
+  HashEntry* const entry = (HashEntry*) NEW_C_HEAP_ARRAY2(char, this->entry_size(), mtTracing, CURRENT_PC);
+  entry->init();
+  entry->set_hash(hash);
+  entry->set_value(data);
+  entry->set_next(NULL);
+  assert(0 == entry->id(), "invariant");
+  return entry;
+}
+
+#endif // SHARE_VM_JFR_UTILITIES_JFRHASHTABLE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/utilities/jfrIterator.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_UTILITIES_JFRLISTITERATOR_HPP
+#define SHARE_VM_JFR_UTILITIES_JFRLISTITERATOR_HPP
+
+#include "memory/allocation.hpp"
+
+enum jfr_iter_direction {
+  forward = 1,
+  backward
+};
+
+template <typename Node>
+class StopOnNullCondition : public AllStatic {
+ public:
+  static bool has_next(const Node* node) {
+    return node != NULL;
+  }
+};
+
+template <typename List, template <typename> class ContinuationPredicate>
+class Navigator {
+ public:
+  typedef typename List::Node Node;
+  typedef jfr_iter_direction Direction;
+  Navigator(List& list, Direction direction) :
+    _list(list), _node(direction == forward ? list.head() : list.tail()), _direction(direction) {}
+  bool has_next() const {
+    return ContinuationPredicate<Node>::has_next(_node);
+  }
+
+  bool direction_forward() const {
+    return _direction == forward;
+  }
+
+  Node* next() const {
+    assert(_node != NULL, "invariant");
+    Node* temp = _node;
+    _node = direction_forward() ? (Node*)_node->next() : (Node*)_node->prev();
+    return temp;
+  }
+
+  void set_direction(Direction direction) {
+    _direction = direction;
+  }
+
+  void reset(Direction direction) {
+    set_direction(direction);
+    _node = direction_forward() ? _list.head() : _list.tail();
+  }
+
+ private:
+  List& _list;
+  mutable Node* _node;
+  Direction _direction;
+};
+
+template <typename List>
+class NavigatorStopOnNull : public Navigator<List, StopOnNullCondition> {
+ public:
+  NavigatorStopOnNull(List& list, jfr_iter_direction direction = forward) : Navigator<List, StopOnNullCondition>(list, direction) {}
+};
+
+template<typename List, template <typename> class Navigator, typename AP = StackObj>
+class IteratorHost : public AP {
+ private:
+  Navigator<List> _navigator;
+
+ public:
+  typedef typename List::Node Node;
+  typedef jfr_iter_direction Direction;
+  IteratorHost(List& list, Direction direction = forward) : AP(), _navigator(list, direction) {}
+  void reset(Direction direction = forward) { _navigator.reset(direction); }
+  bool has_next() const { return _navigator.has_next(); }
+  Node* next() const { return _navigator.next(); }
+  void set_direction(Direction direction) { _navigator.set_direction(direction); }
+};
+
+template<typename List, typename AP = StackObj>
+class StopOnNullIterator : public IteratorHost<List, NavigatorStopOnNull, AP> {
+ public:
+  StopOnNullIterator(List& list, jfr_iter_direction direction = forward) : IteratorHost<List, NavigatorStopOnNull, AP>(list, direction) {}
+};
+
+#endif // SHARE_VM_JFR_UTILITIES_JFRLISTITERATOR_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/utilities/jfrJavaLog.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/jni/jfrJavaSupport.hpp"
+#include "jfr/utilities/jfrJavaLog.hpp"
+#include "jfr/utilities/jfrLogTagSets.hpp"
+#include "logging/log.hpp"
+#include "logging/logConfiguration.hpp"
+#include "memory/resourceArea.hpp"
+#include "runtime/thread.inline.hpp"
+
+#define JFR_LOG_TAGS_CONCATED(T0, T1, T2, T3, T4, T5, ...)  \
+  T0 ## _ ## T1 ## _ ## T2 ## _ ## T3 ## _ ## T4 ## _ ## T5
+
+enum JfrLogTagSetType {
+#define JFR_LOG_TAG(...) \
+    EXPAND_VARARGS(JFR_LOG_TAGS_CONCATED(__VA_ARGS__, _NO_TAG, _NO_TAG, _NO_TAG, _NO_TAG, _NO_TAG, _NO_TAG)),
+
+    JFR_LOG_TAG_SET_LIST
+
+#undef JFR_LOG_TAG
+    JFR_LOG_TAG_SET_COUNT
+};
+
+struct jfrLogSubscriber
+{
+  jobject log_tag_enum_ref;
+  LogTagSet* log_tag_set;
+};
+
+static jfrLogSubscriber log_tag_sets[JFR_LOG_TAG_SET_COUNT];
+
+static void log_cfg_update(LogLevelType llt, JfrLogTagSetType jflt, TRAPS) {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
+  if (log_tag_sets[jflt].log_tag_enum_ref == NULL) {
+    return;
+  }
+  jobject lt = log_tag_sets[jflt].log_tag_enum_ref;
+  // set field tagSetLevel to llt value
+  JavaValue result(T_VOID);
+  JfrJavaArguments args(&result);
+  args.set_klass(JfrJavaSupport::klass(lt));
+  args.set_name("tagSetLevel", CHECK);
+  args.set_signature("I", CHECK);
+  args.set_receiver(JfrJavaSupport::resolve_non_null(lt));
+  args.push_int(llt);
+  JfrJavaSupport::set_field(&args, THREAD);
+}
+
+static LogLevelType highest_level(const LogTagSet& lts) {
+  for (size_t i = 0; i < LogLevel::Count; i++) {
+    if (lts.is_level((LogLevelType)i)) {
+      return (LogLevelType)i;
+    }
+  }
+  return LogLevel::Off;
+}
+
+static void log_config_change_internal(bool init, TRAPS) {
+  LogLevelType llt;
+  LogTagSet* lts;
+
+#define JFR_LOG_TAG(...) \
+  lts = &LogTagSetMapping<LOG_TAGS(__VA_ARGS__)>::tagset(); \
+  if (init) { \
+    JfrLogTagSetType tagSetType = \
+      EXPAND_VARARGS(JFR_LOG_TAGS_CONCATED(__VA_ARGS__, _NO_TAG, _NO_TAG, _NO_TAG, _NO_TAG, _NO_TAG, _NO_TAG)); \
+    assert(NULL == log_tag_sets[tagSetType].log_tag_set, "Init JFR LogTagSets twice"); \
+    log_tag_sets[tagSetType].log_tag_set = lts; \
+  } \
+  llt = highest_level(*lts); \
+  log_cfg_update(llt, \
+  EXPAND_VARARGS(JFR_LOG_TAGS_CONCATED(__VA_ARGS__, _NO_TAG, _NO_TAG, _NO_TAG, _NO_TAG, _NO_TAG, _NO_TAG)), THREAD);
+  JFR_LOG_TAG_SET_LIST
+#undef JFR_LOG_TAG
+}
+
+static void log_config_change() {
+  Thread* t = Thread::current();
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(t));
+  log_config_change_internal(false, t);
+}
+
+void JfrJavaLog::subscribe_log_level(jobject log_tag, jint id, TRAPS) {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
+  static bool subscribed_updates = true;
+  assert(id < JFR_LOG_TAG_SET_COUNT,
+    "LogTag id, java and native not in synch, %d < %d", id, JFR_LOG_TAG_SET_COUNT);
+  assert(NULL == log_tag_sets[id].log_tag_enum_ref, "Subscribing twice");
+  log_tag_sets[id].log_tag_enum_ref = JfrJavaSupport::global_jni_handle(log_tag, THREAD);
+  if (subscribed_updates) {
+    LogConfiguration::register_update_listener(&log_config_change);
+    log_config_change_internal(true, THREAD);
+    subscribed_updates = false;
+  } else {
+    log_config_change_internal(false, THREAD);
+  }
+}
+
+void JfrJavaLog::log(jint tag_set, jint level, jstring message, TRAPS) {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
+  if (message == NULL) {
+    return;
+  }
+  if (level < (jint)LogLevel::First || level > (jint)LogLevel::Last) {
+    JfrJavaSupport::throw_illegal_argument_exception("LogLevel passed is outside valid range", THREAD);
+    return;
+  }
+  if (tag_set < 0 || tag_set >= (jint)JFR_LOG_TAG_SET_COUNT) {
+    JfrJavaSupport::throw_illegal_argument_exception("LogTagSet id is outside valid range", THREAD);
+    return;
+  }
+  ResourceMark rm(THREAD);
+  const char* const s = JfrJavaSupport::c_str(message, CHECK);
+  assert(s != NULL, "invariant");
+  assert(log_tag_sets[tag_set].log_tag_set != NULL, "LogTagSet is not init");
+  log_tag_sets[tag_set].log_tag_set->log((LogLevelType)level, s);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/utilities/jfrJavaLog.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_UTILITIES_JFRJAVALOG_HPP
+#define SHARE_VM_JFR_UTILITIES_JFRJAVALOG_HPP
+
+#include "memory/allocation.hpp"
+#include "utilities/exceptions.hpp"
+
+/*
+ * A thin two-way "bridge" allowing our Java components to interface with Unified Logging (UL)
+ *
+ * Java can "subscribe" to be notified about UL configuration changes.
+ * On such a configuration change, if applicable, the passed in LogTag enum instance
+ * will be updated to reflect a new LogLevel.
+ *
+ * Log messages originating in Java are forwarded to UL for output.
+ *
+ */
+
+class JfrJavaLog : public AllStatic {
+ public:
+  static void subscribe_log_level(jobject log_tag, jint id, TRAPS);
+  static void log(jint tag_set, jint level, jstring message, TRAPS);
+};
+
+#endif // SHARE_VM_JFR_UTILITIES_JFRJAVALOG_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/utilities/jfrLogTagSets.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_UTILITIES_JFRLOGTAGSETS_HPP
+#define SHARE_VM_JFR_UTILITIES_JFRLOGTAGSETS_HPP
+
+#include "logging/logTag.hpp"
+
+/*
+ * This file declares the Unified Logging (UL) tag sets for JFR.
+ *
+ * The JFR_LOG_TAG_SET_LIST macro will generate an enum
+ * (zero-based ordinals) for these log tag sets.
+ * Log tag set order (enum ordinals) is important
+ * because we need to mirror this order in Java.
+ *
+ * Adding a new log tag set:
+ *
+ * 1. Ensure the log tag primitive which you attempt to use in your new log tag set is defined to UL.
+ *    UL log tags are defined in logging/logTag.hpp.
+ * 2. Append the new log tag set to the JFR_LOG_TAG_SET_LIST macro in this file.
+ * 3. Make the corresponding change in Java by updating jdk.jfr.internal.LogTag.java
+ *    to add another enum instance with a corresponding tag id ordinal.
+ *
+ */
+
+#define JFR_LOG_TAG_SET_LIST \
+  JFR_LOG_TAG(jfr) \
+  JFR_LOG_TAG(jfr, system) \
+  JFR_LOG_TAG(jfr, system, event) \
+  JFR_LOG_TAG(jfr, system, setting) \
+  JFR_LOG_TAG(jfr, system, bytecode) \
+  JFR_LOG_TAG(jfr, system, parser) \
+  JFR_LOG_TAG(jfr, system, metadata) \
+  JFR_LOG_TAG(jfr, metadata) \
+  JFR_LOG_TAG(jfr, event) \
+  JFR_LOG_TAG(jfr, setting)
+  /* NEW TAGS, DONT FORGET TO UPDATE JAVA SIDE */
+
+#endif // SHARE_VM_JFR_UTILITIES_JFRLOGTAGSETS_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/utilities/jfrRefCountPointer.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_UTILITIES_JFRREFCOUNTPOINTER_HPP
+#define SHARE_VM_JFR_UTILITIES_JFRREFCOUNTPOINTER_HPP
+
+#include "jfr/utilities/jfrAllocation.hpp"
+#include "runtime/atomic.hpp"
+
+template <typename T>
+class RefCountHandle {
+  template <typename, typename>
+  friend class RefCountPointer;
+ private:
+  const T* _ptr;
+
+  RefCountHandle(const T* ptr) : _ptr(ptr) {
+    assert(_ptr != NULL, "invariant");
+    _ptr->add_ref();
+  }
+
+ public:
+  RefCountHandle() : _ptr(NULL) {}
+
+  RefCountHandle(const RefCountHandle<T>& rhs) : _ptr(rhs._ptr) {
+    if (_ptr != NULL) {
+      _ptr->add_ref();
+    }
+  }
+
+  ~RefCountHandle() {
+    if (_ptr != NULL) {
+      const T* temp = _ptr;
+      _ptr = NULL;
+      temp->remove_ref();
+    }
+  }
+
+  // The copy-and-swap idiom upholds reference counting semantics
+  void operator=(RefCountHandle<T> rhs) {
+    const T* temp = rhs._ptr;
+    rhs._ptr = _ptr;
+    _ptr = temp;
+  }
+
+  bool operator==(const RefCountHandle<T>& rhs) const {
+    return _ptr == rhs._ptr;
+  }
+
+  bool operator!=(const RefCountHandle<T>& rhs) const {
+    return !operator==(rhs);
+  }
+
+  bool valid() const {
+    return _ptr != NULL;
+  }
+
+  const T & operator->() const {
+    return *_ptr;
+  }
+
+  T& operator->() {
+    return *const_cast<T*>(_ptr);
+  }
+};
+
+class MultiThreadedRefCounter {
+ private:
+  mutable volatile int _refs;
+ public:
+  MultiThreadedRefCounter() : _refs(0) {}
+
+  void inc() const {
+    Atomic::add(1, &_refs);
+  }
+
+  bool dec() const {
+    return 0 == Atomic::add((-1), &_refs);
+  }
+
+  int current() const {
+   return _refs;
+  }
+};
+
+template <typename T, typename RefCountImpl = MultiThreadedRefCounter>
+class RefCountPointer : public JfrCHeapObj {
+  template <typename>
+  friend class RefCountHandle;
+  typedef RefCountHandle<RefCountPointer<T, RefCountImpl> > RefHandle;
+ private:
+  const T* _ptr;
+  mutable RefCountImpl _refs;
+
+  // disallow multiple copies
+  RefCountPointer(const RefCountPointer<T, RefCountImpl>& rhs);
+  void operator=(const RefCountPointer<T, RefCountImpl>& rhs);
+
+  ~RefCountPointer() {
+    assert(_refs.current() == 0, "invariant");
+    delete const_cast<T*>(_ptr);
+  }
+
+  void add_ref() const {
+    _refs.inc();
+  }
+
+  void remove_ref() const {
+    if (_refs.dec()) {
+      delete this;
+    }
+  }
+
+  RefCountPointer(const T* ptr) : _ptr(ptr), _refs() {
+    assert(_ptr != NULL, "invariant");
+  }
+
+ public:
+  const T* operator->() const {
+    return _ptr;
+  }
+
+  T* operator->() {
+    return const_cast<T*>(_ptr);
+  }
+
+  static RefHandle make(const T* ptr) {
+    assert(ptr != NULL, "invariant");
+    return RefHandle(new RefCountPointer<T, RefCountImpl>(ptr));
+  }
+};
+
+#endif // SHARE_VM_JFR_UTILITIES_JFRREFCOUNTPOINTER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/utilities/jfrResourceManager.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_UTILITIES_RESOURCEMANAGER_HPP
+#define SHARE_VM_JFR_UTILITIES_RESOURCEMANAGER_HPP
+
+#include "memory/allocation.hpp"
+
+template <class T>
+class ResourceManager : public StackObj {
+ private:
+  T* const _resource;
+ public:
+  ResourceManager(T* resource) : _resource(resource) {}
+  ~ResourceManager() {
+    if (_resource != NULL) {
+      delete _resource;
+    }
+  }
+  operator T*() { return _resource; }
+  T* operator->() { return _resource; }
+};
+
+template <class T>
+class ResourceArrayManager : public StackObj {
+ private:
+  T* const _resource_array;
+ public:
+  ResourceArrayManager(T* resource_array) : _resource_array(resource_array) {}
+  ~ResourceArrayManager() {
+    if (_resource_array != NULL) {
+      delete [] _resource_array;
+    }
+  }
+  operator T*() { return _resource_array; }
+  T* operator->() const { return _resource_array; }
+};
+
+#endif // SHARE_VM_JFR_UTILITIES_RESOURCEMANAGER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/utilities/jfrSpinlockHelper.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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 SHARE_VM_JFR_UTILITIES_JFRSPINLOCKHELPER_HPP
+#define SHARE_VM_JFR_UTILITIES_JFRSPINLOCKHELPER_HPP
+
+#include "runtime/thread.hpp"
+
+// this utility could be useful for non cx8 platforms
+
+class JfrSpinlockHelper {
+ private:
+  volatile int* const _lock;
+
+ public:
+  JfrSpinlockHelper(volatile int* lock) : _lock(lock) {
+    Thread::SpinAcquire(_lock, NULL);
+  }
+
+  JfrSpinlockHelper(volatile int* const lock, const char* name) : _lock(lock) {
+    Thread::SpinAcquire(_lock, name);
+  }
+
+  ~JfrSpinlockHelper() {
+    Thread::SpinRelease(_lock);
+  }
+};
+
+#endif // SHARE_VM_JFR_UTILITIES_JFRSPINLOCKHELPER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/utilities/jfrTime.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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 "jfr/utilities/jfrTime.hpp"
+#include "runtime/os.hpp"
+#ifdef X86
+#include "rdtsc_x86.hpp"
+#endif
+
+#include OS_HEADER_INLINE(os)
+
+bool JfrTime::_ft_enabled = false;
+
+bool JfrTime::initialize() {
+  static bool initialized = false;
+  if (!initialized) {
+#ifdef X86
+    _ft_enabled = Rdtsc::initialize();
+#else
+    _ft_enabled = false;
+#endif
+    initialized = true;
+  }
+  return initialized;
+}
+
+bool JfrTime::is_ft_supported() {
+#ifdef X86
+  return Rdtsc::is_supported();
+#else
+  return false;
+#endif
+}
+
+
+const void* JfrTime::time_function() {
+#ifdef X86
+  return _ft_enabled ? (const void*)Rdtsc::elapsed_counter : (const void*)os::elapsed_counter;
+#else
+  return (const void*)os::elapsed_counter;
+#endif
+}
+
+jlong JfrTime::frequency() {
+#ifdef X86
+  return _ft_enabled ? Rdtsc::frequency() : os::elapsed_frequency();
+#else
+  return os::elapsed_frequency();
+#endif
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/utilities/jfrTime.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_UTILITIES_JFRTIME_HPP
+#define SHARE_VM_JFR_UTILITIES_JFRTIME_HPP
+
+#include "utilities/ticks.hpp"
+
+typedef TimeInstant<CounterRepresentation, FastUnorderedElapsedCounterSource> JfrTicks;
+typedef TimeInterval<CounterRepresentation, FastUnorderedElapsedCounterSource> JfrTickspan;
+
+class JfrTime {
+ private:
+  static bool _ft_enabled;
+ public:
+  static bool initialize();
+  static bool is_ft_enabled() { return _ft_enabled; }
+  static bool is_ft_supported();
+  static jlong frequency();
+  static const void* time_function();
+};
+
+#endif // SHARE_VM_JFR_UTILITIES_JFRTIME_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/utilities/jfrTimeConverter.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/utilities/jfrTimeConverter.hpp"
+#include "jfr/utilities/jfrTime.hpp"
+#include "runtime/os.hpp"
+
+#include OS_HEADER_INLINE(os)
+
+static double ft_counter_to_nanos_factor = .0;
+static double nanos_to_ft_counter_factor = .0;
+static double os_counter_to_nanos_factor = .0;
+static double nanos_to_os_counter_factor = .0;
+
+const double JfrTimeConverter::NANOS_PER_SEC      = 1000000000.0;
+const double JfrTimeConverter::NANOS_PER_MILLISEC = 1000000.0;
+const double JfrTimeConverter::NANOS_PER_MICROSEC = 1000.0;
+
+static bool initialized = false;
+
+void JfrTimeConverter::initialize() {
+  if (!initialized) {
+    nanos_to_os_counter_factor = (double)os::elapsed_frequency() / NANOS_PER_SEC;
+    assert(nanos_to_os_counter_factor != .0, "error in conversion!");
+    os_counter_to_nanos_factor = (double)1.0 / nanos_to_os_counter_factor;
+    assert(os_counter_to_nanos_factor != .0, "error in conversion!");
+    if (JfrTime::is_ft_enabled()) {
+      nanos_to_ft_counter_factor = (double)JfrTime::frequency() / NANOS_PER_SEC;
+      assert(nanos_to_ft_counter_factor != .0, "error in conversion!");
+      ft_counter_to_nanos_factor = (double)1.0 / nanos_to_ft_counter_factor;
+      assert(ft_counter_to_nanos_factor != .0, "error in conversion!");
+    }
+    initialized = true;
+  }
+}
+
+double JfrTimeConverter::counter_to_nano_multiplier(bool is_os_time) {
+  if (!initialized) {
+    initialize();
+  }
+  return JfrTime::is_ft_enabled() && !is_os_time ? ft_counter_to_nanos_factor : os_counter_to_nanos_factor;
+}
+
+double JfrTimeConverter::nano_to_counter_multiplier(bool is_os_time) {
+  if (!initialized) {
+    initialize();
+  }
+  return JfrTime::is_ft_enabled() && !is_os_time ? nanos_to_ft_counter_factor : nanos_to_os_counter_factor;
+}
+
+double JfrTimeConverter::counter_to_nanos_internal(jlong c, bool is_os_time) {
+  return (double)c * counter_to_nano_multiplier(is_os_time);
+}
+
+double JfrTimeConverter::counter_to_millis_internal(jlong c, bool is_os_time) {
+  return (counter_to_nanos_internal(c, is_os_time) / NANOS_PER_MILLISEC);
+}
+
+jlong JfrTimeConverter::counter_to_nanos(jlong c, bool is_os_time) {
+  return (jlong)counter_to_nanos_internal(c, is_os_time);
+}
+
+jlong JfrTimeConverter::counter_to_millis(jlong c, bool is_os_time) {
+  return (jlong)counter_to_millis_internal(c, is_os_time);
+}
+
+jlong JfrTimeConverter::nanos_to_countertime(jlong nanos, bool as_os_time) {
+  return nanos <= 0 ? 0 : (jlong)((double)nanos * nano_to_counter_multiplier(as_os_time));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/utilities/jfrTimeConverter.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_UTILITIES_JFRTIMECONVERTER_HPP
+#define SHARE_VM_JFR_UTILITIES_JFRTIMECONVERTER_HPP
+
+#include "memory/allocation.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+class JfrTimeConverter : AllStatic {
+ private:
+  static double counter_to_nano_multiplier(bool is_os_time = false);
+  static double counter_to_nanos_internal(jlong c, bool is_os_time = false);
+  static double counter_to_millis_internal(jlong c, bool is_os_time = false);
+  static void initialize();
+
+ public:
+  static const double NANOS_PER_SEC;
+  static const double NANOS_PER_MILLISEC;
+  static const double NANOS_PER_MICROSEC;
+
+  // factors
+  static double nano_to_counter_multiplier(bool is_os_time = false);
+  // ticks to nanos
+  static jlong counter_to_nanos(jlong c, bool is_os_time = false);
+  // ticks to millis
+  static jlong counter_to_millis(jlong c, bool is_os_time = false);
+  // nanos to ticks
+  static jlong nanos_to_countertime(jlong c, bool as_os_time = false);
+};
+
+#endif // SHARE_VM_JFR_UTILITIES_JFRTIMECONVERTER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/utilities/jfrTryLock.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_UTILITIES_JFRTRYLOCK_HPP
+#define SHARE_VM_JFR_UTILITIES_JFRTRYLOCK_HPP
+
+#include "runtime/atomic.hpp"
+#include "runtime/orderAccess.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "utilities/debug.hpp"
+
+class JfrTryLock {
+ private:
+  volatile int* const _lock;
+  bool _has_lock;
+
+ public:
+  JfrTryLock(volatile int* lock) : _lock(lock), _has_lock(Atomic::cmpxchg(1, lock, 0) == 0) {}
+
+  ~JfrTryLock() {
+    if (_has_lock) {
+      OrderAccess::fence();
+      *_lock = 0;
+    }
+  }
+
+  bool has_lock() const {
+    return _has_lock;
+  }
+};
+
+class JfrMonitorTryLock : public StackObj {
+ private:
+  Monitor* _lock;
+  bool _acquired;
+
+ public:
+  JfrMonitorTryLock(Monitor* lock) : _lock(lock), _acquired(lock->try_lock()) {}
+
+  ~JfrMonitorTryLock() {
+    if (_acquired) {
+      assert(_lock->owned_by_self(), "invariant");
+      _lock->unlock();
+    }
+  }
+
+  bool acquired() const {
+    return _acquired;
+  }
+
+};
+
+#endif // SHARE_VM_JFR_UTILITIES_JFRTRYLOCK_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/utilities/jfrTypes.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_UTILITIES_JFRTYPES_HPP
+#define SHARE_VM_JFR_UTILITIES_JFRTYPES_HPP
+
+#include "jfrfiles/jfrEventIds.hpp"
+#include "memory/allocation.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+typedef u8 traceid;
+typedef int fio_fd;
+const int invalid_fd = -1;
+const jlong invalid_offset = -1;
+
+enum EventStartTime {
+  UNTIMED,
+  TIMED
+};
+
+#endif // SHARE_VM_JFR_UTILITIES_JFRTYPES_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/writers/jfrBigEndianWriter.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_WRITERS_JFRBIGENDIANWRITER_HPP
+#define SHARE_VM_JFR_WRITERS_JFRBIGENDIANWRITER_HPP
+
+#include "jfr/writers/jfrEncoding.hpp"
+#include "jfr/writers/jfrMemoryWriterHost.inline.hpp"
+#include "jfr/writers/jfrStorageAdapter.hpp"
+#include "jfr/writers/jfrWriterHost.inline.hpp"
+
+typedef MemoryWriterHost<NoOwnershipAdapter, StackObj > MemoryWriter;
+typedef WriterHost<BigEndianEncoder, BigEndianEncoder, MemoryWriter> BigEndianWriterBase;
+
+class JfrBigEndianWriter : public BigEndianWriterBase {
+ public:
+  template <typename StorageType>
+  JfrBigEndianWriter(StorageType* storage, size_t size) : BigEndianWriterBase(storage, size + size_safety_cushion) {}
+};
+
+#endif // SHARE_VM_JFR_WRITERS_JFRBIGENDIANWRITER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/writers/jfrEncoders.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_WRITERS_JFRENCODERS_HPP
+#define SHARE_VM_JFR_WRITERS_JFRENCODERS_HPP
+
+#include "memory/allocation.hpp"
+#include "utilities/bytes.hpp"
+#include "utilities/debug.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+//
+// The Encoding policy prescribes a template
+// method taking a first parameter of type T.
+// This is the value to be encoded. The second
+// parameter is a memory address - where to write
+// the encoded value.
+// The encoder method(s) should return the
+// number of bytes encoded into that memory address.
+//
+// template <typename T>
+// size_t encoder(T value, u1* dest);
+//
+// The caller ensures the destination
+// address is not null and that T can be fitted
+// in encoded form.
+//
+
+// Encoding policy classes
+
+class BigEndianEncoderImpl {
+ public:
+  template <typename T>
+  static size_t encode(T value, u1* dest);
+
+  template <typename T>
+  static size_t encode(const T* src, size_t len, u1* dest);
+
+  template <typename T>
+  static size_t encode_padded(T value, u1* dest);
+
+  template <typename T>
+  static size_t encode_padded(const T* src, size_t len, u1* dest);
+
+};
+
+template <typename T>
+inline size_t BigEndianEncoderImpl::encode(T value, u1* dest) {
+  assert(dest != NULL, "invariant");
+  switch (sizeof(T)) {
+    case 1: {
+      ShouldNotReachHere();
+       return 0;
+     }
+     case 2: {
+       Bytes::put_Java_u2(dest, value);
+       return 2;
+     }
+     case 4: {
+       Bytes::put_Java_u4(dest, value);
+       return 4;
+     }
+     case 8: {
+       Bytes::put_Java_u8(dest, value);
+       return 8;
+     }
+  }
+  ShouldNotReachHere();
+  return 0;
+}
+
+template <typename T>
+inline size_t BigEndianEncoderImpl::encode(const T* src, size_t len, u1* dest) {
+  assert(dest != NULL, "invariant");
+  assert(len >= 1, "invariant");
+  if (1 == sizeof(T)) {
+    memcpy(dest, src, len);
+    return len;
+  }
+  size_t size = encode(*src, dest);
+  if (len > 1) {
+    for (size_t i = 1; i < len; ++i) {
+      size += encode(*(src + i), dest + size);
+    }
+  }
+  return size;
+}
+
+template <typename T>
+inline size_t BigEndianEncoderImpl::encode_padded(T value, u1* dest) {
+  return encode(value, dest);
+}
+
+template <typename T>
+inline size_t BigEndianEncoderImpl::encode_padded(const T* src, size_t len, u1* dest) {
+  assert(dest != NULL, "invariant");
+  assert(len >= 1, "invariant");
+  if (1 == sizeof(T)) {
+    memcpy(dest, src, len);
+    return len;
+  }
+  size_t size = encode_padded(*src, dest);
+  if (len > 1) {
+    for (size_t i = 1; i < len; ++i) {
+      size += encode_padded(*(src + i), dest + size);
+    }
+  }
+  return size;
+}
+
+
+// The Varint128 encoder implements encoding according to
+// msb(it) 128bit encoding (1 encode bit | 7 value bits),
+// using least significant byte order.
+//
+// Example (little endian platform):
+// Value: 25674
+// Binary: 00000000 0000000 01100100 01001010
+// Varint encoded (3 bytes):
+// Value: 13289473
+// Varint encoded: 11001010 11001000 00000001
+//
+
+class Varint128EncoderImpl {
+ private:
+  template <typename T>
+  static u8 to_u8(T value);
+
+ public:
+  template <typename T>
+  static size_t encode(T value, u1* dest);
+
+  template <typename T>
+  static size_t encode(const T* src, size_t len, u1* dest);
+
+  template <typename T>
+  static size_t encode_padded(T value, u1* dest);
+
+  template <typename T>
+  static size_t encode_padded(const T* src, size_t len, u1* dest);
+
+};
+
+template <typename T>
+inline u8 Varint128EncoderImpl::to_u8(T value) {
+  switch(sizeof(T)) {
+    case 1:
+     return static_cast<u8>(static_cast<u1>(value) & static_cast<u1>(0xff));
+    case 2:
+      return static_cast<u8>(static_cast<u2>(value) & static_cast<u2>(0xffff));
+    case 4:
+      return static_cast<u8>(static_cast<u4>(value) & static_cast<u4>(0xffffffff));
+    case 8:
+      return static_cast<u8>(value);
+    default:
+      fatal("unsupported type");
+  }
+  return 0;
+}
+
+static const u1 ext_bit = 0x80;
+#define GREATER_THAN_OR_EQUAL_TO_128(v) (((u8)(~(ext_bit - 1)) & (v)))
+#define LESS_THAN_128(v) !GREATER_THAN_OR_EQUAL_TO_128(v)
+
+template <typename T>
+inline size_t Varint128EncoderImpl::encode(T value, u1* dest) {
+  assert(dest != NULL, "invariant");
+
+  const u8 v = to_u8(value);
+
+  if (LESS_THAN_128(v)) {
+    *dest = static_cast<u1>(v); // set bit 0-6, no extension
+    return 1;
+  }
+  *dest = static_cast<u1>(v | ext_bit); // set bit 0-6, with extension
+  if (LESS_THAN_128(v >> 7)) {
+    *(dest + 1) = static_cast<u1>(v >> 7); // set bit 7-13, no extension
+    return 2;
+  }
+  *(dest + 1) = static_cast<u1>((v >> 7) | ext_bit); // set bit 7-13, with extension
+  if (LESS_THAN_128(v >> 14)) {
+    *(dest + 2) = static_cast<u1>(v >> 14); // set bit 14-20, no extension
+    return 3;
+  }
+  *(dest + 2) = static_cast<u1>((v >> 14) | ext_bit); // set bit 14-20, with extension
+  if (LESS_THAN_128(v >> 21)) {
+    *(dest + 3) = static_cast<u1>(v >> 21); // set bit 21-27, no extension
+    return 4;
+  }
+  *(dest + 3) = static_cast<u1>((v >> 21) | ext_bit); // set bit 21-27, with extension
+  if (LESS_THAN_128(v >> 28)) {
+    *(dest + 4) = static_cast<u1>(v >> 28); // set bit 28-34, no extension
+    return 5;
+  }
+  *(dest + 4) = static_cast<u1>((v >> 28) | ext_bit); // set bit 28-34, with extension
+  if (LESS_THAN_128(v >> 35)) {
+    *(dest + 5) = static_cast<u1>(v >> 35); // set bit 35-41, no extension
+    return 6;
+  }
+  *(dest + 5) = static_cast<u1>((v >> 35) | ext_bit); // set bit 35-41, with extension
+  if (LESS_THAN_128(v >> 42)) {
+    *(dest + 6) = static_cast<u1>(v >> 42); // set bit 42-48, no extension
+    return 7;
+  }
+  *(dest + 6) = static_cast<u1>((v >> 42) | ext_bit); // set bit 42-48, with extension
+  if (LESS_THAN_128(v >> 49)) {
+    *(dest + 7) = static_cast<u1>(v >> 49); // set bit 49-55, no extension
+    return 8;
+  }
+  *(dest + 7) = static_cast<u1>((v >> 49) | ext_bit); // set bit 49-55, with extension
+  // no need to extend since only 64 bits allowed.
+  *(dest + 8) = static_cast<u1>(v >> 56);  // set bit 56-63
+  return 9;
+}
+
+template <typename T>
+inline size_t Varint128EncoderImpl::encode(const T* src, size_t len, u1* dest) {
+  assert(dest != NULL, "invariant");
+  assert(len >= 1, "invariant");
+  size_t size = encode(*src, dest);
+  if (len > 1) {
+    for (size_t i = 1; i < len; ++i) {
+      size += encode(*(src + i), dest + size);
+    }
+  }
+  return size;
+}
+
+template <typename T>
+inline size_t Varint128EncoderImpl::encode_padded(T value, u1* dest) {
+  assert(dest != NULL, "invariant");
+  const u8 v = to_u8(value);
+  switch (sizeof(T)) {
+    case 1:
+      dest[0] = static_cast<u1>(v);
+      return 1;
+    case 2:
+      dest[0] = static_cast<u1>(v | 0x80);
+      dest[1] = static_cast<u1>(v >> 7);
+      return 2;
+    case 4:
+      dest[0] = static_cast<u1>(v | 0x80);
+      dest[1] = static_cast<u1>(v >> 7 | 0x80);
+      dest[2] = static_cast<u1>(v >> 14 | 0x80);
+      dest[3] = static_cast<u1>(v >> 21);
+      return 4;
+    case 8:
+      dest[0] = static_cast<u1>(v | 0x80);
+      dest[1] = static_cast<u1>(v >> 7 | 0x80);
+      dest[2] = static_cast<u1>(v >> 14 | 0x80);
+      dest[3] = static_cast<u1>(v >> 21 | 0x80);
+      dest[4] = static_cast<u1>(v >> 28 | 0x80);
+      dest[5] = static_cast<u1>(v >> 35 | 0x80);
+      dest[6] = static_cast<u1>(v >> 42 | 0x80);
+      dest[7] = static_cast<u1>(v >> 49);
+      return 8;
+    default:
+      ShouldNotReachHere();
+    }
+  return 0;
+}
+
+
+template <typename T>
+inline size_t Varint128EncoderImpl::encode_padded(const T* src, size_t len, u1* dest) {
+  assert(dest != NULL, "invariant");
+  assert(len >= 1, "invariant");
+  size_t size = encode_padded(*src, dest);
+  if (len > 1) {
+    for (size_t i = 1; i < len; ++i) {
+      size += encode_padded(*(src + i), dest + size);
+    }
+  }
+  return size;
+}
+
+#endif // SHARE_VM_JFR_WRITERS_JFRENCODERS_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/writers/jfrEncoding.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_WRITERS_JFRENCODING_HPP
+#define SHARE_VM_JFR_WRITERS_JFRENCODING_HPP
+
+#include "jfr/writers/jfrEncoders.hpp"
+#include "memory/allocation.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+enum JfrStringEncoding {
+  NULL_STRING = 0,
+  EMPTY_STRING,
+  STRING_CONSTANT,
+  UTF8,
+  UTF16,
+  LATIN1,
+  NOF_STRING_ENCODINGS
+};
+
+template <typename IntegerEncoder, typename BaseEncoder>
+class EncoderHost : public AllStatic {
+ public:
+  template <typename T>
+  static u1* be_write(T value, u1* pos) {
+    return be_write(&value, 1, pos);
+  }
+
+  template <typename T>
+  static u1* be_write(const T* value, size_t len, u1* pos) {
+    assert(value != NULL, "invariant");
+    assert(pos != NULL, "invariant");
+    assert(len > 0, "invariant");
+    return pos + BaseEncoder::encode(value, len, pos);
+  }
+
+  template <typename T>
+  static u1* write_padded(T value, u1* pos) {
+    assert(pos != NULL, "invariant");
+    return write_padded(&value, 1, pos);
+  }
+
+  template <typename T>
+  static u1* write_padded(const T* value, size_t len, u1* pos) {
+    assert(value != NULL, "invariant");
+    assert(pos != NULL, "invariant");
+    assert(len > 0, "invariant");
+    return pos + IntegerEncoder::encode_padded(value, len, pos);
+  }
+
+  template <typename T>
+  static u1* write(T value, u1* pos) {
+    return write(&value, 1, pos);
+  }
+
+  template <typename T>
+  static u1* write(const T* value, size_t len, u1* pos) {
+    assert(value != NULL, "invariant");
+    assert(pos != NULL, "invariant");
+    assert(len > 0, "invariant");
+    return pos + IntegerEncoder::encode(value, len, pos);
+  }
+
+  static u1* write(bool value, u1* pos) {
+    return be_write((u1)value, pos);
+  }
+
+  static u1* write(float value, u1* pos) {
+    return be_write(*(u4*)&(value), pos);
+  }
+
+  static u1* write(double value, u1* pos) {
+    return be_write(*(u8*)&(value), pos);
+  }
+
+  static u1* write(const char* value, u1* pos) {
+    u2 len = 0;
+    if (value != NULL) {
+      len = MIN2<u2>(max_jushort, (jushort)strlen(value));
+    }
+    pos = write(len, pos);
+    if (len > 0) {
+      pos = be_write(value, len, pos);
+    }
+    return pos;
+  }
+
+  static u1* write(char* value, u1* pos) {
+    return write(const_cast<const char*>(value), pos);
+  }
+};
+
+typedef EncoderHost<BigEndianEncoderImpl, BigEndianEncoderImpl> BigEndianEncoder;
+typedef EncoderHost<Varint128EncoderImpl, BigEndianEncoderImpl> CompressedIntegerEncoder;
+
+#endif // SHARE_VM_JFR_WRITERS_JFRENCODING_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/writers/jfrEventWriterHost.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_WRITERS_JFREVENTWRITERHOST_HPP
+#define SHARE_VM_JFR_WRITERS_JFREVENTWRITERHOST_HPP
+
+#include "jfr/writers/jfrWriterHost.inline.hpp"
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+class EventWriterHost : public WriterHost<BE, IE, WriterPolicyImpl> {
+ public:
+  template <typename StorageType>
+  EventWriterHost(StorageType* storage, Thread* thread);
+  EventWriterHost(Thread* thread);
+  void begin_write();
+  intptr_t end_write();
+  void begin_event_write();
+  intptr_t end_event_write();
+};
+
+template <typename BE, typename IE, typename WriterPolicyImpl >
+class StackEventWriterHost : public EventWriterHost<BE, IE, WriterPolicyImpl> {
+ public:
+  template <typename StorageType>
+  StackEventWriterHost(StorageType* storage, Thread* thread);
+  StackEventWriterHost(Thread* thread);
+  ~StackEventWriterHost();
+};
+
+#endif // SHARE_VM_JFR_WRITERS_JFREVENTWRITERHOST_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/writers/jfrEventWriterHost.inline.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_WRITERS_JFREVENTWRITERHOST_INLINE_HPP
+#define SHARE_VM_JFR_WRITERS_JFREVENTWRITERHOST_INLINE_HPP
+
+#include "jfr/writers/jfrEventWriterHost.hpp"
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+template <typename StorageType>
+inline EventWriterHost<BE, IE, WriterPolicyImpl>::
+EventWriterHost(StorageType* storage, Thread* thread) : WriterHost<BE, IE, WriterPolicyImpl>(storage, thread) {}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+inline EventWriterHost<BE, IE, WriterPolicyImpl>::EventWriterHost(Thread* thread) : WriterHost<BE, IE, WriterPolicyImpl>(thread) {
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+inline void EventWriterHost<BE, IE, WriterPolicyImpl>::begin_write() {
+  assert(this->is_valid(), "invariant");
+  assert(!this->is_acquired(), "calling begin with writer already in acquired state!");
+  this->acquire();
+  assert(this->used_offset() == 0, "invariant");
+  assert(this->is_acquired(), "invariant");
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+inline intptr_t EventWriterHost<BE, IE, WriterPolicyImpl>::end_write(void) {
+  assert(this->is_acquired(),
+    "state corruption, calling end with writer with non-acquired state!");
+  return this->is_valid() ? this->used_offset() : 0;
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+inline void EventWriterHost<BE, IE, WriterPolicyImpl>::begin_event_write() {
+  assert(this->is_valid(), "invariant");
+  assert(!this->is_acquired(), "calling begin with writer already in acquired state!");
+  this->begin_write();
+  this->reserve(sizeof(u4)); // reserve the event size slot
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+inline intptr_t EventWriterHost<BE, IE, WriterPolicyImpl>::end_event_write() {
+  assert(this->is_acquired(), "invariant");
+  if (!this->is_valid()) {
+    this->release();
+    return 0;
+  }
+  const u4 written = (u4)end_write();
+  if (written > sizeof(u4)) { // larger than header reserve
+    this->write_padded_at_offset(written, 0);
+    this->commit();
+  }
+  this->release();
+  assert(!this->is_acquired(), "invariant");
+  return written;
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+template <typename StorageType>
+inline StackEventWriterHost<BE, IE, WriterPolicyImpl>::
+StackEventWriterHost(StorageType* storage, Thread* thread) : EventWriterHost<BE, IE, WriterPolicyImpl>(storage, thread) {
+  this->begin_event_write();
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+inline StackEventWriterHost<BE, IE, WriterPolicyImpl>::StackEventWriterHost(Thread* thread) : EventWriterHost<BE, IE, WriterPolicyImpl>(thread) {
+  this->begin_event_write();
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+inline StackEventWriterHost<BE, IE, WriterPolicyImpl>::~StackEventWriterHost() {
+  this->end_event_write();
+}
+
+#endif // SHARE_VM_JFR_WRITERS_JFREVENTWRITERHOST_INLINE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/writers/jfrJavaEventWriter.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jni.h"
+#include "classfile/symbolTable.hpp"
+#include "classfile/systemDictionary.hpp"
+#include "classfile/vmSymbols.hpp"
+#include "jfr/jni/jfrJavaSupport.hpp"
+#include "jfr/recorder/storage/jfrStorage.hpp"
+#include "jfr/support/jfrThreadId.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
+#include "jfr/writers/jfrJavaEventWriter.hpp"
+#include "oops/instanceKlass.hpp"
+#include "oops/oop.inline.hpp"
+#include "runtime/fieldDescriptor.hpp"
+#include "runtime/handles.hpp"
+#include "runtime/jniHandles.inline.hpp"
+#include "runtime/thread.inline.hpp"
+
+static int start_pos_offset = invalid_offset;
+static int start_pos_address_offset = invalid_offset;
+static int current_pos_offset = invalid_offset;
+static int max_pos_offset = invalid_offset;
+static int max_event_size_offset = invalid_offset;
+static int notified_offset = invalid_offset;
+static int thread_id_offset = invalid_offset;
+static int valid_offset = invalid_offset;
+
+static bool find_field(InstanceKlass* ik,
+                       Symbol* name_symbol,
+                       Symbol* signature_symbol,
+                       fieldDescriptor* fd,
+                       bool is_static = false,
+                       bool allow_super = false) {
+  if (allow_super || is_static) {
+    return ik->find_field(name_symbol, signature_symbol, is_static, fd) != NULL;
+  } else {
+    return ik->find_local_field(name_symbol, signature_symbol, fd);
+  }
+}
+
+static void compute_offset(int &dest_offset,
+                           Klass* klass,
+                           Symbol* name_symbol,
+                           Symbol* signature_symbol,
+                           bool is_static = false, bool allow_super = false) {
+  fieldDescriptor fd;
+  InstanceKlass* ik = InstanceKlass::cast(klass);
+  if (!find_field(ik, name_symbol, signature_symbol, &fd, is_static, allow_super)) {
+    assert(false, "invariant");
+  }
+  dest_offset = fd.offset();
+}
+
+static bool setup_event_writer_offsets(TRAPS) {
+  const char class_name[] = "jdk/jfr/internal/EventWriter";
+  Symbol* const k_sym = SymbolTable::lookup(class_name, sizeof class_name - 1, CHECK_false);
+  assert(k_sym != NULL, "invariant");
+  Klass* klass = SystemDictionary::resolve_or_fail(k_sym, true, CHECK_false);
+  assert(klass != NULL, "invariant");
+
+  const char start_pos_name[] = "startPosition";
+  Symbol* const start_pos_sym = SymbolTable::lookup(start_pos_name, sizeof start_pos_name - 1, CHECK_false);
+  assert(start_pos_sym != NULL, "invariant");
+  assert(invalid_offset == start_pos_offset, "invariant");
+  compute_offset(start_pos_offset, klass, start_pos_sym, vmSymbols::long_signature());
+  assert(start_pos_offset != invalid_offset, "invariant");
+
+  const char start_pos_address_name[] = "startPositionAddress";
+  Symbol* const start_pos_address_sym = SymbolTable::lookup(start_pos_address_name, sizeof start_pos_address_name - 1, CHECK_false);
+  assert(start_pos_address_sym != NULL, "invariant");
+  assert(invalid_offset == start_pos_address_offset, "invariant");
+  compute_offset(start_pos_address_offset, klass, start_pos_address_sym, vmSymbols::long_signature());
+  assert(start_pos_address_offset != invalid_offset, "invariant");
+
+  const char event_pos_name[] = "currentPosition";
+  Symbol* const event_pos_sym = SymbolTable::lookup(event_pos_name, sizeof event_pos_name - 1, CHECK_false);
+  assert(event_pos_sym != NULL, "invariant");
+  assert(invalid_offset == current_pos_offset, "invariant");
+  compute_offset(current_pos_offset, klass, event_pos_sym,vmSymbols::long_signature());
+  assert(current_pos_offset != invalid_offset, "invariant");
+
+  const char max_pos_name[] = "maxPosition";
+  Symbol* const max_pos_sym = SymbolTable::lookup(max_pos_name, sizeof max_pos_name - 1, CHECK_false);
+  assert(max_pos_sym != NULL, "invariant");
+  assert(invalid_offset == max_pos_offset, "invariant");
+  compute_offset(max_pos_offset, klass, max_pos_sym, vmSymbols::long_signature());
+  assert(max_pos_offset != invalid_offset, "invariant");
+
+  const char max_event_size_name[] = "maxEventSize";
+  Symbol* const max_event_size_sym = SymbolTable::lookup(max_event_size_name, sizeof max_event_size_name - 1, CHECK_false);
+  assert (max_event_size_sym != NULL, "invariant");
+  assert(invalid_offset == max_event_size_offset, "invariant");
+  compute_offset(max_event_size_offset, klass, max_event_size_sym, vmSymbols::int_signature());
+  assert(max_event_size_offset != invalid_offset, "invariant");
+
+  const char notified_name[] = "notified";
+  Symbol* const notified_sym = SymbolTable::lookup(notified_name, sizeof notified_name - 1, CHECK_false);
+  assert (notified_sym != NULL, "invariant");
+  assert(invalid_offset == notified_offset, "invariant");
+  compute_offset(notified_offset, klass, notified_sym, vmSymbols::bool_signature());
+  assert(notified_offset != invalid_offset, "invariant");
+
+  const char valid_name[] = "valid";
+  Symbol* const valid_sym = SymbolTable::lookup(valid_name, sizeof valid_name - 1, CHECK_false);
+  assert (valid_sym != NULL, "invariant");
+  assert(invalid_offset == valid_offset, "invariant");
+  compute_offset(valid_offset, klass, valid_sym, vmSymbols::bool_signature());
+  assert(valid_offset != invalid_offset, "invariant");
+  return true;
+}
+
+bool JfrJavaEventWriter::initialize() {
+  static bool initialized = false;
+  if (!initialized) {
+    Thread* thread = Thread::current();
+    initialized = setup_event_writer_offsets(thread);
+  }
+  return initialized;
+}
+
+jboolean JfrJavaEventWriter::flush(jobject writer, jint used, jint requested, JavaThread* jt) {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt));
+  assert(writer != NULL, "invariant");
+  oop const w = JNIHandles::resolve_non_null(writer);
+  assert(w != NULL, "invariant");
+  JfrBuffer* const current = jt->jfr_thread_local()->java_buffer();
+  assert(current != NULL, "invariant");
+  JfrBuffer* const buffer = JfrStorage::flush(current, used, requested, false, jt);
+  assert(buffer != NULL, "invariant");
+  // "validity" is contextually defined here to mean
+  // that some memory location was provided that is
+  // large enough to accommodate the "requested size".
+  const bool is_valid = buffer->free_size() >= (size_t)(used + requested);
+  u1* const new_current_position = is_valid ? buffer->pos() + used : buffer->pos();
+  w->long_field_put(start_pos_offset, (jlong)buffer->pos());
+  w->long_field_put(current_pos_offset, (jlong)new_current_position);
+  // only update java writer if underlying memory changed
+  if (buffer != current) {
+    w->long_field_put(start_pos_address_offset, (jlong)buffer->pos_address());
+    w->long_field_put(max_pos_offset, (jlong)buffer->end());
+  }
+  if (!is_valid) {
+    // mark writer as invalid for this write attempt
+    w->release_bool_field_put(valid_offset, JNI_FALSE);
+    return JNI_FALSE;
+  }
+  // An exclusive use of a leased buffer is treated equivalent to
+  // holding a system resource. As such, it should be released as soon as possible.
+  // Returning true here signals that the thread will need to call flush again
+  // on EventWriter.endEvent() and that flush will return the lease.
+  return buffer->lease() ? JNI_TRUE : JNI_FALSE;
+}
+
+class JfrJavaEventWriterNotificationClosure : public ThreadClosure {
+ public:
+   void do_thread(Thread* t) {
+     if (t->is_Java_thread()) {
+       JfrJavaEventWriter::notify((JavaThread*)t);
+     }
+   }
+};
+
+void JfrJavaEventWriter::notify() {
+  assert(SafepointSynchronize::is_at_safepoint(), "invariant");
+  JfrJavaEventWriterNotificationClosure closure;
+  Threads::threads_do(&closure);
+}
+
+void JfrJavaEventWriter::notify(JavaThread* jt) {
+  assert(jt != NULL, "invariant");
+  assert(SafepointSynchronize::is_at_safepoint(), "invariant");
+  if (jt->jfr_thread_local()->has_java_event_writer()) {
+    oop buffer_writer = JNIHandles::resolve_non_null(jt->jfr_thread_local()->java_event_writer());
+    assert(buffer_writer != NULL, "invariant");
+    buffer_writer->release_bool_field_put(notified_offset, JNI_TRUE);
+  }
+}
+
+static jobject create_new_event_writer(JfrBuffer* buffer, TRAPS) {
+  assert(buffer != NULL, "invariant");
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
+  HandleMark hm(THREAD);
+  static const char klass[] = "jdk/jfr/internal/EventWriter";
+  static const char method[] = "<init>";
+  static const char signature[] = "(JJJJZ)V";
+  JavaValue result(T_OBJECT);
+  JfrJavaArguments args(&result, klass, method, signature, CHECK_NULL);
+  // parameters
+  args.push_long((jlong)buffer->pos());
+  args.push_long((jlong)buffer->end());
+  args.push_long((jlong)buffer->pos_address());
+  args.push_long((jlong)JFR_THREAD_ID(THREAD));
+  args.push_int((int)JNI_TRUE);
+  JfrJavaSupport::new_object_global_ref(&args, CHECK_NULL);
+  return result.get_jobject();
+}
+
+jobject JfrJavaEventWriter::event_writer(Thread* t) {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(t));
+  JfrThreadLocal* const tl = t->jfr_thread_local();
+  assert(tl->shelved_buffer() == NULL, "invariant");
+  return tl->java_event_writer();
+}
+
+jobject JfrJavaEventWriter::new_event_writer(TRAPS) {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
+  assert(event_writer(THREAD) == NULL, "invariant");
+  JfrThreadLocal* const tl = THREAD->jfr_thread_local();
+  assert(!tl->has_java_buffer(), "invariant");
+  JfrBuffer* const buffer = tl->java_buffer();
+  if (buffer == NULL) {
+    JfrJavaSupport::throw_out_of_memory_error("OOME for thread local buffer", THREAD);
+    return NULL;
+  }
+  jobject java_event_writer = create_new_event_writer(buffer, CHECK_NULL);
+  tl->set_java_event_writer(java_event_writer);
+  assert(tl->has_java_event_writer(), "invariant");
+  return java_event_writer;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/writers/jfrJavaEventWriter.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_WRITERS_JFRJAVAEVENTWRITER_HPP
+#define SHARE_VM_JFR_WRITERS_JFRJAVAEVENTWRITER_HPP
+
+#include "jni.h"
+#include "memory/allocation.hpp"
+
+class JavaThread;
+class Thread;
+
+class JfrJavaEventWriter : AllStatic {
+  friend class JfrCheckpointThreadClosure;
+  friend class JfrJavaEventWriterNotifyOperation;
+  friend class JfrJavaEventWriterNotificationClosure;
+ private:
+  static void notify(JavaThread* jt);
+
+ public:
+  static bool initialize();
+  static void notify();
+  static jobject event_writer(Thread* t);
+  static jobject new_event_writer(TRAPS);
+  static jboolean flush(jobject writer, jint used, jint requested, JavaThread* jt);
+};
+
+#endif // SHARE_VM_JFR_WRITERS_JFRJAVAEVENTWRITER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/writers/jfrMemoryWriterHost.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_WRITERS_JFRMEMORYWRITERHOST_HPP
+#define SHARE_VM_JFR_WRITERS_JFRMEMORYWRITERHOST_HPP
+
+#include "jfr/writers/jfrStorageHost.inline.hpp"
+
+#ifdef ASSERT
+class ExclusiveAccessAssert {
+ private:
+  bool _acquired;
+ public:
+  ExclusiveAccessAssert() : _acquired(false) {}
+  void acquire() { assert_non_acquired(); _acquired = true; }
+  void release() { assert_acquired(); _acquired = false; }
+  bool is_acquired() const { return _acquired; }
+  void assert_acquired() const { assert(_acquired, "Not acquired!"); }
+  void assert_non_acquired() const { assert(!_acquired, "Already acquired!"); }
+};
+#else
+ class ExclusiveAccessAssert {};
+#endif
+
+template <typename Adapter, typename AP, typename AccessAssert = ExclusiveAccessAssert>
+class MemoryWriterHost : public StorageHost<Adapter, AP> {
+  debug_only(AccessAssert _access;)
+ public:
+  typedef typename Adapter::StorageType StorageType;
+ protected:
+  void bytes(void* dest, const void* buf, size_t len);
+  MemoryWriterHost(StorageType* storage, Thread* thread);
+  MemoryWriterHost(StorageType* storage, size_t size);
+  MemoryWriterHost(Thread* thread);
+  debug_only(bool is_acquired() const;)
+ public:
+  void acquire();
+  void release();
+};
+
+template <typename Adapter, typename AP>
+class AcquireReleaseMemoryWriterHost : public MemoryWriterHost<Adapter, AP> {
+ public:
+  typedef typename Adapter::StorageType StorageType;
+  AcquireReleaseMemoryWriterHost(StorageType* storage, Thread* thread);
+  AcquireReleaseMemoryWriterHost(StorageType* storage, size_t size);
+  AcquireReleaseMemoryWriterHost(Thread* thread);
+  ~AcquireReleaseMemoryWriterHost();
+};
+
+#endif // SHARE_VM_JFR_WRITERS_JFRMEMORYWRITERHOST_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/writers/jfrMemoryWriterHost.inline.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_WRITERS_JFRMEMORYWRITERHOST_INLINE_HPP
+#define SHARE_VM_JFR_WRITERS_JFRMEMORYWRITERHOST_INLINE_HPP
+
+#include "jfr/writers/jfrMemoryWriterHost.hpp"
+
+template <typename Adapter, typename AP, typename AccessAssert>
+inline void MemoryWriterHost<Adapter, AP, AccessAssert>::bytes(void* dest, const void* buf, size_t len) {
+  assert(dest != NULL, "invariant");
+  memcpy(dest, buf, len); // no encoding
+  this->set_current_pos(len);
+}
+
+template <typename Adapter, typename AP, typename AccessAssert>
+inline MemoryWriterHost<Adapter, AP, AccessAssert>::MemoryWriterHost(typename Adapter::StorageType* storage, Thread* thread) :
+  StorageHost<Adapter, AP>(storage, thread) {
+}
+
+template <typename Adapter, typename AP, typename AccessAssert>
+inline MemoryWriterHost<Adapter, AP, AccessAssert>::MemoryWriterHost(typename Adapter::StorageType* storage, size_t size) :
+  StorageHost<Adapter, AP>(storage, size) {
+}
+
+template <typename Adapter, typename AP, typename AccessAssert>
+inline MemoryWriterHost<Adapter, AP, AccessAssert>::MemoryWriterHost(Thread* thread) :
+  StorageHost<Adapter, AP>(thread) {
+}
+
+template <typename Adapter, typename AP, typename AccessAssert>
+inline void MemoryWriterHost<Adapter, AP, AccessAssert>::acquire() {
+  debug_only(_access.acquire();)
+  if (!this->is_valid()) {
+    this->flush();
+  }
+  debug_only(is_acquired();)
+}
+
+template <typename Adapter, typename AP, typename AccessAssert>
+inline void MemoryWriterHost<Adapter, AP, AccessAssert>::release() {
+  debug_only(is_acquired();)
+  StorageHost<Adapter, AP>::release();
+  debug_only(_access.release();)
+}
+
+#ifdef ASSERT
+template <typename Adapter, typename AP, typename AccessAssert>
+inline bool MemoryWriterHost<Adapter, AP, AccessAssert>::is_acquired() const {
+  return _access.is_acquired();
+}
+#endif
+
+template <typename Adapter, typename AP>
+inline AcquireReleaseMemoryWriterHost<Adapter, AP>::AcquireReleaseMemoryWriterHost(typename Adapter::StorageType* storage, Thread* thread) :
+  MemoryWriterHost<Adapter, AP>(storage, thread) {
+  this->acquire();
+}
+
+template <typename Adapter, typename AP>
+inline AcquireReleaseMemoryWriterHost<Adapter, AP>::AcquireReleaseMemoryWriterHost(typename Adapter::StorageType* storage, size_t size) :
+  MemoryWriterHost<Adapter, AP>(storage, size) {
+  this->acquire();
+}
+
+template <typename Adapter, typename AP>
+inline AcquireReleaseMemoryWriterHost<Adapter, AP>::AcquireReleaseMemoryWriterHost(Thread* thread) :
+  MemoryWriterHost<Adapter, AP>(thread) {
+  this->acquire();
+}
+
+template <typename Adapter, typename AP>
+inline AcquireReleaseMemoryWriterHost<Adapter, AP>::~AcquireReleaseMemoryWriterHost() {
+  assert(this->is_acquired(), "invariant");
+  this->release();
+}
+
+#endif // SHARE_VM_JFR_WRITERS_JFRMEMORYWRITERHOST_INLINE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/writers/jfrNativeEventWriter.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_WRITERS_JFRNATIVEEVENTWRITER_HPP
+#define SHARE_VM_JFR_WRITERS_JFRNATIVEEVENTWRITER_HPP
+
+#include "jfr/support/jfrFlush.hpp"
+#include "jfr/writers/jfrEncoding.hpp"
+#include "jfr/writers/jfrEventWriterHost.inline.hpp"
+#include "jfr/writers/jfrMemoryWriterHost.inline.hpp"
+#include "jfr/writers/jfrStorageAdapter.hpp"
+
+typedef Adapter<JfrFlush> JfrNativeEventAdapter;
+typedef MemoryWriterHost<JfrNativeEventAdapter, StackObj> JfrNativeEventWriterImpl;
+typedef StackEventWriterHost<BigEndianEncoder, CompressedIntegerEncoder, JfrNativeEventWriterImpl> JfrNativeEventWriter;
+
+#endif // SHARE_VM_JFR_WRITERS_JFRNATIVEEVENTWRITER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/writers/jfrPosition.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_WRITERS_JFRPOSITION_HPP
+#define SHARE_VM_JFR_WRITERS_JFRPOSITION_HPP
+
+#include "utilities/debug.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+template <typename AP> // AllocationPolicy
+class Position : public AP {
+ private:
+  const u1* _start_pos; // logical start
+  u1* _current_pos;
+  const u1* _end_pos;
+
+ protected:
+  const u1* start_pos() const;
+  void set_start_pos(const u1* position);
+  u1* current_pos();
+  void set_current_pos(const u1* new_position);
+  void set_current_pos(size_t size);
+  const u1* end_pos() const;
+  void set_end_pos(const u1* position);
+  Position(const u1* start_pos, size_t size);
+  Position();
+
+ public:
+  size_t available_size() const;
+  intptr_t used_offset() const;
+  intptr_t current_offset() const;
+  size_t used_size() const;
+  void reset();
+};
+
+#endif // SHARE_VM_JFR_WRITERS_JFRPOSITION_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/writers/jfrPosition.inline.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_WRITERS_JFRPOSITION_INLINE_HPP
+#define SHARE_VM_JFR_WRITERS_JFRPOSITION_INLINE_HPP
+
+#include "jfr/writers/jfrPosition.hpp"
+
+template <typename AP>
+inline const u1* Position<AP>::start_pos() const {
+  return _start_pos;
+}
+
+template <typename AP>
+inline void Position<AP>::set_start_pos(const u1* position) {
+  _start_pos = position;
+}
+
+template <typename AP>
+inline u1* Position<AP>::current_pos() {
+  return _current_pos;
+}
+
+template <typename AP>
+inline void Position<AP>::set_current_pos(const u1* new_position) {
+  _current_pos = const_cast<u1*>(new_position);
+}
+
+template <typename AP>
+inline void Position<AP>::set_current_pos(size_t size) {
+  _current_pos += size;
+}
+
+template <typename AP>
+inline const u1* Position<AP>::end_pos() const {
+  return _end_pos;
+}
+
+template <typename AP>
+inline void Position<AP>::set_end_pos(const u1* position) {
+  _end_pos = position;
+}
+
+template <typename AP>
+inline Position<AP>::Position(const u1* start_pos, size_t size) :
+  AP(),
+  _start_pos(start_pos),
+  _current_pos(const_cast<u1*>(start_pos)),
+  _end_pos(start_pos + size) {
+}
+
+template <typename AP>
+inline Position<AP>::Position() : _start_pos(NULL), _current_pos(NULL), _end_pos(NULL) {
+}
+
+template <typename AP>
+inline size_t Position<AP>::available_size() const {
+  return _end_pos - _current_pos;
+}
+
+template <typename AP>
+inline intptr_t Position<AP>::used_offset() const {
+  return _current_pos - _start_pos;
+}
+
+template <typename AP>
+inline intptr_t Position<AP>::current_offset() const {
+  return this->used_offset();
+}
+
+template <typename AP>
+inline size_t Position<AP>::used_size() const {
+  return (size_t)used_offset();
+}
+
+template <typename AP>
+inline void Position<AP>::reset() {
+  set_current_pos(_start_pos);
+}
+
+#endif // SHARE_VM_JFR_WRITERS_JFRPOSITION_INLINE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/writers/jfrStorageAdapter.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_WRITERS_JFRSTORAGEADAPTER_HPP
+#define SHARE_VM_JFR_WRITERS_JFRSTORAGEADAPTER_HPP
+
+#include "jfr/utilities/jfrAllocation.hpp"
+
+class Thread;
+
+//
+// The adapters present writers with a uniform interface over storage.
+//
+// Adapter policy
+//
+// StorageType* storage();
+// const u1* start() const;
+// const u1* pos();
+// const u1* end() const;
+// void commit(u1* position);
+// bool flush(size_t used, size_t requested);
+// void release();
+//
+
+template <typename Flush>
+class Adapter {
+ public:
+  typedef typename Flush::Type StorageType;
+  Adapter(StorageType* storage, Thread* thread) : _storage(storage), _thread(thread) {}
+  Adapter(Thread* thread) : _storage(NULL), _thread(thread) {}
+
+  void set_storage(StorageType* storage) {
+    _storage = storage;
+  }
+
+  StorageType* storage() {
+    return _storage;
+  }
+
+  const u1* start() const {
+    assert(_storage != NULL, "invariant");
+    return _storage->start();
+  }
+
+  u1* pos() {
+    assert(_storage != NULL, "invariant");
+    return _storage->pos();
+  }
+
+  const u1* end() const {
+    assert(_storage != NULL, "invariant");
+    return _storage->end();
+  }
+
+  void commit(u1* position) {
+    assert(_storage != NULL, "invariant");
+    _storage->set_pos(position);
+  }
+
+  bool flush(size_t used, size_t requested) {
+    assert(_thread != NULL, "invariant");
+    Flush f(_storage, used, requested, _thread);
+    _storage = f.result();
+    return _storage != NULL;
+  }
+
+  void release() {
+    if (_storage != NULL && _storage->lease()) {
+      // This flush call will return the lease
+      // of a temporary storage area.
+      // Since the requested size is 0,
+      // the flush implementation will accomodate
+      // that 'size' request in the
+      // original thread local storage,
+      // by implication restoring the original
+      // in the process of returning a lease.
+      flush(0, 0);
+    }
+  }
+
+ private:
+  StorageType* _storage;
+  Thread* _thread;
+};
+
+template <size_t DEFAULT_SIZE = K>
+class MallocAdapter {
+ private:
+  u1* _start;
+  u1* _pos;
+  u1* _end;
+  size_t _initial_size;
+  bool _has_ownership;
+
+  bool allocate(size_t size);
+  void deallocate();
+
+ public:
+  typedef u1 StorageType;
+  MallocAdapter(u1* storage, Thread* thread);
+  MallocAdapter(u1* storage, size_t size);
+  MallocAdapter(Thread* thread);
+  ~MallocAdapter();
+
+  StorageType* storage() { return _start; }
+  const u1* start() const { return _start; }
+  u1* pos() { return _pos; }
+  void commit(u1* position) { _pos = position; }
+  const u1* end() const { return _end; }
+  void release() {}
+  bool flush(size_t used, size_t requested);
+};
+
+template <size_t DEFAULT_SIZE>
+MallocAdapter<DEFAULT_SIZE>::MallocAdapter(u1* storage, size_t size) :
+  _start(storage),
+  _pos(storage),
+  _end(storage + size),
+  _initial_size(size),
+  _has_ownership(false) {
+}
+
+template <size_t DEFAULT_SIZE>
+MallocAdapter<DEFAULT_SIZE> ::MallocAdapter(u1* storage, Thread* thread) :
+  _start(storage),
+  _pos(storage),
+  _end(storage),
+  _initial_size(0),
+  _has_ownership(false) {
+}
+
+template <size_t DEFAULT_SIZE>
+MallocAdapter<DEFAULT_SIZE>::MallocAdapter(Thread* thread) :
+  _start(NULL),
+  _pos(NULL),
+  _end(NULL),
+  _initial_size(DEFAULT_SIZE),
+  _has_ownership(true) {
+  allocate(DEFAULT_SIZE);
+}
+
+template <size_t DEFAULT_SIZE>
+MallocAdapter<DEFAULT_SIZE>::~MallocAdapter() {
+  if (_has_ownership) {
+    deallocate();
+  }
+}
+
+template <size_t DEFAULT_SIZE>
+bool MallocAdapter<DEFAULT_SIZE>::allocate(size_t size) {
+  if (NULL == _start) {
+    _start = JfrCHeapObj::new_array<u1>(size);
+    if (_start) {
+      _pos = _start;
+      _end = _start + size;
+      _initial_size = size;
+    }
+  }
+  return _start != NULL;
+}
+
+template <size_t DEFAULT_SIZE>
+void MallocAdapter<DEFAULT_SIZE>::deallocate() {
+  if (_start != NULL) {
+    JfrCHeapObj::free(_start, (size_t)(_end - _start));
+  }
+}
+
+template <size_t DEFAULT_SIZE>
+bool MallocAdapter<DEFAULT_SIZE>::flush(size_t used, size_t requested) {
+  if (!_has_ownership) {
+    // can't just realloc a storage that we don't own
+    return false;
+  }
+  assert(_start != NULL, "invariant");
+  assert(used <= (size_t)(_end - _pos), "invariant");
+  assert(_pos + used <= _end, "invariant");
+  const size_t previous_storage_size = _end - _start;
+  const size_t new_storage_size = used + requested + (previous_storage_size * 2);
+  u1* const new_storage = JfrCHeapObj::new_array<u1>(new_storage_size);
+  if (!new_storage) {
+    return false;
+  }
+  const size_t previous_pos_offset = _pos - _start;
+  // migrate in-flight data
+  memcpy(new_storage, _start, previous_pos_offset + used);
+  JfrCHeapObj::free(_start, previous_storage_size);
+  _start = new_storage;
+  _pos = _start + previous_pos_offset;
+  _end = _start + new_storage_size;
+  return true;
+}
+
+class NoOwnershipAdapter {
+ private:
+  u1* _start;
+  u1* _pos;
+  u1* _end;
+  size_t _size;
+
+ public:
+  typedef u1 StorageType;
+  NoOwnershipAdapter(u1* storage, size_t size) : _start(storage), _pos(storage), _end(storage + size), _size(size) {}
+  NoOwnershipAdapter(u1* storage, Thread* thread) : _start(storage), _pos(storage), _end(storage), _size(0) {
+    ShouldNotCallThis();
+  }
+  NoOwnershipAdapter(Thread* thread) : _start(NULL), _pos(NULL), _end(NULL), _size(0) {
+    ShouldNotCallThis();
+  }
+  StorageType* storage() { return _start; }
+  const u1* start() const { return _start; }
+  u1* pos() { return _pos; }
+  void commit(u1* position) { _pos = position; }
+  const u1* end() const { return _end; }
+  void release() {}
+  bool flush(size_t used, size_t requested) {
+    // don't flush/expand a buffer that is not our own
+    return false;
+  }
+};
+
+#endif // SHARE_VM_JFR_WRITERS_JFRSTORAGEADAPTER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/writers/jfrStorageHost.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_WRITERS_JFRSTORAGEHOST_HPP
+#define SHARE_VM_JFR_WRITERS_JFRSTORAGEHOST_HPP
+
+#include "jfr/writers/jfrPosition.inline.hpp"
+
+template <typename Adapter, typename AP> // Adapter and AllocationPolicy
+class StorageHost : public Position<AP> {
+ public:
+  typedef typename Adapter::StorageType StorageType;
+ private:
+  Adapter _adapter;
+
+ protected:
+  void bind();
+  void soft_reset();
+  void hard_reset();
+  void cancel();
+  bool is_backed();
+  bool accommodate(size_t used, size_t requested);
+  void commit();
+  void release();
+  StorageHost(StorageType* storage, Thread* thread);
+  StorageHost(StorageType* storage, size_t size);
+  StorageHost(Thread* thread);
+
+ public:
+  StorageType* storage();
+  bool is_valid() const;
+  void set_storage(StorageType* storage);
+  void flush();
+  void seek(intptr_t offset);
+};
+
+#endif // SHARE_VM_JFR_WRITERS_JFRSTORAGEHOST_HPP
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/writers/jfrStorageHost.inline.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_WRITERS_JFRSTORAGEHOST_INLINE_HPP
+#define SHARE_VM_JFR_WRITERS_JFRSTORAGEHOST_INLINE_HPP
+
+#include "jfr/writers/jfrStorageHost.hpp"
+
+template <typename Adapter, typename AP>
+inline void StorageHost<Adapter, AP>::bind() {
+  if (is_backed()) {
+    this->hard_reset();
+    assert(is_valid(), "invariant");
+    return;
+  }
+  this->set_start_pos(NULL);
+  this->set_current_pos((const u1*)NULL);
+  this->set_end_pos(NULL);
+}
+
+template <typename Adapter, typename AP>
+inline void StorageHost<Adapter, AP>::soft_reset() {
+  this->set_start_pos(this->current_pos());
+}
+
+template <typename Adapter, typename AP>
+inline void StorageHost<Adapter, AP>::hard_reset() {
+  this->set_start_pos(_adapter.pos());
+  this->set_current_pos(_adapter.pos());
+  this->set_end_pos(_adapter.end());
+}
+
+template <typename Adapter, typename AP>
+inline void StorageHost<Adapter, AP>::cancel() {
+  this->set_end_pos(NULL);
+}
+
+template <typename Adapter, typename AP>
+inline bool StorageHost<Adapter, AP>::is_backed() {
+  return _adapter.storage() != NULL;
+}
+
+template <typename Adapter, typename AP>
+inline bool StorageHost<Adapter, AP>::accommodate(size_t used, size_t requested) {
+  if (!_adapter.flush(used, requested)) {
+    this->cancel();
+    return false;
+  }
+  assert(is_backed(), "invariant");
+  this->hard_reset();
+  this->set_current_pos(used);
+  return true;
+}
+
+template <typename Adapter, typename AP>
+inline void StorageHost<Adapter, AP>::commit() {
+  if (this->is_valid()) {
+    assert(_adapter.pos() == this->start_pos(), "invariant");
+    assert(_adapter.end() == this->end_pos(), "invariant");
+    u1* new_position = this->current_pos();
+    _adapter.commit(new_position);
+    this->set_start_pos(new_position);
+  }
+}
+
+template <typename Adapter, typename AP>
+inline void StorageHost<Adapter, AP>::release() {
+  _adapter.release();
+}
+
+template <typename Adapter, typename AP>
+inline StorageHost<Adapter, AP>::StorageHost(typename Adapter::StorageType* storage, Thread* thread) : Position<AP>(), _adapter(storage, thread) {
+  bind();
+}
+
+template <typename Adapter, typename AP>
+inline StorageHost<Adapter, AP>::StorageHost(typename Adapter::StorageType* storage, size_t size) : Position<AP>(), _adapter(storage, size) {
+  bind();
+}
+
+template <typename Adapter, typename AP>
+inline StorageHost<Adapter, AP>::StorageHost(Thread* thread) : Position<AP>(), _adapter(thread) {
+  bind();
+}
+
+template <typename Adapter, typename AP>
+inline bool StorageHost<Adapter, AP>::is_valid() const {
+  return this->end_pos() != NULL;
+}
+
+template <typename Adapter, typename AP>
+inline typename Adapter::StorageType* StorageHost<Adapter, AP>::storage() {
+  return _adapter.storage();
+}
+
+template <typename Adapter, typename AP>
+inline void StorageHost<Adapter, AP>::set_storage(typename Adapter::StorageType* storage) {
+  _adapter.set_storage(storage);
+  bind();
+}
+
+template <typename Adapter, typename AP>
+inline void StorageHost<Adapter, AP>::flush() {
+  this->accommodate(this->is_valid() ? this->used_size() : 0, 0);
+}
+
+template <typename Adapter, typename AP>
+inline void StorageHost<Adapter, AP>::seek(intptr_t offset) {
+  if (this->is_valid()) {
+    assert(offset >= 0, "negative offsets not supported");
+    assert(this->start_pos() + offset <= this->end_pos(), "invariant");
+    assert(this->start_pos() + offset >= this->start_pos(), "invariant");
+    this->set_current_pos(this->start_pos() + offset);
+  }
+}
+
+#endif // SHARE_VM_JFR_WRITERS_JFRSTORAGEHOST_INLINE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/writers/jfrStreamWriterHost.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_WRITERS_JFRSTREAMWRITERHOST_HPP
+#define SHARE_VM_JFR_WRITERS_JFRSTREAMWRITERHOST_HPP
+
+#include "jfr/utilities/jfrTypes.hpp"
+#include "jfr/writers/jfrMemoryWriterHost.inline.hpp"
+
+template <typename Adapter, typename AP> // Adapter and AllocationPolicy
+class StreamWriterHost : public MemoryWriterHost<Adapter, AP> {
+ public:
+  typedef typename Adapter::StorageType StorageType;
+ private:
+  intptr_t _stream_pos;
+  fio_fd _fd;
+  intptr_t current_stream_position() const;
+
+ protected:
+  StreamWriterHost(StorageType* storage, Thread* thread);
+  StreamWriterHost(StorageType* storage, size_t size);
+  StreamWriterHost(Thread* thread);
+  bool accommodate(size_t used, size_t requested);
+  void bytes(void* dest, const void* src, size_t len);
+  void flush(size_t size);
+  bool has_valid_fd() const;
+
+ public:
+  intptr_t current_offset() const;
+  void seek(intptr_t offset);
+  void flush();
+  void write_unbuffered(const void* src, size_t len);
+  bool is_valid() const;
+  void close_fd();
+  void reset(fio_fd fd);
+};
+
+#endif // SHARE_VM_JFR_WRITERS_JFRSTREAMWRITERHOST_HPP
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/writers/jfrStreamWriterHost.inline.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_WRITERS_JFRSTREAMWRITERHOST_INLINE_HPP
+#define SHARE_VM_JFR_WRITERS_JFRSTREAMWRITERHOST_INLINE_HPP
+
+#include "jfr/writers/jfrStreamWriterHost.hpp"
+#include "runtime/os.hpp"
+
+template <typename Adapter, typename AP>
+StreamWriterHost<Adapter, AP>::StreamWriterHost(typename Adapter::StorageType* storage, Thread* thread) :
+  MemoryWriterHost<Adapter, AP>(storage, thread), _stream_pos(0), _fd(invalid_fd) {
+}
+
+template <typename Adapter, typename AP>
+StreamWriterHost<Adapter, AP>::StreamWriterHost(typename Adapter::StorageType* storage, size_t size) :
+  MemoryWriterHost<Adapter, AP>(storage, size), _stream_pos(0), _fd(invalid_fd) {
+}
+
+template <typename Adapter, typename AP>
+StreamWriterHost<Adapter, AP>::StreamWriterHost(Thread* thread) :
+  MemoryWriterHost<Adapter, AP>(thread), _stream_pos(0), _fd(invalid_fd) {
+}
+
+template <typename Adapter, typename AP>
+inline intptr_t StreamWriterHost<Adapter, AP>::current_stream_position() const {
+  return this->used_offset() + _stream_pos;
+}
+
+template <typename Adapter, typename AP>
+inline bool StreamWriterHost<Adapter, AP>::accommodate(size_t used, size_t requested) {
+  if (used > 0) {
+    this->flush(used);
+  }
+  assert(this->used_size() == 0, "invariant");
+  if (this->available_size() >= requested) {
+    return true;
+  }
+  return StorageHost<Adapter, AP>::accommodate(0, requested);
+}
+
+template <typename Adapter, typename AP>
+inline void StreamWriterHost<Adapter, AP>::bytes(void* dest, const void* buf, size_t len) {
+  if (len > this->available_size()) {
+    this->write_unbuffered(buf, len);
+    return;
+  }
+  MemoryWriterHost<Adapter, AP>::bytes(dest, buf, len);
+}
+
+template <typename Adapter, typename AP>
+inline void StreamWriterHost<Adapter, AP>::flush(size_t size) {
+  assert(size > 0, "invariant");
+  assert(this->is_valid(), "invariant");
+  _stream_pos += os::write(_fd, this->start_pos(), (int)size);
+  StorageHost<Adapter, AP>::reset();
+  assert(0 == this->used_offset(), "invariant");
+}
+
+template <typename Adapter, typename AP>
+inline bool StreamWriterHost<Adapter, AP>::has_valid_fd() const {
+  return invalid_fd != _fd;
+}
+
+template <typename Adapter, typename AP>
+inline intptr_t StreamWriterHost<Adapter, AP>::current_offset() const {
+  return current_stream_position();
+}
+
+template <typename Adapter, typename AP>
+void StreamWriterHost<Adapter, AP>::seek(intptr_t offset) {
+  this->flush();
+  assert(0 == this->used_offset(), "can only seek from beginning");
+  _stream_pos = os::seek_to_file_offset(_fd, offset);
+}
+
+template <typename Adapter, typename AP>
+void StreamWriterHost<Adapter, AP>::flush() {
+  if (this->is_valid()) {
+    const size_t used = this->used_size();
+    if (used > 0) {
+      this->flush(used);
+    }
+  }
+}
+
+template <typename Adapter, typename AP>
+void StreamWriterHost<Adapter, AP>::write_unbuffered(const void* buf, size_t len) {
+  this->flush();
+  assert(0 == this->used_offset(), "can only seek from beginning");
+  while (len > 0) {
+    const int n = MIN2<int>((int)len, INT_MAX);
+    _stream_pos += os::write(_fd, buf, n);
+    len -= n;
+  }
+}
+
+template <typename Adapter, typename AP>
+inline bool StreamWriterHost<Adapter, AP>::is_valid() const {
+  return has_valid_fd();
+}
+
+template <typename Adapter, typename AP>
+inline void StreamWriterHost<Adapter, AP>::close_fd() {
+  assert(this->has_valid_fd(), "closing invalid fd!");
+  os::close(_fd);
+  _fd = invalid_fd;
+}
+
+template <typename Adapter, typename AP>
+inline void StreamWriterHost<Adapter, AP>::reset(fio_fd fd) {
+  assert(!this->has_valid_fd(), "invariant");
+  _fd = fd;
+  _stream_pos = 0;
+  this->hard_reset();
+}
+
+#endif // SHARE_VM_JFR_WRITERS_JFRSTREAMWRITERHOST_INLINE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/writers/jfrWriterHost.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_WRITERS_JFRWRITERHOST_HPP
+#define SHARE_VM_JFR_WRITERS_JFRWRITERHOST_HPP
+
+#include "jni.h"
+#include "utilities/globalDefinitions.hpp"
+#include "jfr/utilities/jfrTime.hpp"
+
+class ClassLoaderData;
+class Klass;
+class Method;
+class ModuleEntry;
+class PackageEntry;
+class Symbol;
+class Thread;
+
+// BE == Base Encoder
+// IE == Integer Encoder
+template <typename BE, typename IE, typename WriterPolicyImpl >
+class WriterHost : public WriterPolicyImpl {
+ private:
+  const bool _compressed_integers;
+
+  template <typename T>
+  void write_padded(T value);
+  template <typename T>
+  void write_padded(const T* value, size_t len);
+  template <typename T>
+  u1* write_padded(const T* value, size_t len, u1* pos);
+  template <typename T>
+  void write(const T* value, size_t len);
+  template <typename T>
+  u1* write(const T* value, size_t len, u1* pos);
+  void write_utf8(const char* value);
+  void write_utf16(const jchar* value, jint len);
+
+ protected:
+  template <typename T>
+  void be_write(T value);
+  template <typename T>
+  void be_write(const T* value, size_t len);
+  template <typename StorageType>
+  WriterHost(StorageType* storage, Thread* thread);
+  template <typename StorageType>
+  WriterHost(StorageType* storage, size_t size);
+  WriterHost(Thread* thread);
+  u1* ensure_size(size_t requested_size);
+
+ public:
+  template <typename T>
+  void write(T value);
+  void write(bool value);
+  void write(float value);
+  void write(double value);
+  void write(const char* value);
+  void write(char* value);
+  void write(jstring value);
+  void write(const ClassLoaderData* cld);
+  void write(const Klass* klass);
+  void write(const Method* method);
+  void write(const ModuleEntry* module);
+  void write(const PackageEntry* package);
+  void write(const Symbol* symbol);
+  void write(const Ticks& time);
+  void write(const Tickspan& time);
+  void write(const JfrTicks& time);
+  void write(const JfrTickspan& time);
+  void bytes(const void* buf, size_t len);
+  void write_utf8_u2_len(const char* value);
+  template <typename T>
+  void write_padded_at_offset(T value, intptr_t offset);
+  template <typename T>
+  void write_at_offset(T value, intptr_t offset);
+  template <typename T>
+  void write_be_at_offset(T value, intptr_t offset);
+  intptr_t reserve(size_t size);
+};
+
+#endif // SHARE_VM_JFR_WRITERS_JFRWRITERHOST_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/writers/jfrWriterHost.inline.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_WRITERS_JFRWRITERHOST_INLINE_HPP
+#define SHARE_VM_JFR_WRITERS_JFRWRITERHOST_INLINE_HPP
+
+#include "classfile/javaClasses.hpp"
+#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
+#include "jfr/recorder/service/jfrOptionSet.hpp"
+#include "jfr/writers/jfrEncoding.hpp"
+#include "jfr/writers/jfrWriterHost.hpp"
+#include "memory/resourceArea.hpp"
+#include "oops/oop.hpp"
+#include "oops/symbol.hpp"
+#include "oops/typeArrayOop.inline.hpp"
+
+inline bool compressed_integers() {
+  static const bool comp_integers = JfrOptionSet::compressed_integers();
+  return comp_integers;
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl >
+template <typename T>
+inline void WriterHost<BE, IE, WriterPolicyImpl>::write_padded(T value) {
+  write_padded(&value, 1);
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl >
+template <typename T>
+inline void WriterHost<BE, IE, WriterPolicyImpl>::write_padded(const T* value, size_t len) {
+  assert(value != NULL, "invariant");
+  assert(len > 0, "invariant");
+  u1* const pos = ensure_size(sizeof(T) * len);
+  if (pos) {
+    this->set_current_pos(write_padded(value, len, pos));
+  }
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl >
+template <typename T>
+inline u1* WriterHost<BE, IE, WriterPolicyImpl>::write_padded(const T* value, size_t len, u1* pos) {
+  assert(value != NULL, "invariant");
+  assert(len > 0, "invariant");
+  assert(pos != NULL, "invariant");
+  return _compressed_integers ? IE::write_padded(value, len, pos) : BE::write_padded(value, len, pos);
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl >
+template <typename T>
+inline void WriterHost<BE, IE, WriterPolicyImpl>::write(const T* value, size_t len) {
+  assert(value != NULL, "invariant");
+  assert(len > 0, "invariant");
+  u1* const pos = ensure_size(sizeof(T) * len);
+  if (pos) {
+    this->set_current_pos(write(value, len, pos));
+  }
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl >
+template <typename T>
+inline u1* WriterHost<BE, IE, WriterPolicyImpl>::write(const T* value, size_t len, u1* pos) {
+  assert(value != NULL, "invariant");
+  assert(len > 0, "invariant");
+  assert(pos != NULL, "invariant");
+  return _compressed_integers ? IE::write(value, len, pos) : BE::write(value, len, pos);
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+void WriterHost<BE, IE, WriterPolicyImpl>::write_utf8(const char* value) {
+  if (NULL == value) {
+    // only write encoding byte indicating NULL string
+    write<u1>(NULL_STRING);
+    return;
+  }
+  write<u1>(UTF8); // designate encoding
+  const jint len = MIN2<jint>(max_jint, (jint)strlen(value));
+  write(len);
+  if (len > 0) {
+    be_write(value, len);
+  }
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+void WriterHost<BE, IE, WriterPolicyImpl>::write_utf16(const jchar* value, jint len) {
+  assert(value != NULL, "invariant");
+  write((u1)UTF16); // designate encoding
+  write(len);
+  if (len > 0) {
+    write(value, len);
+  }
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl >
+template <typename T>
+inline void WriterHost<BE, IE, WriterPolicyImpl>::be_write(T value) {
+  u1* const pos = ensure_size(sizeof(T));
+  if (pos) {
+    this->set_current_pos(BE::be_write(&value, 1, pos));
+  }
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl >
+template <typename T>
+inline void WriterHost<BE, IE, WriterPolicyImpl>::be_write(const T* value, size_t len) {
+  assert(value != NULL, "invariant");
+  assert(len > 0, "invariant");
+  u1* const pos = ensure_size(sizeof(T) * len);
+  if (pos) {
+    this->set_current_pos(BE::be_write(value, len, pos));
+  }
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl >
+template <typename StorageType>
+inline WriterHost<BE, IE, WriterPolicyImpl>::WriterHost(StorageType* storage, Thread* thread) :
+  WriterPolicyImpl(storage, thread),
+  _compressed_integers(compressed_integers()) {
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl >
+template <typename StorageType>
+inline WriterHost<BE, IE, WriterPolicyImpl>::WriterHost(StorageType* storage, size_t size) :
+  WriterPolicyImpl(storage, size),
+  _compressed_integers(compressed_integers()) {
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl >
+inline WriterHost<BE, IE, WriterPolicyImpl>::WriterHost(Thread* thread) :
+  WriterPolicyImpl(thread),
+  _compressed_integers(compressed_integers()) {
+}
+
+// Extra size added as a safety cushion when dimensioning memory.
+// With varint encoding, the worst case is
+// associated with writing negative values.
+// For example, writing a negative s1 (-1)
+// will encode as 0xff 0x0f (2 bytes).
+// In this example, the sizeof(T) == 1 and length == 1,
+// but the implementation will need to dimension
+// 2 bytes for the encoding.
+// Hopefully, negative values should be relatively rare.
+static const size_t size_safety_cushion = 1;
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+inline u1* WriterHost<BE, IE, WriterPolicyImpl>::ensure_size(size_t requested) {
+  if (!this->is_valid()) {
+    // cancelled
+    return NULL;
+  }
+  if (this->available_size() < requested + size_safety_cushion) {
+    if (!this->accommodate(this->used_size(), requested + size_safety_cushion)) {
+      this->cancel();
+      return NULL;
+    }
+  }
+  assert(requested + size_safety_cushion <= this->available_size(), "invariant");
+  return this->current_pos();
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+template <typename T>
+inline void WriterHost<BE, IE, WriterPolicyImpl>::write(T value) {
+  write(&value, 1);
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+inline void WriterHost<BE, IE, WriterPolicyImpl>::write(bool value) {
+  be_write((u1)value);
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+inline void WriterHost<BE, IE, WriterPolicyImpl>::write(float value) {
+  be_write(*(u4*)&(value));
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+inline void WriterHost<BE, IE, WriterPolicyImpl>::write(double value) {
+  be_write(*(uintptr_t*)&(value));
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+inline void WriterHost<BE, IE, WriterPolicyImpl>::write(const char* value) {
+  // UTF-8, max_jint len
+  write_utf8(value);
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+inline void WriterHost<BE, IE, WriterPolicyImpl>::write(char* value) {
+  write(const_cast<const char*>(value));
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+inline void WriterHost<BE, IE, WriterPolicyImpl>::write(jstring string) {
+  if (string == NULL) {
+    write<u1>(NULL_STRING);
+    return;
+  }
+  const oop string_oop = JNIHandles::resolve_external_guard(string);
+  assert(string_oop != NULL, "invariant");
+  const size_t length = (size_t)java_lang_String::length(string_oop);
+  if (0 == length) {
+    write<u1>(EMPTY_STRING);
+    return;
+  }
+  const bool is_latin1_encoded = java_lang_String::is_latin1(string_oop);
+  const typeArrayOop value = java_lang_String::value(string_oop);
+  assert(value != NULL, "invariant");
+  if (is_latin1_encoded) {
+    write<u1>(LATIN1);
+    write<u4>((u4)length);
+    be_write(value->byte_at_addr(0), length);
+  } else {
+    write<u1>(UTF16);
+    write<u4>((u4)length);
+    write(value->char_at_addr(0), length);
+  }
+}
+
+template <typename Writer, typename T>
+inline void tag_write(Writer* w, const T* t) {
+  assert(w != NULL, "invariant");
+  const traceid id = t == NULL ? 0 : JfrTraceId::use(t);
+  w->write(id);
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+void WriterHost<BE, IE, WriterPolicyImpl>::write(const ClassLoaderData* cld) {
+  tag_write(this, cld);
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+void WriterHost<BE, IE, WriterPolicyImpl>::write(const Klass* klass) {
+  tag_write(this, klass);
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+void WriterHost<BE, IE, WriterPolicyImpl>::write(const Method* method) {
+  tag_write(this, method);
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+void WriterHost<BE, IE, WriterPolicyImpl>::write(const ModuleEntry* module) {
+  tag_write(this, module);
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+void WriterHost<BE, IE, WriterPolicyImpl>::write(const PackageEntry* package) {
+  tag_write(this, package);
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+void WriterHost<BE, IE, WriterPolicyImpl>::write(const Symbol* symbol) {
+  ResourceMark rm;
+  write_utf8(symbol != NULL ? symbol->as_C_string() : NULL);
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+void WriterHost<BE, IE, WriterPolicyImpl>::write(const Ticks& time) {
+  write((uintptr_t)JfrTime::is_ft_enabled() ? time.ft_value() : time.value());
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+void WriterHost<BE, IE, WriterPolicyImpl>::write(const Tickspan& time) {
+  write((uintptr_t)JfrTime::is_ft_enabled() ? time.ft_value() : time.value());
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+void WriterHost<BE, IE, WriterPolicyImpl>::write(const JfrTicks& time) {
+  write((uintptr_t)time.value());
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+void WriterHost<BE, IE, WriterPolicyImpl>::write(const JfrTickspan& time) {
+  write((uintptr_t)time.value());
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+void WriterHost<BE, IE, WriterPolicyImpl>::bytes(const void* buf, size_t len) {
+  u1* const pos = this->ensure_size(len);
+  if (pos != NULL) {
+    WriterPolicyImpl::bytes(pos, buf, len); // WriterPolicyImpl responsible for position update
+  }
+}
+
+// UTF-8 for use with classfile/bytecodes
+template <typename BE, typename IE, typename WriterPolicyImpl>
+inline void WriterHost<BE, IE, WriterPolicyImpl>::write_utf8_u2_len(const char* value) {
+  u2 len = 0;
+  if (value != NULL) {
+    len = MIN2<u2>(max_jushort, (u2)strlen(value));
+  }
+  write(len);
+  if (len > 0) {
+    be_write(value, len);
+  }
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+inline intptr_t WriterHost<BE, IE, WriterPolicyImpl>::reserve(size_t size) {
+  if (ensure_size(size) != NULL) {
+    intptr_t reserved_offset = this->current_offset();
+    this->set_current_pos(size);
+    return reserved_offset;
+  }
+  this->cancel();
+  return 0;
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+template <typename T>
+inline void WriterHost<BE, IE, WriterPolicyImpl>::write_padded_at_offset(T value, intptr_t offset) {
+  if (this->is_valid()) {
+    const intptr_t current = this->current_offset();
+    this->seek(offset);
+    write_padded(value);
+    this->seek(current); // restore
+  }
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+template <typename T>
+inline void WriterHost<BE, IE, WriterPolicyImpl>::write_at_offset(T value, intptr_t offset) {
+  if (this->is_valid()) {
+    const intptr_t current = this->current_offset();
+    this->seek(offset);
+    write(value);
+    this->seek(current); // restore
+  }
+}
+
+template <typename BE, typename IE, typename WriterPolicyImpl>
+template <typename T>
+inline void WriterHost<BE, IE, WriterPolicyImpl>::write_be_at_offset(T value, intptr_t offset) {
+  if (this->is_valid()) {
+    const intptr_t current = this->current_offset();
+    this->seek(offset);
+    be_write(value);
+    this->seek(current); // restore
+  }
+}
+
+#endif // SHARE_VM_JFR_WRITERS_JFRWRITERHOST_INLINE_HPP
+
--- a/src/hotspot/share/logging/logTag.hpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/logging/logTag.hpp	Tue May 15 20:24:34 2018 +0200
@@ -156,6 +156,14 @@
   LOG_TAG(vmthread) \
   LOG_TAG(vtables) \
   LOG_TAG(workgang) \
+  LOG_TAG(jfr) \
+  LOG_TAG(system) \
+  LOG_TAG(parser) \
+  LOG_TAG(bytecode) \
+  LOG_TAG(setting) \
+  LOG_TAG(oldobject) \
+  LOG_TAG(sampling) \
+  LOG_TAG(event)
   LOG_TAG_LIST_EXT
 
 #define PREFIX_LOG_TAG(T) (LogTag::_##T)
--- a/src/hotspot/share/memory/metaspaceTracer.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/memory/metaspaceTracer.cpp	Tue May 15 20:24:34 2018 +0200
@@ -24,10 +24,9 @@
 
 #include "precompiled.hpp"
 #include "classfile/classLoaderData.hpp"
+#include "jfr/jfrEvents.hpp"
 #include "memory/metaspaceTracer.hpp"
 #include "oops/oop.inline.hpp"
-#include "trace/tracing.hpp"
-#include "trace/traceBackend.hpp"
 
 void MetaspaceTracer::report_gc_threshold(size_t old_val,
                                           size_t new_val,
--- a/src/hotspot/share/oops/arrayKlass.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/oops/arrayKlass.cpp	Tue May 15 20:24:34 2018 +0200
@@ -91,7 +91,7 @@
     set_super(Universe::is_bootstrapping() ? (Klass*)NULL : SystemDictionary::Object_klass());
     set_layout_helper(Klass::_lh_neutral_value);
     set_is_cloneable(); // All arrays are considered to be cloneable (See JLS 20.1.5)
-    TRACE_INIT_ID(this);
+    JFR_ONLY(INIT_ID(this);)
 }
 
 
--- a/src/hotspot/share/oops/instanceKlass.hpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/oops/instanceKlass.hpp	Tue May 15 20:24:34 2018 +0200
@@ -38,10 +38,13 @@
 #include "oops/klassVtable.hpp"
 #include "runtime/handles.hpp"
 #include "runtime/os.hpp"
-#include "trace/traceMacros.hpp"
 #include "utilities/accessFlags.hpp"
 #include "utilities/align.hpp"
 #include "utilities/macros.hpp"
+#if INCLUDE_JFR
+#include "jfr/support/jfrKlassExtension.hpp"
+#endif
+
 
 // An InstanceKlass is the VM level representation of a Java class.
 // It contains all information needed for at class at execution runtime.
@@ -962,7 +965,7 @@
 
   // support for stub routines
   static ByteSize init_state_offset()  { return in_ByteSize(offset_of(InstanceKlass, _init_state)); }
-  TRACE_DEFINE_KLASS_TRACE_ID_OFFSET;
+  JFR_ONLY(DEFINE_KLASS_TRACE_ID_OFFSET;)
   static ByteSize init_thread_offset() { return in_ByteSize(offset_of(InstanceKlass, _init_thread)); }
 
   // subclass/subinterface checks
--- a/src/hotspot/share/oops/klass.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/oops/klass.cpp	Tue May 15 20:24:34 2018 +0200
@@ -44,7 +44,6 @@
 #include "runtime/atomic.hpp"
 #include "runtime/handles.inline.hpp"
 #include "runtime/orderAccess.inline.hpp"
-#include "trace/traceMacros.hpp"
 #include "utilities/macros.hpp"
 #include "utilities/stack.inline.hpp"
 
@@ -467,7 +466,7 @@
 
 void Klass::remove_unshareable_info() {
   assert (DumpSharedSpaces, "only called for DumpSharedSpaces");
-  TRACE_REMOVE_ID(this);
+  JFR_ONLY(REMOVE_ID(this);)
   if (log_is_enabled(Trace, cds, unshareable)) {
     ResourceMark rm;
     log_trace(cds, unshareable)("remove: %s", external_name());
@@ -495,7 +494,7 @@
 void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) {
   assert(is_klass(), "ensure C++ vtable is restored");
   assert(is_shared(), "must be set");
-  TRACE_RESTORE_ID(this);
+  JFR_ONLY(RESTORE_ID(this);)
   if (log_is_enabled(Trace, cds, unshareable)) {
     ResourceMark rm;
     log_trace(cds, unshareable)("restore: %s", external_name());
--- a/src/hotspot/share/oops/klass.hpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/oops/klass.hpp	Tue May 15 20:24:34 2018 +0200
@@ -32,9 +32,11 @@
 #include "oops/metadata.hpp"
 #include "oops/oop.hpp"
 #include "oops/oopHandle.hpp"
-#include "trace/traceMacros.hpp"
 #include "utilities/accessFlags.hpp"
 #include "utilities/macros.hpp"
+#if INCLUDE_JFR
+#include "jfr/support/jfrTraceIdExtension.hpp"
+#endif
 
 //
 // A Klass provides:
@@ -138,7 +140,7 @@
   jint        _modifier_flags;  // Processed access flags, for use by Class.getModifiers.
   AccessFlags _access_flags;    // Access flags. The class/interface distinction is stored here.
 
-  TRACE_DEFINE_TRACE_ID_FIELD;
+  JFR_ONLY(DEFINE_TRACE_ID_FIELD;)
 
   // Biased locking implementation and statistics
   // (the 64-bit chunk goes first, to avoid some fragmentation)
@@ -628,7 +630,7 @@
   jlong last_biased_lock_bulk_revocation_time() { return _last_biased_lock_bulk_revocation_time; }
   void  set_last_biased_lock_bulk_revocation_time(jlong cur_time) { _last_biased_lock_bulk_revocation_time = cur_time; }
 
-  TRACE_DEFINE_TRACE_ID_METHODS;
+  JFR_ONLY(DEFINE_TRACE_ID_METHODS;)
 
   virtual void metaspace_pointers_do(MetaspaceClosure* iter);
   virtual MetaspaceObj::Type type() const { return ClassType; }
--- a/src/hotspot/share/oops/method.hpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/oops/method.hpp	Tue May 15 20:24:34 2018 +0200
@@ -39,6 +39,11 @@
 #include "utilities/accessFlags.hpp"
 #include "utilities/align.hpp"
 #include "utilities/growableArray.hpp"
+#include "utilities/macros.hpp"
+#if INCLUDE_JFR
+#include "jfr/support/jfrTraceIdExtension.hpp"
+#endif
+
 
 // A Method represents a Java method.
 //
@@ -89,7 +94,7 @@
   };
   mutable u2 _flags;
 
-  TRACE_DEFINE_FLAG;
+  JFR_ONLY(DEFINE_TRACE_FLAG;)
 
 #ifndef PRODUCT
   int               _compiled_invocation_count;  // Number of nmethod invocations so far (for perf. debugging)
@@ -879,7 +884,7 @@
     _flags = x ? (_flags | _reserved_stack_access) : (_flags & ~_reserved_stack_access);
   }
 
-  TRACE_DEFINE_FLAG_ACCESSOR;
+  JFR_ONLY(DEFINE_TRACE_FLAG_ACCESSOR;)
 
   ConstMethod::MethodType method_type() const {
       return _constMethod->method_type();
--- a/src/hotspot/share/opto/bytecodeInfo.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/opto/bytecodeInfo.cpp	Tue May 15 20:24:34 2018 +0200
@@ -29,6 +29,7 @@
 #include "compiler/compileBroker.hpp"
 #include "compiler/compileLog.hpp"
 #include "interpreter/linkResolver.hpp"
+#include "jfr/jfrEvents.hpp"
 #include "oops/objArrayKlass.hpp"
 #include "opto/callGenerator.hpp"
 #include "opto/parse.hpp"
@@ -484,6 +485,25 @@
   return NULL;
 }
 
+static void post_inlining_event(int compile_id,const char* msg, bool success, int bci, ciMethod* caller, ciMethod* callee) {
+  assert(caller != NULL, "invariant");
+  assert(callee != NULL, "invariant");
+  EventCompilerInlining event;
+  if (event.should_commit()) {
+    JfrStructCalleeMethod callee_struct;
+    callee_struct.set_type(callee->holder()->name()->as_utf8());
+    callee_struct.set_name(callee->name()->as_utf8());
+    callee_struct.set_descriptor(callee->signature()->as_symbol()->as_utf8());
+    event.set_compileId(compile_id);
+    event.set_message(msg);
+    event.set_succeeded(success);
+    event.set_bci(bci);
+    event.set_caller(caller->get_Method());
+    event.set_callee(callee_struct);
+    event.commit();
+  }
+}
+
 //------------------------------print_inlining---------------------------------
 void InlineTree::print_inlining(ciMethod* callee_method, int caller_bci,
                                 ciMethod* caller_method, bool success) const {
@@ -507,18 +527,7 @@
       //tty->print("  bcs: %d+%d  invoked: %d", top->count_inline_bcs(), callee_method->code_size(), callee_method->interpreter_invocation_count());
     }
   }
-#if INCLUDE_TRACE
-  EventCompilerInlining event;
-  if (event.should_commit()) {
-    event.set_compileId(C->compile_id());
-    event.set_message(inline_msg);
-    event.set_succeeded(success);
-    event.set_bci(caller_bci);
-    event.set_caller(caller_method->get_Method());
-    event.set_callee(callee_method->to_trace_struct());
-    event.commit();
-  }
-#endif // INCLUDE_TRACE
+  post_inlining_event(C->compile_id(), inline_msg, success, caller_bci, caller_method, callee_method);
 }
 
 //------------------------------ok_to_inline-----------------------------------
--- a/src/hotspot/share/opto/c2compiler.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/opto/c2compiler.cpp	Tue May 15 20:24:34 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,11 +23,14 @@
  */
 
 #include "precompiled.hpp"
+#include "jfr/support/jfrIntrinsics.hpp"
 #include "opto/c2compiler.hpp"
 #include "opto/compile.hpp"
 #include "opto/optoreg.hpp"
 #include "opto/output.hpp"
 #include "opto/runtime.hpp"
+#include "utilities/macros.hpp"
+
 
 // register information defined by ADLC
 extern const char register_save_policy[];
@@ -537,10 +540,10 @@
   case vmIntrinsics::_fullFence:
   case vmIntrinsics::_currentThread:
   case vmIntrinsics::_isInterrupted:
-#ifdef TRACE_HAVE_INTRINSICS
+#ifdef JFR_HAVE_INTRINSICS
   case vmIntrinsics::_counterTime:
   case vmIntrinsics::_getClassId:
-  case vmIntrinsics::_getBufferWriter:
+  case vmIntrinsics::_getEventWriter:
 #endif
   case vmIntrinsics::_currentTimeMillis:
   case vmIntrinsics::_nanoTime:
--- a/src/hotspot/share/opto/compile.hpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/opto/compile.hpp	Tue May 15 20:24:34 2018 +0200
@@ -33,6 +33,7 @@
 #include "compiler/compileBroker.hpp"
 #include "libadt/dict.hpp"
 #include "libadt/vectset.hpp"
+#include "jfr/jfrEvents.hpp"
 #include "memory/resourceArea.hpp"
 #include "oops/methodData.hpp"
 #include "opto/idealGraphPrinter.hpp"
@@ -42,7 +43,6 @@
 #include "runtime/deoptimization.hpp"
 #include "runtime/timerTrace.hpp"
 #include "runtime/vmThread.hpp"
-#include "trace/tracing.hpp"
 #include "utilities/ticks.hpp"
 
 class AddPNode;
--- a/src/hotspot/share/opto/graphKit.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/opto/graphKit.cpp	Tue May 15 20:24:34 2018 +0200
@@ -49,7 +49,7 @@
 #include "gc/g1/g1CardTable.hpp"
 #include "gc/g1/g1ThreadLocalData.hpp"
 #include "gc/g1/heapRegion.hpp"
-#endif // INCLUDE_ALL_GCS
+#endif // INCLUDE_G1GC
 
 //----------------------------GraphKit-----------------------------------------
 // Main utility constructor.
--- a/src/hotspot/share/opto/library_call.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/opto/library_call.cpp	Tue May 15 20:24:34 2018 +0200
@@ -30,6 +30,7 @@
 #include "compiler/compileBroker.hpp"
 #include "compiler/compileLog.hpp"
 #include "memory/resourceArea.hpp"
+#include "jfr/support/jfrIntrinsics.hpp"
 #include "oops/objArrayKlass.hpp"
 #include "opto/addnode.hpp"
 #include "opto/arraycopynode.hpp"
@@ -54,9 +55,8 @@
 #include "prims/unsafe.hpp"
 #include "runtime/objectMonitor.hpp"
 #include "runtime/sharedRuntime.hpp"
-#ifdef TRACE_HAVE_INTRINSICS
-#include "trace/traceMacros.hpp"
-#endif
+#include "utilities/macros.hpp"
+
 
 class LibraryIntrinsic : public InlineCallGenerator {
   // Extend the set of intrinsics known to the runtime:
@@ -258,9 +258,9 @@
   bool inline_native_currentThread();
 
   bool inline_native_time_funcs(address method, const char* funcName);
-#ifdef TRACE_HAVE_INTRINSICS
+#ifdef JFR_HAVE_INTRINSICS
   bool inline_native_classID();
-  bool inline_native_getBufferWriter();
+  bool inline_native_getEventWriter();
 #endif
   bool inline_native_isInterrupted();
   bool inline_native_Class_query(vmIntrinsics::ID id);
@@ -746,10 +746,10 @@
   case vmIntrinsics::_currentThread:            return inline_native_currentThread();
   case vmIntrinsics::_isInterrupted:            return inline_native_isInterrupted();
 
-#ifdef TRACE_HAVE_INTRINSICS
-  case vmIntrinsics::_counterTime:              return inline_native_time_funcs(CAST_FROM_FN_PTR(address, TRACE_TIME_METHOD), "counterTime");
+#ifdef JFR_HAVE_INTRINSICS
+  case vmIntrinsics::_counterTime:              return inline_native_time_funcs(CAST_FROM_FN_PTR(address, JFR_TIME_FUNCTION), "counterTime");
   case vmIntrinsics::_getClassId:               return inline_native_classID();
-  case vmIntrinsics::_getBufferWriter:          return inline_native_getBufferWriter();
+  case vmIntrinsics::_getEventWriter:           return inline_native_getEventWriter();
 #endif
   case vmIntrinsics::_currentTimeMillis:        return inline_native_time_funcs(CAST_FROM_FN_PTR(address, os::javaTimeMillis), "currentTimeMillis");
   case vmIntrinsics::_nanoTime:                 return inline_native_time_funcs(CAST_FROM_FN_PTR(address, os::javaTimeNanos), "nanoTime");
@@ -3286,7 +3286,7 @@
   return true;
 }
 
-#ifdef TRACE_HAVE_INTRINSICS
+#ifdef JFR_HAVE_INTRINSICS
 
 /*
 * oop -> myklass
@@ -3298,7 +3298,7 @@
   Node* kls = load_klass_from_mirror(cls, false, NULL, 0);
   kls = null_check(kls, T_OBJECT);
 
-  ByteSize offset = TRACE_KLASS_TRACE_ID_OFFSET;
+  ByteSize offset = KLASS_TRACE_ID_OFFSET;
   Node* insp = basic_plus_adr(kls, in_bytes(offset));
   Node* tvalue = make_load(NULL, insp, TypeLong::LONG, T_LONG, MemNode::unordered);
 
@@ -3311,8 +3311,8 @@
   Node* mbits = longcon(~TRACE_ID_META_BITS);
   tvalue = _gvn.transform(new AndLNode(tvalue, mbits));
 #endif
-#ifdef TRACE_ID_CLASS_SHIFT
-  Node* cbits = intcon(TRACE_ID_CLASS_SHIFT);
+#ifdef TRACE_ID_SHIFT
+  Node* cbits = intcon(TRACE_ID_SHIFT);
   tvalue = _gvn.transform(new URShiftLNode(tvalue, cbits));
 #endif
 
@@ -3321,11 +3321,11 @@
 
 }
 
-bool LibraryCallKit::inline_native_getBufferWriter() {
+bool LibraryCallKit::inline_native_getEventWriter() {
   Node* tls_ptr = _gvn.transform(new ThreadLocalNode());
 
   Node* jobj_ptr = basic_plus_adr(top(), tls_ptr,
-                                  in_bytes(TRACE_THREAD_DATA_WRITER_OFFSET)
+                                  in_bytes(THREAD_LOCAL_WRITER_OFFSET_JFR)
                                   );
 
   Node* jobj = make_load(control(), jobj_ptr, TypeRawPtr::BOTTOM, T_ADDRESS, MemNode::unordered);
@@ -3358,7 +3358,7 @@
   return true;
 }
 
-#endif
+#endif // JFR_HAVE_INTRINSICS
 
 //------------------------inline_native_currentThread------------------
 bool LibraryCallKit::inline_native_currentThread() {
--- a/src/hotspot/share/prims/jni.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/prims/jni.cpp	Tue May 15 20:24:34 2018 +0200
@@ -38,6 +38,8 @@
 #include "classfile/vmSymbols.hpp"
 #include "gc/shared/gcLocker.inline.hpp"
 #include "interpreter/linkResolver.hpp"
+#include "jfr/jfrEvents.hpp"
+#include "jfr/support/jfrThreadId.hpp"
 #include "logging/log.hpp"
 #include "memory/allocation.hpp"
 #include "memory/allocation.inline.hpp"
@@ -80,8 +82,6 @@
 #include "runtime/vm_operations.hpp"
 #include "services/memTracker.hpp"
 #include "services/runtimeService.hpp"
-#include "trace/traceMacros.hpp"
-#include "trace/tracing.hpp"
 #include "utilities/defaultStream.hpp"
 #include "utilities/dtrace.hpp"
 #include "utilities/events.hpp"
@@ -3828,6 +3828,14 @@
   return &jni_NativeInterface;
 }
 
+static void post_thread_start_event(const JavaThread* jt) {
+  assert(jt != NULL, "invariant");
+  EventThreadStart event;
+  if (event.should_commit()) {
+    event.set_thread(JFR_THREAD_ID(jt));
+    event.commit();
+  }
+}
 
 // Invocation API
 
@@ -3960,11 +3968,7 @@
        JvmtiExport::post_thread_start(thread);
     }
 
-    EventThreadStart event;
-    if (event.should_commit()) {
-      event.set_thread(THREAD_TRACE_ID(thread));
-      event.commit();
-    }
+    post_thread_start_event(thread);
 
 #ifndef PRODUCT
     // Check if we should compile all classes on bootclasspath
@@ -4194,11 +4198,7 @@
     JvmtiExport::post_thread_start(thread);
   }
 
-  EventThreadStart event;
-  if (event.should_commit()) {
-    event.set_thread(THREAD_TRACE_ID(thread));
-    event.commit();
-  }
+  post_thread_start_event(thread);
 
   *(JNIEnv**)penv = thread->jni_environment();
 
--- a/src/hotspot/share/prims/jvm.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/prims/jvm.cpp	Tue May 15 20:24:34 2018 +0200
@@ -37,6 +37,7 @@
 #include "classfile/vmSymbols.hpp"
 #include "gc/shared/collectedHeap.inline.hpp"
 #include "interpreter/bytecode.hpp"
+#include "jfr/jfrEvents.hpp"
 #include "memory/oopFactory.hpp"
 #include "memory/referenceType.hpp"
 #include "memory/resourceArea.hpp"
@@ -75,7 +76,6 @@
 #include "services/attachListener.hpp"
 #include "services/management.hpp"
 #include "services/threadService.hpp"
-#include "trace/tracing.hpp"
 #include "utilities/copy.hpp"
 #include "utilities/defaultStream.hpp"
 #include "utilities/dtrace.hpp"
@@ -2983,6 +2983,12 @@
   os::naked_yield();
 JVM_END
 
+static void post_thread_sleep_event(EventThreadSleep* event, jlong millis) {
+  assert(event != NULL, "invariant");
+  assert(event->should_commit(), "invariant");
+  event->set_time(millis);
+  event->commit();
+}
 
 JVM_ENTRY(void, JVM_Sleep(JNIEnv* env, jclass threadClass, jlong millis))
   JVMWrapper("JVM_Sleep");
@@ -3000,7 +3006,6 @@
   JavaThreadSleepState jtss(thread);
 
   HOTSPOT_THREAD_SLEEP_BEGIN(millis);
-
   EventThreadSleep event;
 
   if (millis == 0) {
@@ -3013,8 +3018,7 @@
       // us while we were sleeping. We do not overwrite those.
       if (!HAS_PENDING_EXCEPTION) {
         if (event.should_commit()) {
-          event.set_time(millis);
-          event.commit();
+          post_thread_sleep_event(&event, millis);
         }
         HOTSPOT_THREAD_SLEEP_END(1);
 
@@ -3026,8 +3030,7 @@
     thread->osthread()->set_state(old_state);
   }
   if (event.should_commit()) {
-    event.set_time(millis);
-    event.commit();
+    post_thread_sleep_event(&event, millis);
   }
   HOTSPOT_THREAD_SLEEP_END(0);
 JVM_END
--- a/src/hotspot/share/prims/nativeLookup.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/prims/nativeLookup.cpp	Tue May 15 20:24:34 2018 +0200
@@ -42,8 +42,8 @@
 #include "runtime/sharedRuntime.hpp"
 #include "runtime/signature.hpp"
 #include "utilities/macros.hpp"
-#if INCLUDE_TRACE
-#include "trace/traceMacros.hpp"
+#if INCLUDE_JFR
+#include "jfr/jfr.hpp"
 #endif
 
 static void mangle_name_on(outputStream* st, Symbol* name, int begin, int end) {
@@ -131,8 +131,8 @@
   { CC"Java_jdk_vm_ci_runtime_JVMCI_initializeRuntime",            NULL, FN_PTR(JVM_GetJVMCIRuntime)             },
   { CC"Java_jdk_vm_ci_hotspot_CompilerToVM_registerNatives",       NULL, FN_PTR(JVM_RegisterJVMCINatives)        },
 #endif
-#if INCLUDE_TRACE
-  { CC"Java_jdk_jfr_internal_JVM_registerNatives",                 NULL, TRACE_REGISTER_NATIVES                  },
+#if INCLUDE_JFR
+  { CC"Java_jdk_jfr_internal_JVM_registerNatives",                 NULL, FN_PTR(jfr_register_natives)            },
 #endif
 };
 
--- a/src/hotspot/share/prims/unsafe.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/prims/unsafe.cpp	Tue May 15 20:24:34 2018 +0200
@@ -27,6 +27,7 @@
 #include "jvm.h"
 #include "classfile/classFileStream.hpp"
 #include "classfile/vmSymbols.hpp"
+#include "jfr/jfrEvents.hpp"
 #include "memory/allocation.inline.hpp"
 #include "memory/resourceArea.hpp"
 #include "oops/access.inline.hpp"
@@ -45,7 +46,6 @@
 #include "runtime/threadSMR.hpp"
 #include "runtime/vm_version.hpp"
 #include "services/threadService.hpp"
-#include "trace/tracing.hpp"
 #include "utilities/align.hpp"
 #include "utilities/copy.hpp"
 #include "utilities/dtrace.hpp"
@@ -926,22 +926,25 @@
   }
 } UNSAFE_END
 
+static void post_thread_park_event(EventThreadPark* event, const oop obj, jlong timeout) {
+  assert(event != NULL, "invariant");
+  assert(event->should_commit(), "invariant");
+  event->set_parkedClass((obj != NULL) ? obj->klass() : NULL);
+  event->set_timeout(timeout);
+  event->set_address((obj != NULL) ? (u8)cast_from_oop<uintptr_t>(obj) : 0);
+  event->commit();
+}
+
 UNSAFE_ENTRY(void, Unsafe_Park(JNIEnv *env, jobject unsafe, jboolean isAbsolute, jlong time)) {
+  HOTSPOT_THREAD_PARK_BEGIN((uintptr_t) thread->parker(), (int) isAbsolute, time);
   EventThreadPark event;
-  HOTSPOT_THREAD_PARK_BEGIN((uintptr_t) thread->parker(), (int) isAbsolute, time);
 
   JavaThreadParkedState jtps(thread, time != 0);
   thread->parker()->park(isAbsolute != 0, time);
-
+  if (event.should_commit()) {
+    post_thread_park_event(&event, thread->current_park_blocker(), time);
+  }
   HOTSPOT_THREAD_PARK_END((uintptr_t) thread->parker());
-
-  if (event.should_commit()) {
-    oop obj = thread->current_park_blocker();
-    event.set_parkedClass((obj != NULL) ? obj->klass() : NULL);
-    event.set_timeout(time);
-    event.set_address((obj != NULL) ? (TYPE_ADDRESS) cast_from_oop<uintptr_t>(obj) : 0);
-    event.commit();
-  }
 } UNSAFE_END
 
 UNSAFE_ENTRY(void, Unsafe_Unpark(JNIEnv *env, jobject unsafe, jobject jthread)) {
--- a/src/hotspot/share/runtime/arguments.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/runtime/arguments.cpp	Tue May 15 20:24:34 2018 +0200
@@ -61,6 +61,9 @@
 #if INCLUDE_JVMCI
 #include "jvmci/jvmciRuntime.hpp"
 #endif
+#if INCLUDE_JFR
+#include "jfr/jfr.hpp"
+#endif
 
 // Note: This is a special bug reporting site for the JVM
 #ifdef VENDOR_URL_VM_BUG
@@ -264,6 +267,20 @@
   return false;
 }
 
+#if INCLUDE_JFR
+// return true on failure
+static bool match_jfr_option(const JavaVMOption** option) {
+  assert((*option)->optionString != NULL, "invariant");
+  char* tail = NULL;
+  if (match_option(*option, "-XX:StartFlightRecording", (const char**)&tail)) {
+    return Jfr::on_start_flight_recording_option(option, tail);
+  } else if (match_option(*option, "-XX:FlightRecorderOptions", (const char**)&tail)) {
+    return Jfr::on_flight_recorder_option(option, tail);
+  }
+  return false;
+}
+#endif
+
 static void logOption(const char* opt) {
   if (PrintVMOptions) {
     jio_fprintf(defaultStream::output_stream(), "VM option '%s'\n", opt);
@@ -545,6 +562,8 @@
   { "UseUTCFileTimestamp",           JDK_Version::undefined(), JDK_Version::jdk(11), JDK_Version::jdk(12) },
   { "UseAppCDS",                     JDK_Version::undefined(), JDK_Version::jdk(11), JDK_Version::jdk(12) },
   { "InlineNotify",                  JDK_Version::undefined(), JDK_Version::jdk(11), JDK_Version::jdk(12) },
+  { "EnableTracing",                 JDK_Version::undefined(), JDK_Version::jdk(11), JDK_Version::jdk(12) },
+  { "UseLockedTracing",              JDK_Version::undefined(), JDK_Version::jdk(11), JDK_Version::jdk(12) },
 
 #ifdef TEST_VERIFY_SPECIAL_JVM_FLAGS
   { "dep > obs",                    JDK_Version::jdk(9), JDK_Version::jdk(8), JDK_Version::undefined() },
@@ -3159,6 +3178,10 @@
           "ManagementServer is not supported in this VM.\n");
         return JNI_ERR;
 #endif // INCLUDE_MANAGEMENT
+#if INCLUDE_JFR
+    } else if (match_jfr_option(&option)) {
+      return JNI_EINVAL;
+#endif
     } else if (match_option(option, "-XX:", &tail)) { // -XX:xxxx
       // Skip -XX:Flags= and -XX:VMOptionsFile= since those cases have
       // already been handled
--- a/src/hotspot/share/runtime/biasedLocking.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/runtime/biasedLocking.cpp	Tue May 15 20:24:34 2018 +0200
@@ -23,6 +23,8 @@
  */
 
 #include "precompiled.hpp"
+#include "jfr/jfrEvents.hpp"
+#include "jfr/support/jfrThreadId.hpp"
 #include "logging/log.hpp"
 #include "memory/resourceArea.hpp"
 #include "oops/klass.inline.hpp"
@@ -37,7 +39,7 @@
 #include "runtime/vframe.hpp"
 #include "runtime/vmThread.hpp"
 #include "runtime/vm_operations.hpp"
-#include "trace/tracing.hpp"
+
 
 static bool _biased_locking_enabled = false;
 BiasedLockingCounters BiasedLocking::_counters;
@@ -540,7 +542,7 @@
       JavaThread* biased_locker = NULL;
       _status_code = revoke_bias((*_obj)(), false, false, _requesting_thread, &biased_locker);
       if (biased_locker != NULL) {
-        _biased_locker_id = THREAD_TRACE_ID(biased_locker);
+        _biased_locker_id = JFR_THREAD_ID(biased_locker);
       }
       clean_up_cached_monitor_info();
       return;
@@ -582,6 +584,41 @@
   }
 };
 
+template <typename E>
+static void set_safepoint_id(E* event) {
+  assert(event != NULL, "invariant");
+  // Subtract 1 to match the id of events committed inside the safepoint
+  event->set_safepointId(SafepointSynchronize::safepoint_counter() - 1);
+}
+
+static void post_self_revocation_event(EventBiasedLockSelfRevocation* event, Klass* k) {
+  assert(event != NULL, "invariant");
+  assert(k != NULL, "invariant");
+  assert(event->should_commit(), "invariant");
+  event->set_lockClass(k);
+  event->commit();
+}
+
+static void post_revocation_event(EventBiasedLockRevocation* event, Klass* k, VM_RevokeBias* revoke) {
+  assert(event != NULL, "invariant");
+  assert(k != NULL, "invariant");
+  assert(revoke != NULL, "invariant");
+  assert(event->should_commit(), "invariant");
+  event->set_lockClass(k);
+  set_safepoint_id(event);
+  event->set_previousOwner(revoke->biased_locker());
+  event->commit();
+}
+
+static void post_class_revocation_event(EventBiasedLockClassRevocation* event, Klass* k, bool disabled_bias) {
+  assert(event != NULL, "invariant");
+  assert(k != NULL, "invariant");
+  assert(event->should_commit(), "invariant");
+  event->set_revokedClass(k);
+  event->set_disableBiasing(disabled_bias);
+  set_safepoint_id(event);
+  event->commit();
+}
 
 BiasedLocking::Condition BiasedLocking::revoke_and_rebias(Handle obj, bool attempt_rebias, TRAPS) {
   assert(!SafepointSynchronize::is_at_safepoint(), "must not be called while at safepoint");
@@ -669,20 +706,15 @@
       ((JavaThread*) THREAD)->set_cached_monitor_info(NULL);
       assert(cond == BIAS_REVOKED, "why not?");
       if (event.should_commit()) {
-        event.set_lockClass(k);
-        event.commit();
+        post_self_revocation_event(&event, k);
       }
       return cond;
     } else {
       EventBiasedLockRevocation event;
       VM_RevokeBias revoke(&obj, (JavaThread*) THREAD);
       VMThread::execute(&revoke);
-      if (event.should_commit() && (revoke.status_code() != NOT_BIASED)) {
-        event.set_lockClass(k);
-        // Subtract 1 to match the id of events committed inside the safepoint
-        event.set_safepointId(SafepointSynchronize::safepoint_counter() - 1);
-        event.set_previousOwner(revoke.biased_locker());
-        event.commit();
+      if (event.should_commit() && revoke.status_code() != NOT_BIASED) {
+        post_revocation_event(&event, k, &revoke);
       }
       return revoke.status_code();
     }
@@ -696,11 +728,7 @@
                                 attempt_rebias);
   VMThread::execute(&bulk_revoke);
   if (event.should_commit()) {
-    event.set_revokedClass(obj->klass());
-    event.set_disableBiasing((heuristics != HR_BULK_REBIAS));
-    // Subtract 1 to match the id of events committed inside the safepoint
-    event.set_safepointId(SafepointSynchronize::safepoint_counter() - 1);
-    event.commit();
+    post_class_revocation_event(&event, obj->klass(), heuristics != HR_BULK_REBIAS);
   }
   return bulk_revoke.status_code();
 }
--- a/src/hotspot/share/runtime/flags/jvmFlag.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/runtime/flags/jvmFlag.cpp	Tue May 15 20:24:34 2018 +0200
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "jfr/jfrEvents.hpp"
 #include "memory/allocation.inline.hpp"
 #include "runtime/arguments.hpp"
 #include "runtime/flags/jvmFlag.hpp"
@@ -30,7 +31,6 @@
 #include "runtime/flags/jvmFlagWriteableList.hpp"
 #include "runtime/flags/jvmFlagRangeList.hpp"
 #include "runtime/globals_extension.hpp"
-#include "trace/tracing.hpp"
 #include "utilities/defaultStream.hpp"
 #include "utilities/stringUtils.hpp"
 
--- a/src/hotspot/share/runtime/globals.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/runtime/globals.cpp	Tue May 15 20:24:34 2018 +0200
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "jfr/jfrEvents.hpp"
 #include "jvm.h"
 #include "memory/allocation.inline.hpp"
 #include "oops/oop.inline.hpp"
@@ -34,7 +35,6 @@
 #include "runtime/flags/jvmFlagRangeList.hpp"
 #include "runtime/os.hpp"
 #include "runtime/sharedRuntime.hpp"
-#include "trace/tracing.hpp"
 #include "utilities/defaultStream.hpp"
 #include "utilities/macros.hpp"
 #include "utilities/ostream.hpp"
--- a/src/hotspot/share/runtime/globals.hpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/runtime/globals.hpp	Tue May 15 20:24:34 2018 +0200
@@ -2597,12 +2597,6 @@
   experimental(bool, AlwaysAtomicAccesses, false,                           \
           "Accesses to all variables should always be atomic")              \
                                                                             \
-  product(bool, EnableTracing, false,                                       \
-          "Enable event-based tracing")                                     \
-                                                                            \
-  product(bool, UseLockedTracing, false,                                    \
-          "Use locked-tracing when doing event-based tracing")              \
-                                                                            \
   diagnostic(bool, UseUnalignedAccesses, false,                             \
           "Use unaligned memory accesses in Unsafe")                        \
                                                                             \
@@ -2650,6 +2644,18 @@
                                                                             \
   experimental(bool, UseSwitchProfiling, true,                              \
           "leverage profiling for table/lookup switch")                     \
+                                                                            \
+  JFR_ONLY(product(bool, FlightRecorder, false,                             \
+          "Enable Flight Recorder"))                                        \
+                                                                            \
+  JFR_ONLY(product(ccstr, FlightRecorderOptions, NULL,                      \
+          "Flight Recorder options"))                                       \
+                                                                            \
+  JFR_ONLY(product(ccstr, StartFlightRecording, NULL,                       \
+          "Start flight recording with options"))                           \
+                                                                            \
+  experimental(bool, UseFastUnorderedTimeStamps, false,                     \
+          "Use platform unstable time where supported for timestamps only")
 
 #define VM_FLAGS(develop,                                                   \
                  develop_pd,                                                \
--- a/src/hotspot/share/runtime/java.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/runtime/java.cpp	Tue May 15 20:24:34 2018 +0200
@@ -32,6 +32,7 @@
 #include "compiler/compileBroker.hpp"
 #include "compiler/compilerOracle.hpp"
 #include "interpreter/bytecodeHistogram.hpp"
+#include "jfr/support/jfrThreadId.hpp"
 #if INCLUDE_JVMCI
 #include "jvmci/jvmciCompiler.hpp"
 #include "jvmci/jvmciRuntime.hpp"
@@ -67,8 +68,6 @@
 #include "runtime/timer.hpp"
 #include "runtime/vm_operations.hpp"
 #include "services/memTracker.hpp"
-#include "trace/traceMacros.hpp"
-#include "trace/tracing.hpp"
 #include "utilities/dtrace.hpp"
 #include "utilities/globalDefinitions.hpp"
 #include "utilities/histogram.hpp"
@@ -85,6 +84,9 @@
 #include "opto/indexSet.hpp"
 #include "opto/runtime.hpp"
 #endif
+#if INCLUDE_JFR
+#include "jfr/jfr.hpp"
+#endif
 
 GrowableArray<Method*>* collected_profiled_methods;
 
@@ -464,11 +466,11 @@
 
   EventThreadEnd event;
   if (event.should_commit()) {
-    event.set_thread(THREAD_TRACE_ID(thread));
+    event.set_thread(JFR_THREAD_ID(thread));
     event.commit();
   }
 
-  TRACE_VM_EXIT();
+  JFR_ONLY(Jfr::on_vm_shutdown();)
 
   // Stop the WatcherThread. We do this before disenrolling various
   // PeriodicTasks to reduce the likelihood of races.
--- a/src/hotspot/share/runtime/jniHandles.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/runtime/jniHandles.cpp	Tue May 15 20:24:34 2018 +0200
@@ -32,7 +32,6 @@
 #include "runtime/jniHandles.inline.hpp"
 #include "runtime/mutexLocker.hpp"
 #include "runtime/thread.inline.hpp"
-#include "trace/traceMacros.hpp"
 #include "utilities/align.hpp"
 #include "utilities/debug.hpp"
 
--- a/src/hotspot/share/runtime/mutexLocker.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/runtime/mutexLocker.cpp	Tue May 15 20:24:34 2018 +0200
@@ -128,7 +128,7 @@
 Monitor* PeriodicTask_lock            = NULL;
 Monitor* RedefineClasses_lock         = NULL;
 
-#if INCLUDE_TRACE
+#if INCLUDE_JFR
 Mutex*   JfrStacktrace_lock           = NULL;
 Monitor* JfrMsg_lock                  = NULL;
 Mutex*   JfrBuffer_lock               = NULL;
@@ -293,7 +293,7 @@
     def(Compilation_lock           , PaddedMonitor, leaf,        false, Monitor::_safepoint_check_never);
   }
 
-#if INCLUDE_TRACE
+#if INCLUDE_JFR
   def(JfrMsg_lock                  , PaddedMonitor, leaf,        true,  Monitor::_safepoint_check_always);
   def(JfrBuffer_lock               , PaddedMutex  , leaf,        true,  Monitor::_safepoint_check_never);
   def(JfrStream_lock               , PaddedMutex  , leaf+1,      true,  Monitor::_safepoint_check_never);      // ensure to rank lower than 'safepoint'
--- a/src/hotspot/share/runtime/mutexLocker.hpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/runtime/mutexLocker.hpp	Tue May 15 20:24:34 2018 +0200
@@ -128,7 +128,7 @@
 extern Monitor* PeriodicTask_lock;               // protects the periodic task structure
 extern Monitor* RedefineClasses_lock;            // locks classes from parallel redefinition
 
-#if INCLUDE_TRACE
+#if INCLUDE_JFR
 extern Mutex*   JfrStacktrace_lock;              // used to guard access to the JFR stacktrace table
 extern Monitor* JfrMsg_lock;                     // protects JFR messaging
 extern Mutex*   JfrBuffer_lock;                  // protects JFR buffer operations
--- a/src/hotspot/share/runtime/objectMonitor.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/runtime/objectMonitor.cpp	Tue May 15 20:24:34 2018 +0200
@@ -24,6 +24,8 @@
 
 #include "precompiled.hpp"
 #include "classfile/vmSymbols.hpp"
+#include "jfr/jfrEvents.hpp"
+#include "jfr/support/jfrThreadId.hpp"
 #include "memory/allocation.inline.hpp"
 #include "memory/resourceArea.hpp"
 #include "oops/markOop.hpp"
@@ -41,11 +43,12 @@
 #include "runtime/stubRoutines.hpp"
 #include "runtime/thread.inline.hpp"
 #include "services/threadService.hpp"
-#include "trace/tracing.hpp"
-#include "trace/traceMacros.hpp"
 #include "utilities/dtrace.hpp"
 #include "utilities/macros.hpp"
 #include "utilities/preserveException.hpp"
+#if INCLUDE_JFR
+#include "jfr/support/jfrFlush.hpp"
+#endif
 
 #ifdef DTRACE_ENABLED
 
@@ -317,7 +320,12 @@
   // Ensure the object-monitor relationship remains stable while there's contention.
   Atomic::inc(&_count);
 
+  JFR_ONLY(JfrConditionalFlushWithStacktrace<EventJavaMonitorEnter> flush(jt);)
   EventJavaMonitorEnter event;
+  if (event.should_commit()) {
+    event.set_monitorClass(((oop)this->object())->klass());
+    event.set_address((uintptr_t)(this->object_addr()));
+  }
 
   { // Change java thread status to indicate blocked on monitor enter.
     JavaThreadBlockedOnMonitorEnterState jtbmes(jt, this);
@@ -403,18 +411,13 @@
     // event handler consumed an unpark() issued by the thread that
     // just exited the monitor.
   }
-
   if (event.should_commit()) {
-    event.set_monitorClass(((oop)this->object())->klass());
-    event.set_previousOwner((TYPE_THREAD)_previous_owner_tid);
-    event.set_address((TYPE_ADDRESS)(uintptr_t)(this->object_addr()));
+    event.set_previousOwner((uintptr_t)_previous_owner_tid);
     event.commit();
   }
-
   OM_PERFDATA_OP(ContendedLockAttempts, inc());
 }
 
-
 // Caveat: TryLock() is not necessarily serializing if it returns failure.
 // Callers must compensate as needed.
 
@@ -938,11 +941,11 @@
     _Responsible = NULL;
   }
 
-#if INCLUDE_TRACE
+#if INCLUDE_JFR
   // get the owner's thread id for the MonitorEnter event
   // if it is enabled and the thread isn't suspended
-  if (not_suspended && Tracing::is_event_enabled(TraceJavaMonitorEnterEvent)) {
-    _previous_owner_tid = THREAD_TRACE_ID(Self);
+  if (not_suspended && EventJavaMonitorEnter::is_enabled()) {
+    _previous_owner_tid = JFR_THREAD_ID(Self);
   }
 #endif
 
@@ -1390,15 +1393,16 @@
   return v;
 }
 
-// helper method for posting a monitor wait event
-void ObjectMonitor::post_monitor_wait_event(EventJavaMonitorWait* event,
-                                            jlong notifier_tid,
-                                            jlong timeout,
-                                            bool timedout) {
+static void post_monitor_wait_event(EventJavaMonitorWait* event,
+                                    ObjectMonitor* monitor,
+                                    jlong notifier_tid,
+                                    jlong timeout,
+                                    bool timedout) {
   assert(event != NULL, "invariant");
-  event->set_monitorClass(((oop)this->object())->klass());
+  assert(monitor != NULL, "invariant");
+  event->set_monitorClass(((oop)monitor->object())->klass());
   event->set_timeout(timeout);
-  event->set_address((TYPE_ADDRESS)this->object_addr());
+  event->set_address((uintptr_t)monitor->object_addr());
   event->set_notifier(notifier_tid);
   event->set_timedOut(timedout);
   event->commit();
@@ -1438,7 +1442,7 @@
       // this ObjectMonitor.
     }
     if (event.should_commit()) {
-      post_monitor_wait_event(&event, 0, millis, false);
+      post_monitor_wait_event(&event, this, 0, millis, false);
     }
     TEVENT(Wait - Throw IEX);
     THROW(vmSymbols::java_lang_InterruptedException());
@@ -1580,7 +1584,7 @@
     }
 
     if (event.should_commit()) {
-      post_monitor_wait_event(&event, node._notifier_tid, millis, ret == OS_TIMEOUT);
+      post_monitor_wait_event(&event, this, node._notifier_tid, millis, ret == OS_TIMEOUT);
     }
 
     OrderAccess::fence();
@@ -1660,7 +1664,7 @@
       iterator->TState = ObjectWaiter::TS_ENTER;
     }
     iterator->_notified = 1;
-    iterator->_notifier_tid = THREAD_TRACE_ID(Self);
+    iterator->_notifier_tid = JFR_THREAD_ID(Self);
 
     ObjectWaiter * list = _EntryList;
     if (list != NULL) {
--- a/src/hotspot/share/runtime/objectMonitor.hpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/runtime/objectMonitor.hpp	Tue May 15 20:24:34 2018 +0200
@@ -59,9 +59,6 @@
   void wait_reenter_end(ObjectMonitor *mon);
 };
 
-// forward declaration to avoid include tracing.hpp
-class EventJavaMonitorWait;
-
 // The ObjectMonitor class implements the heavyweight version of a
 // JavaMonitor. The lightweight BasicLock/stack lock version has been
 // inflated into an ObjectMonitor. This inflation is typically due to
@@ -324,11 +321,6 @@
   int       TrySpin(Thread * Self);
   void      ExitEpilog(Thread * Self, ObjectWaiter * Wakee);
   bool      ExitSuspendEquivalent(JavaThread * Self);
-  void      post_monitor_wait_event(EventJavaMonitorWait * event,
-                                    jlong notifier_tid,
-                                    jlong timeout,
-                                    bool timedout);
-
 };
 
 #undef TEVENT
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/runtime/os_perf.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_RUNTIME_OS_PERF_HPP
+#define SHARE_VM_RUNTIME_OS_PERF_HPP
+
+#include "utilities/macros.hpp"
+#include "memory/allocation.inline.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+#define FUNCTIONALITY_NOT_IMPLEMENTED -8
+
+class EnvironmentVariable : public CHeapObj<mtInternal> {
+ public:
+  char* _key;
+  char* _value;
+
+  EnvironmentVariable() {
+    _key = NULL;
+    _value = NULL;
+  }
+
+  ~EnvironmentVariable() {
+    if (_key != NULL) {
+      FREE_C_HEAP_ARRAY(char, _key);
+    }
+    if (_value != NULL) {
+      FREE_C_HEAP_ARRAY(char, _value);
+    }
+  }
+
+  EnvironmentVariable(char* key, char* value) {
+    _key = key;
+    _value = value;
+  }
+
+};
+
+
+class CPUInformation : public CHeapObj<mtInternal> {
+ private:
+  int   _no_of_sockets;
+  int   _no_of_cores;
+  int   _no_of_hw_threads;
+  const char* _description;
+  const char* _name;
+
+ public:
+  CPUInformation() {
+    _no_of_sockets = 0;
+    _no_of_cores = 0;
+    _no_of_hw_threads = 0;
+    _description = NULL;
+    _name = NULL;
+  }
+
+  int number_of_sockets(void) const {
+    return _no_of_sockets;
+  }
+
+  void set_number_of_sockets(int no_of_sockets) {
+    _no_of_sockets = no_of_sockets;
+  }
+
+  int number_of_cores(void) const {
+    return _no_of_cores;
+  }
+
+  void set_number_of_cores(int no_of_cores) {
+    _no_of_cores = no_of_cores;
+  }
+
+  int number_of_hardware_threads(void) const {
+    return _no_of_hw_threads;
+  }
+
+  void set_number_of_hardware_threads(int no_of_hw_threads) {
+    _no_of_hw_threads = no_of_hw_threads;
+  }
+
+  const char* cpu_name(void)  const {
+    return _name;
+  }
+
+  void set_cpu_name(const char* cpu_name) {
+    _name = cpu_name;
+  }
+
+  const char* cpu_description(void) const {
+    return _description;
+  }
+
+  void set_cpu_description(const char* cpu_description) {
+    _description = cpu_description;
+  }
+};
+
+class SystemProcess : public CHeapObj<mtInternal> {
+ private:
+  int   _pid;
+  char* _name;
+  char* _path;
+  char* _command_line;
+  SystemProcess* _next;
+
+ public:
+  SystemProcess() {
+    _pid  = 0;
+    _name = NULL;
+    _path = NULL;
+    _command_line = NULL;
+    _next = NULL;
+  }
+
+  SystemProcess(int pid, char* name, char* path, char* command_line, SystemProcess* next) {
+    _pid = pid;
+    _name = name;
+    _path = path;
+    _command_line = command_line;
+    _next = next;
+  }
+
+  void set_next(SystemProcess* sys_process) {
+    _next = sys_process;
+  }
+
+  SystemProcess* next(void) const {
+    return _next;
+  }
+
+  int pid(void) const {
+    return _pid;
+  }
+
+  void set_pid(int pid) {
+    _pid = pid;
+  }
+
+  const char* name(void) const {
+    return _name;
+  }
+
+  void set_name(char* name) {
+    _name = name;
+  }
+
+  const char* path(void) const {
+    return _path;
+  }
+
+  void set_path(char* path) {
+    _path = path;
+  }
+
+  const char* command_line(void) const {
+    return _command_line;
+  }
+
+  void set_command_line(char* command_line) {
+    _command_line = command_line;
+  }
+
+  virtual ~SystemProcess(void) {
+    if (_name != NULL) {
+      FREE_C_HEAP_ARRAY(char, _name);
+    }
+    if (_path != NULL) {
+      FREE_C_HEAP_ARRAY(char, _path);
+    }
+    if (_command_line != NULL) {
+      FREE_C_HEAP_ARRAY(char, _command_line);
+    }
+  }
+};
+
+class CPUInformationInterface : public CHeapObj<mtInternal> {
+ private:
+  CPUInformation* _cpu_info;
+ public:
+  CPUInformationInterface();
+  bool initialize();
+  ~CPUInformationInterface();
+  int cpu_information(CPUInformation& cpu_info);
+};
+
+class CPUPerformanceInterface : public CHeapObj<mtInternal> {
+ private:
+  class CPUPerformance;
+  CPUPerformance* _impl;
+ public:
+  CPUPerformanceInterface();
+  ~CPUPerformanceInterface();
+  bool initialize();
+
+  int cpu_load(int which_logical_cpu, double* const cpu_load) const;
+  int context_switch_rate(double* const rate) const;
+  int cpu_load_total_process(double* const cpu_load) const;
+  int cpu_loads_process(double* const pjvmUserLoad,
+                        double* const pjvmKernelLoad,
+                        double* const psystemTotalLoad) const;
+};
+
+class SystemProcessInterface : public CHeapObj<mtInternal> {
+ private:
+   class SystemProcesses;
+   SystemProcesses* _impl;
+ public:
+   SystemProcessInterface();
+   ~SystemProcessInterface();
+   bool initialize();
+
+  // information about system processes
+  int system_processes(SystemProcess** system_procs, int* const no_of_sys_processes) const;
+};
+
+#endif // SHARE_VM_RUNTIME_OS_PERF_HPP
--- a/src/hotspot/share/runtime/safepoint.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/runtime/safepoint.cpp	Tue May 15 20:24:34 2018 +0200
@@ -37,6 +37,7 @@
 #include "gc/shared/strongRootsScope.hpp"
 #include "gc/shared/workgroup.hpp"
 #include "interpreter/interpreter.hpp"
+#include "jfr/jfrEvents.hpp"
 #include "logging/log.hpp"
 #include "logging/logStream.hpp"
 #include "memory/resourceArea.hpp"
@@ -62,14 +63,79 @@
 #include "runtime/threadSMR.hpp"
 #include "runtime/timerTrace.hpp"
 #include "services/runtimeService.hpp"
-#include "trace/tracing.hpp"
-#include "trace/traceMacros.hpp"
 #include "utilities/events.hpp"
 #include "utilities/macros.hpp"
 #ifdef COMPILER1
 #include "c1/c1_globals.hpp"
 #endif
 
+template <typename E>
+static void set_current_safepoint_id(E* event, int adjustment = 0) {
+  assert(event != NULL, "invariant");
+  event->set_safepointId(SafepointSynchronize::safepoint_counter() + adjustment);
+}
+
+static void post_safepoint_begin_event(EventSafepointBegin* event,
+                                       int thread_count,
+                                       int critical_thread_count) {
+  assert(event != NULL, "invariant");
+  assert(event->should_commit(), "invariant");
+  set_current_safepoint_id(event);
+  event->set_totalThreadCount(thread_count);
+  event->set_jniCriticalThreadCount(critical_thread_count);
+  event->commit();
+}
+
+static void post_safepoint_cleanup_event(EventSafepointCleanup* event) {
+  assert(event != NULL, "invariant");
+  assert(event->should_commit(), "invariant");
+  set_current_safepoint_id(event);
+  event->commit();
+}
+
+static void post_safepoint_synchronize_event(EventSafepointStateSynchronization* event,
+                                             int initial_number_of_threads,
+                                             int threads_waiting_to_block,
+                                             unsigned int iterations) {
+  assert(event != NULL, "invariant");
+  if (event->should_commit()) {
+    // Group this event together with the ones committed after the counter is increased
+    set_current_safepoint_id(event, 1);
+    event->set_initialThreadCount(initial_number_of_threads);
+    event->set_runningThreadCount(threads_waiting_to_block);
+    event->set_iterations(iterations);
+    event->commit();
+  }
+}
+
+static void post_safepoint_wait_blocked_event(EventSafepointWaitBlocked* event,
+                                              int initial_threads_waiting_to_block) {
+  assert(event != NULL, "invariant");
+  assert(event->should_commit(), "invariant");
+  set_current_safepoint_id(event);
+  event->set_runningThreadCount(initial_threads_waiting_to_block);
+  event->commit();
+}
+
+static void post_safepoint_cleanup_task_event(EventSafepointCleanupTask* event,
+                                              const char* name) {
+  assert(event != NULL, "invariant");
+  if (event->should_commit()) {
+    set_current_safepoint_id(event);
+    event->set_name(name);
+    event->commit();
+  }
+}
+
+static void post_safepoint_end_event(EventSafepointEnd* event) {
+  assert(event != NULL, "invariant");
+  if (event->should_commit()) {
+    // Group this event together with the ones committed before the counter increased
+    set_current_safepoint_id(event, -1);
+    event->commit();
+  }
+}
+
 // --------------------------------------------------------------------------------------------------
 // Implementation of Safepoint begin/end
 
@@ -339,16 +405,10 @@
     if (PrintSafepointStatistics) {
       update_statistics_on_spin_end();
     }
-
     if (sync_event.should_commit()) {
-      // Group this event together with the ones committed after the counter is increased
-      sync_event.set_safepointId(safepoint_counter() + 1);
-      sync_event.set_initialThreadCount(initial_running);
-      sync_event.set_runningThreadCount(_waiting_to_block);
-      sync_event.set_iterations(iterations);
-      sync_event.commit();
+      post_safepoint_synchronize_event(&sync_event, initial_running, _waiting_to_block, iterations);
     }
-  } // EventSafepointStateSynchronization destroyed here.
+  }
 
   // wait until all threads are stopped
   {
@@ -391,13 +451,10 @@
     _state = _synchronized;
 
     OrderAccess::fence();
-
     if (wait_blocked_event.should_commit()) {
-      wait_blocked_event.set_safepointId(safepoint_counter());
-      wait_blocked_event.set_runningThreadCount(initial_waiting_to_block);
-      wait_blocked_event.commit();
+      post_safepoint_wait_blocked_event(&wait_blocked_event, initial_waiting_to_block);
     }
-  } // EventSafepointWaitBlocked
+  }
 
 #ifdef ASSERT
   // Make sure all the threads were visited.
@@ -421,8 +478,7 @@
     EventSafepointCleanup cleanup_event;
     do_cleanup_tasks();
     if (cleanup_event.should_commit()) {
-      cleanup_event.set_safepointId(safepoint_counter());
-      cleanup_event.commit();
+      post_safepoint_cleanup_event(&cleanup_event);
     }
   }
 
@@ -430,22 +486,18 @@
     // Record how much time spend on the above cleanup tasks
     update_statistics_on_cleanup_end(os::javaTimeNanos());
   }
+
   if (begin_event.should_commit()) {
-    begin_event.set_safepointId(safepoint_counter());
-    begin_event.set_totalThreadCount(nof_threads);
-    begin_event.set_jniCriticalThreadCount(_current_jni_active_count);
-    begin_event.commit();
+    post_safepoint_begin_event(&begin_event, nof_threads, _current_jni_active_count);
   }
 }
 
 // Wake up all threads, so they are ready to resume execution after the safepoint
 // operation has been carried out
 void SafepointSynchronize::end() {
-  EventSafepointEnd event;
-  int safepoint_id = safepoint_counter(); // Keep the odd counter as "id"
-
   assert(Threads_lock->owned_by_self(), "must hold Threads_lock");
   assert((_safepoint_counter & 0x1) == 1, "must be odd");
+  EventSafepointEnd event;
   _safepoint_counter ++;
   // memory fence isn't required here since an odd _safepoint_counter
   // value can do no harm and a fence is issued below anyway.
@@ -541,10 +593,8 @@
   // record this time so VMThread can keep track how much time has elapsed
   // since last safepoint.
   _end_of_last_safepoint = os::javaTimeMillis();
-
   if (event.should_commit()) {
-    event.set_safepointId(safepoint_id);
-    event.commit();
+    post_safepoint_end_event(&event);
   }
 }
 
@@ -556,14 +606,6 @@
   return false;
 }
 
-static void event_safepoint_cleanup_task_commit(EventSafepointCleanupTask& event, const char* name) {
-  if (event.should_commit()) {
-    event.set_safepointId(SafepointSynchronize::safepoint_counter());
-    event.set_name(name);
-    event.commit();
-  }
-}
-
 class ParallelSPCleanupThreadClosure : public ThreadClosure {
 private:
   CodeBlobClosure* _nmethod_cl;
@@ -607,7 +649,9 @@
       EventSafepointCleanupTask event;
       TraceTime timer(name, TRACETIME_LOG(Info, safepoint, cleanup));
       ObjectSynchronizer::deflate_idle_monitors(_counters);
-      event_safepoint_cleanup_task_commit(event, name);
+      if (event.should_commit()) {
+        post_safepoint_cleanup_task_event(&event, name);
+      }
     }
 
     if (!_subtasks.is_task_claimed(SafepointSynchronize::SAFEPOINT_CLEANUP_UPDATE_INLINE_CACHES)) {
@@ -615,7 +659,9 @@
       EventSafepointCleanupTask event;
       TraceTime timer(name, TRACETIME_LOG(Info, safepoint, cleanup));
       InlineCacheBuffer::update_inline_caches();
-      event_safepoint_cleanup_task_commit(event, name);
+      if (event.should_commit()) {
+        post_safepoint_cleanup_task_event(&event, name);
+      }
     }
 
     if (!_subtasks.is_task_claimed(SafepointSynchronize::SAFEPOINT_CLEANUP_COMPILATION_POLICY)) {
@@ -623,7 +669,9 @@
       EventSafepointCleanupTask event;
       TraceTime timer(name, TRACETIME_LOG(Info, safepoint, cleanup));
       CompilationPolicy::policy()->do_safepoint_work();
-      event_safepoint_cleanup_task_commit(event, name);
+      if (event.should_commit()) {
+        post_safepoint_cleanup_task_event(&event, name);
+      }
     }
 
     if (!_subtasks.is_task_claimed(SafepointSynchronize::SAFEPOINT_CLEANUP_SYMBOL_TABLE_REHASH)) {
@@ -632,7 +680,9 @@
         EventSafepointCleanupTask event;
         TraceTime timer(name, TRACETIME_LOG(Info, safepoint, cleanup));
         SymbolTable::rehash_table();
-        event_safepoint_cleanup_task_commit(event, name);
+        if (event.should_commit()) {
+          post_safepoint_cleanup_task_event(&event, name);
+        }
       }
     }
 
@@ -642,7 +692,9 @@
         EventSafepointCleanupTask event;
         TraceTime timer(name, TRACETIME_LOG(Info, safepoint, cleanup));
         StringTable::rehash_table();
-        event_safepoint_cleanup_task_commit(event, name);
+        if (event.should_commit()) {
+          post_safepoint_cleanup_task_event(&event, name);
+        }
       }
     }
 
@@ -653,7 +705,9 @@
       EventSafepointCleanupTask event;
       TraceTime timer(name, TRACETIME_LOG(Info, safepoint, cleanup));
       ClassLoaderDataGraph::purge_if_needed();
-      event_safepoint_cleanup_task_commit(event, name);
+      if (event.should_commit()) {
+        post_safepoint_cleanup_task_event(&event, name);
+      }
     }
 
     if (!_subtasks.is_task_claimed(SafepointSynchronize::SAFEPOINT_CLEANUP_SYSTEM_DICTIONARY_RESIZE)) {
@@ -661,7 +715,9 @@
       EventSafepointCleanupTask event;
       TraceTime timer(name, TRACETIME_LOG(Info, safepoint, cleanup));
       ClassLoaderDataGraph::resize_if_needed();
-      event_safepoint_cleanup_task_commit(event, name);
+      if (event.should_commit()) {
+        post_safepoint_cleanup_task_event(&event, name);
+      }
     }
     _subtasks.all_tasks_completed(_num_workers);
   }
--- a/src/hotspot/share/runtime/sharedRuntime.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/runtime/sharedRuntime.cpp	Tue May 15 20:24:34 2018 +0200
@@ -40,6 +40,7 @@
 #include "gc/shared/gcLocker.inline.hpp"
 #include "interpreter/interpreter.hpp"
 #include "interpreter/interpreterRuntime.hpp"
+#include "jfr/jfrEvents.hpp"
 #include "logging/log.hpp"
 #include "memory/metaspaceShared.hpp"
 #include "memory/resourceArea.hpp"
@@ -66,7 +67,6 @@
 #include "runtime/stubRoutines.hpp"
 #include "runtime/vframe.inline.hpp"
 #include "runtime/vframeArray.hpp"
-#include "trace/tracing.hpp"
 #include "utilities/copy.hpp"
 #include "utilities/dtrace.hpp"
 #include "utilities/events.hpp"
--- a/src/hotspot/share/runtime/sweeper.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/runtime/sweeper.cpp	Tue May 15 20:24:34 2018 +0200
@@ -28,6 +28,7 @@
 #include "code/icBuffer.hpp"
 #include "code/nmethod.hpp"
 #include "compiler/compileBroker.hpp"
+#include "jfr/jfrEvents.hpp"
 #include "logging/log.hpp"
 #include "logging/logStream.hpp"
 #include "memory/allocation.inline.hpp"
@@ -43,9 +44,7 @@
 #include "runtime/thread.inline.hpp"
 #include "runtime/vm_operations.hpp"
 #include "runtime/vmThread.hpp"
-#include "trace/tracing.hpp"
 #include "utilities/events.hpp"
-#include "utilities/ticks.inline.hpp"
 #include "utilities/xmlstream.hpp"
 
 #ifdef ASSERT
@@ -410,6 +409,24 @@
   }
 }
 
+static void post_sweep_event(EventSweepCodeCache* event,
+                             const Ticks& start,
+                             const Ticks& end,
+                             s4 traversals,
+                             int swept,
+                             int flushed,
+                             int zombified) {
+  assert(event != NULL, "invariant");
+  assert(event->should_commit(), "invariant");
+  event->set_starttime(start);
+  event->set_endtime(end);
+  event->set_sweepId(traversals);
+  event->set_sweptCount(swept);
+  event->set_flushedCount(flushed);
+  event->set_zombifiedCount(zombified);
+  event->commit();
+}
+
 void NMethodSweeper::sweep_code_cache() {
   ResourceMark rm;
   Ticks sweep_start_counter = Ticks::now();
@@ -496,15 +513,10 @@
     _total_nof_c2_methods_reclaimed += flushed_c2_count;
     _peak_sweep_time = MAX2(_peak_sweep_time, _total_time_this_sweep);
   }
+
   EventSweepCodeCache event(UNTIMED);
   if (event.should_commit()) {
-    event.set_starttime(sweep_start_counter);
-    event.set_endtime(sweep_end_counter);
-    event.set_sweepId(_traversals);
-    event.set_sweptCount(swept_count);
-    event.set_flushedCount(flushed_count);
-    event.set_zombifiedCount(zombified_count);
-    event.commit();
+    post_sweep_event(&event, sweep_start_counter, sweep_end_counter, (s4)_traversals, swept_count, flushed_count, zombified_count);
   }
 
 #ifdef ASSERT
--- a/src/hotspot/share/runtime/synchronizer.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/runtime/synchronizer.cpp	Tue May 15 20:24:34 2018 +0200
@@ -25,6 +25,7 @@
 #include "precompiled.hpp"
 #include "classfile/vmSymbols.hpp"
 #include "logging/log.hpp"
+#include "jfr/jfrEvents.hpp"
 #include "memory/allocation.inline.hpp"
 #include "memory/metaspaceShared.hpp"
 #include "memory/padded.hpp"
@@ -46,8 +47,6 @@
 #include "runtime/thread.inline.hpp"
 #include "runtime/vframe.hpp"
 #include "runtime/vmThread.hpp"
-#include "trace/traceMacros.hpp"
-#include "trace/tracing.hpp"
 #include "utilities/align.hpp"
 #include "utilities/dtrace.hpp"
 #include "utilities/events.hpp"
@@ -128,10 +127,6 @@
 static volatile int gMonitorFreeCount  = 0;  // # on gFreeList
 static volatile int gMonitorPopulation = 0;  // # Extant -- in circulation
 
-static void post_monitor_inflate_event(EventJavaMonitorInflate&,
-                                       const oop,
-                                       const ObjectSynchronizer::InflateCause);
-
 #define CHAINMARKER (cast_to_oop<intptr_t>(-1))
 
 
@@ -1365,6 +1360,17 @@
   TEVENT(omFlush);
 }
 
+static void post_monitor_inflate_event(EventJavaMonitorInflate* event,
+                                       const oop obj,
+                                       ObjectSynchronizer::InflateCause cause) {
+  assert(event != NULL, "invariant");
+  assert(event->should_commit(), "invariant");
+  event->set_monitorClass(obj->klass());
+  event->set_address((uintptr_t)(void*)obj);
+  event->set_cause((u1)cause);
+  event->commit();
+}
+
 // Fast path code shared by multiple functions
 ObjectMonitor* ObjectSynchronizer::inflate_helper(oop obj) {
   markOop mark = obj->mark();
@@ -1519,7 +1525,7 @@
         }
       }
       if (event.should_commit()) {
-        post_monitor_inflate_event(event, object, cause);
+        post_monitor_inflate_event(&event, object, cause);
       }
       return m;
     }
@@ -1570,7 +1576,7 @@
       }
     }
     if (event.should_commit()) {
-      post_monitor_inflate_event(event, object, cause);
+      post_monitor_inflate_event(&event, object, cause);
     }
     return m;
   }
@@ -1897,18 +1903,6 @@
   return "Unknown";
 }
 
-static void post_monitor_inflate_event(EventJavaMonitorInflate& event,
-                                       const oop obj,
-                                       const ObjectSynchronizer::InflateCause cause) {
-#if INCLUDE_TRACE
-  assert(event.should_commit(), "check outside");
-  event.set_monitorClass(obj->klass());
-  event.set_address((TYPE_ADDRESS)(uintptr_t)(void*)obj);
-  event.set_cause((u1)cause);
-  event.commit();
-#endif
-}
-
 //------------------------------------------------------------------------------
 // Debugging code
 
--- a/src/hotspot/share/runtime/thread.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/runtime/thread.cpp	Tue May 15 20:24:34 2018 +0200
@@ -40,6 +40,8 @@
 #include "interpreter/interpreter.hpp"
 #include "interpreter/linkResolver.hpp"
 #include "interpreter/oopMapCache.hpp"
+#include "jfr/jfrEvents.hpp"
+#include "jfr/support/jfrThreadId.hpp"
 #include "jvmtifiles/jvmtiEnv.hpp"
 #include "logging/log.hpp"
 #include "logging/logConfiguration.hpp"
@@ -103,9 +105,6 @@
 #include "services/management.hpp"
 #include "services/memTracker.hpp"
 #include "services/threadService.hpp"
-#include "trace/traceMacros.hpp"
-#include "trace/tracing.hpp"
-#include "trace/tracingExport.hpp"
 #include "utilities/align.hpp"
 #include "utilities/copy.hpp"
 #include "utilities/defaultStream.hpp"
@@ -129,6 +128,9 @@
 #if INCLUDE_RTM_OPT
 #include "runtime/rtmLocking.hpp"
 #endif
+#if INCLUDE_JFR
+#include "jfr/jfr.hpp"
+#endif
 
 // Initialization after module runtime initialization
 void universe_post_module_init();  // must happen after call_initPhase2
@@ -365,7 +367,7 @@
 
 
 Thread::~Thread() {
-  EVENT_THREAD_DESTRUCT(this);
+  JFR_ONLY(Jfr::on_thread_destruct(this);)
 
   // Notify the barrier set that a thread is being destroyed. Note that a barrier
   // set might not be available if we encountered errors during bootstrapping.
@@ -374,6 +376,7 @@
     barrier_set->on_thread_destroy(this);
   }
 
+
   // stack_base can be NULL if the thread is never started or exited before
   // record_stack_base_and_size called. Although, we would like to ensure
   // that all started threads do call record_stack_base_and_size(), there is
@@ -1738,7 +1741,7 @@
 
   EventThreadStart event;
   if (event.should_commit()) {
-    event.set_thread(THREAD_TRACE_ID(this));
+    event.set_thread(JFR_THREAD_ID(this));
     event.commit();
   }
 
@@ -1845,12 +1848,12 @@
     // from java_lang_Thread object
     EventThreadEnd event;
     if (event.should_commit()) {
-      event.set_thread(THREAD_TRACE_ID(this));
+      event.set_thread(JFR_THREAD_ID(this));
       event.commit();
     }
 
     // Call after last event on thread
-    EVENT_THREAD_EXIT(this);
+    JFR_ONLY(Jfr::on_thread_exit(this);)
 
     // Call Thread.exit(). We try 3 times in case we got another Thread.stop during
     // the execution of the method. If that is not enough, then we don't really care. Thread.stop
@@ -2207,11 +2210,8 @@
   if (check_asyncs) {
     check_and_handle_async_exceptions();
   }
-#if INCLUDE_TRACE
-  if (is_trace_suspend()) {
-    TRACE_SUSPEND_THREAD(this);
-  }
-#endif
+
+  JFR_ONLY(SUSPEND_THREAD_CONDITIONAL(this);)
 }
 
 void JavaThread::send_thread_stop(oop java_throwable)  {
@@ -2433,11 +2433,8 @@
       fatal("missed deoptimization!");
     }
   }
-#if INCLUDE_TRACE
-  if (thread->is_trace_suspend()) {
-    TRACE_SUSPEND_THREAD(thread);
-  }
-#endif
+
+  JFR_ONLY(SUSPEND_THREAD_CONDITIONAL(thread);)
 }
 
 // Slow path when the native==>VM/Java barriers detect a safepoint is in
@@ -3422,11 +3419,12 @@
     tc->do_thread(wt);
   }
 
-#if INCLUDE_TRACE
-  Thread* sampler_thread = TracingExport::sampler_thread_acquire();
+#if INCLUDE_JFR
+  Thread* sampler_thread = Jfr::sampler_thread();
   if (sampler_thread != NULL) {
     tc->do_thread(sampler_thread);
   }
+
 #endif
 
   // If CompilerThreads ever become non-JavaThreads, add them here
@@ -3735,9 +3733,7 @@
     return status;
   }
 
-  if (TRACE_INITIALIZE() != JNI_OK) {
-    vm_exit_during_initialization("Failed to initialize tracing backend");
-  }
+  JFR_ONLY(Jfr::on_vm_init();)
 
   // Should be done after the heap is fully created
   main_thread->cache_global_variables();
@@ -3908,9 +3904,7 @@
   // Notify JVMTI agents that VM initialization is complete - nop if no agents.
   JvmtiExport::post_vm_initialized();
 
-  if (TRACE_START() != JNI_OK) {
-    vm_exit_during_initialization("Failed to start tracing backend.");
-  }
+  JFR_ONLY(Jfr::on_vm_start();)
 
 #if INCLUDE_MANAGEMENT
   Management::initialize(THREAD);
--- a/src/hotspot/share/runtime/thread.hpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/runtime/thread.hpp	Tue May 15 20:24:34 2018 +0200
@@ -44,14 +44,16 @@
 #include "runtime/stubRoutines.hpp"
 #include "runtime/threadLocalStorage.hpp"
 #include "runtime/unhandledOops.hpp"
-#include "trace/traceBackend.hpp"
-#include "trace/traceMacros.hpp"
 #include "utilities/align.hpp"
 #include "utilities/exceptions.hpp"
 #include "utilities/macros.hpp"
 #ifdef ZERO
 # include "stack_zero.hpp"
 #endif
+#if INCLUDE_JFR
+#include "jfr/support/jfrThreadExtension.hpp"
+#endif
+
 
 class SafeThreadsListPtr;
 class ThreadSafepointState;
@@ -337,7 +339,7 @@
   jlong _allocated_bytes;                       // Cumulative number of bytes allocated on
                                                 // the Java heap
 
-  mutable TRACE_DATA _trace_data;               // Thread-local data for tracing
+  JFR_ONLY(DEFINE_THREAD_LOCAL_FIELD_JFR;)      // Thread-local data for jfr
 
   int   _vm_operation_started_count;            // VM_Operation support
   int   _vm_operation_completed_count;          // VM_Operation support
@@ -515,8 +517,8 @@
   void incr_allocated_bytes(jlong size) { _allocated_bytes += size; }
   inline jlong cooked_allocated_bytes();
 
-  TRACE_DEFINE_THREAD_TRACE_DATA_OFFSET;
-  TRACE_DATA* trace_data() const        { return &_trace_data; }
+  JFR_ONLY(DEFINE_THREAD_LOCAL_ACCESSOR_JFR;)
+
   bool is_trace_suspend()               { return (_suspend_flags & _trace_flag) != 0; }
 
   // VM operation support
@@ -698,6 +700,8 @@
 
   static ByteSize allocated_bytes_offset()       { return byte_offset_of(Thread, _allocated_bytes); }
 
+  JFR_ONLY(DEFINE_THREAD_LOCAL_OFFSET_JFR;)
+
  public:
   volatile intptr_t _Stalled;
   volatile int _TypeTag;
--- a/src/hotspot/share/runtime/vmStructs.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/runtime/vmStructs.cpp	Tue May 15 20:24:34 2018 +0200
@@ -107,9 +107,6 @@
 # include "jvmci/vmStructs_jvmci.hpp"
 #endif
 
-#if INCLUDE_TRACE
-#include "runtime/vmStructs_trace.hpp"
-#endif
 
 #ifdef COMPILER2
 #include "opto/addnode.hpp"
@@ -2807,10 +2804,6 @@
              GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY,
              GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY)
 
-#if INCLUDE_TRACE
-  VM_STRUCTS_TRACE(GENERATE_NONSTATIC_VM_STRUCT_ENTRY,
-                   GENERATE_STATIC_VM_STRUCT_ENTRY)
-#endif
 
   VM_STRUCTS_OS(GENERATE_NONSTATIC_VM_STRUCT_ENTRY,
                 GENERATE_STATIC_VM_STRUCT_ENTRY,
@@ -2857,10 +2850,6 @@
            GENERATE_C2_VM_TYPE_ENTRY,
            GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY)
 
-#if INCLUDE_TRACE
-  VM_TYPES_TRACE(GENERATE_VM_TYPE_ENTRY,
-              GENERATE_TOPLEVEL_VM_TYPE_ENTRY)
-#endif
 
   VM_TYPES_OS(GENERATE_VM_TYPE_ENTRY,
               GENERATE_TOPLEVEL_VM_TYPE_ENTRY,
@@ -2905,10 +2894,6 @@
                    GENERATE_C2_VM_INT_CONSTANT_ENTRY,
                    GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY)
 
-#if INCLUDE_TRACE
-  VM_INT_CONSTANTS_TRACE(GENERATE_VM_INT_CONSTANT_ENTRY)
-#endif
-
   VM_INT_CONSTANTS_OS(GENERATE_VM_INT_CONSTANT_ENTRY,
                       GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY,
                       GENERATE_C1_VM_INT_CONSTANT_ENTRY,
@@ -2982,10 +2967,6 @@
              CHECK_NO_OP,
              CHECK_NO_OP);
 
-#if INCLUDE_TRACE
-  VM_STRUCTS_TRACE(CHECK_NONSTATIC_VM_STRUCT_ENTRY,
-                   CHECK_STATIC_VM_STRUCT_ENTRY);
-#endif
 
   VM_STRUCTS_CPU(CHECK_NONSTATIC_VM_STRUCT_ENTRY,
                  CHECK_STATIC_VM_STRUCT_ENTRY,
@@ -3014,10 +2995,6 @@
            CHECK_C2_VM_TYPE_ENTRY,
            CHECK_C2_TOPLEVEL_VM_TYPE_ENTRY);
 
-#if INCLUDE_TRACE
-  VM_TYPES_TRACE(CHECK_VM_TYPE_ENTRY,
-              CHECK_SINGLE_ARG_VM_TYPE_NO_OP);
-#endif
 
   VM_TYPES_CPU(CHECK_VM_TYPE_ENTRY,
                CHECK_SINGLE_ARG_VM_TYPE_NO_OP,
@@ -3075,11 +3052,6 @@
                         CHECK_NO_OP,
                         CHECK_NO_OP));
 
-#if INCLUDE_TRACE
-  debug_only(VM_STRUCTS_TRACE(ENSURE_FIELD_TYPE_PRESENT,
-                           ENSURE_FIELD_TYPE_PRESENT));
-#endif
-
   debug_only(VM_STRUCTS_CPU(ENSURE_FIELD_TYPE_PRESENT,
                             ENSURE_FIELD_TYPE_PRESENT,
                             CHECK_NO_OP,
--- a/src/hotspot/share/runtime/vmStructs_trace.hpp	Tue May 15 11:28:29 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2014, 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 SHARE_VM_RUNTIME_VMSTRUCTS_TRACE_HPP
-#define SHARE_VM_RUNTIME_VMSTRUCTS_TRACE_HPP
-
-#define VM_INT_CONSTANTS_TRACE(a)
-
-#define VM_STRUCTS_TRACE(a, b)
-
-#define VM_TYPES_TRACE(a, b)
-
-
-#endif // SHARE_VM_RUNTIME_VMSTRUCTS_TRACE_HPP
--- a/src/hotspot/share/runtime/vmThread.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/runtime/vmThread.cpp	Tue May 15 20:24:34 2018 +0200
@@ -25,6 +25,8 @@
 #include "precompiled.hpp"
 #include "compiler/compileBroker.hpp"
 #include "gc/shared/collectedHeap.hpp"
+#include "jfr/jfrEvents.hpp"
+#include "jfr/support/jfrThreadId.hpp"
 #include "logging/log.hpp"
 #include "logging/logConfiguration.hpp"
 #include "memory/resourceArea.hpp"
@@ -39,7 +41,6 @@
 #include "runtime/vmThread.hpp"
 #include "runtime/vm_operations.hpp"
 #include "services/runtimeService.hpp"
-#include "trace/tracing.hpp"
 #include "utilities/dtrace.hpp"
 #include "utilities/events.hpp"
 #include "utilities/vmError.hpp"
@@ -339,6 +340,23 @@
   }
 }
 
+static void post_vm_operation_event(EventExecuteVMOperation* event, VM_Operation* op) {
+  assert(event != NULL, "invariant");
+  assert(event->should_commit(), "invariant");
+  assert(op != NULL, "invariant");
+  const bool is_concurrent = op->evaluate_concurrently();
+  const bool evaluate_at_safepoint = op->evaluate_at_safepoint();
+  event->set_operation(op->type());
+  event->set_safepoint(evaluate_at_safepoint);
+  event->set_blocking(!is_concurrent);
+  // Only write caller thread information for non-concurrent vm operations.
+  // For concurrent vm operations, the thread id is set to 0 indicating thread is unknown.
+  // This is because the caller thread could have exited already.
+  event->set_caller(is_concurrent ? 0 : JFR_THREAD_ID(op->calling_thread()));
+  event->set_safepointId(evaluate_at_safepoint ? SafepointSynchronize::safepoint_counter() : 0);
+  event->commit();
+}
+
 void VMThread::evaluate_operation(VM_Operation* op) {
   ResourceMark rm;
 
@@ -349,21 +367,9 @@
                      op->evaluation_mode());
 
     EventExecuteVMOperation event;
-
     op->evaluate();
-
     if (event.should_commit()) {
-      const bool is_concurrent = op->evaluate_concurrently();
-      const bool evaluate_at_safepoint = op->evaluate_at_safepoint();
-      event.set_operation(op->type());
-      event.set_safepoint(evaluate_at_safepoint);
-      event.set_blocking(!is_concurrent);
-      // Only write caller thread information for non-concurrent vm operations.
-      // For concurrent vm operations, the thread id is set to 0 indicating thread is unknown.
-      // This is because the caller thread could have exited already.
-      event.set_caller(is_concurrent ? 0 : THREAD_TRACE_ID(op->calling_thread()));
-      event.set_safepointId(evaluate_at_safepoint ? SafepointSynchronize::safepoint_counter() : 0);
-      event.commit();
+      post_vm_operation_event(&event, op);
     }
 
     HOTSPOT_VMOPS_END(
--- a/src/hotspot/share/runtime/vm_operations.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/runtime/vm_operations.cpp	Tue May 15 20:24:34 2018 +0200
@@ -42,7 +42,6 @@
 #include "runtime/threadSMR.inline.hpp"
 #include "runtime/vm_operations.hpp"
 #include "services/threadService.hpp"
-#include "trace/tracing.hpp"
 
 #define VM_OP_NAME_INITIALIZE(name) #name,
 
--- a/src/hotspot/share/trace/noTraceBackend.hpp	Tue May 15 11:28:29 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2013, 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 SHARE_VM_TRACE_NOTRACEBACKEND_HPP
-#define SHARE_VM_TRACE_NOTRACEBACKEND_HPP
-
-#include "jni.h"
-#include "trace/traceTime.hpp"
-
-class NoTraceBackend {
-public:
-  static TracingTime time() {
-    return 0;
-  }
-};
-
-class TraceThreadData {
-public:
-    TraceThreadData() {}
-};
-
-typedef NoTraceBackend Tracing;
-
-#endif // SHARE_VM_TRACE_NOTRACEBACKEND_HPP
--- a/src/hotspot/share/trace/trace.dtd	Tue May 15 11:28:29 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-
- This code is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License version 2 only, as
- published by the Free Software Foundation.
-
- This code is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- version 2 for more details (a copy is included in the LICENSE file that
- accompanied this code).
-
- You should have received a copy of the GNU General Public License version
- 2 along with this work; if not, write to the Free Software Foundation,
- Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-
- Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- or visit www.oracle.com if you need additional information or have any
- questions.
-  
--->
-
-<!ELEMENT trace (xi:include*)>
-<!ELEMENT types (content_types, primary_types)>
-<!ELEMENT content_types (content_type|struct_type)*>
-<!ELEMENT content_type (value|structvalue|structarray|array)*>
-<!ELEMENT struct_type (value*)>
-<!ELEMENT primary_types (primary_type*)>
-<!ELEMENT primary_type EMPTY>
-<!ELEMENT relation_decls (relation_decl*)>
-<!ELEMENT relation_decl EMPTY>
-<!ELEMENT events (event|struct)*>
-<!ELEMENT event (value|structvalue)*>
-<!ELEMENT struct (value|structvalue)*>
-<!ELEMENT value EMPTY>
-<!ELEMENT structvalue EMPTY>
-<!ELEMENT structarray EMPTY>
-<!ELEMENT array EMPTY>
-<!ATTLIST content_type  id             CDATA #REQUIRED
-                        hr_name        CDATA #REQUIRED
-                        type           CDATA #REQUIRED
-                        jvm_type       CDATA #IMPLIED
-                        builtin_type   CDATA #IMPLIED>
-<!ATTLIST struct_type   id             CDATA #REQUIRED>
-<!ATTLIST structarray   type           CDATA #REQUIRED
-                        field          CDATA #REQUIRED
-                        label          CDATA #REQUIRED>
-<!ATTLIST primary_type  symbol         CDATA #REQUIRED
-                        datatype       CDATA #REQUIRED
-                        contenttype    CDATA #REQUIRED
-                        type           CDATA #REQUIRED
-                        sizeop         CDATA #REQUIRED>
-<!ATTLIST relation_decl id             CDATA #REQUIRED
-                        uri            CDATA #REQUIRED>
-<!ATTLIST event         id             CDATA #REQUIRED
-                        path           CDATA #REQUIRED
-                        label          CDATA #REQUIRED
-                        description    CDATA #IMPLIED
-                        has_thread     CDATA "false"
-                        ignore_check   CDATA "false"
-                        has_stacktrace CDATA "false"
-                        is_instant     CDATA "false"
-                        is_constant    CDATA "false"
-                        is_requestable CDATA "false"
-                        experimental   CDATA "false"
-                        cutoff         CDATA "false">
-<!ATTLIST struct        id             CDATA #REQUIRED>
-<!ATTLIST value         type           CDATA #REQUIRED
-                        field          CDATA #REQUIRED
-                        label          CDATA #REQUIRED
-                        description    CDATA #IMPLIED
-                        relation       CDATA "NOT_AVAILABLE"
-                        transition     CDATA "NONE"
-                        experimental   CDATA "false">
-<!ATTLIST array         type           CDATA #REQUIRED
-                        field          CDATA #REQUIRED
-                        label          CDATA #REQUIRED
-                        description    CDATA #IMPLIED
-                        experimental   CDATA "false">
-<!ATTLIST structarray   type           CDATA #REQUIRED
-                        field          CDATA #REQUIRED
-                        label          CDATA #REQUIRED
-                        description    CDATA #IMPLIED
-                        experimental   CDATA "false">
-<!ATTLIST structvalue   type           CDATA #REQUIRED
-                        field          CDATA #REQUIRED
-                        label          CDATA #REQUIRED
-                        description    CDATA #IMPLIED
-                        experimental   CDATA "false">
--- a/src/hotspot/share/trace/trace.xml	Tue May 15 11:28:29 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (c) 2012, 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.
-
--->
-
-
-<!DOCTYPE trace SYSTEM "trace.dtd" [
-<!ENTITY % xinclude SYSTEM "xinclude.mod">
-%xinclude;
-]>
-
-<trace>
-  <xi:include href="tracetypes.xml"
-              xmlns:xi="http://www.w3.org/2001/XInclude"/>
-  <xi:include href="tracerelationdecls.xml"
-              xmlns:xi="http://www.w3.org/2001/XInclude"/>
-  <xi:include href="traceevents.xml"
-              xmlns:xi="http://www.w3.org/2001/XInclude"/>
-</trace>
--- a/src/hotspot/share/trace/traceBackend.cpp	Tue May 15 11:28:29 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-/*
-* Copyright (c) 2016, 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 "jni.h"
-
-extern "C" void JNICALL trace_register_natives(JNIEnv*, jclass) {}
--- a/src/hotspot/share/trace/traceBackend.hpp	Tue May 15 11:28:29 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2012, 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.
- *
- */
-#ifndef SHARE_VM_TRACE_TRACEBACKEND_HPP
-#define SHARE_VM_TRACE_TRACEBACKEND_HPP
-
-#include "utilities/macros.hpp"
-#if INCLUDE_TRACE
-#include "runtime/globals.hpp"
-#include "runtime/os.hpp"
-#include "trace/traceTime.hpp"
-#include "tracefiles/traceEventIds.hpp"
-
-class TraceBackend {
-public:
-  static bool enabled(void) {
-    return EnableTracing;
-  }
-
-  static bool is_event_enabled(TraceEventId id) {
-    return enabled();
-  }
-
-  static TracingTime time() {
-    return os::elapsed_counter();
-  }
-
-  static void on_unloading_classes(void) {
-  }
-
-};
-
-class TraceThreadData {
-public:
-    TraceThreadData() {}
-};
-
-typedef TraceBackend Tracing;
-
-#else // !INCLUDE_TRACE
-#include "trace/noTraceBackend.hpp"
-#endif // INCLUDE_TRACE
-#endif // SHARE_VM_TRACE_TRACEBACKEND_HPP
--- a/src/hotspot/share/trace/traceDataTypes.hpp	Tue May 15 11:28:29 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/*
- * Copyright (c) 2012, 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 SHARE_VM_TRACE_TRACEDATATYPES_HPP
-#define SHARE_VM_TRACE_TRACEDATATYPES_HPP
-
-#include <stddef.h>
-
-#include "utilities/globalDefinitions.hpp"
-#include "utilities/ticks.hpp"
-
-enum {
-  CONTENT_TYPE_NONE             = 0,
-  CONTENT_TYPE_CLASS            = 20,
-  CONTENT_TYPE_THREAD           = 22,
-  CONTENT_TYPE_STACKTRACE       = 23,
-  CONTENT_TYPE_BYTES            = 24,
-  CONTENT_TYPE_EPOCHMILLIS      = 25,
-  CONTENT_TYPE_MILLIS           = 26,
-  CONTENT_TYPE_NANOS            = 27,
-  CONTENT_TYPE_TICKS            = 28,
-  CONTENT_TYPE_ADDRESS          = 29,
-  CONTENT_TYPE_PERCENTAGE       = 30,
-
-  JVM_CONTENT_TYPES_START       = 33,
-  JVM_CONTENT_TYPES_END         = 255
-};
-
-enum ReservedEvent {
-  EVENT_METADATA,
-  EVENT_CHECKPOINT,
-  EVENT_BUFFERLOST,
-
-  NUM_RESERVED_EVENTS = JVM_CONTENT_TYPES_END
-};
-
-typedef u8 traceid;
-
-class ClassLoaderData;
-class Klass;
-class Method;
-class ModuleEntry;
-class PackageEntry;
-class Symbol;
-
-#endif // SHARE_VM_TRACE_TRACEDATATYPES_HPP
--- a/src/hotspot/share/trace/traceEvent.hpp	Tue May 15 11:28:29 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,130 +0,0 @@
-/*
- * Copyright (c) 2012, 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 SHARE_VM_TRACE_TRACEEVENT_HPP
-#define SHARE_VM_TRACE_TRACEEVENT_HPP
-
-#include "trace/traceTime.hpp"
-#include "utilities/macros.hpp"
-
-enum EventStartTime {
-  UNTIMED,
-  TIMED
-};
-
-#if INCLUDE_TRACE
-#include "trace/traceBackend.hpp"
-#include "tracefiles/traceEventIds.hpp"
-#include "utilities/ticks.hpp"
-
-template<typename T>
-class TraceEvent {
- private:
-  bool _started;
-
- protected:
-  jlong _startTime;
-  jlong _endTime;
-  DEBUG_ONLY(bool _committed;)
-
-  void set_starttime(const TracingTime& time) {
-    _startTime = time;
-  }
-
-  void set_endtime(const TracingTime& time) {
-    _endTime = time;
-  }
-
-  TraceEvent(EventStartTime timing=TIMED) :
-    _startTime(0),
-    _endTime(0),
-    _started(false)
-#ifdef ASSERT
-    , _committed(false)
-#endif
-  {
-    if (T::is_enabled()) {
-      _started = true;
-      if (TIMED == timing && !T::isInstant) {
-        static_cast<T*>(this)->set_starttime(Tracing::time());
-      }
-    }
-  }
-
- public:
-  void set_starttime(const Ticks& time) {
-    _startTime = time.value();
-  }
-
-  void set_endtime(const Ticks& time) {
-    _endTime = time.value();
-  }
-
-  static bool is_enabled() {
-    return Tracing::is_event_enabled(T::eventId);
-  }
-
-  bool should_commit() {
-    return _started;
-  }
-
-  void commit() {
-    if (!should_commit()) {
-      return;
-    }
-    assert(!_committed, "event already committed");
-    if (_startTime == 0) {
-      static_cast<T*>(this)->set_starttime(Tracing::time());
-    } else if (_endTime == 0) {
-      static_cast<T*>(this)->set_endtime(Tracing::time());
-    }
-    if (static_cast<T*>(this)->should_write()) {
-      static_cast<T*>(this)->writeEvent();
-      DEBUG_ONLY(_committed = true;)
-    }
-  }
-
-  static TraceEventId id() {
-    return T::eventId;
-  }
-
-  static bool is_instant() {
-    return T::isInstant;
-  }
-
-  static bool is_requestable() {
-    return T::isRequestable;
-  }
-
-  static bool has_thread() {
-    return T::hasThread;
-  }
-
-  static bool has_stacktrace() {
-    return T::hasStackTrace;
-  }
-};
-
-#endif // INCLUDE_TRACE
-#endif // SHARE_VM_TRACE_TRACEEVENT_HPP
--- a/src/hotspot/share/trace/traceEventClasses.xsl	Tue May 15 11:28:29 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,304 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
- DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-
- This code is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License version 2 only, as
- published by the Free Software Foundation.
-
- This code is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- version 2 for more details (a copy is included in the LICENSE file that
- accompanied this code).
-
- You should have received a copy of the GNU General Public License version
- 2 along with this work; if not, write to the Free Software Foundation,
- Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-
- Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- or visit www.oracle.com if you need additional information or have any
- questions.
--->
-
-<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
-<xsl:import href="xsl_util.xsl"/>
-<xsl:output method="text" indent="no" omit-xml-declaration="yes"/>
-
-<xsl:template match="/">
-  <xsl:call-template name="file-header"/>
-
-#ifndef TRACEFILES_TRACEEVENTCLASSES_HPP
-#define TRACEFILES_TRACEEVENTCLASSES_HPP
-
-// On purpose outside the INCLUDE_TRACE
-// Some parts of traceEvent.hpp are used outside of
-// INCLUDE_TRACE
-
-#include "tracefiles/traceTypes.hpp"
-#include "utilities/macros.hpp"
-
-#if INCLUDE_TRACE
-#include "trace/traceEvent.hpp"
-#include "trace/traceStream.hpp"
-#include "utilities/ostream.hpp"
-
-  <xsl:apply-templates select="trace/events/struct" mode="trace"/>
-  <xsl:apply-templates select="trace/events/event" mode="trace"/>
-
-#else // !INCLUDE_TRACE
-
-class TraceEvent {
-public:
-  TraceEvent() {}
-  void set_starttime(const Ticks&amp; ignore) {}
-  void set_endtime(const Ticks&amp; ignore) {}
-  bool should_commit() const { return false; }
-  static bool is_enabled() { return false; }
-  void commit() {}
-};
-
-  <xsl:apply-templates select="trace/events/struct" mode="empty"/>
-  <xsl:apply-templates select="trace/events/event" mode="empty"/>
-
-#endif // INCLUDE_TRACE
-#endif // TRACEFILES_TRACEEVENTCLASSES_HPP
-</xsl:template>
-
-<xsl:template match="struct" mode="trace">
-struct TraceStruct<xsl:value-of select="@id"/>
-{
-private:
-<xsl:apply-templates select="value" mode="write-fields"/>
-public:
-<xsl:apply-templates select="value" mode="write-setters"/>
-
-  void writeStruct(TraceStream&amp; ts) {
-<xsl:apply-templates select="value" mode="write-data"/>
-  }
-};
-
-</xsl:template>
-
-<xsl:template match="struct" mode="empty">
-struct TraceStruct<xsl:value-of select="@id"/> 
-{
-public:
-<xsl:apply-templates select="value" mode="write-empty-setters"/>
-};
-</xsl:template>
-
-
-<xsl:template match="event" mode="empty">
-  <xsl:value-of select="concat('class Event', @id, ' : public TraceEvent')"/>
-{
- public:
-<xsl:value-of select="concat('  Event', @id, '(bool ignore=true) {}')"/>
-<xsl:text>
-</xsl:text>
-
-<xsl:apply-templates select="value|structvalue|transition_value|relation" mode="write-empty-setters"/>
-};
-
-</xsl:template>
-
-
-<xsl:template match="event" mode="trace">
-  <xsl:value-of select="concat('class Event', @id, ' : public TraceEvent&lt;Event', @id, '&gt;')"/>
-{
- public:
-  static const bool hasThread = <xsl:value-of select="@has_thread"/>;
-  static const bool hasStackTrace = <xsl:value-of select="@has_stacktrace"/>;
-  static const bool isInstant = <xsl:value-of select="@is_instant"/>;
-  static const bool isRequestable = <xsl:value-of select="@is_requestable"/>;
-  static const TraceEventId eventId = <xsl:value-of select="concat('Trace', @id, 'Event')"/>;
-
- private:
-<xsl:apply-templates select="value|structvalue|transition_value|relation" mode="write-fields"/>
-
-  void writeEventContent(void) {
-    TraceStream ts;
-    ts.print("<xsl:value-of select="@label"/>: [");
-<xsl:apply-templates select="value|structvalue" mode="write-data"/>
-    ts.print("]\n");
-  }
-
- public:
-<xsl:apply-templates select="value|structvalue|transition_value|relation" mode="write-setters"/>
-
-  bool should_write(void) {
-    return true;
-  }
-<xsl:text>
-
-</xsl:text>
-  <xsl:value-of select="concat('  Event', @id, '(EventStartTime timing=TIMED) : TraceEvent&lt;Event', @id, '&gt;(timing) {}', $newline)"/>
-  void writeEvent(void) {
-    if (UseLockedTracing) {
-      ttyLocker lock;
-      writeEventContent();
-    } else {
-      writeEventContent();
-    }
-  }
-
-  using <xsl:value-of select="concat('TraceEvent&lt;Event', @id, '&gt;')"/>::commit; // else commit() is hidden by overloaded versions in this class
-
-<xsl:variable name="instant" select="@is_instant"/>
-<!-- non static method (only for non instant events)-->
-<xsl:if test="$instant='false'">
-  <xsl:value-of select="concat('  Event', @id)"/>(
-    <xsl:for-each select="value|structvalue|transition_value|relation">
-    <xsl:apply-templates select="." mode="cpp-type"/><xsl:value-of select="concat(' ', @field)"/>
-    <xsl:if test="position() != last()">,
-    </xsl:if></xsl:for-each>) : TraceEvent&lt;<xsl:value-of select="concat('Event', @id)"/>&gt;(TIMED) {
-    if (should_commit()) {<xsl:for-each select="value|structvalue|transition_value|relation">
-      set_<xsl:value-of select="@field"/>(<xsl:value-of select="@field"/>);</xsl:for-each>
-    }
-  }
-
-  void commit(<xsl:for-each select="value|structvalue|transition_value|relation">
-    <xsl:apply-templates select="." mode="cpp-type"/><xsl:value-of select="concat(' ', @field)"/>
-    <xsl:if test="position() != last()">,
-              </xsl:if></xsl:for-each>) {
-    if (should_commit()) {
-      <xsl:for-each select="value|structvalue|transition_value|relation">set_<xsl:value-of select="@field"/>(<xsl:value-of select="@field"/>);
-      </xsl:for-each>commit();
-    }
-  }</xsl:if>
-<!-- static method (for all events) -->
-  static void commit(<xsl:if test="$instant='false'">const Ticks&amp; startTicks,
-                     const Ticks&amp; endTicks<xsl:choose><xsl:when test="value|structvalue|transition_value|relation">,
-                     </xsl:when></xsl:choose></xsl:if>
-                     <xsl:for-each select="value|structvalue|transition_value|relation">
-    <xsl:apply-templates select="." mode="cpp-type"/><xsl:value-of select="concat(' ', @field)"/>
-    <xsl:if test="position() != last()">,
-                     </xsl:if></xsl:for-each>) {
-    <xsl:value-of select="concat('Event', @id)"/> me(UNTIMED);
-
-    if (me.should_commit()) {
-      <xsl:if test="$instant='false'">me.set_starttime(startTicks);
-      me.set_endtime(endTicks);
-      </xsl:if>
-      <xsl:for-each select="value|structvalue|transition_value|relation">me.set_<xsl:value-of select="@field"/>(<xsl:value-of select="@field"/>);
-      </xsl:for-each>me.commit();
-    }
-  }
-};
-
-</xsl:template>
-
-<xsl:template match="value|transition_value|relation" mode="write-empty-setters">
-  <xsl:param name="cls"/>
-  <xsl:variable name="type" select="@type"/>
-  <xsl:variable name="wt" select="//primary_type[@symbol=$type]/@type"/>
-  <xsl:value-of select="concat('  void set_', @field, '(', $wt, ' value) { }')"/>
-  <xsl:if test="position() != last()">
-    <xsl:text>
-</xsl:text>
-  </xsl:if>
-</xsl:template>
-
-<xsl:template match="structvalue" mode="write-empty-setters">
-  <xsl:param name="cls"/>
-  <xsl:value-of select="concat('  void set_', @field, '(const TraceStruct', @type, '&amp; value) { }')"/>
-  <xsl:if test="position() != last()">
-    <xsl:text>
-</xsl:text>
-  </xsl:if>
-</xsl:template>
-
-<xsl:template match="value[@type='TICKS']" mode="write-setters">
-#if INCLUDE_TRACE
-<xsl:value-of select="concat('  void set_', @field, '(const Ticks&amp; time) { _', @field, ' = time; }')"/>
-#else
-<xsl:value-of select="concat('  void set_', @field, '(const Ticks&amp; ignore) {}')"/>
-#endif
-</xsl:template>
-
-<xsl:template match="value[@type='TICKSPAN']" mode="write-setters">
-#if INCLUDE_TRACE
-  <xsl:value-of select="concat('  void set_', @field, '(const Tickspan&amp; time) { _', @field, ' = time; }')"/>
-#else
-  <xsl:value-of select="concat('  void set_', @field, '(const Tickspan&amp; ignore) {}')"/>
-#endif
-</xsl:template>
-
-
-<xsl:template match="value" mode="write-fields">
-  <xsl:variable name="type" select="@type"/>
-  <xsl:variable name="wt" select="//primary_type[@symbol=$type]/@type"/>
-  <xsl:value-of select="concat('  ', $wt, ' _', @field, ';')"/>
-  <xsl:if test="position() != last()">
-    <xsl:text> 
-</xsl:text>
-  </xsl:if>
-</xsl:template>
-
-<xsl:template match="structvalue" mode="write-fields">
-  <xsl:value-of select="concat('  TraceStruct', @type, ' _', @field, ';')"/>
-  <xsl:text>
-</xsl:text>
-</xsl:template>
-
-<xsl:template match="value|transition_value|relation" mode="write-setters">
-  <xsl:param name="cls"/>
-  <xsl:variable name="type" select="@type"/>
-  <xsl:variable name="wt" select="//primary_type[@symbol=$type]/@type"/>
-  <xsl:value-of select="concat('  void set_', @field, '(', $wt, ' value) { this->_', @field, ' = value; }')"/>
-  <xsl:if test="position() != last()">
-    <xsl:text>
-</xsl:text>
-  </xsl:if>
-</xsl:template>
-
-<xsl:template match="structvalue" mode="write-setters">
-  <xsl:param name="cls"/>
-  <xsl:value-of select="concat('  void set_', @field, '(const TraceStruct', @type, '&amp; value) { this->_', @field, ' = value; }')"/>
-  <xsl:if test="position() != last()">
-    <xsl:text>
-</xsl:text>
-  </xsl:if>
-</xsl:template>
-
-<xsl:template match="value" mode="write-data">
-  <xsl:variable name="type" select="@type"/>
-  <xsl:variable name="wt" select="//primary_type[@symbol=$type]/@writetype"/>
-  <xsl:choose>
-    <xsl:when test="@type='TICKSPAN'">
-      <xsl:value-of select="concat('    ts.print_val(&quot;', @label, '&quot;, _', @field, '.value());')"/>
-    </xsl:when>
-    <xsl:when test="@type='TICKS'">
-      <xsl:value-of select="concat('    ts.print_val(&quot;', @label, '&quot;, _', @field, '.value());')"/>
-    </xsl:when>
-    <xsl:otherwise>
-      <xsl:value-of select="concat('    ts.print_val(&quot;', @label, '&quot;, _', @field, ');')"/>
-    </xsl:otherwise>
-  </xsl:choose>
-  <xsl:if test="position() != last()">
-    <xsl:text>
-    ts.print(", ");
-</xsl:text>
-  </xsl:if>
-</xsl:template>
-
-<xsl:template match="structvalue" mode="write-data">
-  <xsl:value-of select="concat('    _', @field, '.writeStruct(ts);')"/>
-  <xsl:if test="position() != last()">
-    <xsl:text>
-    ts.print(", ");
-</xsl:text>
-  </xsl:if>
-</xsl:template>
-
-
-<xsl:template match="value|transition_value|relation" mode="cpp-type">
-  <xsl:variable name="type" select="@type"/>
-  <xsl:value-of select="//primary_type[@symbol=$type]/@type"/>
-</xsl:template>
-<xsl:template match="structvalue" mode="cpp-type">
-  <xsl:value-of select="concat('const TraceStruct', @type, '&amp;')"/>
-</xsl:template>
-
-</xsl:stylesheet>
--- a/src/hotspot/share/trace/traceEventIds.xsl	Tue May 15 11:28:29 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-
- This code is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License version 2 only, as
- published by the Free Software Foundation.
-
- This code is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- version 2 for more details (a copy is included in the LICENSE file that
- accompanied this code).
-
- You should have received a copy of the GNU General Public License version
- 2 along with this work; if not, write to the Free Software Foundation,
- Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-
- Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- or visit www.oracle.com if you need additional information or have any
- questions.
--->
-
-<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
-<xsl:import href="xsl_util.xsl"/>
-<xsl:output method="text" indent="no" omit-xml-declaration="yes"/>
-
-<xsl:template match="/">
-  <xsl:call-template name="file-header"/>
-
-#ifndef TRACEFILES_TRACEEVENTIDS_HPP
-#define TRACEFILES_TRACEEVENTIDS_HPP
-
-#include "utilities/macros.hpp"
-#if INCLUDE_TRACE
-#include "trace/traceDataTypes.hpp"
-
-/**
- * Enum of the event types in the JVM
- */
-enum TraceEventId {
-  _traceeventbase = (NUM_RESERVED_EVENTS-1), // Make sure we start at right index.
-  
-  // Events -> enum entry
-<xsl:for-each select="trace/events/*">
-  <xsl:value-of select="concat('  Trace', @id, 'Event,', $newline)"/>
-</xsl:for-each>
-  MaxTraceEventId
-};
-
-/**
- * Struct types in the JVM
- */
-enum TraceStructId {
-<xsl:for-each select="trace/types/content_types/*">
-  <xsl:value-of select="concat('  Trace', @id, 'Struct,', $newline)"/>
-</xsl:for-each>
-<xsl:for-each select="trace/events/*">
-  <xsl:value-of select="concat('  Trace', @id, 'Struct,', $newline)"/>
-</xsl:for-each>
-  MaxTraceStructId
-};
-
-typedef enum TraceEventId  TraceEventId;
-typedef enum TraceStructId TraceStructId;
-
-#endif // INCLUDE_TRACE
-#endif // TRACEFILES_TRACEEVENTIDS_HPP
-</xsl:template>
-
-</xsl:stylesheet>
--- a/src/hotspot/share/trace/traceMacros.hpp	Tue May 15 11:28:29 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2012, 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 SHARE_VM_TRACE_TRACEMACROS_HPP
-#define SHARE_VM_TRACE_TRACEMACROS_HPP
-
-typedef u8 traceid;
-
-#define EVENT_THREAD_EXIT(thread)
-#define EVENT_THREAD_DESTRUCT(thread)
-#define TRACE_KLASS_CREATION(k, p, t)
-
-#define TRACE_INIT_ID(k)
-#define TRACE_REMOVE_ID(k)
-#define TRACE_RESTORE_ID(k)
-#define TRACE_DATA TraceThreadData
-
-#define THREAD_TRACE_ID(thread) ((traceid)thread->osthread()->thread_id())
-extern "C" void JNICALL trace_register_natives(JNIEnv*, jclass);
-#define TRACE_REGISTER_NATIVES ((void*)((address_word)(&trace_register_natives)))
-#define TRACE_START() JNI_OK
-#define TRACE_INITIALIZE() JNI_OK
-#define TRACE_ALLOCATION(obj, size, thread)
-#define TRACE_WEAK_OOPS_DO(is_alive, f)
-#define TRACE_VM_EXIT()
-#define TRACE_VM_ERROR()
-#define TRACE_SUSPEND_THREAD(t)
-
-#define TRACE_DEFINE_TRACE_ID_METHODS typedef int ___IGNORED_hs_trace_type1
-#define TRACE_DEFINE_TRACE_ID_FIELD typedef int ___IGNORED_hs_trace_type2
-#define TRACE_DEFINE_KLASS_TRACE_ID_OFFSET typedef int ___IGNORED_hs_trace_type3
-#define TRACE_KLASS_TRACE_ID_OFFSET in_ByteSize(0); ShouldNotReachHere()
-#define TRACE_DEFINE_THREAD_TRACE_DATA_OFFSET typedef int ___IGNORED_hs_trace_type4
-#define TRACE_THREAD_TRACE_DATA_OFFSET in_ByteSize(0); ShouldNotReachHere()
-#define TRACE_DEFINE_THREAD_TRACE_ID_OFFSET typedef int ___IGNORED_hs_trace_type5
-#define TRACE_THREAD_TRACE_ID_OFFSET in_ByteSize(0); ShouldNotReachHere()
-#define TRACE_DEFINE_THREAD_ID_SIZE typedef int ___IGNORED_hs_trace_type6
-#define TRACE_DEFINE_THREAD_DATA_WRITER_OFFSET typedef int ___IGNORED_hs_trace_type7
-#define TRACE_THREAD_DATA_WRITER_OFFSET in_ByteSize(0); ShouldNotReachHere()
-#define TRACE_DEFINE_FLAG typedef int ___IGNORED_hs_trace_type8
-#define TRACE_DEFINE_FLAG_ACCESSOR typedef int ___IGNORED_hs_trace_type9
-#define TRACE_TEMPLATES(template)
-#define TRACE_INTRINSICS(do_intrinsic, do_class, do_name, do_signature, do_alias)
-
-#endif // SHARE_VM_TRACE_TRACEMACROS_HPP
--- a/src/hotspot/share/trace/traceStream.cpp	Tue May 15 11:28:29 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,91 +0,0 @@
-/*
-* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
-* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-*
-* This code is free software; you can redistribute it and/or modify it
-* under the terms of the GNU General Public License version 2 only, as
-* published by the Free Software Foundation.
-*
-* This code is distributed in the hope that it will be useful, but WITHOUT
-* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-* version 2 for more details (a copy is included in the LICENSE file that
-* accompanied this code).
-*
-* You should have received a copy of the GNU General Public License version
-* 2 along with this work; if not, write to the Free Software Foundation,
-* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-*
-* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-* or visit www.oracle.com if you need additional information or have any
-* questions.
-*
-*/
-
-#include "precompiled.hpp"
-#include "trace/traceStream.hpp"
-#if INCLUDE_TRACE
-#include "classfile/classLoaderData.inline.hpp"
-#include "classfile/javaClasses.inline.hpp"
-#include "memory/resourceArea.hpp"
-#include "oops/klass.hpp"
-#include "oops/method.hpp"
-#include "oops/symbol.hpp"
-
-void TraceStream::print_val(const char* label, const Klass* val) const {
-  ResourceMark rm;
-  const char* description = "NULL";
-  if (val != NULL) {
-    const Symbol* name = val->name();
-    if (name != NULL) {
-      description = name->as_C_string();
-    }
-  }
-  tty->print("%s = %s", label, description);
-}
-
-void TraceStream::print_val(const char* label, const Method* val) const {
-  ResourceMark rm;
-  const char* description = "NULL";
-  if (val != NULL) {
-    description = val->name_and_sig_as_C_string();
-  }
-  tty->print("%s = %s", label, description);
-}
-
-void TraceStream::print_val(const char* label, const ClassLoaderData* cld) const {
-  ResourceMark rm;
-  if (cld == NULL || cld->is_anonymous()) {
-    tty->print("%s = NULL", label);
-    return;
-  }
-  const char* class_loader_name = "NULL";
-  const char* class_loader_type_name = "NULL";
-  const oop class_loader_oop = cld->class_loader();
-
-  if (class_loader_oop != NULL) {
-    const Klass* k = class_loader_oop->klass();
-    assert(k != NULL, "invariant");
-    const Symbol* klass_name_sym = k->name();
-    if (klass_name_sym != NULL) {
-      class_loader_type_name = klass_name_sym->as_C_string();
-    }
-    const oop class_loader_name_oop =
-      java_lang_ClassLoader::name(class_loader_oop);
-    if (class_loader_name_oop != NULL) {
-      const char* class_loader_name_from_oop =
-        java_lang_String::as_utf8_string(class_loader_name_oop);
-      if (class_loader_name_from_oop != NULL &&
-            class_loader_name_from_oop[0] != '\0') {
-        class_loader_name = class_loader_name_from_oop;
-      }
-    }
-  } else {
-    assert(class_loader_oop == NULL, "invariant");
-    // anonymous CLDs are excluded, this would be the boot loader
-    class_loader_name = "boot";
-  }
-  tty->print("%s = name=%s class=%s", label, class_loader_name, class_loader_type_name);
-}
-
-#endif // INCLUDE_TRACE
--- a/src/hotspot/share/trace/traceStream.hpp	Tue May 15 11:28:29 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,98 +0,0 @@
-/*
- * Copyright (c) 2012, 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.
- *
- */
-
-#ifndef SHARE_VM_TRACE_TRACESTREAM_HPP
-#define SHARE_VM_TRACE_TRACESTREAM_HPP
-
-#include "utilities/macros.hpp"
-#if INCLUDE_TRACE
-#include "memory/allocation.hpp"
-#include "utilities/debug.hpp"
-#include "utilities/ostream.hpp"
-
-class ClassLoaderData;
-class Klass;
-class Method;
-
-class TraceStream : public StackObj {
- public:
-  TraceStream() {
-    assert(tty != NULL, "invariant");
-  }
-
-  void print(const char* val) const {
-    tty->print("%s", val);
-  }
-
-  void print_val(const char* label, u1 val) const {
-    tty->print("%s = " UINT32_FORMAT, label, val);
-  }
-
-  void print_val(const char* label, u2 val) const {
-    tty->print("%s = " UINT32_FORMAT, label, val);
-  }
-
-  void print_val(const char* label, s2 val) const {
-    tty->print("%s = " INT32_FORMAT, label, val);
-  }
-
-  void print_val(const char* label, u4 val) const {
-    tty->print("%s = " UINT32_FORMAT, label, val);
-  }
-
-  void print_val(const char* label, s4 val) const {
-    tty->print("%s = " INT32_FORMAT, label, val);
-  }
-
-  void print_val(const char* label, u8 val) const {
-    tty->print("%s = " UINT64_FORMAT, label, val);
-  }
-
-  void print_val(const char* label, s8 val) const {
-    tty->print("%s = " INT64_FORMAT, label, (int64_t) val);
-  }
-
-  void print_val(const char* label, bool val) const {
-    tty->print("%s = %s", label, val ? "true" : "false");
-  }
-
-  void print_val(const char* label, float val) const {
-    tty->print("%s = %f", label, val);
-  }
-
-  void print_val(const char* label, double val) const {
-    tty->print("%s = %f", label, val);
-  }
-
-  void print_val(const char* label, const char* val) const {
-    tty->print("%s = '%s'", label, val);
-  }
-
-  void print_val(const char* label, const Klass* val) const;
-  void print_val(const char* label, const Method* val) const ;
-  void print_val(const char* label, const ClassLoaderData* cld) const;
-};
-
-#endif // INCLUDE_TRACE
-#endif // SHARE_VM_TRACE_TRACESTREAM_HPP
--- a/src/hotspot/share/trace/traceTime.hpp	Tue May 15 11:28:29 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-/*
- * Copyright (c) 2012, 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 SHARE_VM_TRACE_TRACETIME_HPP
-#define SHARE_VM_TRACE_TRACETIME_HPP
-
-#include "jni.h"
-
-typedef jlong TracingTime;
-
-#endif // SHARE_VM_TRACE_TRACETIME_HPP
--- a/src/hotspot/share/trace/traceTypes.xsl	Tue May 15 11:28:29 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (c) 2012, 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.
--->
-
-<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
-<xsl:import href="xsl_util.xsl"/>
-<xsl:output method="text" indent="no" omit-xml-declaration="yes"/>
-
-<xsl:template match="/">
-  <xsl:call-template name="file-header"/>
-
-#ifndef TRACEFILES_TRACETYPES_HPP
-#define TRACEFILES_TRACETYPES_HPP
-
-#include "trace/traceDataTypes.hpp"
-
-enum JVMContentType {
-  _not_a_content_type = (JVM_CONTENT_TYPES_START - 1),
-  
-<xsl:for-each select="trace/types/content_types/content_type[@jvm_type]">
-  <xsl:value-of select="concat('  CONTENT_TYPE_', @jvm_type, ',',  $newline)"/>
-</xsl:for-each>
-  NUM_JVM_CONTENT_TYPES
-};
-
-
-enum JVMEventRelations {
-  JVM_REL_NOT_AVAILABLE = 0,
-  
-<xsl:for-each select="trace/relation_decls/relation_decl">
-  <xsl:value-of select="concat('  JVM_REL_', @id, ',', $newline)"/>
-</xsl:for-each>
-  NUM_EVENT_RELATIONS
-};
-
-/**
- * Create typedefs for the TRACE types:
- *   typedef s8 TYPE_LONG;
- *   typedef s4 TYPE_INTEGER;
- *   typedef const char * TYPE_STRING;
- *   ...
- */
-<xsl:for-each select="trace/types/primary_types/primary_type">
-typedef <xsl:value-of select="@type"/>  TYPE_<xsl:value-of select="@symbol"/>;
-</xsl:for-each>
-
-#endif // TRACEFILES_TRACETYPES_HPP
-</xsl:template>
-
-</xsl:stylesheet>
--- a/src/hotspot/share/trace/traceevents.xml	Tue May 15 11:28:29 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,648 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
- DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-
- This code is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License version 2 only, as
- published by the Free Software Foundation.
-
- This code is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- version 2 for more details (a copy is included in the LICENSE file that
- accompanied this code).
-
- You should have received a copy of the GNU General Public License version
- 2 along with this work; if not, write to the Free Software Foundation,
- Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-
- Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- or visit www.oracle.com if you need additional information or have any
- questions.
-
--->
-
-
-<!DOCTYPE events SYSTEM "trace.dtd">
-
-<events>
-
-<!--
-
-Events in the JVM are by default timed (it's more common)
-Perhaps a little strange. Might change.
-
-EVENTS
-
-Declard with the 'event' tag.
-
-<value fields> can be one or more of
-   value            - a simple primitive or constant type value
-   structvalue      - value is a sub-struct. This type must be previously defined
-                      with 'struct'
-All these require you to declare type, field and label of the field. They also accept
-an optional description of the field. If the meaning of the field is not obvious
-from the label you should provide a description. If an event however is not actually
-meant for end-users, you should probably _not_ write descriptions at all, since you
-might just add more concepts the user has no notion of/interest in.
-
-Events should be modeled after what conceptual process you are expressing, _NOT_
-from whatever data structures you might use inside the JVM for expressing a process.
-
-
-STRUCT
-
-Declared with the 'struct' tag.
-
-Declares a structure type that can be used in other events.
-
--->
-
-  <event id="ThreadStart" path="java/thread_start" label="Java Thread Start"
-         has_thread="true" is_instant="true">
-    <value type="THREAD" field="thread" label="Java Thread"/>
-  </event>
-
-  <event id="ThreadEnd" path="java/thread_end" label="Java Thread End"
-         has_thread="true" is_instant="true">
-    <value type="THREAD" field="thread" label="Java Thread"/>
-  </event>
-
-  <event id="ThreadSleep" path="java/thread_sleep" label="Java Thread Sleep"
-          has_thread="true" has_stacktrace="true" is_instant="false">
-    <value type="MILLIS" field="time" label="Sleep Time"/>
-  </event>
-
-  <event id="ThreadPark" path="java/thread_park" label="Java Thread Park"
-          has_thread="true" has_stacktrace="true" is_instant="false">
-    <value type="CLASS" field="parkedClass" label="Class Parked On"/>
-    <value type="MILLIS" field="timeout" label="Park Timeout"/>
-    <value type="ADDRESS" field="address" label="Address of Object Parked" relation="JavaMonitorAddress"/>
-  </event>
-
-  <event id="JavaMonitorEnter" path="java/monitor_enter" label="Java Monitor Blocked"
-          has_thread="true" has_stacktrace="true" is_instant="false">
-    <value type="CLASS" field="monitorClass" label="Monitor Class"/>
-    <value type="THREAD" field="previousOwner" label="Previous Monitor Owner"/>
-    <value type="ADDRESS" field="address" label="Monitor Address" relation="JavaMonitorAddress"/>
-  </event>
-
-  <event id="JavaMonitorWait" path="java/monitor_wait" label="Java Monitor Wait" description="Waiting on a Java monitor"
-          has_thread="true" has_stacktrace="true" is_instant="false">
-    <value type="CLASS" field="monitorClass" label="Monitor Class" description="Class of object waited on"/>
-    <value type="THREAD" field="notifier" label="Notifier Thread" description="Notifying Thread"/>
-    <value type="MILLIS" field="timeout" label="Timeout" description="Maximum wait time"/>
-    <value type="BOOLEAN" field="timedOut" label="Timed Out" description="Wait has been timed out"/>
-    <value type="ADDRESS" field="address" label="Monitor Address" description="Address of object waited on" relation="JavaMonitorAddress"/>
-  </event>
-
-  <event id="JavaMonitorInflate" path="java/monitor_inflate" label="Java Monitor Inflated"
-         has_thread="true" has_stacktrace="true" is_instant="false">
-    <value type="CLASS" field="monitorClass" label="Monitor Class"/>
-    <value type="ADDRESS" field="address" label="Monitor Address" relation="JavaMonitorAddress"/>
-    <value type="INFLATECAUSE" field="cause" label="Monitor Inflation Cause" description="Cause of inflation"/>
-  </event>
-
-  <event id="BiasedLockRevocation" path="java/biased_lock_revocation" label="Biased Lock Revocation"
-         description="Revoked bias of object" has_thread="true" has_stacktrace="true" is_instant="false">
-    <value type="CLASS" field="lockClass" label="Lock Class" description="Class of object whose biased lock was revoked"/>
-    <value type="INTEGER" field="safepointId" label="Safepoint Identifier" relation="SafepointId"/>
-    <value type="THREAD" field="previousOwner" label="Previous Owner" description="Thread owning the bias before revocation"/>
-  </event>
-
-  <event id="BiasedLockSelfRevocation" path="java/biased_lock_self_revocation" label="Biased Lock Self Revocation"
-         description="Revoked bias of object biased towards own thread" has_thread="true" has_stacktrace="true" is_instant="false">
-    <value type="CLASS" field="lockClass" label="Lock Class" description="Class of object whose biased lock was revoked"/>
-  </event>
-
-  <event id="BiasedLockClassRevocation" path="java/biased_lock_class_revocation" label="Biased Lock Class Revocation"
-         description="Revoked biases for all instances of a class" has_thread="true" has_stacktrace="true" is_instant="false">
-    <value type="CLASS" field="revokedClass" label="Revoked Class" description="Class whose biased locks were revoked"/>
-    <value type="BOOLEAN" field="disableBiasing" label="Disable Further Biasing" description="Whether further biasing for instances of this class will be allowed"/>
-    <value type="INTEGER" field="safepointId" label="Safepoint Identifier" relation="SafepointId"/>
-  </event>
-
-  <event id="ReservedStackActivation" path="vm/runtime/reserved_stack_activation" label="Reserved Stack Activation"
-         description="Activation of Reserved Stack Area caused by stack overflow with ReservedStackAccess annotated method in call stack"
-         has_thread="true" has_stacktrace="true" is_instant="true">
-      <value type="METHOD" field="method" label="Java Method"/>
-  </event>
-
-  <event id="ClassLoad" path="vm/class/load" label="Class Load"
-         has_thread="true" has_stacktrace="true" is_instant="false">
-    <value type="CLASS" field="loadedClass" label="Loaded Class"/>
-    <value type="CLASSLOADER" field="definingClassLoader" label="Defining Class Loader"/>
-    <value type="CLASSLOADER" field="initiatingClassLoader" label="Initiating Class Loader"/>
-  </event>
-
-  <event id="ClassDefine" path="vm/class/define" label="Class Define"
-         has_thread="true" has_stacktrace="true" is_instant="true">
-    <value type="CLASS" field="definedClass" label="Defined Class"/>
-    <value type="CLASSLOADER" field="definingClassLoader" label="Defining Class Loader"/>
-  </event>
-
-  <event id="ClassUnload" path="vm/class/unload" label="Class Unload"
-         has_thread="true" is_instant="true">
-    <value type="CLASS" field="unloadedClass" label="Unloaded Class"/>
-    <value type="CLASSLOADER" field="definingClassLoader" label="Defining Class Loader"/>
-  </event>
-
-  <event id="IntFlagChanged" path="vm/flag/int_changed" label="Int Flag Changed"
-         is_instant="true">
-    <value type="STRING" field="name" label="Name" />
-    <value type="INTEGER" field="oldValue" label="Old Value" />
-    <value type="INTEGER" field="newValue" label="New Value" />
-    <value type="FLAGVALUEORIGIN" field="origin" label="Origin" />
-  </event>
-
-  <event id="UnsignedIntFlagChanged" path="vm/flag/uint_changed" label="Unsigned Int Flag Changed"
-         is_instant="true">
-    <value type="STRING" field="name" label="Name" />
-    <value type="UINT" field="oldValue" label="Old Value" />
-    <value type="UINT" field="newValue" label="New Value" />
-    <value type="FLAGVALUEORIGIN" field="origin" label="Origin" />
-  </event>
-
-  <event id="LongFlagChanged" path="vm/flag/long_changed" label="Long Flag Changed"
-         is_instant="true">
-    <value type="STRING" field="name" label="Name" />
-    <value type="LONG" field="oldValue" label="Old Value" />
-    <value type="LONG" field="newValue" label="New Value" />
-    <value type="FLAGVALUEORIGIN" field="origin" label="Origin" />
-  </event>
-
-  <event id="UnsignedLongFlagChanged" path="vm/flag/ulong_changed" label="Unsigned Long Flag Changed"
-         is_instant="true">
-    <value type="STRING" field="name" label="Name" />
-    <value type="ULONG" field="oldValue" label="Old Value" />
-    <value type="ULONG" field="newValue" label="New Value" />
-    <value type="FLAGVALUEORIGIN" field="origin" label="Origin" />
-  </event>
-
-  <event id="DoubleFlagChanged" path="vm/flag/double_changed" label="Double Flag Changed"
-         is_instant="true">
-    <value type="STRING" field="name" label="Name" />
-    <value type="DOUBLE" field="oldValue" label="Old Value" />
-    <value type="DOUBLE" field="newValue" label="New Value" />
-    <value type="FLAGVALUEORIGIN" field="origin" label="Origin" />
-  </event>
-
-  <event id="BooleanFlagChanged" path="vm/flag/boolean_changed" label="Boolean Flag Changed"
-         is_instant="true">
-    <value type="STRING" field="name" label="Name" />
-    <value type="BOOLEAN" field="oldValue" label="Old Value" />
-    <value type="BOOLEAN" field="newValue" label="New Value" />
-    <value type="FLAGVALUEORIGIN" field="origin" label="Origin" />
-  </event>
-
-  <event id="StringFlagChanged" path="vm/flag/string_changed" label="String Flag Changed"
-         is_instant="true">
-    <value type="STRING" field="name" label="Name" />
-    <value type="STRING" field="oldValue" label="Old Value" />
-    <value type="STRING" field="newValue" label="New Value" />
-    <value type="FLAGVALUEORIGIN" field="origin" label="Origin" />
-  </event>
-
-  <struct id="VirtualSpace">
-    <value type="ADDRESS" field="start" label="Start Address" description="Start address of the virtual space" />
-    <value type="ADDRESS" field="committedEnd" label="Committed End Address" description="End address of the committed memory for the virtual space" />
-    <value type="BYTES64" field="committedSize" label="Committed Size" description="Size of the committed memory for the virtual space" />
-    <value type="ADDRESS" field="reservedEnd" label="Reserved End Address" description="End address of the reserved memory for the virtual space" />
-    <value type="BYTES64" field="reservedSize" label="Reserved Size" description="Size of the reserved memory for the virtual space" />
-  </struct>
-
-  <struct id="ObjectSpace">
-    <value type="ADDRESS" field="start" label="Start Address" description="Start address of the space" />
-    <value type="ADDRESS" field="end" label="End Address" description="End address of the space" />
-    <value type="BYTES64" field="used" label="Used" description="Bytes allocated by objects in the space" />
-    <value type="BYTES64" field="size" label="Size" description="Size of the space" />
-  </struct>
-
-  <event id="GCHeapSummary" path="vm/gc/heap/summary" label="Heap Summary" is_instant="true">
-    <value type="UINT" field="gcId" label="GC Identifier" relation="GcId"/>
-    <value type="GCWHEN" field="when" label="When" />
-    <structvalue type="VirtualSpace" field="heapSpace" label="Heap Space"/>
-    <value type="BYTES64" field="heapUsed" label="Heap Used" description="Bytes allocated by objects in the heap"/>
-  </event>
-
-  <struct id="MetaspaceSizes">
-    <value type="BYTES64" field="committed" label="Committed" description="Committed memory for this space" />
-    <value type="BYTES64" field="used" label="Used" description="Bytes allocated by objects in the space" />
-    <value type="BYTES64" field="reserved" label="Reserved" description="Reserved memory for this space" />
-  </struct>
-
-  <event id="MetaspaceSummary" path="vm/gc/heap/metaspace_summary" label="Metaspace Summary" is_instant="true">
-    <value type="UINT" field="gcId" label="GC Identifier" relation="GcId"/>
-    <value type="GCWHEN" field="when" label="When" />
-    <value type="BYTES64" field="gcThreshold" label="GC Threshold" />
-    <structvalue type="MetaspaceSizes" field="metaspace" label="Total"/>
-    <structvalue type="MetaspaceSizes" field="dataSpace" label="Data"/>
-    <structvalue type="MetaspaceSizes" field="classSpace" label="Class"/>
-  </event>
-
-  <event id="MetaspaceGCThreshold" path="vm/gc/metaspace/gc_threshold" label="Metaspace GC Threshold" is_instant="true">
-    <value type="BYTES64" field="oldValue" label="Old Value" />
-    <value type="BYTES64" field="newValue" label="New Value" />
-    <value type="GCTHRESHOLDUPDATER" field="updater" label="Updater" />
-  </event>
-
-  <event id="MetaspaceAllocationFailure" path="vm/gc/metaspace/allocation_failure" label="Metaspace Allocation Failure" is_instant="true" has_stacktrace="true">
-    <value type="CLASSLOADER" field="classLoader" label="Class Loader" />
-    <value type="BOOLEAN" field="anonymousClassLoader" label="Anonymous Class Loader" />
-    <value type="BYTES64" field="size" label="Size" />
-    <value type="METADATATYPE" field="metadataType" label="Metadata Type" />
-    <value type="METASPACEOBJTYPE" field="metaspaceObjectType" label="Metaspace Object Type" />
-  </event>
-
-  <event id="MetaspaceOOM" path="vm/gc/metaspace/out_of_memory" label="Metaspace Out of Memory" is_instant="true" has_stacktrace="true">
-    <value type="CLASSLOADER" field="classLoader" label="Class Loader" />
-    <value type="BOOLEAN" field="anonymousClassLoader" label="Anonymous Class Loader" />
-    <value type="BYTES64" field="size" label="Size" />
-    <value type="METADATATYPE" field="metadataType" label="Metadata Type" />
-    <value type="METASPACEOBJTYPE" field="metaspaceObjectType" label="Metaspace Object Type" />
-  </event>
-
-  <event id="MetaspaceChunkFreeListSummary" path="vm/gc/metaspace/chunk_free_list_summary" label="Metaspace Chunk Free List Summary" is_instant="true">
-    <value type="UINT" field="gcId" label="GC Identifier" relation="GcId"/>
-    <value type="GCWHEN" field="when" label="When" />
-    <value type="METADATATYPE" field="metadataType" label="Metadata Type" />
-    <value type="ULONG" field="specializedChunks" label="Specialized Chunks" />
-    <value type="BYTES64" field="specializedChunksTotalSize" label="Specialized Chunks Total Size" />
-    <value type="ULONG" field="smallChunks" label="Small Chunks" />
-    <value type="BYTES64" field="smallChunksTotalSize" label="Small Chunks Total Size" />
-    <value type="ULONG" field="mediumChunks" label="Medium Chunks" />
-    <value type="BYTES64" field="mediumChunksTotalSize" label="Medium Chunks Total Size" />
-    <value type="ULONG" field="humongousChunks" label="Humongous Chunks" />
-    <value type="BYTES64" field="humongousChunksTotalSize" label="Humongous Chunks Total Size" />
-  </event>
-
-  <event id="PSHeapSummary" path="vm/gc/heap/ps_summary" label="Parallel Scavenge Heap Summary" is_instant="true">
-    <value type="UINT" field="gcId" label="GC Identifier" relation="GcId"/>
-    <value type="GCWHEN" field="when" label="When" />
-
-    <structvalue type="VirtualSpace" field="oldSpace" label="Old Space"/>
-    <structvalue type="ObjectSpace" field="oldObjectSpace" label="Old Object Space"/>
-
-    <structvalue type="VirtualSpace" field="youngSpace" label="Young Space"/>
-    <structvalue type="ObjectSpace" field="edenSpace" label="Eden Space"/>
-    <structvalue type="ObjectSpace" field="fromSpace" label="From Space"/>
-    <structvalue type="ObjectSpace" field="toSpace" label="To Space"/>
-  </event>
-
-  <event id="G1HeapSummary" path="vm/gc/heap/g1_summary" label="G1 Heap Summary" is_instant="true">
-    <value type="UINT" field="gcId" label="GC Identifier" relation="GcId"/>
-    <value type="GCWHEN" field="when" label="When" />
-
-    <value type="BYTES64" field="edenUsedSize" label="Eden Used Size" />
-    <value type="BYTES64" field="edenTotalSize" label="Eden Total Size" />
-    <value type="BYTES64" field="survivorUsedSize" label="Survivor Used Size" />
-    <value type="UINT" field="numberOfRegions" label="Number of Regions" />
-  </event>
-
-  <event id="GarbageCollection" path="vm/gc/collector/garbage_collection" label="Garbage Collection"
-         description="Garbage collection performed by the JVM">
-    <value type="UINT" field="gcId"  label="GC Identifier" relation="GcId" />
-    <value type="GCNAME" field="name" label="Name" description="The name of the Garbage Collector" />
-    <value type="GCCAUSE" field="cause" label="Cause" description="The reason for triggering this Garbage Collection" />
-    <value type="TICKSPAN" field="sumOfPauses" label="Sum of Pauses" description="Sum of all the times in which Java execution was paused during the garbage collection" />
-    <value type="TICKSPAN" field="longestPause" label="Longest Pause" description="Longest individual pause during the garbage collection" />
-  </event>
-
-  <event id="ParallelOldGarbageCollection" path="vm/gc/collector/parold_garbage_collection" label="Parallel Old Garbage Collection"
-         description="Extra information specific to Parallel Old Garbage Collections">
-    <value type="UINT" field="gcId"  label="GC Identifier" relation="GcId" />
-    <value type="ADDRESS" field="densePrefix" label="Dense Prefix" description="The address of the dense prefix, used when compacting" />
-  </event>
-
-  <event id="YoungGarbageCollection" path="vm/gc/collector/young_garbage_collection" label="Young Garbage Collection"
-         description="Extra information specific to Young Garbage Collections">
-    <value type="UINT" field="gcId"  label="GC Identifier" relation="GcId" />
-    <value type="UINT" field="tenuringThreshold" label="Tenuring Threshold" />
-  </event>
-
-  <event id="OldGarbageCollection" path="vm/gc/collector/old_garbage_collection" label="Old Garbage Collection"
-         description="Extra information specific to Old Garbage Collections">
-    <value type="UINT" field="gcId" label="GC Identifier" relation="GcId"/>
-  </event>
-
-  <event id="G1GarbageCollection" path="vm/gc/collector/g1_garbage_collection" label="G1 Garbage Collection"
-         description="Extra information specific to G1 Garbage Collections">
-    <value type="UINT" field="gcId" label="GC Identifier" relation="GcId"/>
-    <value type="G1YCTYPE" field="type" label="Type" />
-  </event>
-
-  <event id="G1MMU" path="vm/gc/detailed/g1_mmu_info" label="G1 MMU Information" is_instant="true">
-    <value type="UINT" field="gcId" label="GC Identifier" relation="GcId"/>
-    <value type="MILLIS" field="timeSlice" label="Time Slice" description="Time slice used to calculate MMU"/>
-    <value type="MILLIS" field="gcTime" label="GC Time" description="Time stopped because of GC during last time slice"/>
-    <value type="MILLIS" field="pauseTarget" label="Pause Target" description="Max time allowed to be spent on GC during last time slice"/>
-  </event>
-
-  <event id="EvacuationInformation" path="vm/gc/detailed/evacuation_info" label="Evacuation Information" is_instant="true">
-    <value type="UINT" field="gcId" label="GC Identifier" relation="GcId"/>
-    <value type="UINT" field="cSetRegions" label="Collection Set Regions"/>
-    <value type="BYTES64" field="cSetUsedBefore" label="Collection Set Before" description="Memory usage before GC in the collection set regions"/>
-    <value type="BYTES64" field="cSetUsedAfter" label="Collection Set After" description="Memory usage after GC in the collection set regions"/>
-    <value type="UINT" field="allocationRegions" label="Allocation Regions" description="Regions chosen as allocation regions during evacuation (includes survivors and old space regions)"/>
-    <value type="BYTES64" field="allocationRegionsUsedBefore" label="Allocation Regions Before" description="Memory usage before GC in allocation regions"/>
-    <value type="BYTES64" field="allocationRegionsUsedAfter" label="Allocation Regions After" description="Memory usage after GC in allocation regions"/>
-    <value type="BYTES64" field="bytesCopied" label="Bytes Copied"/>
-    <value type="UINT" field="regionsFreed" label="Regions Freed"/>
-  </event>
-
-  <event id="GCReferenceStatistics" path="vm/gc/reference/statistics"
-         label="GC Reference Statistics" is_instant="true"
-         description="Total count of processed references during GC">
-    <value type="UINT" field="gcId" label="GC Identifier" relation="GcId"/>
-    <value type="REFERENCETYPE" field="type" label="Type" />
-    <value type="ULONG" field="count" label="Total Count" />
-  </event>
-
-  <struct id="CopyFailed">
-    <value type="ULONG" field="objectCount" label="Object Count"/>
-    <value type="BYTES64" field="firstSize" label="First Failed Object Size"/>
-    <value type="BYTES64" field="smallestSize" label="Smallest Failed Object Size"/>
-    <value type="BYTES64" field="totalSize" label="Total Object Size"/>
-  </struct>
-
-  <event id="ObjectCountAfterGC" path="vm/gc/detailed/object_count_after_gc" is_instant="true" label="Object Count after GC">
-    <value type="UINT" field="gcId"  label="GC Identifier" relation="GcId" />
-    <value type="CLASS" field="objectClass" label="Object Class" />
-    <value type="LONG" field="count" label="Count" />
-    <value type="BYTES64" field="totalSize" label="Total Size" />
-  </event>
-
-  <struct id="G1EvacuationStatistics">
-    <value type="UINT" field="gcId" label="GC Identifier" relation="GcId"/>
-    <value type="BYTES64" field="allocated" label="Allocated" description="Total memory allocated by PLABs"/>
-    <value type="BYTES64" field="wasted" label="Wasted" description="Total memory wasted within PLABs due to alignment or refill"/>
-    <value type="BYTES64" field="used" label="Used" description="Total memory occupied by objects within PLABs"/>
-    <value type="BYTES64" field="undoWaste" label="Undo Wasted" description="Total memory wasted due to allocation undo within PLABs"/>
-    <value type="BYTES64" field="regionEndWaste" label="Region End Wasted" description="Total memory wasted at the end of regions due to refill"/>
-    <value type="UINT" field="regionsRefilled" label="Region Refills" description="Total memory wasted at the end of regions due to refill"/>
-    <value type="BYTES64" field="directAllocated" label="Allocated (direct)" description="Total memory allocated using direct allocation outside of PLABs"/>
-    <value type="BYTES64" field="failureUsed" label="Used (failure)" description="Total memory occupied by objects in regions where evacuation failed"/>
-    <value type="BYTES64" field="failureWaste" label="Wasted (failure)" description="Total memory left unused in regions where evacuation failed"/>
-  </struct>
-
-  <event id="G1EvacuationYoungStatistics" path="vm/gc/detailed/g1_evac_young_stats" label="G1 Evacuation Statistics for Young"
-         is_instant="true" description="Memory related evacuation statistics during GC for the young generation">
-    <structvalue type="G1EvacuationStatistics" field="statistics" label="Evacuation Statistics"/>
-  </event>
-
-  <event id="G1EvacuationOldStatistics" path="vm/gc/detailed/g1_evac_old_stats" label="G1 Evacuation Memory Statistics for Old"
-         is_instant="true" description="Memory related evacuation statistics during GC for the old generation">
-    <structvalue type="G1EvacuationStatistics" field="statistics" label="Evacuation Statistics"/>
-  </event>
-
-  <event id="G1BasicIHOP" path="vm/gc/detailed/g1_basic_ihop_status" label="G1 Basic IHOP Statistics"
-         is_instant="true" description="Basic statistics related to current IHOP calculation">
-    <value type="UINT" field="gcId" label="GC Identifier" relation="GcId"/>
-    <value type="BYTES64" field="threshold" label="Current IHOP Threshold" description="Current IHOP threshold"/>
-    <value type="PERCENTAGE" field="thresholdPercentage" label="Current IHOP Threshold" description="Current IHOP threshold in percent of old generation"/>
-    <value type="BYTES64" field="targetOccupancy" label="Target Occupancy" description="Target old generation occupancy to reach at the start of mixed GC"/>
-    <value type="BYTES64" field="currentOccupancy" label="Current Occupancy" description="Current old generation occupancy"/>
-    <value type="BYTES64" field="recentMutatorAllocationSize" label="Recent Mutator Allocation Size" description="Mutator allocation during mutator operation in the most recent interval"/>
-    <value type="MILLIS" field="recentMutatorDuration" label="Recent Mutator Duration" description="Time the mutator ran in the most recent interval"/>
-    <value type="DOUBLE" field="recentAllocationRate" label="Recent Allocation Rate" description="Allocation rate of the mutator in the most recent interval in bytes/second"/>
-    <value type="MILLIS" field="lastMarkingDuration" label="Last Marking Duration" description="Last time from the end of the last initial mark to the first mixed GC"/>
-  </event>
-
-  <event id="G1AdaptiveIHOP" path="vm/gc/detailed/g1_adaptive_ihop_status" label="G1 Adaptive IHOP Statistics"
-         is_instant="true" description="Statistics related to current adaptive IHOP calculation">
-    <value type="UINT" field="gcId" label="GC Identifier" relation="GcId"/>
-    <value type="BYTES64" field="threshold" label="Threshold" description="Current IHOP Threshold"/>
-    <value type="PERCENTAGE" field="thresholdPercentage" label="Threshold" description="Current IHOP threshold in percent of the internal target occupancy"/>
-    <value type="BYTES64" field="ihopTargetOccupancy" label="IHOP Target Occupancy" description="Internal target old generation occupancy to reach at the start of mixed GC"/>
-    <value type="BYTES64" field="currentOccupancy" label="Current Occupancy" description="Current old generation occupancy"/>
-    <value type="BYTES64" field="additionalBufferSize" label="Additional Buffer" description="Additional buffer size" experimental="true"/>
-    <value type="DOUBLE" field="predictedAllocationRate" label="Predicted Allocation Rate" description="Current predicted allocation rate for the mutator in bytes/second"/>
-    <value type="MILLIS" field="predictedMarkingDuration" label="Predicted Marking Duration" description="Current predicted time from the end of the last initial mark to the first mixed GC"/>
-    <value type="BOOLEAN" field="predictionActive" label="Prediction Active" description="Indicates whether the adaptive IHOP prediction is active"/>
-  </event>
-
-  <!-- Promotion events, Supported GCs are Parallel Scavange, G1 and CMS with Parallel New. -->
-  <event id="PromoteObjectInNewPLAB" path="vm/gc/detailed/object_promotion_in_new_PLAB" label="Promotion in new PLAB"
-         description="Object survived scavenge and was copied to a new Promotion Local Allocation Buffer (PLAB). Supported GCs are Parallel Scavange, G1 and CMS with Parallel New. Due to promotion being done in parallel an object might be reported multiple times as the GC threads race to copy all objects."
-         has_thread="true" has_stacktrace="false" is_instant="true">
-    <value type="UINT" field="gcId" label="GC Identifier" relation="GcId" description="Identifier signifying GC during which the object was promoted"/>
-    <value type="CLASS" field="objectClass" label="Object Class" description="Class of promoted object"/>
-    <value type="BYTES64" field="objectSize" label="Object Size" description="Size of promoted object"/>
-    <value type="UINT" field="tenuringAge" label="Object Tenuring Age" description="Tenuring age of a surviving object before being copied. The tenuring age of an object is a value between 0-15 and is incremented each scavange the object survives. Newly allocated objects have tenuring age 0."/>
-    <value type="BOOLEAN" field="tenured" label="Tenured" description="True if object was promoted to Old space, otherwise the object was aged and copied to a Survivor space"/>
-    <value type="BYTES64" field="plabSize" label="PLAB Size" description="Size of the allocated PLAB to which the object was copied"/>
-  </event>
-
-  <event id="PromoteObjectOutsidePLAB" path="vm/gc/detailed/object_promotion_outside_PLAB" label="Promotion outside PLAB"
-         description="Object survived scavenge and was copied directly to the heap. Supported GCs are Parallel Scavange, G1 and CMS with Parallel New. Due to promotion being done in parallel an object might be reported multiple times as the GC threads race to copy all objects."
-         has_thread="true" has_stacktrace="false" is_instant="true">
-    <value type="UINT" field="gcId" label="GC Identifier" relation="GcId" description="Identifier signifying GC during which the object was promoted"/>
-    <value type="CLASS" field="objectClass" label="Object Class" description="Class of promoted object"/>
-    <value type="BYTES64" field="objectSize" label="Object Size" description="Size of promoted object"/>
-    <value type="UINT" field="tenuringAge" label="Object Tenuring Age" description="Tenuring age of a surviving object before being copied. The tenuring age of an object is a value between 0-15 and is incremented each scavange the object survives. Newly allocated objects have tenuring age 0."/>
-    <value type="BOOLEAN" field="tenured" label="Tenured" description="True if object was promoted to Old space, otherwise the object was aged and copied to a Survivor space"/>
-  </event>
-
-  <event id="PromotionFailed" path="vm/gc/detailed/promotion_failed" label="Promotion Failed" is_instant="true"
-         description="Promotion of an object failed">
-    <value type="UINT" field="gcId" label="GC Identifier" relation="GcId"/>
-    <structvalue type="CopyFailed" field="promotionFailed" label="Promotion Failed Data"/>
-    <value type="THREAD" field="thread" label="Running thread"/>
-  </event>
-
-  <event id="EvacuationFailed" path="vm/gc/detailed/evacuation_failed" label="Evacuation Failed" is_instant="true"
-         description="Evacuation of an object failed">
-    <value type="UINT" field="gcId" label="GC Identifier" relation="GcId"/>
-    <structvalue type="CopyFailed" field="evacuationFailed" label="Evacuation Failed Data"/>
-  </event>
-
-  <event id="ConcurrentModeFailure" path="vm/gc/detailed/concurrent_mode_failure" label="Concurrent Mode Failure"
-         is_instant="true" description="Concurrent Mode failed">
-    <value type="UINT" field="gcId" label="GC Identifier" relation="GcId"/>
-  </event>
-
-  <event id="GCPhasePause" path="vm/gc/phases/pause" label="GC Phase Pause" has_thread="true">
-    <value type="UINT" field="gcId" label="GC Identifier" relation="GcId"/>
-    <value type="STRING" field="name" label="Name" />
-  </event>
-
-  <event id="GCPhasePauseLevel1" path="vm/gc/phases/pause_level_1" label="GC Phase Pause Level 1" has_thread="true">
-    <value type="UINT" field="gcId" label="GC Identifier" relation="GcId"/>
-    <value type="STRING" field="name" label="Name" />
-  </event>
-
-  <event id="GCPhasePauseLevel2" path="vm/gc/phases/pause_level_2" label="GC Phase Pause Level 2" has_thread="true">
-    <value type="UINT" field="gcId" label="GC Identifier" relation="GcId"/>
-    <value type="STRING" field="name" label="Name" />
-  </event>
-
-  <event id="GCPhasePauseLevel3" path="vm/gc/phases/pause_level_3" label="GC Phase Pause Level 3" has_thread="true">
-    <value type="UINT" field="gcId" label="GC Identifier" relation="GcId"/>
-    <value type="STRING" field="name" label="Name" />
-  </event>
-
-  <event id="GCPhasePauseLevel4" path="vm/gc/phases/pause_level_4" label="GC Phase Pause Level 4" has_thread="true">
-    <value type="UINT" field="gcId" label="GC Identifier" relation="GcId"/>
-    <value type="STRING" field="name" label="Name" />
-  </event>
-
-  <event id="GCPhaseConcurrent" path="vm/gc/phases/concurrent" label="GC Phase Concurrent" has_thread="true">
-    <value type="UINT" field="gcId" label="GC Identifier" relation="GcId"/>
-    <value type="STRING" field="name" label="Name" />
-  </event>
-
-  <event id="AllocationRequiringGC" path="vm/gc/detailed/allocation_requiring_gc" label="Allocation Requiring GC"
-         has_thread="true" has_stacktrace="true"  is_instant="true">
-    <value type="UINT" field="gcId"  label="Pending GC Identifier" relation="GcId" />
-    <value type="BYTES64" field="size" label="Allocation Size" />
-  </event>
-
-  <event id="TenuringDistribution" path="vm/gc/detailed/tenuring_distribution" label="Tenuring Distribution"
-         is_instant="true">
-    <value type="UINT" field="gcId" label="GC Identifier" relation="GcId"/>
-    <value type="UINT" field="age" label="Age" />
-    <value type="BYTES64" field="size" label="Size" />
-  </event>
-
-  <event id="G1HeapRegionTypeChange" path="vm/gc/detailed/g1_heap_region_type_change" label="G1 Heap Region Type Change"
-         description="Information about a G1 heap region type change" is_instant="true">
-    <value type="UINT" field="index" label="Index" />
-    <value type="G1HEAPREGIONTYPE" field="from" label="From" />
-    <value type="G1HEAPREGIONTYPE" field="to" label="To" />
-    <value type="ADDRESS" field="start" label="Start" />
-    <value type="BYTES64" field="used" label="Used" />
-  </event>
-
-  <!-- Compiler events -->
-
-  <event id="Compilation" path="vm/compiler/compilation" label="Compilation"
-         has_thread="true" is_requestable="false" is_constant="false">
-    <value type="METHOD" field="method" label="Java Method"/>
-    <value type="UINT" field="compileId" label="Compilation Identifier" relation="CompileId"/>
-    <value type="USHORT" field="compileLevel" label="Compilation Level"/>
-    <value type="BOOLEAN" field="succeded" label="Succeeded"/>
-    <value type="BOOLEAN" field="isOsr" label="On Stack Replacement"/>
-    <value type="BYTES" field="codeSize" label="Compiled Code Size"/>
-    <value type="BYTES" field="inlinedBytes" label="Inlined Code Size"/>
-  </event>
-
-  <event id="CompilerPhase" path="vm/compiler/phase" label="Compiler Phase"
-         has_thread="true" is_requestable="false" is_constant="false">
-    <value type="COMPILERPHASETYPE" field="phase" label="Compile Phase"/>
-    <value type="UINT" field="compileId" label="Compilation Identifier" relation="CompileId"/>
-    <value type="USHORT" field="phaseLevel" label="Phase Level"/>
-  </event>
-
-  <event id="CompilationFailure" path="vm/compiler/failure" label="Compilation Failure"
-         has_thread="true" is_requestable="false" is_constant="false" is_instant="true">
-    <value type="STRING" field="failureMessage" label="Failure Message"/>
-    <value type="UINT" field="compileId" label="Compilation Identifier" relation="CompileId"/>
-  </event>
-
-  <struct id="CalleeMethod">
-    <value type="STRING" field="type" label="Class"/>
-    <value type="STRING" field="name" label="Method Name"/>
-    <value type="STRING" field="descriptor" label="Method Descriptor"/>
-  </struct>
-
-  <event id="CompilerInlining" path="vm/compiler/optimization/inlining" label="Method Inlining"
-         has_thread="true" is_instant="true">
-    <value type="UINT" field="compileId" label="Compilation Identifier" relation="CompileId"/>
-    <value type="METHOD" field="caller" label="Caller Method"/>
-    <structvalue type="CalleeMethod" field="callee" label="Callee Method"/>
-    <value type="BOOLEAN" field="succeeded" label="Succeeded"/>
-    <value type="STRING" field="message" label="Message"/>
-    <value type="INTEGER" field="bci" label="Byte Code Index"/>
-  </event>
-
-  <!-- Code sweeper events -->
-
-  <event id="SweepCodeCache" path="vm/code_sweeper/sweep" label="Sweep Code Cache"
-         has_thread="true" is_requestable="false" is_constant="false">
-    <value type="INTEGER" field="sweepId" label="Sweep Identifier" relation="SweepId"/>
-    <value type="UINT" field="sweptCount" label="Methods Swept"/>
-    <value type="UINT" field="flushedCount" label="Methods Flushed"/>
-    <value type="UINT" field="zombifiedCount" label="Methods Zombified"/>
-  </event>
-
-  <!-- Code cache events -->
-
-  <event id="CodeCacheFull" path="vm/code_cache/full" label="Code Cache Full"
-         has_thread="true" is_requestable="false" is_constant="false" is_instant="true">
-    <value type="CODEBLOBTYPE" field="codeBlobType" label="Code Heap"/>
-    <value type="ADDRESS" field="startAddress" label="Start Address"/>
-    <value type="ADDRESS" field="commitedTopAddress" label="Commited Top"/>
-    <value type="ADDRESS" field="reservedTopAddress" label="Reserved Top"/>
-    <value type="INTEGER" field="entryCount" label="Entries"/>
-    <value type="INTEGER" field="methodCount" label="Methods"/>
-    <value type="INTEGER" field="adaptorCount" label="Adaptors"/>
-    <value type="BYTES64" field="unallocatedCapacity" label="Unallocated"/>
-    <value type="INTEGER" field="fullCount" label="Full Count"/>
-  </event>
-
-  <event id="SafepointBegin" path="vm/runtime/safepoint/begin" label="Safepoint Begin"
-         description="Safepointing begin" has_thread="true">
-    <value type="INTEGER" field="safepointId" label="Safepoint Identifier" relation="SafepointId"/>
-    <value type="INTEGER" field="totalThreadCount" label="Total Threads" description="The total number of threads at the start of safe point"/>
-    <value type="INTEGER" field="jniCriticalThreadCount" label="JNI Critical Threads" description="The number of threads in JNI critical sections"/>
-  </event>
-
-  <event id="SafepointStateSynchronization" path="vm/runtime/safepoint/statesync" label="Safepoint State Synchronization"
-         description="Synchronize run state of threads" has_thread="true">
-    <value type="INTEGER" field="safepointId" label="Safepoint Identifier" relation="SafepointId"/>
-    <value type="INTEGER" field="initialThreadCount" label="Initial Threads" description="The number of threads running at the beginning of state check"/>
-    <value type="INTEGER" field="runningThreadCount" label="Running Threads" description="The number of threads still running"/>
-    <value type="INTEGER" field="iterations" label="Iterations" description="Number of state check iterations"/>
-  </event>
-
-  <event id="SafepointWaitBlocked" path="vm/runtime/safepoint/waitblocked" label="Safepoint Wait Blocked"
-         description="Safepointing begin waiting on running threads to block" has_thread="true">
-    <value type="INTEGER" field="safepointId" label="Safepoint Identifier" relation="SafepointId"/>
-    <value type="INTEGER" field="runningThreadCount" label="Running Threads" description="The number running of threads wait for safe point"/>
-  </event>
-
-  <event id="SafepointCleanup" path="vm/runtime/safepoint/cleanup" label="Safepoint Cleanup"
-         description="Safepointing begin running cleanup tasks" has_thread="true">
-    <value type="INTEGER" field="safepointId" label="Safepoint Identifier" relation="SafepointId"/>
-  </event>
-
-  <event id="SafepointCleanupTask" path="vm/runtime/safepoint/cleanuptask" label="Safepoint Cleanup Task"
-         description="Safepointing begin running cleanup tasks" has_thread="true">
-    <value type="INTEGER" field="safepointId" label="Safepoint Identifier" relation="SafepointId"/>
-    <value type="STRING" field="name" label="Task Name" description="The task name"/>
-  </event>
-
-  <event id="SafepointEnd" path="vm/runtime/safepoint/end" label="Safepoint End"
-         description="Safepointing end" has_thread="true">
-    <value type="INTEGER" field="safepointId" label="Safepoint Identifier" relation="SafepointId"/>
-  </event>
-
-  <event id="ExecuteVMOperation" path="vm/runtime/execute_vm_operation" label="VM Operation"
-         description="Execution of a VM Operation" has_thread="true">
-    <value type="VMOPERATIONTYPE" field="operation" label="Operation" />
-    <value type="BOOLEAN" field="safepoint" label="At Safepoint" description="If the operation occured at a safepoint"/>
-    <value type="BOOLEAN" field="blocking" label="Caller Blocked" description="If the calling thread was blocked until the operation was complete"/>
-    <value type="THREAD" field="caller" label="Caller" transition="FROM" description="Thread requesting operation. If non-blocking, will be set to 0 indicating thread is unknown"/>
-    <value type="INTEGER" field="safepointId" label="Safepoint Identifier" description="The safepoint (if any) under which this operation was completed" relation="SafepointId"/>
-  </event>
-
-  <event id="Shutdown" path="vm/runtime/shutdown" label="VM Shutdown"
-         description="VM shutting down" has_thread="true" has_stacktrace="true" is_instant="true">
-    <value type="STRING" field="reason" label="Reason" description="Reason for VM shutdown"/>
-  </event>
-
-  <!-- Allocation events -->
-  <event id="ObjectAllocationInNewTLAB" path="java/object_alloc_in_new_TLAB" label="Allocation in new TLAB"
-         description="Allocation in new Thread Local Allocation Buffer" has_thread="true" has_stacktrace="true" is_instant="true">
-    <value type="CLASS" field="objectClass" label="Object Class" description="Class of allocated object"/>
-    <value type="BYTES64" field="allocationSize" label="Allocation Size"/>
-    <value type="BYTES64" field="tlabSize" label="TLAB Size"/>
-  </event>
-
-  <event id="ObjectAllocationOutsideTLAB" path="java/object_alloc_outside_TLAB" label="Allocation outside TLAB"
-         description="Allocation outside Thread Local Allocation Buffers" has_thread="true" has_stacktrace="true" is_instant="true">
-    <value type="CLASS" field="objectClass" label="Object Class" description="Class of allocated object"/>
-    <value type="BYTES64" field="allocationSize" label="Allocation Size"/>
-  </event>
-</events>
--- a/src/hotspot/share/trace/tracerelationdecls.xml	Tue May 15 11:28:29 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (c) 2012, 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.
-
--->
-
-
-<!DOCTYPE relation_decls SYSTEM "trace.dtd">
-
-<relation_decls>
-  <relation_decl id="GcId" uri="vm/gc/id"/>
-  <relation_decl id="CompileId" uri="vm/compiler/id"/>
-  <relation_decl id="SweepId" uri="vm/code_sweeper/id"/>
-  <relation_decl id="JavaMonitorAddress" uri="java/monitor/address"/>
-  <relation_decl id="SafepointId" uri="vm/runtime/safepoint/id"/>
-</relation_decls>
--- a/src/hotspot/share/trace/tracetypes.xml	Tue May 15 11:28:29 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,408 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (c) 2012, 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.
--->
-
-<!DOCTYPE types SYSTEM "trace.dtd">
-
-<!--
-
-Content types (complex) should create constant pool data
-in the recording.
-Currently at least, there is _NO_ verification that whatever
-writer you have is actually writing correctly. So BE CAREFUL!
-
-Declared with the 'content_type' tag.
-
-<type> is the ID type, i.e the integer type that resolves this. Most often
-U4 or U8, but for example really small number constants, like GCTYPE uses U1.
-
-<content-type> is where it gets interesting. 'builtin_type' means we're
-defining how we resolve one of the trace built-in types (Class, Thread etc),
-jvm_type means defining a new one for our own use.
-
-Example: (GcMode)
-
-<content_type id="GCMode" hr_name="GC mode" type="U1" jvm_type="GCMODE">
-  <value type="STRING" field="desc" description="Description"/>
-</content_type>
-
-This creates a content type CONTENT_TYPE_GCMODE
-The field type referencing it is u1 (U1), and the constant pool struct has one field, the name.
-
-Before we can use it we need also define a primary field data type:
-
-<primary_type symbol="GCMODE" datatype="U1" contenttype="NONE"
-              type="u8" sizeop="sizeof(u1)"/>
-
-Now we can use the content + data type in declaring event fields.
- -->
-
- <types>
-  <content_types>
-    <content_type id="Thread" hr_name="Thread"
-                  type="U8" builtin_type="THREAD">
-      <value type="STRING" field="osName" label="OS Thread Name"/>
-      <value type="LONG" field="osThreadId" label="OS Thread Id"/>
-      <value type="STRING" field="javaName" label="Java Thread Name"/>
-      <value type="LONG" field="javaThreadId" label="Java Thread Id"/>
-      <value type="THREADGROUP" field="group" label="Java Thread Group"/>
-    </content_type>
-
-    <content_type id="ThreadGroup" hr_name="Thread Group"
-                  type="U8" jvm_type="THREADGROUP">
-      <value type="THREADGROUP" field="parent" label="Parent"/>
-      <value type="STRING" field="name" label="Name"/>
-    </content_type>
-
-    <content_type id="Class" hr_name="Java Class"
-                  type="U8" builtin_type="CLASS">
-      <value type="CLASSLOADER" field="classLoader" label="Class Loader"/>
-      <value type="SYMBOL" field="name" label="Name"/>
-      <value type="PACKAGE" field="package" label="Package"/>
-      <value type="INTEGER" field="modifiers" label="Access Modifiers"/>
-    </content_type>
-
-    <content_type id="ClassLoader" hr_name="Java Class Loader"
-                  type="U8" jvm_type="CLASSLOADER">
-      <value type="CLASS" field="type" label="Type"/>
-      <value type="SYMBOL" field="name" label="Name"/>
-    </content_type>
-
-    <content_type id="Method" hr_name="Java Method"
-                  type="U8" jvm_type="METHOD">
-      <value type="CLASS" field="type" label="Type"/>
-      <value type="SYMBOL" field="name" label="Name"/>
-      <value type="SYMBOL" field="descriptor" label="Descriptor"/>
-      <value type="INTEGER" field="modifiers" label="Access Modifiers"/>
-      <value type="BOOLEAN" field="hidden" label="Hidden"/>
-    </content_type>
-
-    <content_type id="Symbol" hr_name="Symbol"
-                  type="U8" jvm_type="SYMBOL">
-      <value type="STRING" field="string" label="String"/>
-    </content_type>
-
-    <content_type id="ThreadState" hr_name="Java Thread State"
-                  type="U8" jvm_type="THREADSTATE">
-      <value type="STRING" field="name" label="Name"/>
-    </content_type>
-
-    <content_type id="GCName" hr_name="GC Name"
-                  type="U8" jvm_type="GCNAME">
-      <value type="STRING" field="name" label="Name" />
-    </content_type>
-
-    <content_type id="GCCause" hr_name="GC Cause"
-                  type="U8" jvm_type="GCCAUSE">
-      <value type="STRING" field="cause" label="Cause" />
-    </content_type>
-
-    <content_type id="GCWhen" hr_name="GC When"
-                  type="U8" jvm_type="GCWHEN">
-      <value type="STRING" field="when" label="When" />
-    </content_type>
-
-    <content_type id="G1HeapRegionType" hr_name="G1 Heap Region Type"
-                  type="U8" jvm_type="G1HEAPREGIONTYPE">
-      <value type="STRING" field="type" label="Type" />
-    </content_type>
-    
-    <content_type id="G1YCType" hr_name="G1 YC Type"
-                  type="U8" jvm_type="G1YCTYPE">
-      <value type="STRING" field="type" label="Type" />
-    </content_type>
-
-    <content_type id="GCThresholdUpdater" hr_name="GC Threshold Updater"
-                  type="U8" jvm_type="GCTHRESHOLDUPDATER">
-      <value type="STRING" field="updater" label="Updater" />
-    </content_type>
-
-    <content_type id="ReferenceType" hr_name="Reference Type"
-                  type="U8" jvm_type="REFERENCETYPE">
-      <value type="STRING" field="type" label="Type" />
-    </content_type>
-
-    <content_type id="MetadataType" hr_name="Metadata Type"
-                  type="U8" jvm_type="METADATATYPE">
-      <value type="STRING" field="type" label="Type" />
-    </content_type>
-
-    <content_type id="MetaspaceObjectType" hr_name="Metaspace Object Type"
-                  type="U8" jvm_type="METASPACEOBJTYPE">
-      <value type="STRING" field="type" label="Type" />
-    </content_type>
-
-    <content_type id="NarrowOopMode" hr_name="Narrow Oop Mode"
-                  type="U8" jvm_type="NARROWOOPMODE">
-      <value type="STRING" field="mode" label="Mode" />
-    </content_type>
-
-    <content_type id="VMOperationType" hr_name="VM Operation Type"
-                  type="U8" jvm_type="VMOPERATIONTYPE">
-      <value type="STRING" field="type" label="Type" />
-    </content_type>
-
-    <content_type id="CompilerPhaseType" hr_name="Compiler Phase Type"
-                  type="U8" jvm_type="COMPILERPHASETYPE">
-      <value type="STRING" field="phase" label="Phase" />
-    </content_type>
-
-    <content_type id="FlagValueOrigin" hr_name="Flag Value Origin"
-                  type="U8" jvm_type="FLAGVALUEORIGIN">
-      <value type="STRING" field="origin" label="Origin" />
-    </content_type>
-
-    <content_type id="CodeBlobType" hr_name="Code Blob Type"
-                  type="U8" jvm_type="CODEBLOBTYPE">
-      <value type="STRING" field="type" label="Type" />
-    </content_type>
-
-    <content_type id="InflateCause" hr_name="Inflation Cause"
-                  type="U8" jvm_type="INFLATECAUSE">
-      <value type="STRING" field="cause" label="Cause" />
-    </content_type>
-
-    <content_type id="Module" hr_name="Module"
-                  type="U8" jvm_type="MODULE">
-      <value type="SYMBOL" field="name" label="Name"/>
-      <value type="SYMBOL" field="version" label="Version"/>
-      <value type="SYMBOL" field="location" label="Location"/>
-      <value type="CLASSLOADER" field="classLoader" label="Class Loader"/>
-    </content_type>
-
-    <content_type id="Package" hr_name="Package"
-                  type="U8" jvm_type="PACKAGE">
-      <value type="SYMBOL" field="name" label="Name"/>
-      <value type="MODULE" field="module" label="Module"/>
-      <value type="BOOLEAN" field="exported" label="Exported"/>
-    </content_type>
-  </content_types>
-
-
-  <primary_types>
-    <!--
-      - primary_type takes these attributes:
-      -   symbol      INTEGER, LONG etc
-      -   datatype    The trace datatype, see enum DataType
-      -   contenttype Either resolved content type or the semantic meaning
-      -   type        The actual type as used in structures etc
-      -   sizeop      A function/macro that can be applied on a single
-      -               struct value of type "type" and yield the factual byte
-      -               size we need to write.  The % is replaced by the value
-      -->
-
-    <!-- SIGNED 64bit -->
-    <primary_type symbol="LONG" datatype="LONG" contenttype="NONE"
-                  type="s8" sizeop="sizeof(s8)"/>
-
-    <!-- UNSIGNED 64bit -->
-    <primary_type symbol="ULONG" datatype="U8" contenttype="NONE"
-                  type="u8" sizeop="sizeof(u8)"/>
-
-    <!-- SIGNED 32bit -->
-    <primary_type symbol="INTEGER" datatype="INT" contenttype="NONE"
-                  type="s4" sizeop="sizeof(s4)"/>
-
-    <!-- UNSIGNED 32bit -->
-    <primary_type symbol="UINT" datatype="U4" contenttype="NONE"
-                  type="unsigned" sizeop="sizeof(unsigned)"/>
-
-    <!-- UNSIGNED 16bit -->
-    <primary_type symbol="USHORT" datatype="U2" contenttype="NONE"
-                  type="u2" sizeop="sizeof(u2)"/>
-
-    <!--  SIGNED 16bit -->
-    <primary_type symbol="SHORT" datatype="SHORT" contenttype="NONE"
-                  type="s2" sizeop="sizeof(s2)"/>
-
-    <!--  SIGNED 8bit -->
-    <primary_type symbol="BYTE" datatype="BYTE" contenttype="NONE"
-                  type="s1" sizeop="sizeof(s1)"/>
-
-    <!--  UNSIGNED 8bit -->
-    <primary_type symbol="UBYTE" datatype="U1" contenttype="NONE"
-                  type="u1" sizeop="sizeof(u1)"/>
-
-    <!--  float 32bit -->
-    <primary_type symbol="FLOAT" datatype="FLOAT" contenttype="NONE"
-                  type="float" sizeop="sizeof(float)"/>
-
-    <!--  float 64bit -->
-    <primary_type symbol="DOUBLE" datatype="DOUBLE" contenttype="NONE"
-                  type="double" sizeop="sizeof(double)"/>
-
-    <!-- boolean type (1-byte) -->
-    <primary_type symbol="BOOLEAN" datatype="BOOLEAN" contenttype="NONE"
-                  type="bool" sizeop="1"/>
-
-    <!-- 32-bit unsigned integer, SEMANTIC value BYTES -->
-    <primary_type symbol="BYTES" datatype="U8" contenttype="BYTES"
-                  type="u8" sizeop="sizeof(u8)"/>
-
-    <primary_type symbol="IOBYTES" datatype="U8" contenttype="BYTES"
-                  type="u8" sizeop="sizeof(u8)"/>
-
-    <!-- 64-bit unsigned integer, SEMANTIC value BYTES -->
-    <primary_type symbol="BYTES64" datatype="U8" contenttype="BYTES"
-                  type="u8" sizeop="sizeof(u8)"/>
-
-    <!-- 64-bit unsigned integer, SEMANTIC value ABSOLUTE MILLISECONDS -->
-    <primary_type symbol="EPOCHMILLIS" datatype="LONG" contenttype="EPOCHMILLIS"
-                  type="s8" sizeop="sizeof(s8)"/>
-
-    <!-- 64-bit unsigned integer, SEMANTIC value RELATIVE MILLISECONDS -->
-    <primary_type symbol="MILLIS" datatype="LONG" contenttype="MILLIS"
-                  type="s8" sizeop="sizeof(s8)"/>
-
-    <!-- 64-bit unsigned integer, SEMANTIC value RELATIVE NANOSECONDS -->
-    <primary_type symbol="NANOS" datatype="LONG" contenttype="NANOS"
-                  type="s8" sizeop="sizeof(s8)"/>
-
-    <!-- 64-bit signed integer, SEMANTIC value TICKS -->
-    <primary_type symbol="TICKS" datatype="LONG" contenttype="TICKS"
-                  type="Ticks" sizeop="sizeof(s8)"/>
-
-    <!-- 64-bit signed integer, SEMANTIC value TICKS duration -->
-    <primary_type symbol="TICKSPAN" datatype="LONG" contenttype="TICKS"
-                  type="Tickspan" sizeop="sizeof(s8)"/>
-
-    <!-- 64-bit unsigned integer, SEMANTIC value ADDRESS (mem loc) -->
-    <primary_type symbol="ADDRESS" datatype="U8" contenttype="ADDRESS"
-                  type="u8" sizeop="sizeof(u8)"/>
-
-    <!-- 32-bit float, SEMANTIC value PERCENTAGE (0.0-1.0) -->
-    <primary_type symbol="PERCENTAGE" datatype="FLOAT" contenttype="PERCENTAGE"
-                  type="float" sizeop="sizeof(float)"/>
-
-    <!-- STRING is a virtual type - depending on encoding
-         it will have polymorphic content -->
-    <primary_type symbol="STRING" datatype="STRING" contenttype="NONE"
-                  type="const char*" sizeop="sizeof_utf(%)"/>
-
-    <!-- Symbol* constant. Note that this may currently ONLY be used by
-          classes, methods fields.  This restriction might be lifted. -->
-    <primary_type symbol="SYMBOL" datatype="U8" contenttype="SYMBOL"
-                  type="const Symbol*" sizeop="sizeof(u8)"/>
-
-    <!-- A Klass *. The actual class is marked as "used" and will
-         eventually be written into the recording constant pool -->
-    <primary_type symbol="CLASS" datatype="U8" contenttype="CLASS"
-                  type="const Klass*" sizeop="sizeof(u8)"/>
-
-    <primary_type symbol="CLASSLOADER" datatype="U8" contenttype="CLASSLOADER"
-              type="const ClassLoaderData*" sizeop="sizeof(u8)"/>
-
-    <primary_type symbol="MODULE" datatype="U8" contenttype="MODULE"
-                  type="const ModuleEntry*" sizeop="sizeof(u8)"/>
-
-    <primary_type symbol="PACKAGE" datatype="U8" contenttype="PACKAGE"
-                  type="const PackageEntry*" sizeop="sizeof(u8)"/>
-
-    <!-- A Method *. The method is marked as "used" and will eventually be
-         written into the recording constant pool. -->
-    <primary_type symbol="METHOD" datatype="U8" contenttype="METHOD"
-                  type="const Method*" sizeop="sizeof(u8)"/>
-
-    <!--  The type for stacktraces in the recording. Shoudl not be used by
-          events explicitly -->
-    <primary_type symbol="STACKTRACE" datatype="U8" contenttype="STACKTRACE"
-                  type="u8" sizeop="sizeof(u8)"/>
-
-    <!-- Thread ID -->
-    <primary_type symbol="THREAD" datatype="U8" contenttype="THREAD"
-                  type="u8" sizeop="sizeof(u8)"/>
-
-    <!-- Threadgroup THIS TYPE MAY NOT BE USED IN NORMAL EVENTS (ATM). Only
-          for thread constant pool // KK TODO: u8 should be ObjectP -->
-    <primary_type symbol="THREADGROUP" datatype="U8" contenttype="THREADGROUP"
-                  type="u8" sizeop="sizeof(u8)"/>
-
-    <!-- FRAMETYPE enum -->
-    <primary_type symbol="FRAMETYPE" datatype="U8" contenttype="FRAMETYPE"
-                  type="u8" sizeop="sizeof(u8)"/>
-
-    <!-- THREADSTATE enum -->
-    <primary_type symbol="THREADSTATE" datatype="U8" contenttype="THREADSTATE"
-                  type="u8" sizeop="sizeof(u8)"/>
-
-    <!-- GCName -->
-    <primary_type symbol="GCNAME" datatype="U8" contenttype="GCNAME"
-                  type="u8" sizeop="sizeof(u8)" />
-
-    <!-- GCCAUSE -->
-    <primary_type symbol="GCCAUSE" datatype="U8" contenttype="GCCAUSE"
-                  type="u8" sizeop="sizeof(u8)" />
-
-    <!-- GCWHEN -->
-    <primary_type symbol="GCWHEN" datatype="U8" contenttype="GCWHEN"
-                  type="u8" sizeop="sizeof(u8)" />
-
-    <!-- G1HEAPREGIONTYPE -->
-    <primary_type symbol="G1HEAPREGIONTYPE" datatype="U8" contenttype="G1HEAPREGIONTYPE"
-                  type="u8" sizeop="sizeof(u8)" />
-
-    <!-- G1YCType -->
-    <primary_type symbol="G1YCTYPE" datatype="U8" contenttype="G1YCTYPE"
-                  type="u8" sizeop="sizeof(u8)" />
-
-    <!-- GCTHRESHOLDUPDATER -->
-    <primary_type symbol="GCTHRESHOLDUPDATER" datatype="U8" contenttype="GCTHRESHOLDUPDATER"
-                  type="u8" sizeop="sizeof(u8)" />
-
-    <!-- REFERENCETYPE -->
-    <primary_type symbol="REFERENCETYPE" datatype="U8" contenttype="REFERENCETYPE"
-                  type="u8" sizeop="sizeof(u8)" />
-
-    <!-- METADATATYPE -->
-    <primary_type symbol="METADATATYPE" datatype="U8" contenttype="METADATATYPE"
-                  type="u8" sizeop="sizeof(u8)" />
-
-    <!-- METADATAOBJTYPE -->
-    <primary_type symbol="METASPACEOBJTYPE" datatype="U8" contenttype="METASPACEOBJTYPE"
-                  type="u8" sizeop="sizeof(u8)" />
-
-    <!-- NARROWOOPMODE -->
-    <primary_type symbol="NARROWOOPMODE" datatype="U8" contenttype="NARROWOOPMODE"
-                  type="u8" sizeop="sizeof(u8)" />
-
-    <!-- COMPILERPHASETYPE -->
-    <primary_type symbol="COMPILERPHASETYPE" datatype="U8" contenttype="COMPILERPHASETYPE"
-                  type="u8" sizeop="sizeof(u8)" />
-
-    <!-- VMOPERATIONTYPE -->
-    <primary_type symbol="VMOPERATIONTYPE" datatype="U8" contenttype="VMOPERATIONTYPE"
-                  type="u8" sizeop="sizeof(u8)" />
-                  
-    <!-- FLAGVALUEORIGIN -->
-    <primary_type symbol="FLAGVALUEORIGIN" datatype="U8" contenttype="FLAGVALUEORIGIN"
-                  type="u8" sizeop="sizeof(u8)" />
-                  
-    <!-- CODEBLOBTYPE -->
-    <primary_type symbol="CODEBLOBTYPE" datatype="U8" contenttype="CODEBLOBTYPE"
-                  type="u8" sizeop="sizeof(u8)" />
-
-    <!-- INFLATECAUSE -->
-    <primary_type symbol="INFLATECAUSE" datatype="U8" contenttype="INFLATECAUSE"
-                  type="u8" sizeop="sizeof(u8)" />
-  </primary_types>
-</types>
--- a/src/hotspot/share/trace/tracing.hpp	Tue May 15 11:28:29 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef SHARE_VM_TRACE_TRACING_HPP
-#define SHARE_VM_TRACE_TRACING_HPP
-
-#include "tracefiles/traceEventClasses.hpp"
-#include "tracefiles/traceEventIds.hpp"
-
-#endif // SHARE_VM_TRACE_TRACING_HPP
--- a/src/hotspot/share/trace/tracingExport.cpp	Tue May 15 11:28:29 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "precompiled.hpp"
-#include "runtime/orderAccess.inline.hpp"
-#include "trace/tracingExport.hpp"
-
-// Allow lock-free reads of _sampler_thread.
-Thread* volatile TracingExport::_sampler_thread = NULL;
-
-Thread* TracingExport::sampler_thread_acquire() {
-  return (Thread*)OrderAccess::load_acquire(&_sampler_thread);
-}
-
-void TracingExport::set_sampler_thread_with_lock(Thread* thread) {
-  // Grab Threads_lock to avoid conflicts with Thread-SMR scans.
-  MutexLocker ml(Threads_lock);
-  assert(thread == NULL || _sampler_thread == NULL, "_sampler_thread should not already be set.");
-  // To match with the lock-free load_acquire():
-  OrderAccess::release_store(&_sampler_thread, thread);
-}
--- a/src/hotspot/share/trace/tracingExport.hpp	Tue May 15 11:28:29 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef SHARE_VM_TRACE_TRACINGEXPORT_HPP
-#define SHARE_VM_TRACE_TRACINGEXPORT_HPP
-
-#include "runtime/thread.hpp"
-
-class TracingExport : AllStatic {
- public:
-  static Thread* sampler_thread_acquire();
-  static void set_sampler_thread_with_lock(Thread* thread);
-
- private:
-  static Thread* volatile _sampler_thread;
-};
-
-#endif // SHARE_VM_TRACE_TRACINGEXPORT_HPP
--- a/src/hotspot/share/trace/xinclude.mod	Tue May 15 11:28:29 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-
- This code is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License version 2 only, as
- published by the Free Software Foundation.
-
- This code is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- version 2 for more details (a copy is included in the LICENSE file that
- accompanied this code).
-
- You should have received a copy of the GNU General Public License version
- 2 along with this work; if not, write to the Free Software Foundation,
- Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-
- Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- or visit www.oracle.com if you need additional information or have any
- questions.
-  
--->
-<!ELEMENT xi:include (xi:fallback?) >
-<!ATTLIST xi:include
-    xmlns:xi   CDATA       #FIXED    "http://www.w3.org/2001/XInclude"
-    href       CDATA       #IMPLIED
-    parse      (xml|text)  "xml"
-    xpointer   CDATA       #IMPLIED
-    encoding   CDATA       #IMPLIED 
-    accept     CDATA       #IMPLIED
-    accept-language CDATA  #IMPLIED >
-
-<!ELEMENT xi:fallback ANY>
-<!ATTLIST xi:fallback
-    xmlns:xi   CDATA   #FIXED   "http://www.w3.org/2001/XInclude" >
--- a/src/hotspot/share/trace/xsl_util.xsl	Tue May 15 11:28:29 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-
- This code is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License version 2 only, as
- published by the Free Software Foundation.
-
- This code is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- version 2 for more details (a copy is included in the LICENSE file that
- accompanied this code).
-
- You should have received a copy of the GNU General Public License version
- 2 along with this work; if not, write to the Free Software Foundation,
- Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-
- Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- or visit www.oracle.com if you need additional information or have any
- questions.
--->
-
-<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
-
-<!-- utilities used when generating code -->
-
-<xsl:variable name="newline">
-  <xsl:text>&#xA;</xsl:text>
-</xsl:variable>
-
-<xsl:variable name="indent1">
-  <xsl:text>&#xA;  </xsl:text>
-</xsl:variable>
-
-<xsl:variable name="indent2">
-  <xsl:text>&#xA;    </xsl:text>
-</xsl:variable>
-
-<xsl:variable name="indent3">
-  <xsl:text>&#xA;      </xsl:text>
-</xsl:variable>
-
-<xsl:variable name="indent4">
-  <xsl:text>&#xA;        </xsl:text>
-</xsl:variable>
-
-<xsl:variable name="quote">
-  <xsl:text>"</xsl:text>
-</xsl:variable>
-
-<xsl:template name="file-header">
-  <xsl:text>/* AUTOMATICALLY GENERATED FILE - DO NOT EDIT */</xsl:text>
-</xsl:template>
-
-<xsl:template name="string-replace-all">
-  <xsl:param name="text" />
-  <xsl:param name="replace" />
-  <xsl:param name="by" />
-  <xsl:choose>
-    <xsl:when test="contains($text, $replace)">
-      <xsl:value-of select="substring-before($text,$replace)" />
-      <xsl:value-of select="$by" />
-      <xsl:call-template name="string-replace-all">
-        <xsl:with-param name="text" select="substring-after($text,$replace)" />
-        <xsl:with-param name="replace" select="$replace" />
-        <xsl:with-param name="by" select="$by" />
-      </xsl:call-template>
-    </xsl:when>
-    <xsl:otherwise>
-      <xsl:value-of select="$text" />
-    </xsl:otherwise>
-  </xsl:choose>
-</xsl:template>
-
-
-</xsl:stylesheet>
--- a/src/hotspot/share/utilities/hashtable.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/utilities/hashtable.cpp	Tue May 15 20:24:34 2018 +0200
@@ -473,11 +473,6 @@
 template class BasicHashtable<mtCode>;
 template class BasicHashtable<mtInternal>;
 template class BasicHashtable<mtModule>;
-#if INCLUDE_TRACE
-template class Hashtable<Symbol*, mtTracing>;
-template class HashtableEntry<Symbol*, mtTracing>;
-template class BasicHashtable<mtTracing>;
-#endif
 template class BasicHashtable<mtCompiler>;
 
 template void BasicHashtable<mtClass>::verify_table<DictionaryEntry>(char const*);
--- a/src/hotspot/share/utilities/macros.hpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/utilities/macros.hpp	Tue May 15 20:24:34 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -227,9 +227,15 @@
 #define NOT_NMT(x) x
 #endif // INCLUDE_NMT
 
-#ifndef INCLUDE_TRACE
-#define INCLUDE_TRACE 1
-#endif // INCLUDE_TRACE
+#ifndef INCLUDE_JFR
+#define INCLUDE_JFR 1
+#endif
+
+#if INCLUDE_JFR
+#define JFR_ONLY(code) code
+#else
+#define JFR_ONLY(code)
+#endif
 
 #ifndef INCLUDE_JVMCI
 #define INCLUDE_JVMCI 1
--- a/src/hotspot/share/utilities/spinYield.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/utilities/spinYield.cpp	Tue May 15 20:24:34 2018 +0200
@@ -26,7 +26,6 @@
 #include "runtime/os.hpp"
 #include "utilities/ostream.hpp"
 #include "utilities/spinYield.hpp"
-#include "utilities/ticks.inline.hpp"
 
 SpinYield::SpinYield(uint spin_limit, uint yield_limit) :
   _sleep_time(),
@@ -43,8 +42,7 @@
   } else {
     Ticks sleep_start = Ticks::now();
     os::naked_short_sleep(1);
-    Ticks sleep_end = Ticks::now();
-    _sleep_time += (sleep_end - sleep_start);
+    _sleep_time += Ticks::now() - sleep_start;
   }
 }
 
@@ -66,8 +64,8 @@
   }
   if (_sleep_time.value() != 0) { // Report sleep duration, if slept.
     separator = print_separator(s, separator);
-    s->print("sleep = " JLONG_FORMAT " usecs",
-             TicksToTimeHelper::milliseconds(_sleep_time));
+    s->print("sleep = " UINT64_FORMAT " usecs",
+             _sleep_time.milliseconds());
   }
   if (separator == initial_separator) {
     s->print("no waiting");
--- a/src/hotspot/share/utilities/ticks.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/utilities/ticks.cpp	Tue May 15 20:24:34 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,45 +24,115 @@
 
 #include "precompiled.hpp"
 #include "runtime/os.hpp"
-#include "utilities/ticks.inline.hpp"
+#include "utilities/ticks.hpp"
 
-#ifdef ASSERT
- const jlong Ticks::invalid_time_stamp = -2; // 0xFFFF FFFF`FFFF FFFE
+#ifdef X86
+#include "rdtsc_x86.hpp"
 #endif
 
-void Ticks::stamp() {
-  _stamp_ticks = os::elapsed_counter();
+#include OS_CPU_HEADER(os)
+
+template <typename TimeSource, const int unit>
+inline double conversion(typename TimeSource::Type& value) {
+  return (double)value * ((double)unit / (double)TimeSource::frequency());
+}
+
+uint64_t ElapsedCounterSource::frequency() {
+  static const uint64_t freq = (uint64_t)os::elapsed_frequency();
+  return freq;
+}
+
+ElapsedCounterSource::Type ElapsedCounterSource::now() {
+  return os::elapsed_counter();
+}
+
+double ElapsedCounterSource::seconds(Type value) {
+  return conversion<ElapsedCounterSource, 1>(value);
 }
 
-const Ticks Ticks::now() {
-  Ticks t;
-  t.stamp();
-  return t;
+uint64_t ElapsedCounterSource::milliseconds(Type value) {
+  return (uint64_t)conversion<ElapsedCounterSource, MILLIUNITS>(value);
+}
+
+uint64_t ElapsedCounterSource::microseconds(Type value) {
+  return (uint64_t)conversion<ElapsedCounterSource, MICROUNITS>(value);
+}
+
+uint64_t ElapsedCounterSource::nanoseconds(Type value) {
+  return (uint64_t)conversion<ElapsedCounterSource, NANOUNITS>(value);
+}
+
+uint64_t FastUnorderedElapsedCounterSource::frequency() {
+#ifdef X86
+  static bool valid_rdtsc = Rdtsc::initialize();
+  if (valid_rdtsc) {
+    static const uint64_t freq = (uint64_t)Rdtsc::frequency();
+    return freq;
+  }
+#endif
+  static const uint64_t freq = (uint64_t)os::elapsed_frequency();
+  return freq;
 }
 
-Tickspan::Tickspan(const Ticks& end, const Ticks& start) {
-  assert(end.value() != Ticks::invalid_time_stamp, "end is unstamped!");
-  assert(start.value() != Ticks::invalid_time_stamp, "start is unstamped!");
+FastUnorderedElapsedCounterSource::Type FastUnorderedElapsedCounterSource::now() {
+#ifdef X86
+  static bool valid_rdtsc = Rdtsc::initialize();
+  if (valid_rdtsc) {
+    return Rdtsc::elapsed_counter();
+  }
+#endif
+  return os::elapsed_counter();
+}
+
+double FastUnorderedElapsedCounterSource::seconds(Type value) {
+  return conversion<FastUnorderedElapsedCounterSource, 1>(value);
+}
 
-  assert(end >= start, "negative time!");
+uint64_t FastUnorderedElapsedCounterSource::milliseconds(Type value) {
+  return (uint64_t)conversion<FastUnorderedElapsedCounterSource, MILLIUNITS>(value);
+}
 
-  _span_ticks = end.value() - start.value();
+uint64_t FastUnorderedElapsedCounterSource::microseconds(Type value) {
+  return (uint64_t)conversion<FastUnorderedElapsedCounterSource, MICROUNITS>(value);
+}
+
+uint64_t FastUnorderedElapsedCounterSource::nanoseconds(Type value) {
+  return (uint64_t)conversion<FastUnorderedElapsedCounterSource, NANOUNITS>(value);
+}
+
+uint64_t CompositeElapsedCounterSource::frequency() {
+  return ElapsedCounterSource::frequency();
 }
 
-template <typename ReturnType>
-static ReturnType time_conversion(const Tickspan& span, TicksToTimeHelper::Unit unit) {
-  assert(TicksToTimeHelper::SECONDS == unit ||
-         TicksToTimeHelper::MILLISECONDS == unit, "invalid unit!");
-
-  ReturnType frequency_per_unit = (ReturnType)os::elapsed_frequency() / (ReturnType)unit;
-
-  return (ReturnType) ((ReturnType)span.value() / frequency_per_unit);
+CompositeElapsedCounterSource::Type CompositeElapsedCounterSource::now() {
+  CompositeTime ct;
+  ct.val1 = ElapsedCounterSource::now();
+#ifdef X86
+  static bool initialized = false;
+  static bool valid_rdtsc = false;
+  if (!initialized) {
+    valid_rdtsc = Rdtsc::initialize();
+    initialized = true;
+  }
+  if (valid_rdtsc) {
+    ct.val2 = Rdtsc::elapsed_counter();
+  }
+#endif
+  return ct;
 }
 
-double TicksToTimeHelper::seconds(const Tickspan& span) {
-  return time_conversion<double>(span, SECONDS);
+double CompositeElapsedCounterSource::seconds(Type value) {
+  return conversion<ElapsedCounterSource, 1>(value.val1);
+}
+
+uint64_t CompositeElapsedCounterSource::milliseconds(Type value) {
+  return (uint64_t)conversion<ElapsedCounterSource, MILLIUNITS>(value.val1);
 }
 
-jlong TicksToTimeHelper::milliseconds(const Tickspan& span) {
-  return time_conversion<jlong>(span, MILLISECONDS);
+uint64_t CompositeElapsedCounterSource::microseconds(Type value) {
+  return (uint64_t)conversion<ElapsedCounterSource, MICROUNITS>(value.val1);
 }
+
+uint64_t CompositeElapsedCounterSource::nanoseconds(Type value) {
+  return (uint64_t)conversion<ElapsedCounterSource, NANOUNITS>(value.val1);
+}
--- a/src/hotspot/share/utilities/ticks.hpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/utilities/ticks.hpp	Tue May 15 20:24:34 2018 +0200
@@ -1,116 +1,249 @@
 /*
- * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * 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.
- *
- */
+* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* This code is free software; you can redistribute it and/or modify it
+* 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 SHARE_VM_UTILITIES_TICKS_HPP
 #define SHARE_VM_UTILITIES_TICKS_HPP
 
+#include "jni.h"
 #include "memory/allocation.hpp"
-#include "utilities/globalDefinitions.hpp"
+#include "utilities/macros.hpp"
 
-class Ticks;
+// Time sources
+class ElapsedCounterSource {
+ public:
+  typedef jlong Type;
+  static uint64_t frequency();
+  static Type now();
+  static double seconds(Type value);
+  static uint64_t milliseconds(Type value);
+  static uint64_t microseconds(Type value);
+  static uint64_t nanoseconds(Type value);
+};
 
-class Tickspan {
-  friend class Ticks;
-  friend Tickspan operator-(const Ticks& end, const Ticks& start);
+// Not guaranteed to be synchronized across hardware threads and
+// therefore software threads, and can be updated asynchronously
+// by software. now() can jump backwards as well as jump forward
+// when threads query different cores/sockets.
+// Very much not recommended for general use. Caveat emptor.
+class FastUnorderedElapsedCounterSource {
+ public:
+  typedef jlong Type;
+  static uint64_t frequency();
+  static Type now();
+  static double seconds(Type value);
+  static uint64_t milliseconds(Type value);
+  static uint64_t microseconds(Type value);
+  static uint64_t nanoseconds(Type value);
+};
 
- private:
-  jlong _span_ticks;
-
-  Tickspan(const Ticks& end, const Ticks& start);
-
+template <typename T1, typename T2>
+class PairRep {
  public:
-  Tickspan() : _span_ticks(0) {}
-
-  Tickspan& operator+=(const Tickspan& rhs) {
-    _span_ticks += rhs._span_ticks;
-    return *this;
-  }
+  T1 val1;
+  T2 val2;
 
-  Tickspan& operator-=(const Tickspan& rhs) {
-    _span_ticks -= rhs._span_ticks;
-    return *this;
+  PairRep() : val1((T1)0), val2((T2)0) {}
+  void operator+=(const PairRep& rhs) {
+    val1 += rhs.val1;
+    val2 += rhs.val2;
+  }
+  void operator-=(const PairRep& rhs) {
+    val1 -= rhs.val1;
+    val2 -= rhs.val2;
   }
+  bool operator==(const PairRep& rhs) const {
+    return val1 == rhs.val1;
+  }
+  bool operator!=(const PairRep& rhs) const {
+    return !operator==(rhs);
+  }
+  bool operator<(const PairRep& rhs) const {
+    return val1 < rhs.val1;
+  }
+  bool operator>(const PairRep& rhs) const {
+    return val1 > rhs.val1;
+  }
+};
 
-  jlong value() const {
-    return _span_ticks;
-  }
+template <typename T1, typename T2>
+PairRep<T1, T2> operator-(const PairRep<T1, T2>& lhs, const PairRep<T1, T2>& rhs) {
+  PairRep<T1, T2> temp(lhs);
+  temp -= rhs;
+  return temp;
+}
+
+typedef PairRep<ElapsedCounterSource::Type, FastUnorderedElapsedCounterSource::Type> CompositeTime;
 
+class CompositeElapsedCounterSource {
+ public:
+  typedef CompositeTime Type;
+  static uint64_t frequency();
+  static Type now();
+  static double seconds(Type value);
+  static uint64_t milliseconds(Type value);
+  static uint64_t microseconds(Type value);
+  static uint64_t nanoseconds(Type value);
 };
 
-class Ticks {
- private:
-  jlong _stamp_ticks;
-
+template <typename TimeSource>
+class Representation {
+ public:
+  typedef typename TimeSource::Type Type;
+ protected:
+  Type _rep;
+  Representation(const Representation<TimeSource>& end, const Representation<TimeSource>& start) : _rep(end._rep - start._rep) {}
+  Representation() : _rep() {}
  public:
-  Ticks() : _stamp_ticks(0) {
-    assert((_stamp_ticks = invalid_time_stamp) == invalid_time_stamp,
-      "initial unstamped time value assignment");
+  void operator+=(const Representation<TimeSource>& rhs) {
+    _rep += rhs._rep;
+  }
+  void operator-=(const Representation<TimeSource>& rhs) {
+    _rep -= rhs._rep;
+  }
+  bool operator==(const Representation<TimeSource>& rhs) const {
+    return _rep == rhs._rep;
+  }
+  bool operator!=(const Representation<TimeSource>& rhs) const {
+    return !operator==(rhs);
+  }
+  bool operator<(const Representation<TimeSource>& rhs) const {
+    return _rep < rhs._rep;
+  }
+  bool operator>(const Representation<TimeSource>& rhs) const {
+    return _rep > rhs._rep;
+  }
+  bool operator<=(const Representation<TimeSource>& rhs) const {
+    return !operator>(rhs);
+  }
+  bool operator>=(const Representation<TimeSource>& rhs) const {
+    return !operator<(rhs);
+  }
+  double seconds() const {
+    return TimeSource::seconds(_rep);
+  }
+  uint64_t milliseconds() const {
+    return TimeSource::milliseconds(_rep);
+  }
+  uint64_t microseconds() const {
+    return TimeSource::microseconds(_rep);
+  }
+  uint64_t nanoseconds() const {
+    return TimeSource::nanoseconds(_rep);
   }
+};
 
-  Ticks& operator+=(const Tickspan& span) {
-    _stamp_ticks += span.value();
-    return *this;
+template <typename TimeSource>
+class CounterRepresentation : public Representation<TimeSource> {
+ protected:
+  CounterRepresentation(const CounterRepresentation& end, const CounterRepresentation& start) : Representation<TimeSource>(end, start) {}
+  explicit CounterRepresentation(jlong value) : Representation<TimeSource>() {
+    this->_rep = value;
+  }
+ public:
+  CounterRepresentation() : Representation<TimeSource>() {}
+  typename TimeSource::Type value() const { return this->_rep; }
+  operator typename TimeSource::Type() { return value(); }
+};
+
+template <typename TimeSource>
+class CompositeCounterRepresentation : public Representation<TimeSource> {
+ protected:
+  CompositeCounterRepresentation(const CompositeCounterRepresentation& end, const CompositeCounterRepresentation& start) :
+    Representation<TimeSource>(end, start) {}
+  explicit CompositeCounterRepresentation(jlong value) : Representation<TimeSource>() {
+    this->_rep.val1 = value;
+    this->_rep.val2 = value;
   }
+ public:
+  CompositeCounterRepresentation() : Representation<TimeSource>() {}
+  ElapsedCounterSource::Type value() const { return this->_rep.val1; }
+  FastUnorderedElapsedCounterSource::Type ft_value() const { return this->_rep.val2; }
+};
 
-  Ticks& operator-=(const Tickspan& span) {
-    _stamp_ticks -= span.value();
+template <template <typename> class, typename>
+class TimeInstant;
+
+template <template <typename> class Rep, typename TimeSource>
+class TimeInterval : public Rep<TimeSource> {
+  template <template <typename> class, typename>
+  friend class TimeInstant;
+  TimeInterval(const TimeInstant<Rep, TimeSource>& end, const TimeInstant<Rep, TimeSource>& start) : Rep<TimeSource>(end, start) {}
+ public:
+  TimeInterval() : Rep<TimeSource>() {}
+  TimeInterval<Rep, TimeSource> operator+(const TimeInterval<Rep, TimeSource>& rhs) const {
+    TimeInterval<Rep, TimeSource> temp(*this);
+    temp += rhs;
+    return temp;
+  }
+  TimeInterval<Rep, TimeSource> operator-(const TimeInterval<Rep, TimeSource>& rhs) const {
+    TimeInterval<Rep, TimeSource> temp(*this);
+    temp -= rhs;
+    return temp;
+  }
+};
+
+template <template <typename> class Rep, typename TimeSource>
+class TimeInstant : public Rep<TimeSource> {
+ public:
+  TimeInstant() : Rep<TimeSource>() {}
+  TimeInstant<Rep, TimeSource>& operator+=(const TimeInterval<Rep, TimeSource>& rhs) {
+    Rep<TimeSource>::operator+=(rhs);
     return *this;
   }
-
-  void stamp();
-
-  jlong value() const {
-    return _stamp_ticks;
+  TimeInstant<Rep, TimeSource>& operator-=(const TimeInterval<Rep, TimeSource>& rhs) {
+    Rep<TimeSource>::operator-=(rhs);
+    return *this;
+  }
+  TimeInterval<Rep, TimeSource> operator+(const TimeInstant<Rep, TimeSource>& end) const {
+    return TimeInterval<Rep, TimeSource>(end, *this);
+  }
+  TimeInterval<Rep, TimeSource> operator-(const TimeInstant<Rep, TimeSource>& start) const {
+    return TimeInterval<Rep, TimeSource>(*this, start);
   }
-
-  static const Ticks now();
-
-#ifdef ASSERT
-  static const jlong invalid_time_stamp;
-#endif
-
-#ifndef PRODUCT
-  // only for internal use by GC VM tests
+  void stamp() {
+    this->_rep = TimeSource::now();
+  }
+  static TimeInstant<Rep, TimeSource> now() {
+    TimeInstant<Rep, TimeSource> temp;
+    temp.stamp();
+    return temp;
+  }
+ private:
+  TimeInstant(jlong ticks) : Rep<TimeSource>(ticks) {}
+  friend class GranularTimer;
+  friend class ObjectSample;
+  //  GC VM tests
   friend class TimePartitionPhasesIteratorTest;
   friend class GCTimerTest;
-
- private:
-  // implicit type conversion
-  Ticks(int ticks) : _stamp_ticks(ticks) {}
-
-#endif // !PRODUCT
-
 };
 
-class TicksToTimeHelper : public AllStatic {
- public:
-  enum Unit {
-    SECONDS = 1,
-    MILLISECONDS = 1000
-  };
-  static double seconds(const Tickspan& span);
-  static jlong milliseconds(const Tickspan& span);
-};
+#if INCLUDE_JFR
+typedef TimeInstant<CompositeCounterRepresentation, CompositeElapsedCounterSource> Ticks;
+typedef TimeInterval<CompositeCounterRepresentation, CompositeElapsedCounterSource> Tickspan;
+#else
+typedef TimeInstant<CounterRepresentation, ElapsedCounterSource> Ticks;
+typedef TimeInterval<CounterRepresentation, ElapsedCounterSource> Tickspan;
+#endif
 
 #endif // SHARE_VM_UTILITIES_TICKS_HPP
--- a/src/hotspot/share/utilities/ticks.inline.hpp	Tue May 15 11:28:29 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef SHARE_VM_UTILITIES_TICKS_INLINE_HPP
-#define SHARE_VM_UTILITIES_TICKS_INLINE_HPP
-
-#include "utilities/ticks.hpp"
-
-inline Tickspan operator+(Tickspan lhs, const Tickspan& rhs) {
-  lhs += rhs;
-  return lhs;
-}
-
-inline Tickspan operator-(Tickspan lhs, const Tickspan& rhs) {
-  lhs -= rhs;
-  return lhs;
-}
-
-inline bool operator==(const Tickspan& lhs, const Tickspan& rhs) {
-  return lhs.value() == rhs.value();
-}
-
-inline bool operator!=(const Tickspan& lhs, const Tickspan& rhs) {
-  return !operator==(lhs,rhs);
-}
-
-inline bool operator<(const Tickspan& lhs, const Tickspan& rhs) {
-  return lhs.value() < rhs.value();
-}
-
-inline bool operator>(const Tickspan& lhs, const Tickspan& rhs) {
-  return operator<(rhs,lhs);
-}
-
-inline bool operator<=(const Tickspan& lhs, const Tickspan& rhs) {
-  return !operator>(lhs,rhs);
-}
-
-inline bool operator>=(const Tickspan& lhs, const Tickspan& rhs) {
-  return !operator<(lhs,rhs);
-}
-
-inline Ticks operator+(Ticks lhs, const Tickspan& span) {
-  lhs += span;
-  return lhs;
-}
-
-inline Ticks operator-(Ticks lhs, const Tickspan& span) {
-  lhs -= span;
-  return lhs;
-}
-
-inline Tickspan operator-(const Ticks& end, const Ticks& start) {
-  return Tickspan(end, start);
-}
-
-inline bool operator==(const Ticks& lhs, const Ticks& rhs) {
-  return lhs.value() == rhs.value();
-}
-
-inline bool operator!=(const Ticks& lhs, const Ticks& rhs) {
-  return !operator==(lhs,rhs);
-}
-
-inline bool operator<(const Ticks& lhs, const Ticks& rhs) {
-  return lhs.value() < rhs.value();
-}
-
-inline bool operator>(const Ticks& lhs, const Ticks& rhs) {
-  return operator<(rhs,lhs);
-}
-
-inline bool operator<=(const Ticks& lhs, const Ticks& rhs) {
-  return !operator>(lhs,rhs);
-}
-
-inline bool operator>=(const Ticks& lhs, const Ticks& rhs) {
-  return !operator<(lhs,rhs);
-}
-
-#endif // SHARE_VM_UTILITIES_TICKS_INLINE_HPP
--- a/src/hotspot/share/utilities/vmError.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/src/hotspot/share/utilities/vmError.cpp	Tue May 15 20:24:34 2018 +0200
@@ -29,6 +29,7 @@
 #include "compiler/disassembler.hpp"
 #include "gc/shared/gcConfig.hpp"
 #include "logging/logConfiguration.hpp"
+#include "jfr/jfrEvents.hpp"
 #include "memory/resourceArea.hpp"
 #include "prims/whitebox.hpp"
 #include "runtime/arguments.hpp"
@@ -42,13 +43,16 @@
 #include "runtime/vm_operations.hpp"
 #include "runtime/vm_version.hpp"
 #include "services/memTracker.hpp"
-#include "trace/traceMacros.hpp"
 #include "utilities/debug.hpp"
 #include "utilities/decoder.hpp"
 #include "utilities/defaultStream.hpp"
 #include "utilities/errorReporter.hpp"
 #include "utilities/events.hpp"
 #include "utilities/vmError.hpp"
+#include "utilities/macros.hpp"
+#if INCLUDE_JFR
+#include "jfr/jfr.hpp"
+#endif
 
 #ifndef PRODUCT
 #include <signal.h>
@@ -1321,7 +1325,7 @@
       e.commit();
     }
 
-    TRACE_VM_ERROR();
+    JFR_ONLY(Jfr::on_vm_shutdown(true);)
 
   } else {
     // If UseOsErrorReporting we call this for each level of the call stack
--- a/src/java.base/share/classes/module-info.java	Tue May 15 11:28:29 2018 -0700
+++ b/src/java.base/share/classes/module-info.java	Tue May 15 20:24:34 2018 +0200
@@ -134,6 +134,8 @@
 
     exports com.sun.security.ntlm to
         java.security.sasl;
+    exports jdk.internal to
+        jdk.jfr;
     exports jdk.internal.jimage to
         jdk.jlink;
     exports jdk.internal.jimage.decompressor to
@@ -148,17 +150,25 @@
         java.logging;
     exports jdk.internal.org.objectweb.asm to
         jdk.jartool,
+        jdk.jfr,
         jdk.jlink,
         jdk.scripting.nashorn,
         jdk.internal.vm.ci;
     exports jdk.internal.org.objectweb.asm.tree to
+        jdk.jfr,
         jdk.jlink;
     exports jdk.internal.org.objectweb.asm.util to
+        jdk.jfr,
         jdk.scripting.nashorn;
     exports jdk.internal.org.objectweb.asm.commons to
+        jdk.jfr,
         jdk.scripting.nashorn;
     exports jdk.internal.org.objectweb.asm.signature to
         jdk.scripting.nashorn;
+    exports jdk.internal.org.xml.sax to
+        jdk.jfr;
+    exports jdk.internal.org.xml.sax.helpers to
+        jdk.jfr;
     exports jdk.internal.misc to
         java.desktop,
         java.logging,
@@ -173,6 +183,7 @@
         jdk.compiler,
         java.net.http,
         jdk.jdeps,
+        jdk.jfr,
         jdk.jlink,
         jdk.jshell,
         jdk.net,
@@ -184,6 +195,7 @@
         java.instrument,
         java.management.rmi,
         jdk.jartool,
+        jdk.jfr,
         jdk.jlink;
     exports jdk.internal.perf to
         java.management,
@@ -207,6 +219,10 @@
         jdk.internal.vm.ci;
     exports jdk.internal.util.jar to
         jdk.jartool;
+    exports jdk.internal.util.xml to
+        jdk.jfr;
+    exports jdk.internal.util.xml.impl to
+        jdk.jfr;
     exports sun.net to
         java.net.http,
         jdk.naming.dns;
--- a/src/java.management/share/classes/module-info.java	Tue May 15 11:28:29 2018 -0700
+++ b/src/java.management/share/classes/module-info.java	Tue May 15 20:24:34 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -64,7 +64,8 @@
     exports sun.management.counter.perf to
         jdk.management.agent;
     exports sun.management.spi to
-        jdk.management;
+        jdk.management,
+        jdk.management.jfr;
 
     uses javax.management.remote.JMXConnectorProvider;
     uses javax.management.remote.JMXConnectorServerProvider;
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VMOps.java	Tue May 15 11:28:29 2018 -0700
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VMOps.java	Tue May 15 20:24:34 2018 +0200
@@ -79,7 +79,6 @@
   HeapWalkOperation,
   HeapIterateOperation,
   ReportJavaOutOfMemory,
-  JFRCheckpoint,
   Exit,
   LinuxDllLoad,
   Terminating
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/AnnotationElement.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,420 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.StringJoiner;
+
+import jdk.jfr.internal.Type;
+import jdk.jfr.internal.TypeLibrary;
+import jdk.jfr.internal.Utils;
+
+/**
+ * Describes event metadata, such as labels, descriptions and units.
+ * <p>
+ * The following example shows how {@code AnnotationElement} can be used to dynamically define events.
+ *
+ * <pre>
+ * <code>
+ *   List{@literal <}AnnotationElement{@literal >} typeAnnotations = new ArrayList{@literal <}{@literal >}();
+ *   typeannotations.add(new AnnotationElement(Name.class, "com.example.HelloWorld");
+ *   typeAnnotations.add(new AnnotationElement(Label.class, "Hello World"));
+ *   typeAnnotations.add(new AnnotationElement(Description.class, "Helps programmer getting started"));
+ *
+ *   List{@literal <}AnnotationElement{@literal >} fieldAnnotations = new ArrayList{@literal <}{@literal >}();
+ *   fieldAnnotations.add(new AnnotationElement(Label.class, "Message"));
+ *
+ *   List{@literal <}ValueDescriptor{@literal >} fields = new ArrayList{@literal <}{@literal >}();
+ *   fields.add(new ValueDescriptor(String.class, "message", fieldAnnotations));
+ *
+ *   EventFactory f = EventFactory.create(typeAnnotations, fields);
+ *   Event event = f.newEvent();
+ *   event.commit();
+ * </code>
+ * </pre>
+ *
+ * @since 9
+ */
+public final class AnnotationElement {
+    private final Type type;
+    private final List<Object> annotationValues;
+    private final List<String> annotationNames;
+    private final boolean inBootClassLoader;
+
+    // package private
+    AnnotationElement(Type type, List<Object> objects, boolean boot) {
+        Objects.requireNonNull(type);
+        Objects.requireNonNull(objects);
+        this.type = type;
+        if (objects.size() != type.getFields().size()) {
+            StringJoiner descriptors = new StringJoiner(",", "[", "]");
+            for (ValueDescriptor v : type.getFields()) {
+                descriptors.add(v.getName());
+            }
+            StringJoiner values = new StringJoiner(",", "[", "]");
+            for (Object object : objects) {
+                descriptors.add(String.valueOf(object));
+            }
+            throw new IllegalArgumentException("Annotation " + descriptors + " for " + type.getName() + " doesn't match number of values " + values);
+        }
+
+        List<String> n = new ArrayList<>();
+        List<Object> v = new ArrayList<>();
+        int index = 0;
+        for (ValueDescriptor valueDescriptor : type.getFields()) {
+            Object object = objects.get(index);
+            if (object == null) {
+                throw new IllegalArgumentException("Annotation value can't be null");
+            }
+            Class<?> valueType = object.getClass();
+            if (valueDescriptor.isArray()) {
+                valueType = valueType.getComponentType();
+            }
+            checkType(Utils.unboxType(valueType));
+            n.add(valueDescriptor.getName());
+            v.add(object);
+            index++;
+        }
+        this.annotationValues = Utils.smallUnmodifiable(v);
+        this.annotationNames = Utils.smallUnmodifiable(n);
+        this.inBootClassLoader = boot;
+    }
+
+    /**
+     * Creates an annotation element to use for dynamically defined events.
+     * <p>
+     * Supported value types are {@code byte}, {@code int}, {@code short},
+     * {@code long}, {@code double}, {@code float}, {@code boolean}, {@code char},
+     * and {@code String}. Enums, arrays and classes, are not supported.
+     * <p>
+     * If {@code annotationType} has annotations (directly present, indirectly
+     * present, or associated), then those annotation are recursively included.
+     * However, both the {@code annotationType} and any annotation found recursively
+     * must have the {@link MetadataDefinition} annotation.
+     * <p>
+     * To statically define events, see {@link Event} class.
+     *
+     * @param annotationType interface extending
+     *        {@code java.lang.annotation.Annotation}, not {@code null}
+     * @param values a {@code Map} with keys that match method names of the specified
+     *        annotation interface
+     * @throws IllegalArgumentException if value/key is {@code null}, an unsupported
+     *         value type is used, or a value/key is used that doesn't match the
+     *         signatures in the {@code annotationType}
+     */
+    public AnnotationElement(Class<? extends Annotation> annotationType, Map<String, Object> values) {
+        Objects.requireNonNull(annotationType);
+        Objects.requireNonNull(values);
+        Utils.checkRegisterPermission();
+        // copy values to avoid modification after validation
+        HashMap<String, Object> map = new HashMap<>(values);
+        for (Map.Entry<String, Object> entry : map.entrySet()) {
+            if (entry.getKey() == null) {
+                throw new NullPointerException("Name of annotation method can't be null");
+            }
+            if (entry.getValue() == null) {
+                throw new NullPointerException("Return value for annotation method can't be null");
+            }
+        }
+
+        if (AnnotationElement.class.isAssignableFrom(annotationType) && annotationType.isInterface()) {
+            throw new IllegalArgumentException("Must be interface extending " + Annotation.class.getName());
+        }
+        if (!isKnownJFRAnnotation(annotationType) && annotationType.getAnnotation(MetadataDefinition.class) == null) {
+            throw new IllegalArgumentException("Annotation class must be annotated with jdk.jfr.MetadataDefinition to be valid");
+        }
+        if (isKnownJFRAnnotation(annotationType)) {
+            this.type = new Type(annotationType.getCanonicalName(), Type.SUPER_TYPE_ANNOTATION, Type.getTypeId(annotationType));
+        } else {
+            this.type = TypeLibrary.createAnnotationType(annotationType);
+        }
+        Method[] methods = annotationType.getDeclaredMethods();
+        if (methods.length != map.size()) {
+            throw new IllegalArgumentException("Number of declared methods must match size of value map");
+        }
+        List<String> n = new ArrayList<>();
+        List<Object> v = new ArrayList<>();
+        Set<String> nameSet = new HashSet<>();
+        for (Method method : methods) {
+            String fieldName = method.getName();
+            Object object = map.get(fieldName);
+            if (object == null) {
+                throw new IllegalArgumentException("No method in annotation interface " + annotationType.getName() + " matching name " + fieldName);
+            }
+            Class<?> fieldType = object.getClass();
+
+            if (fieldType == Class.class) {
+                throw new IllegalArgumentException("Annotation value for " + fieldName + " can't be class");
+            }
+            if (object instanceof Enum) {
+                throw new IllegalArgumentException("Annotation value for " + fieldName + " can't be enum");
+            }
+            if (!fieldType.equals(object.getClass())) {
+                throw new IllegalArgumentException("Return type of annotation " + fieldType.getName() + " must match type of object" + object.getClass());
+            }
+
+            if (fieldType.isArray()) {
+                Class<?> componentType = fieldType.getComponentType();
+                checkType(componentType);
+                if (componentType.equals(String.class)) {
+                    String[] stringArray = (String[]) object;
+                    for (int i = 0; i < stringArray.length; i++) {
+                        if (stringArray[i] == null) {
+                            throw new IllegalArgumentException("Annotation value for " + fieldName + " contains null");
+                        }
+                    }
+                }
+            } else {
+                fieldType = Utils.unboxType(object.getClass());
+                checkType(fieldType);
+            }
+            if (nameSet.contains(fieldName)) {
+                throw new IllegalArgumentException("Value with name '" + fieldName + "' already exists");
+            }
+            if (isKnownJFRAnnotation(annotationType)) {
+                ValueDescriptor vd = new ValueDescriptor(fieldType, fieldName, Collections.emptyList(), true);
+                type.add(vd);
+            }
+            n.add(fieldName);
+            v.add(object);
+        }
+        this.annotationValues = Utils.smallUnmodifiable(v);
+        this.annotationNames = Utils.smallUnmodifiable(n);
+        this.inBootClassLoader = annotationType.getClassLoader() == null;
+    }
+
+    /**
+     * Creates an annotation element to use for dynamically defined events.
+     * <p>
+     * Supported value types are {@code byte}, {@code int}, {@code short},
+     * {@code long}, {@code double}, {@code float}, {@code boolean}, {@code char},
+     * and {@code String}. Enums, arrays, and classes are not supported.
+     * <p>
+     * If {@code annotationType} has annotations (directly present, indirectly
+     * present, or associated), then those annotations are recursively included.
+     * However, both {@code annotationType} and any annotation found recursively
+     * must have the {@link MetadataDefinition} annotation.
+     * <p>
+     * To statically define events, see {@link Event} class.
+     *
+     * @param annotationType interface extending
+     *        {@code java.lang.annotation.Annotation,} not {@code null}
+     * @param value the value that matches the {@code value} method of the specified
+     *        {@code annotationType}
+     * @throws IllegalArgumentException if value/key is {@code null}, an unsupported
+     *         value type is used, or a value/key is used that doesn't match the
+     *         signatures in the {@code annotationType}
+     */
+    public AnnotationElement(Class<? extends Annotation> annotationType, Object value) {
+        this(annotationType, Collections.singletonMap("value", Objects.requireNonNull(value)));
+    }
+
+    /**
+     * Creates an annotation element to use for dynamically defined events.
+     * <p>
+     * Supported value types are {@code byte}, {@code short}, {@code int},
+     * {@code long}, {@code double}, {@code float}, {@code boolean}, {@code char},
+     * and {@code String}. Enums, arrays, and classes are not supported.
+     * <p>
+     * If {@code annotationType} has annotations (directly present, indirectly
+     * present or associated), then those annotation are recursively included.
+     * However, both {@code annotationType} and any annotation found recursively
+     * must have the {@link MetadataDefinition} annotation.
+     * <p>
+     * To statically define events, see {@link Event} class.
+     *
+     * @param annotationType interface extending java.lang.annotation.Annotation,
+     *        not {@code null}
+     */
+    public AnnotationElement(Class<? extends Annotation> annotationType) {
+        this(annotationType, Collections.emptyMap());
+    }
+
+    /**
+     * Returns an immutable list of annotation values in an order that matches the
+     * value descriptors for this {@code AnnotationElement}.
+     *
+     * @return list of values, not {@code null}
+     */
+    public List<Object> getValues() {
+        return annotationValues;
+    }
+
+    /**
+     * Returns an immutable list of descriptors that describes the annotation values
+     * for this {@code AnnotationElement}.
+     *
+     * @return the list of value descriptors for this {@code Annotation}, not
+     *         {@code null}
+     */
+    public List<ValueDescriptor> getValueDescriptors() {
+        return Collections.unmodifiableList(type.getFields());
+    }
+
+    /**
+     * Returns an immutable list of annotation elements for this
+     * {@code AnnotationElement}.
+     *
+     * @return a list of meta annotation, not {@code null}
+     */
+    public List<AnnotationElement> getAnnotationElements() {
+        return type.getAnnotationElements();
+    }
+
+    /**
+     * Returns the fully qualified name of the annotation type that corresponds to
+     * this {@code AnnotationElement} (for example, {@code "jdk.jfr.Label"}).
+     *
+     * @return type name, not {@code null}
+     */
+    public String getTypeName() {
+        return type.getName();
+    }
+
+    /**
+     * Returns a value for this {@code AnnotationElement}.
+     *
+     * @param name the name of the method in the annotation interface, not
+     *        {@code null}.
+     *
+     * @return the annotation value, not {@code null}.
+     *
+     * @throws IllegalArgumentException if a method with the specified name does
+     *         not exist in the annotation
+     */
+    public Object getValue(String name) {
+        Objects.requireNonNull(name);
+        int index = 0;
+        for (String n : annotationNames) {
+            if (name.equals(n)) {
+                return annotationValues.get(index);
+            }
+            index++;
+        }
+        StringJoiner valueNames = new StringJoiner(",", "[", "]");
+        for (ValueDescriptor v : type.getFields()) {
+            valueNames.add(v.getName());
+        }
+        throw new IllegalArgumentException("No value with name '" + name + "'. Valid names are " + valueNames);
+    }
+
+    /**
+     * Returns {@code true} if an annotation value with the specified name exists in
+     * this {@code AnnotationElement}.
+     *
+     * @param name name of the method in the annotation interface to find, not
+     *        {@code null}
+     *
+     * @return {@code true} if method exists, {@code false} otherwise
+     */
+    public boolean hasValue(String name) {
+        Objects.requireNonNull(name);
+        for (String n : annotationNames) {
+            if (name.equals(n)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns the first annotation for the specified type if an
+     * {@code AnnotationElement} with the same name exists, else {@code null}.
+     *
+     * @param <A> the type of the annotation to query for and return if it exists
+     * @param annotationType the {@code Class object} corresponding to the annotation type,
+     *        not {@code null}
+     * @return this element's annotation for the specified annotation type if
+     *         it it exists, else {@code null}
+     */
+    public final <A> A getAnnotation(Class<? extends Annotation> annotationType) {
+        Objects.requireNonNull(annotationType);
+        return type.getAnnotation(annotationType);
+    }
+
+    /**
+     * Returns the type ID for this {@code AnnotationElement}.
+     * <p>
+     * The ID is a unique identifier for the type in the Java Virtual Machine (JVM). The ID might not
+     * be the same between JVM instances.
+     *
+     * @return the type ID, not negative
+     */
+    public long getTypeId() {
+        return type.getId();
+    }
+
+    // package private
+    Type getType() {
+        return type;
+    }
+
+    private static void checkType(Class<?> type) {
+        if (type.isPrimitive()) {
+            return;
+        }
+        if (type == String.class) {
+            return;
+        }
+        throw new IllegalArgumentException("Only primitives types or java.lang.String are allowed");
+    }
+
+    // Whitelist of annotation classes that are allowed, even though
+    // they don't have @MetadataDefinition.
+    private static boolean isKnownJFRAnnotation(Class<? extends Annotation> annotationType) {
+        if (annotationType == Registered.class) {
+            return true;
+        }
+        if (annotationType == Threshold.class) {
+            return true;
+        }
+        if (annotationType == StackTrace.class) {
+            return true;
+        }
+        if (annotationType == Period.class) {
+            return true;
+        }
+        if (annotationType == Enabled.class) {
+            return true;
+        }
+        return false;
+    }
+
+    // package private
+    boolean isInBoot() {
+        return inBootClassLoader;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/BooleanFlag.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Event field annotation, specifies that the value is a boolean flag, a {@code true} or
+ * {@code false} value
+ *
+ * @since 9
+ */
+@MetadataDefinition
+@ContentType
+@Label("Flag")
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})
+public @interface BooleanFlag {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/Category.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Event annotation, to associate the event type with a category, in the format
+ * of a human-readable path.
+ * <p>
+ * The category determines how an event is presented to the user. Events that
+ * are in the same category are typically displayed together in graphs and
+ * trees. To avoid the overlap of durational events in graphical
+ * representations, overlapping events must be in separate categories.
+ * <p>
+ * For example, to monitor image uploads to a web server with a separate thread
+ * for each upload, an event called File Upload starts when the user uploads a
+ * file and ends when the upload is complete. For advanced diagnostics about
+ * image uploads, more detailed events are created (for example, Image Read,
+ * Image Resize, and Image Write). During these detailed events. other low
+ * level-events could occur (for example, Socket Read and File Write).
+ * <p>
+ * The following example shows a visualization that avoids overlaps:
+ *
+ * <pre>
+ * -------------------------------------------------------------------
+ *   |                         File Upload                        |
+ * ------------------------------------------------------------------
+ *   |       Image Read          | Image Resize |   Image Write   |
+ * ------------------------------------------------------------------
+ *   | Socket Read | Socket Read |              |    File Write   |
+ * -------------------------------------------------------------------
+ * </pre>
+ *
+ * The example can be achieved by using the following categories:
+ *
+ * <table class="striped">
+ * <caption>Recording options and their purpose.</caption> <thead>
+ * <tr>
+ * <th scope="col">Event Name</th>
+ * <th scope="col">Annotation</th>
+ * </tr>
+ * </thead> <tbody>
+ * <tr>
+ * <th scope="row">File Upload</th>
+ * <td><code>@Category("Upload")</code></td>
+ * </tr>
+ * <tr>
+ * <th scope="row">Image Read</th>
+ * <td><code>@Category({"Upload", "Image Upload"})</code></td>
+ * </tr>
+ * <tr>
+ * <th scope="row">Image Resize</th>
+ * <td><code>@Category({"Upload", "Image Upload"})</code></td>
+ * </tr>
+ * <tr>
+ * <th scope="row">Image Write</th>
+ * <td><code>@Category({"Upload", "Image Upload"})</code></td>
+ * </tr>
+ * <tr>
+ * <th scope="row">Socket Read</th>
+ * <td><code>@Category("Java Application")</code></td>
+ * </tr>
+ * <tr>
+ * <th scope="row">File Write</th>
+ * <td><code>@Category("Java Application")</code></td>
+ * </tr>
+ * </tbody>
+ * </table>
+ * <p>
+ * The File Upload, Image Read, and Socket Read events happen concurrently (in
+ * the same thread), but the events are in different categories so they do not
+ * overlap in the visualization.
+ * <p>
+ * The following examples shows how the category is used to determine how events
+ * are visualized in a tree:
+ *
+ * <pre>
+ *  |- Java Application
+ *  |  |- Socket Read
+ *  |  |- File Write
+ *  |- Upload
+ *     |- File Upload
+ *     |- Image Upload
+ *        |- Image Read
+ *        |- Image Resize
+ *        |- File Write
+ * </pre>
+ *
+ * @since 9
+ */
+@MetadataDefinition
+@Target({ ElementType.TYPE })
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Category {
+    /**
+     * Returns the category names for this annotation, starting with the root.
+     *
+     * @return the category names
+     */
+    String[] value();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/Configuration.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import jdk.jfr.internal.JVMSupport;
+import jdk.jfr.internal.jfc.JFC;
+
+/**
+ * A collection of settings and metadata describing the configuration.
+ *
+ * @since 9
+ */
+public final class Configuration {
+    private final Map<String, String> settings;
+    private final String label;
+    private final String description;
+    private final String provider;
+    private final String contents;
+    private final String name;
+
+    // package private
+    Configuration(String name, String label, String description, String provider, Map<String, String> settings, String contents) {
+        this.name = name;
+        this.label = label;
+        this.description = description;
+        this.provider = provider;
+        this.settings = settings;
+        this.contents = contents;
+    }
+
+    /**
+     * Returns the settings that specifies how a recording is configured.
+     * <p>
+     * Modifying the returned {@code Map} object doesn't change the
+     * configuration.
+     *
+     * @return settings, not {@code null}
+     */
+    public Map<String, String> getSettings() {
+        return new LinkedHashMap<String, String>(settings);
+    }
+
+    /**
+     * Returns an identifying name (for example, {@code "default" or "profile")}.
+     *
+     * @return the name, or {@code null} if it doesn't exist
+     */
+    public String getName() {
+        return this.name;
+    }
+
+    /**
+     * Returns a human-readable name (for example, {@code "Continuous" or "Profiling"}}.
+     *
+     * @return the label, or {@code null} if it doesn't exist
+     */
+    public String getLabel() {
+        return this.label;
+    }
+
+    /**
+     * Returns a short sentence that describes the configuration (for example
+     * {@code "Low
+     * overhead configuration safe for continuous use in production
+     * environments"})
+     *
+     * @return the description, or {@code null} if it doesn't exist
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * Returns who created the configuration (for example {@code "OpenJDK"}).
+     *
+     * @return the provider, or {@code null} if it doesn't exist
+     */
+    public String getProvider() {
+        return provider;
+    }
+
+    /**
+     * Returns a textual representation of the configuration (for example, the
+     * contents of a JFC file).
+     *
+     * @return contents, or {@code null} if it doesn't exist
+     *
+     * @see Configuration#getContents()
+     */
+    public String getContents() {
+        return contents;
+    }
+
+    /**
+     * Reads a configuration from a file.
+     *
+     * @param path the file that contains the configuration, not {@code null}
+     * @return the read {@link Configuration}, not {@code null}
+     * @throws ParseException if the file can't be parsed
+     * @throws IOException if the file can't be read
+     * @throws SecurityException if a security manager exists and its
+     *         {@code checkRead} method denies read access to the file.
+     *
+     * @see java.io.File#getPath()
+     * @see java.lang.SecurityManager#checkRead(java.lang.String)
+     */
+    public static Configuration create(Path path) throws IOException, ParseException {
+        Objects.requireNonNull(path);
+        JVMSupport.ensureWithIOException();
+        try (Reader reader = Files.newBufferedReader(path)) {
+            return JFC.create(JFC.nameFromPath(path), reader);
+        }
+    }
+
+    /**
+     * Reads a configuration from a character stream.
+     *
+     * @param reader a {@code Reader} that provides the configuration contents, not
+     *        {@code null}
+     * @return a configuration, not {@code null}
+     * @throws IOException if an I/O error occurs while trying to read contents
+     *         from the {@code Reader}
+     * @throws ParseException if the file can't be parsed
+     */
+    public static Configuration create(Reader reader) throws IOException, ParseException {
+        Objects.requireNonNull(reader);
+        JVMSupport.ensureWithIOException();
+        return JFC.create(null, reader);
+    }
+
+    /**
+     * Returns a predefined configuration.
+     * <p>
+     * See {@link Configuration#getConfigurations()} for available configuration
+     * names.
+     *
+     * @param name the name of the configuration (for example, {@code "default"} or
+     *        {@code "profile"})
+     * @return a configuration, not {@code null}
+     *
+     * @throws IOException if a configuration with the given name does not
+     *         exist, or if an I/O error occurs while reading the
+     *         configuration file
+     * @throws ParseException if the configuration file can't be parsed
+     */
+    public static Configuration getConfiguration(String name) throws IOException, ParseException {
+        JVMSupport.ensureWithIOException();
+        return JFC.getPredefined(name);
+    }
+
+    /**
+     * Returns an immutable list of predefined configurations for this Java Virtual Machine (JVM).
+     *
+     * @return the list of predefined configurations, not {@code null}
+     */
+    public static List<Configuration> getConfigurations() {
+        if (JVMSupport.isNotAvailable()) {
+            return new ArrayList<>();
+        }
+        return Collections.unmodifiableList(JFC.getConfigurations());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/ContentType.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Meta annotation, specifies that an annotation represents a content type, such
+ * as a time span or a frequency.
+ *
+ * @since 9
+ */
+@MetadataDefinition
+@Label("Content Type")
+@Description("Semantic meaning of a value")
+@Target(ElementType.ANNOTATION_TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ContentType {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/DataAmount.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Event field annotation, specifies that a value represents an amount of data (for example, bytes).
+ *
+ * @since 9
+ */
+@MetadataDefinition
+@ContentType
+@Label("Data Amount")
+@Description("Amount of data")
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})
+public @interface DataAmount {
+    /**
+     * Unit for bits
+     */
+    public static final String BITS = "BITS";
+    /**
+     * Unit for bytes
+     */
+    public static final String BYTES = "BYTES";
+
+    /**
+     * Returns the unit for the data amount, by default bytes.
+     *
+     * @return the data amount unit, default {@code BYTES}, not {@code null}
+     */
+    String value() default BYTES;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/Description.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation that describes an element by using a sentence or two.
+ * <p>
+ * Use sentence-style capitalization, capitalize the first letter of the first
+ * word, and any proper names such as the word Java. If the description is one
+ * sentence, a period should not be included.
+ *
+ * @since 9
+ */
+@MetadataDefinition
+@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Description {
+    /**
+     * Returns a sentence or two that describes the annotated element.
+     *
+     * @return a description, not {@code null}
+     */
+    String value();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/Enabled.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Event annotation, determines if an event should be enabled by default.
+ * <p>
+ * If an event doesn't have the annotation, then by default the event is enabled.
+ *
+ * @since 9
+ */
+@Target({ ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+@MetadataDefinition
+public @interface Enabled {
+    /**
+     * Setting name {@code "enabled"}, signifies that the event should be
+     * recorded.
+     */
+    public final static String NAME = "enabled";
+
+    /**
+     * Returns {@code true} if by default the event should be enabled, {@code false} otherwise.
+     *
+     * @return {@code true} if by default the event should be enabled by default, {@code false} otherwise
+     */
+    boolean value() default true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/Event.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+/**
+ * Base class for events, to be subclassed in order to define events and their
+ * fields.
+ * <p>
+ * The following example shows how to implement an {@code Event} class.
+ *
+ * <pre>
+ * <code>
+ * import jdk.jfr.Event;
+ * import jdk.jfr.Description;
+ * import jdk.jfr.Label;
+ *
+ * public class Example {
+ *
+ *   &#064;Label("Hello World")
+ *   &#064;Description("Helps programmer getting started")
+ *   static class HelloWorld extends Event {
+ *       &#064;Label("Message")
+ *       String message;
+ *   }
+ *
+ *   public static void main(String... args) {
+ *       HelloWorld event = new HelloWorld();
+ *       event.message = "hello, world!";
+ *       event.commit();
+ *   }
+ * }
+ * </code>
+ * </pre>
+ * <p>
+ * After an event is allocated and its field members are populated, it can be
+ * written to the Flight Recorder system by using the {@code #commit()} method.
+ * <p>
+ * By default, an event is enabled. To disable an event annotate the
+ * {@link Event} class with {@code @Enabled(false)}.
+ * <p>
+ * Supported field types are the Java primitives: {@code boolean}, {@code char},
+ * {@code byte}, {@code short}, {@code int}, {@code long}, {@code float}, and
+ * {@code double}. Supported reference types are: {@code String}, {@code Thread}
+ * and {@code Class}. Arrays, enums, and other reference types are silently
+ * ignored and not included. Fields that are of the supported types can be
+ * excluded by using the transient modifier. Static fields, even of the
+ * supported types, are not included.
+ * <p>
+ * Tools can visualize data in a meaningful way when annotations are used (for
+ * example, {@code Label}, {@code Description}, and {@code Timespan}).
+ * Annotations applied to an {@link Event} class or its fields are included if
+ * they are present (indirectly, directly, or associated), have the
+ * {@code MetadataDefinition} annotation, and they do not contain enums, arrays,
+ * or classes.
+ * <p>
+ * Gathering data to store in an event can be expensive. The
+ * {@link Event#shouldCommit()} method can be used to verify whether an event
+ * instance would actually be written to the system when the
+ * {@code Event#commit()commit} method is invoked. If
+ * {@link Event#shouldCommit()} returns false, then those operations can be
+ * avoided.
+ *
+ * @since 9
+ */
+@Enabled(true)
+@StackTrace(true)
+@Registered(true)
+abstract public class Event {
+    /**
+     * Sole constructor, for invocation by subclass constructors, typically
+     * implicit.
+     */
+    protected Event() {
+    }
+
+    /**
+     * Starts the timing of this event.
+     */
+    final public void begin() {
+    }
+
+    /**
+     * Ends the timing of this event.
+     *
+     * The {@code end} method must be invoked after the {@code begin} method.
+     */
+    final public void end() {
+    }
+
+    /**
+     * Writes the field values, time stamp, and event duration to the Flight
+     * Recorder system.
+     * <p>
+     * If the event starts with an invocation of the {@code begin} method, but does
+     * not end with an explicit invocation of the {@code end} method, then the event
+     * ends when the {@code commit} method is invoked.
+     */
+    final public void commit() {
+    }
+
+    /**
+     * Returns {@code true} if at least one recording is running, and the
+     * enabled setting for this event is set to {@code true}, otherwise
+     * {@code false} is returned.
+     *
+     * @return {@code true} if event is enabled, {@code false} otherwise
+     */
+    final public boolean isEnabled() {
+        return false;
+    }
+
+    /**
+     * Returns {@code true} if the enabled setting for this event is set to
+     * {@code true} and if the duration is within the threshold for the event,
+     * {@code false} otherwise. The threshold is the minimum threshold for all
+     * running recordings.
+     *
+     * @return {@code true} if the event can be written to the Flight Recorder
+     *         system, {@code false} otherwise
+     */
+    final public boolean shouldCommit() {
+        return false;
+    }
+
+    /**
+     * Sets a field value.
+     * <p>
+     * Applicable only if the event is dynamically defined using the
+     * {@code EventFactory} class.
+     * <p>
+     * The supplied {@code index} corresponds to the index of the
+     * {@link ValueDescriptor} object passed to the factory method of the
+     * {@code EventFactory} class.
+     *
+     * @param index the index of the field that is passed to
+     *        {@code EventFactory#create(String, java.util.List, java.util.List)}
+     * @param value value to set, can be {@code null}
+     * @throws UnsupportedOperationException if it's not a dynamically generated
+     *         event
+     * @throws IndexOutOfBoundsException if {@code index} is less than {@code 0} or
+     *         greater than or equal to the number of fields specified for the event
+     *
+     * @see EventType#getFields()
+     * @see EventFactory
+     */
+    final public void set(int index, Object value) {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/EventFactory.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+import jdk.jfr.internal.EventClassBuilder;
+import jdk.jfr.internal.JVMSupport;
+import jdk.jfr.internal.MetadataRepository;
+import jdk.jfr.internal.Type;
+import jdk.jfr.internal.Utils;
+
+/**
+ * Class for defining an event at runtime.
+ * <p>
+ * It's highly recommended that the event is defined at compile time, if the
+ * field layout is known, so the Java Virtual Machine (JVM) can optimize the
+ * code, possibly remove all instrumentation if Flight Recorder is inactive or
+ * if the enabled setting for this event is set to {@code false}.
+ * <p>
+ * To define an event at compile time, see {@link Event}.
+ * <p>
+ * The following example shows how to implement a dynamic {@code Event} class.
+ *
+ * <pre>
+ * {@code
+ * List<ValueDescriptor> fields = new ArrayList<>();
+ * List<AnnotationElement> messageAnnotations = Collections.singletonList(new AnnotationElement(Label.class, "Message"));
+ * fields.add(new ValueDescriptor(String.class, "message", messageAnnotations));
+ * List<AnnotationElement> numberAnnotations = Collections.singletonList(new AnnotationElement(Label.class, "Number"));
+ * fields.add(new ValueDescriptor(int.class, "number", numberAnnotations));
+ *
+ * String[] category = { "Example", "Getting Started" };
+ * List<AnnotationElement> eventAnnotations = new ArrayList<>();
+ * eventAnnotations.add(new AnnotationElement(Name.class, "com.example.HelloWorld"));
+ * eventAnnotations.add(new AnnotationElement(Label.class, "Hello World"));
+ * eventAnnotations.add(new AnnotationElement(Description.class, "Helps programmer getting started"));
+ * eventAnnotations.add(new AnnotationElement(Category.class, category));
+ *
+ * EventFactory f = EventFactory.create(eventAnnotations, fields);
+ *
+ * Event event = f.newEvent();
+ * event.set(0, "hello, world!");
+ * event.set(1, 4711);
+ * event.commit();
+ * }
+ * </pre>
+ *
+ * @since 9
+ */
+public final class EventFactory {
+
+    private static final long REGISTERED_ID = Type.getTypeId(Registered.class);
+
+    private final Class<? extends Event> eventClass;
+    private final MethodHandle constructorHandle;
+    private final List<AnnotationElement> sanitizedAnnotation;
+    private final List<ValueDescriptor> sanitizedFields;
+
+    private EventFactory(Class<? extends Event> eventClass, List<AnnotationElement> sanitizedAnnotation, List<ValueDescriptor> sanitizedFields) throws IllegalAccessException, NoSuchMethodException, SecurityException {
+        this.constructorHandle = MethodHandles.lookup().unreflectConstructor(eventClass.getConstructor());
+        this.eventClass = eventClass;
+        this.sanitizedAnnotation = sanitizedAnnotation;
+        this.sanitizedFields = sanitizedFields;
+    }
+
+    /**
+     * Creates an {@code EventFactory} object.
+     * <p>
+     * The order of the value descriptors specifies the index to use when setting
+     * event values.
+     *
+     * @param annotationElements list of annotation elements that describes the
+     *        annotations on the event, not {@code null}
+     *
+     * @param fields list of descriptors that describes the fields of the event, not
+     *        {@code null}
+     *
+     * @return event factory, not {@code null}
+     *
+     * @throws IllegalArgumentException if the input is not valid. For example,
+     *         input might not be valid if the field type or name is not valid in
+     *         the Java language or an annotation element references a type that
+     *         can't be found.
+     *
+     * @throws SecurityException if a security manager exists and the caller does
+     *         not have {@code FlightRecorderPermission("registerEvent")}
+     *
+     * @see Event#set(int, Object)
+     */
+    public static EventFactory create(List<AnnotationElement> annotationElements, List<ValueDescriptor> fields) {
+        Objects.requireNonNull(fields);
+        Objects.requireNonNull(annotationElements);
+        JVMSupport.ensureWithInternalError();
+
+        Utils.checkRegisterPermission();
+
+        List<AnnotationElement> sanitizedAnnotation = Utils.sanitizeNullFreeList(annotationElements, AnnotationElement.class);
+        List<ValueDescriptor> sanitizedFields = Utils.sanitizeNullFreeList(fields, ValueDescriptor.class);
+        Set<String> nameSet = new HashSet<>();
+        for (ValueDescriptor v : sanitizedFields) {
+            String name = v.getName();
+            if (v.isArray()) {
+                throw new IllegalArgumentException("Array types are not allowed for fields");
+            }
+            if (!Type.isValidJavaFieldType(v.getTypeName())) {
+                throw new IllegalArgumentException(v.getTypeName() + " is not a valid type for an event field");
+            }
+            if (!Type.isValidJavaIdentifier(v.getName())) {
+                throw new IllegalArgumentException(name + " is not a valid name for an event field");
+            }
+            if (nameSet.contains(name)) {
+                throw new IllegalArgumentException("Name of fields must be unique. Found two instances of " + name);
+            }
+            nameSet.add(name);
+        }
+
+        // Prevent event from being registered in <clinit>
+        // and only use annotations that can be resolved (those in boot class loader)
+        boolean needRegister = true;
+        List<AnnotationElement> bootAnnotations = new ArrayList<>();
+        for (AnnotationElement ae : sanitizedAnnotation) {
+            long id = ae.getTypeId();
+            if (ae.isInBoot()) {
+                if (id == REGISTERED_ID) {
+                    if (Boolean.FALSE.equals(ae.getValue("value"))) {
+                        needRegister = false;
+                    }
+                } else {
+                    bootAnnotations.add(ae);
+                }
+            }
+        }
+        bootAnnotations.add(new AnnotationElement(Registered.class, false));
+
+        EventClassBuilder ecb = new EventClassBuilder(bootAnnotations, sanitizedFields);
+        Class<? extends Event> eventClass = ecb.build();
+
+        if (needRegister) {
+            MetadataRepository.getInstance().register(eventClass, sanitizedAnnotation, sanitizedFields);
+        }
+        try {
+            return new EventFactory(eventClass, sanitizedAnnotation, sanitizedFields);
+        } catch (IllegalAccessException e) {
+            throw new IllegalAccessError("Could not accees constructor of generated event handler, " + e.getMessage());
+        } catch (NoSuchMethodException e) {
+            throw new InternalError("Could not find constructor in generated event handler, " + e.getMessage());
+        }
+    }
+
+    /**
+     * Instantiates an event, so it can be populated with data and written to the
+     * Flight Recorder system.
+     * <p>
+     * Use the {@link Event#set(int, Object)} method to set a value.
+     *
+     * @return an event instance, not {@code null}
+     */
+    public Event newEvent() {
+        try {
+            return (Event) constructorHandle.invoke();
+        } catch (Throwable e) {
+            throw new InstantiationError("Could not instantaite dynamically generated event class " + eventClass.getName() + ". " + e.getMessage());
+        }
+    }
+
+    /**
+     * Returns the event type that is associated with this event factory.
+     *
+     * @return event type that is associated with this event factory, not
+     *         {@code null}
+     *
+     * @throws java.lang.IllegalStateException if the event factory is created with
+     *         the {@code Registered(false)} annotation and the event class is not
+     *         manually registered before the invocation of this method
+     */
+    public EventType getEventType() {
+        return EventType.getEventType(eventClass);
+    }
+
+    /**
+     * Registers an unregistered event.
+     * <p>
+     * By default, the event class associated with this event factory is registered
+     * when the event factory is created, unless the event has the
+     * {@link Registered} annotation.
+     * <p>
+     * A registered event class can write data to Flight Recorder and event metadata
+     * can be obtained by invoking {@link FlightRecorder#getEventTypes()}.
+     * <p>
+     * If the event class associated with this event factory is already registered,
+     * the call to this method is ignored.
+     *
+     * @throws SecurityException if a security manager exists and the caller
+     *         does not have {@code FlightRecorderPermission("registerEvent")}
+     * @see Registered
+     * @see FlightRecorder#register(Class)
+     */
+    public void register() {
+        MetadataRepository.getInstance().register(eventClass, sanitizedAnnotation, sanitizedFields);
+    }
+
+    /**
+     * Unregisters the event that is associated with this event factory.
+     * <p>
+     * A unregistered event class can't write data to Flight Recorder and event
+     * metadata can't be obtained by invoking
+     * {@link FlightRecorder#getEventTypes()}.
+     * <p>
+     * If the event class associated with this event factory is not already
+     * registered, the call to this method is ignored.
+     *
+     * @throws SecurityException if a security manager exists and the caller does
+     *         not have {@code FlightRecorderPermission("registerEvent")}
+     * @see Registered
+     * @see FlightRecorder#unregister(Class)
+     */
+    public void unregister() {
+        MetadataRepository.getInstance().unregister(eventClass);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/EventSettings.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.time.Duration;
+import java.util.Map;
+
+/**
+ * Convenience class for applying event settings to a recording.
+ * <p>
+ * An {@code EventSettings} object for a recording can be obtained by invoking
+ * the {@link Recording#enable(String)} method which is configured using method
+ * chaining.
+ * <p>
+ * The following example shows how to use the {@code EventSettings} class.
+ * <pre>
+ * {@code
+ * Recording r = new Recording();
+ * r.enable("jdk.CPULoad")
+ *    .withPeriod(Duration.ofSeconds(1));
+ * r.enable("jdk.FileWrite")
+ *    .withoutStackTrace()
+ *    .withThreshold(Duration.ofNanos(10));
+ * r.start();
+ * Thread.sleep(10_000);
+ * r.stop();
+ * r.dump(Files.createTempFile("recording", ".jfr"));
+ *
+ * }
+ * </pre>
+ * @since 9
+ */
+public abstract class EventSettings {
+
+    // package private
+    EventSettings() {
+    }
+
+    /**
+     * Enables stack traces for the event that is associated with this event setting.
+     * <p>
+     * Equivalent to invoking the {@code with("stackTrace", "true")} method.
+     *
+     * @return event settings object for further configuration, not {@code null}
+     */
+    final public EventSettings withStackTrace() {
+        return with(StackTrace.NAME, "true");
+    }
+
+    /**
+     * Disables stack traces for the event that is associated with this event setting.
+     * <p>
+     * Equivalent to invoking the {@code with("stackTrace", "false")} method.
+     *
+     * @return event settings object for further configuration, not {@code null}
+     */
+    final public EventSettings withoutStackTrace() {
+        return with(StackTrace.NAME, "false");
+    }
+
+    /**
+     * Specifies that a threshold is not used.
+     * <p>
+     * This is a convenience method, equivalent to invoking the
+     * {@code with("threshold", "0 s")} method.
+     *
+     * @return event settings object for further configuration, not {@code null}
+     */
+    final public EventSettings withoutThreshold() {
+        return with(Threshold.NAME, "0 s");
+    }
+
+    /**
+     * Sets the interval for the event that is associated with this event setting.
+     *
+     * @param duration the duration, not {@code null}
+     *
+     * @return event settings object for further configuration, not {@code null}
+     */
+    final public EventSettings withPeriod(Duration duration) {
+        return with(Period.NAME, duration.toNanos() + " ns");
+    }
+
+    /**
+     * Sets the threshold for the event that is associated with this event setting.
+     *
+     * @param duration the duration, or {@code null} if no duration is used
+     *
+     * @return event settings object for further configuration, not {@code null}
+     */
+    final public EventSettings withThreshold(Duration duration) {
+        if (duration == null) {
+            return with(Threshold.NAME, "0 ns");
+        } else {
+            return with(Threshold.NAME, duration.toNanos() + " ns");
+        }
+    }
+
+    /**
+     * Sets a setting value for the event that is associated with this event setting.
+     *
+     * @param name the name of the setting (for example, {@code "threshold"})
+     *
+     * @param value the value to set (for example {@code "20 ms"} not
+     *        {@code null})
+     *
+     * @return event settings object for further configuration, not {@code null}
+     */
+    abstract public EventSettings with(String name, String value);
+
+    /**
+     * Creates a settings {@code Map} for the event that is associated with this
+     * event setting.
+     *
+     * @return a settings {@code Map}, not {@code null}
+     */
+    abstract Map<String, String> toMap();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/EventType.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.lang.annotation.Annotation;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import jdk.jfr.internal.JVMSupport;
+import jdk.jfr.internal.MetadataRepository;
+import jdk.jfr.internal.PlatformEventType;
+import jdk.jfr.internal.Type;
+import jdk.jfr.internal.Utils;
+
+/**
+ * Describes an event, its fields, settings and annotations.
+ *
+ * @since 9
+ */
+public final class EventType {
+    private final PlatformEventType platformEventType;
+    private final List<String> UNCATEGORIZED = Collections.singletonList("Uncategorized");
+    private Map<String, ValueDescriptor> cache; // create lazy to avoid memory overhead
+    // helper constructor
+    EventType(PlatformEventType platformEventType) {
+        this.platformEventType = platformEventType;
+    }
+
+    /**
+     * Returns an immutable list of descriptors that describe the event fields of
+     * this event type.
+     *
+     * @return the list of field descriptors, not {@code null}
+     */
+    public List<ValueDescriptor> getFields() {
+        return platformEventType.getFields();
+    }
+
+    /**
+     * Returns the field with the specified name, or {@code null} if it doesn't
+     * exist.
+     *
+     * @return a value descriptor that describes the field, or <code>null</code> if
+     *         the field with the specified name doesn't exist
+     *
+     * @return a value descriptor, or <code>null</code> if it doesn't exist
+     */
+    public ValueDescriptor getField(String name) {
+        Objects.requireNonNull(name);
+        if (cache == null) {
+            List<ValueDescriptor> fields = getFields();
+            Map<String, ValueDescriptor> newCache = new LinkedHashMap<String, ValueDescriptor>(fields.size());
+            for (ValueDescriptor v :fields) {
+                newCache.put(v.getName(), v);
+            }
+            cache = newCache;
+        }
+        return cache.get(name);
+    }
+
+    /**
+     * Returns an identifier for the event (for example,
+     * {@code "jdk.CPULoad"}).
+     * <p>
+     * The identifier is the fully qualified name of the event class, if not set using
+     * the {@link Name} annotation.
+     *
+     * @return the name, not {@code null}
+     *
+     * @see Name
+     */
+    public String getName() {
+        return platformEventType.getName();
+    }
+
+    /**
+     * Returns a human-readable name (for example, {@code "CPU Load"}).
+     * <p>
+     * The label of an event class can be set with {@link Label}.
+     *
+     * @return the label, or {@code null} if a label is not set
+     *
+     * @see Label
+     */
+    public String getLabel() {
+        return platformEventType.getLabel();
+    }
+
+    /**
+     * Returns a unique ID for this event type in the Java Virtual Machine (JVM).
+     *
+     * @return the ID that is used in the JVM
+     */
+    public long getId() {
+        return platformEventType.getId();
+    }
+
+    /**
+     * Returns an immutable list of annotation elements for this event type.
+     *
+     * @return an immutable list of annotations or an empty list if no
+     *         annotations exists, not {@code null}
+     */
+    public List<AnnotationElement> getAnnotationElements() {
+        return platformEventType.getAnnotationElements();
+    }
+
+    /**
+     * Returns {@code true} if the event is enabled and at least one recording is
+     * running, {@code false} otherwise.
+     * <p>
+     * By default, the event is enabled. The event can be enabled or disabled by
+     * setting the enabled setting to {@code true} or {@code false}, programmatically or by using a
+     * configuration file. The event can also be disabled by annotating event with
+     * the {@code @Enabled(false)} annotation.
+     *
+     * @return true if event is enabled, false otherwise
+     *
+     * @see Enabled
+     * @see Recording#enable(Class)
+     */
+    public boolean isEnabled() {
+        return platformEventType.isEnabled();
+    }
+
+    /**
+     * Returns a short sentence that describes the event class.
+     * <p>
+     * The description of an event class can be set with {@link Description}.
+     *
+     * @return the description, or {@code null} if no description exists
+     *
+     * @see Description
+     */
+    public String getDescription() {
+        return platformEventType.getDescription();
+    }
+
+    /**
+     * Returns the first annotation for the specified type if an annotation
+     * element with the same name is directly present, otherwise {@code null}.
+     *
+     * @param <A> the type of the annotation to query for and return if present
+     * @param annotationClass the {@code Class} object that corresponds to the
+     *        annotation type, not {@code null}
+     * @return this element's annotation for the specified annotation type if
+     *         directly present, else {@code null}
+     */
+    public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
+        Objects.requireNonNull(annotationClass);
+        return platformEventType.getAnnotation(annotationClass);
+    }
+
+    /**
+     * Returns the event type for an event class, or {@code null} if it doesn't
+     * exist.
+     *
+     * @param eventClass the event class, not {@code null}
+     * @return the event class, or null if class doesn't exist
+     *
+     * @throws IllegalArgumentException if {@code eventClass} is an abstract class
+     *
+     * @throws IllegalStateException if the class is annotated with
+     *         {@code Registered(false)}, but not manually registered
+     */
+    public static EventType getEventType(Class<? extends Event> eventClass) {
+        Objects.requireNonNull(eventClass);
+        Utils.ensureValidEventSubclass(eventClass);
+        JVMSupport.ensureWithInternalError();
+        return MetadataRepository.getInstance().getEventType(eventClass);
+    }
+
+    /**
+     * Returns an immutable list of the setting descriptors that describe the available
+     * event settings for this event type.
+     *
+     * @return the list of setting descriptors for this event type, not
+     *         {@code null}
+     */
+    public List<SettingDescriptor> getSettingDescriptors() {
+        return Collections.unmodifiableList(platformEventType.getSettings());
+    }
+
+    /**
+     * Returns the list of human-readable names that makes up the categories for
+     * this event type (for example, {@code "Java Application"}, {@code "Statistics"}).
+     *
+     * @return an immutable list of category names, or a list with the name
+     *         {@code "Uncategorized"} if no category is set
+     *
+     * @see Category
+     */
+    public List<String> getCategoryNames() {
+        Category c = platformEventType.getAnnotation(Category.class);
+        if (c == null) {
+            return UNCATEGORIZED;
+        }
+        return Collections.unmodifiableList(Arrays.asList(c.value()));
+    }
+
+    // package private
+    Type getType() {
+        return platformEventType;
+    }
+
+    // package private
+    PlatformEventType getPlatformEventType() {
+        return platformEventType;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/Experimental.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation that specifies that an element is experimental and may change
+ * without notice.
+ * <p>
+ * Clients that visualize Flight Recorder events should <em>not</em> show the
+ * events or fields annotated with the {@code Experimental} annotation by
+ * default. This annotation allows event producers the freedom to try out new
+ * events without committing to them.
+ * <p>
+ * Clients may provide a check box (for example, in a preference page) where a
+ * user can opt-in to display experimental data. If the user decide to do so,
+ * the user interface should mark experimental events or fields so users can
+ * distinguish them from non-experimental events.
+ * <p>
+ * This annotation is inherited.
+ *
+ * @since 9
+ */
+@MetadataDefinition
+@Label("Experimental")
+@Description("Element is not to be shown to a user by default")
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.FIELD, ElementType.TYPE })
+public @interface Experimental {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/FlightRecorder.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import static jdk.jfr.internal.LogLevel.DEBUG;
+import static jdk.jfr.internal.LogLevel.INFO;
+import static jdk.jfr.internal.LogTag.JFR;
+
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import jdk.jfr.internal.JVM;
+import jdk.jfr.internal.JVMSupport;
+import jdk.jfr.internal.LogLevel;
+import jdk.jfr.internal.Logger;
+import jdk.jfr.internal.MetadataRepository;
+import jdk.jfr.internal.Options;
+import jdk.jfr.internal.PlatformRecorder;
+import jdk.jfr.internal.PlatformRecording;
+import jdk.jfr.internal.Repository;
+import jdk.jfr.internal.RequestEngine;
+import jdk.jfr.internal.Utils;
+
+/**
+ * Class for accessing, controlling, and managing Flight Recorder.
+ * <p>
+ * This class provides the methods necessary for creating, starting, stopping,
+ * and destroying recordings.
+ *
+ * @since 9
+ */
+public final class FlightRecorder {
+    private static volatile FlightRecorder platformRecorder;
+    private static volatile boolean initialized;
+    private final PlatformRecorder internal;
+
+    private FlightRecorder(PlatformRecorder internal) {
+        this.internal = internal;
+    }
+
+    /**
+     * Returns an immutable list of the available recordings.
+     * <p>
+     * A recording becomes available when it is created. It becomes unavailable when it
+     * is in the {@code CLOSED} state, typically after a call to
+     * {@link Recording#close()}.
+     *
+     * @return a list of recordings, not {@code null}
+     */
+    public List<Recording> getRecordings() {
+        List<Recording> recs = new ArrayList<>();
+        for (PlatformRecording internal : internal.getRecordings()) {
+            recs.add(internal.getRecording());
+        }
+        return Collections.unmodifiableList(recs);
+    }
+
+    /**
+     * Creates a snapshot of all available recorded data.
+     * <p>
+     * A snapshot is a synthesized recording in a {@code STOPPPED} state. If no data is
+     * available, a recording with size {@code 0} is returned.
+     * <p>
+     * A snapshot provides stable access to data for later operations (for example,
+     * operations to change the interval or to reduce the data size).
+     * <p>
+     * The following example shows how to create a snapshot and write a subset of the data to a file.
+     *
+     * <pre>
+     * <code>
+     * try (Recording snapshot = FlightRecorder.getFlightRecorder().takeSnapshot()) {
+     *   if (snapshot.getSize() &gt; 0) {
+     *     snapshot.setMaxSize(100_000_000);
+     *     snapshot.setMaxAge(Duration.ofMinutes(5));
+     *     snapshot.dump(Paths.get("snapshot.jfr"));
+     *   }
+     * }
+     * </code>
+     * </pre>
+     *
+     * The caller must close the recording when access to the data is no longer
+     * needed.
+     *
+     * @return a snapshot of all available recording data, not {@code null}
+     */
+    public Recording takeSnapshot() {
+        return internal.newSnapshot();
+    }
+
+    /**
+     * Registers an event class.
+     * <p>
+     * If the event class is already registered, then the invocation of this method is
+     * ignored.
+     *
+     * @param eventClass the event class to register, not {@code null}
+     *
+     * @throws IllegalArgumentException if class is abstract or not a subclass
+     *         of {@link Event}
+     * @throws SecurityException if a security manager exists and the caller
+     *         does not have {@code FlightRecorderPermission("registerEvent")}
+     */
+    public static void register(Class<? extends Event> eventClass) {
+        Objects.requireNonNull(eventClass);
+        if (JVMSupport.isNotAvailable()) {
+            return;
+        }
+        Utils.ensureValidEventSubclass(eventClass);
+        MetadataRepository.getInstance().register(eventClass);
+    }
+
+    /**
+     * Unregisters an event class.
+     * <p>
+     * If the event class is not registered, then the invocation of this method is
+     * ignored.
+     *
+     * @param eventClass the event class to unregistered, not {@code null}
+     * @throws IllegalArgumentException if a class is abstract or not a subclass
+     *         of {@link Event}
+     *
+     * @throws SecurityException if a security manager exists and the caller
+     *         does not have {@code FlightRecorderPermission("registerEvent")}
+     */
+    public static void unregister(Class<? extends Event> eventClass) {
+        Objects.requireNonNull(eventClass);
+        if (JVMSupport.isNotAvailable()) {
+            return;
+        }
+        Utils.ensureValidEventSubclass(eventClass);
+        MetadataRepository.getInstance().unregister(eventClass);
+    }
+
+    /**
+     * Returns the Flight Recorder for the platform.
+     *
+     * @return a Flight Recorder instance, not {@code null}
+     *
+     * @throws IllegalStateException if Flight Recorder can't be created (for
+     *         example, if the Java Virtual Machine (JVM) lacks Flight Recorder
+     *         support, or if the file repository can't be created or accessed)
+     *
+     * @throws SecurityException if a security manager exists and the caller does
+     *         not have {@code FlightRecorderPermission("accessFlightRecorder")}
+     */
+    public static FlightRecorder getFlightRecorder() throws IllegalStateException, SecurityException {
+        synchronized (PlatformRecorder.class) {
+            Utils.checkAccessFlightRecorder();
+            JVMSupport.ensureWithIllegalStateException();
+            if (platformRecorder == null) {
+                try {
+                    platformRecorder = new FlightRecorder(new PlatformRecorder());
+                } catch (IllegalStateException ise) {
+                    throw ise;
+                } catch (Exception e) {
+                    throw new IllegalStateException("Can't create Flight Recorder. " + e.getMessage(), e);
+                }
+                // Must be in synchronized block to prevent instance leaking out
+                // before initialization is done
+                initialized = true;
+                Logger.log(JFR, INFO, "Flight Recorder initialized");
+                Logger.log(JFR, DEBUG, "maxchunksize: " + Options.getMaxChunkSize()+ " bytes");
+                Logger.log(JFR, DEBUG, "memorysize: " + Options.getMemorySize()+ " bytes");
+                Logger.log(JFR, DEBUG, "globalbuffersize: " + Options.getGlobalBufferSize()+ " bytes");
+                Logger.log(JFR, DEBUG, "globalbuffercount: " + Options.getGlobalBufferCount());
+                Logger.log(JFR, DEBUG, "dumppath: " + Options.getDumpPath());
+                Logger.log(JFR, DEBUG, "samplethreads: " + Options.getSampleThreads());
+                Logger.log(JFR, DEBUG, "stackdepth: " + Options.getStackDepth());
+                Logger.log(JFR, DEBUG, "threadbuffersize: " + Options.getThreadBufferSize());
+                Logger.log(JFR, LogLevel.INFO, "Created repository " + Repository.getRepository().getRepositoryPath().toString());
+                PlatformRecorder.notifyRecorderInitialized(platformRecorder);
+            }
+        }
+        return platformRecorder;
+    }
+
+    /**
+     * Adds a hook for a periodic event.
+     * <p>
+     * The implementation of the hook should return as soon as possible, to
+     * avoid blocking other Flight Recorder operations. The hook should emit
+     * one or more events of the specified type. When a hook is added, the
+     * interval at which the call is invoked is configurable using the
+     * {@code "period"} setting.
+     *
+     * @param eventClass the class that the hook should run for, not {@code null}
+     * @param hook the hook, not {@code null}
+     * @throws IllegalArgumentException if a class is not a subclass of
+     *         {@link Event}, is abstract, or the hook is already added
+     * @throws IllegalStateException if the event class has the
+     *         {@code Registered(false)} annotation and is not registered manually
+     * @throws SecurityException if a security manager exists and the caller
+     *         does not have {@code FlightRecorderPermission("registerEvent")}
+     */
+    public static void addPeriodicEvent(Class<? extends Event> eventClass, Runnable hook) throws SecurityException {
+        Objects.requireNonNull(eventClass);
+        Objects.requireNonNull(hook);
+        if (JVMSupport.isNotAvailable()) {
+            return;
+        }
+
+        Utils.ensureValidEventSubclass(eventClass);
+        Utils.checkRegisterPermission();
+        AccessControlContext acc = AccessController.getContext();
+        RequestEngine.addHook(acc, EventType.getEventType(eventClass).getPlatformEventType(), hook);
+    }
+
+    /**
+     * Removes a hook for a periodic event.
+     *
+     * @param hook the hook to remove, not {@code null}
+     * @return {@code true} if hook is removed, {@code false} otherwise
+     * @throws SecurityException if a security manager exists and the caller
+     *         does not have {@code FlightRecorderPermission("registerEvent")}
+     */
+    public static boolean removePeriodicEvent(Runnable hook) throws SecurityException {
+        Objects.requireNonNull(hook);
+        Utils.checkRegisterPermission();
+        if (JVMSupport.isNotAvailable()) {
+            return false;
+        }
+        return RequestEngine.removeHook(hook);
+    }
+
+    /**
+     * Returns an immutable list that contains all currently registered events.
+     * <p>
+     * By default, events are registered when they are first used, typically
+     * when an event object is allocated. To ensure an event is visible early,
+     * registration can be triggered by invoking the
+     * {@link FlightRecorder#register(Class)} method.
+     *
+     * @return list of events, not {@code null}
+     */
+    public List<EventType> getEventTypes() {
+        return Collections.unmodifiableList(MetadataRepository.getInstance().getRegisteredEventTypes());
+    }
+
+    /**
+     * Adds a recorder listener and captures the {@code AccessControlContext} to
+     * use when invoking the listener.
+     * <p>
+     * If Flight Recorder is already initialized when the listener is added, then the method
+     * {@link FlightRecorderListener#recorderInitialized(FlightRecorder)} method is
+     * invoked before returning from this method.
+     *
+     * @param changeListener the listener to add, not {@code null}
+     *
+     * @throws SecurityException if a security manager exists and the caller
+     *         does not have
+     *         {@code FlightRecorderPermission("accessFlightRecorder")}
+     */
+    public static void addListener(FlightRecorderListener changeListener) {
+        Objects.requireNonNull(changeListener);
+        Utils.checkAccessFlightRecorder();
+        if (JVMSupport.isNotAvailable()) {
+            return;
+        }
+        PlatformRecorder.addListener(changeListener);
+    }
+
+    /**
+     * Removes a recorder listener.
+     * <p>
+     * If the same listener is added multiple times, only one instance is
+     * removed.
+     *
+     * @param changeListener listener to remove, not {@code null}
+     *
+     * @throws SecurityException if a security manager exists and the caller
+     *         does not have
+     *         {@code FlightRecorderPermission("accessFlightRecorder")}
+     *
+     * @return {@code true}, if the listener could be removed, {@code false}
+     *         otherwise
+     */
+    public static boolean removeListener(FlightRecorderListener changeListener) {
+        Objects.requireNonNull(changeListener);
+        Utils.checkAccessFlightRecorder();
+        if (JVMSupport.isNotAvailable()) {
+            return false;
+        }
+
+        return PlatformRecorder.removeListener(changeListener);
+    }
+
+    /**
+     * Returns {@code true} if the Java Virtual Machine (JVM) has Flight Recorder capabilities.
+     * <p>
+     * This method can quickly check whether Flight Recorder can be
+     * initialized, without actually doing the initialization work. The value may
+     * change during runtime and it is not safe to cache it.
+     *
+     * @return {@code true}, if Flight Recorder is available, {@code false}
+     *         otherwise
+     *
+     * @see FlightRecorderListener for callback when Flight Recorder is
+     *      initialized
+     */
+    public static boolean isAvailable() {
+        if (JVMSupport.isNotAvailable()) {
+            return false;
+        }
+        return JVM.getJVM().isAvailable();
+    }
+
+    /**
+     * Returns {@code true} if Flight Recorder is initialized.
+     *
+     * @return {@code true}, if Flight Recorder is initialized,
+     *         {@code false} otherwise
+     *
+     * @see FlightRecorderListener for callback when Flight Recorder is
+     *      initialized
+     */
+    public static boolean isInitialized() {
+        return initialized;
+    }
+
+    // package private
+    PlatformRecording newInternalRecording(Map<String, String> settings) {
+        return internal.newRecording(settings);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/FlightRecorderListener.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+
+/**
+ * Callback interface to monitor Flight Recorder's life cycle.
+ *
+ * @since 9
+ */
+public interface FlightRecorderListener {
+
+    /**
+     * Receives notification when Flight Recorder is initialized.
+     * <p>
+     * This method is also be invoked when a listener is added to an already
+     * initialized Flight Recorder.
+     * <p>
+     * This method allows clients to implement their own initialization mechanism
+     * that is executed before a {@code FlightRecorder} instance is returned by
+     * {@code FlightRecorder#getFlightRecorder()}.
+     *
+     * @implNote This method should return as soon as possible, to avoid blocking
+     *           initialization of Flight Recorder. To avoid deadlocks or unexpected
+     *           behavior, this method should not call
+     *           {@link FlightRecorder#getFlightRecorder()} or start new recordings.
+     *
+     * @implSpec The default implementation of this method is empty.
+     *
+     * @param recorder Flight Recorder instance, not {@code null}
+     *
+     * @see FlightRecorder#addListener(FlightRecorderListener)
+     */
+    default void recorderInitialized(FlightRecorder recorder) {
+    }
+
+    /**
+     * Receives notification when the state of a recording changes.
+     * <p>
+     * Callback is invoked when a recording reaches the {@code RUNNING},
+     * {@code STOPPED} and {@code CLOSED} state.
+     *
+     * @implNote The implementation of this method should return as soon as possible
+     *           to avoid blocking normal operation of Flight Recorder.
+     *
+     * @implSpec The default implementation of this method is empty.
+     *
+     * @param recording the recording where the state change occurred, not
+     *        {@code null}
+     *
+     * @see FlightRecorder#addListener(FlightRecorderListener)
+     * @see RecordingState
+     *
+     */
+    default void recordingStateChanged(Recording recording) {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/FlightRecorderPermission.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import jdk.jfr.internal.PlatformEventType;
+import jdk.jfr.internal.PlatformRecording;
+import jdk.jfr.internal.PrivateAccess;
+import jdk.jfr.internal.Type;
+import jdk.jfr.internal.Utils;
+
+/**
+ * Permission for controlling access to Flight Recorder.
+ * <p>
+ * The following table provides a summary of what the permission
+ * allows, and the risks of granting code the permission.
+ *
+ * <table class="striped">
+ * <caption style="display:none">Table shows permission target name,
+ *      what the permission allows, and associated risks</caption>
+ * <thead>
+ * <tr>
+ * <th scope="col">Permission Target Name</th>
+ * <th scope="col">What the Permission Allows</th>
+ * <th scope="col">Risks of Allowing this Permission</th>
+ * </tr>
+ * </thead>
+ *
+ * <tbody>
+ * <tr>
+ * <th scope="row">{@code accessFlightRecorder}</th>
+ * <td>Ability to create a Flight Recorder instance, register callbacks to
+ * monitor the Flight Recorder life cycle, and control an existing instance
+ * of Flight Recorder, which can record and dump runtime information, such as
+ * stack traces, class names, and data in user defined events.</td>
+ * <td>A malicious user may be able to extract sensitive information that is stored in
+ * events and interrupt Flight Recorder by installing listeners or hooks that
+ * never finish.</td>
+ * </tr>
+ * <tr>
+ * <th scope="row">{@code registerEvent}</th>
+ * <td>Ability to register events, write data to the Flight Recorder buffers,
+ * and execute code in a callback function for periodic events.
+ *
+ * <td>A malicious user may be able to write sensitive information to Flight
+ * Recorder buffers.</td>
+ * </tr>
+ * </tbody>
+ * </table>
+ *
+ * <p>
+ * Typically, programmers do not create {@code FlightRecorderPermission} objects
+ * directly. Instead the objects are created by the security policy code that is based on
+ * reading the security policy file.
+ *
+ * @since 9
+ *
+ * @see java.security.BasicPermission
+ * @see java.security.Permission
+ * @see java.security.Permissions
+ * @see java.security.PermissionCollection
+ * @see java.lang.SecurityManager
+ *
+ */
+@SuppressWarnings("serial")
+public final class FlightRecorderPermission extends java.security.BasicPermission {
+
+    // Purpose of InternalAccess is to give classes in jdk.jfr.internal
+    // access to package private methods in this package (jdk.jfr).
+    //
+    // The initialization could be done in any class in this package,
+    // but this one was chosen because it is light weight and
+    // lacks dependencies on other public classes.
+    static {
+        PrivateAccess.setPrivateAccess(new InternalAccess());
+    }
+
+    private final static class InternalAccess extends PrivateAccess {
+
+        @Override
+        public Type getType(Object o) {
+            if (o instanceof AnnotationElement) {
+                return ((AnnotationElement) o).getType();
+            }
+            if (o instanceof EventType) {
+                return ((EventType) o).getType();
+            }
+            if (o instanceof ValueDescriptor) {
+                return ((ValueDescriptor) o).getType();
+            }
+            if (o instanceof SettingDescriptor) {
+                return ((SettingDescriptor) o).getType();
+            }
+            throw new Error("Unknown type " + o.getClass());
+        }
+
+        @Override
+        public Configuration newConfiguration(String name, String label, String description, String provider, Map<String, String> settings, String contents) {
+            return new Configuration(name, label, description, provider, settings, contents);
+        }
+
+        @Override
+        public EventType newEventType(PlatformEventType platformEventType) {
+            return new EventType(platformEventType);
+        }
+
+        @Override
+        public AnnotationElement newAnnotation(Type annotationType, List<Object> values, boolean boot) {
+            return new AnnotationElement(annotationType, values, boot);
+        }
+
+        @Override
+        public ValueDescriptor newValueDescriptor(String name, Type fieldType, List<AnnotationElement> annos, int dimension, boolean constantPool, String fieldName) {
+            return new ValueDescriptor(fieldType, name, annos, dimension, constantPool, fieldName);
+        }
+
+        @Override
+        public PlatformRecording getPlatformRecording(Recording r) {
+            return r.getInternal();
+        }
+
+        @Override
+        public PlatformEventType getPlatformEventType(EventType eventType) {
+            return eventType.getPlatformEventType();
+        }
+
+        @Override
+        public boolean isConstantPool(ValueDescriptor v) {
+            return v.isConstantPool();
+        }
+
+        @Override
+        public void setAnnotations(ValueDescriptor v, List<AnnotationElement> a) {
+            v.setAnnotations(a);
+        }
+
+        @Override
+        public void setAnnotations(SettingDescriptor s, List<AnnotationElement> a) {
+           s.setAnnotations(a);
+        }
+
+        @Override
+        public String getFieldName(ValueDescriptor v) {
+            return v.getJavaFieldName();
+        }
+
+        @Override
+        public ValueDescriptor newValueDescriptor(Class<?> type, String name) {
+            return new ValueDescriptor(type, name, Collections.emptyList(), true);
+        }
+
+        @Override
+        public SettingDescriptor newSettingDescriptor(Type type, String name, String defaultValue, List<AnnotationElement> annotations) {
+            return new SettingDescriptor(type, name, defaultValue, annotations);
+        }
+
+        @Override
+        public boolean isUnsigned(ValueDescriptor v) {
+            return v.isUnsigned();
+        }
+    }
+
+    /**
+     * Constructs a {@code FlightRecorderPermission} with the specified name.
+     *
+     * @param name the permission name, must be either
+     *        {@code "accessFlightRecorder"} or {@code "registerEvent"}, not
+     *        {@code null}
+     *
+     * @throws IllegalArgumentException if {@code name} is empty or not valid
+     */
+    public FlightRecorderPermission(String name) {
+        super(Objects.requireNonNull(name));
+        if (!name.equals(Utils.ACCESS_FLIGHT_RECORDER) && !name.equals(Utils.REGISTER_EVENT)) {
+            throw new IllegalArgumentException("name: " + name);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/Frequency.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Event field annotation, specifies that the value is a frequency, measured in Hz.
+ *
+ * @since 9
+ */
+@MetadataDefinition
+@ContentType
+@Label("Frequency")
+@Description("Measure of how often something occurs, in Hertz")
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD, ElementType.METHOD})
+public @interface Frequency {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/Label.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation that sets a human-readable name for an element (for example,
+ * {@code "Maximum Throughput"}).
+ * <p>
+ * Use headline-style capitalization, capitalize the first and last words, and
+ * all nouns, pronouns, adjectives, verbs and adverbs. Do not include ending
+ * punctuation.
+ * <p>
+ * The label should not be used as an identifier, see {@link Name}.
+ *
+ * @since 9
+ */
+@MetadataDefinition
+@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Label {
+    /**
+     * Returns a human-readable name for the annotated element.
+     *
+     * @return a human-readable name, not {@code null}
+     */
+    String value();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/MemoryAddress.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Event field annotation, specifies that the value is a memory address.
+ *
+ * @since 9
+ */
+@MetadataDefinition
+@ContentType
+@Label("Memory Address")
+@Description("Represents a physical memory address")
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.FIELD, ElementType.TYPE, ElementType.METHOD })
+public @interface MemoryAddress {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/MetadataDefinition.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Meta annotation for defining new types of event metadata.
+ * <p>
+ * In the following example, a transaction event is defined with two
+ * user-defined annotations, {@code @Severity} and {@code @TransactionId}.
+ *
+ * <pre>
+ * <code>
+ *{@literal @}MetadataDefinition
+ *{@literal @}Label("Severity")
+ *{@literal @}Description("Value between 0 and 100 that indicates severity. 100 is most severe.")
+ *{@literal @}Retention(RetentionPolicy.RUNTIME)
+ *{@literal @}Target({ ElementType.TYPE })
+ * public {@literal @}interface {@literal @}Severity {
+ *   int value() default 50;
+ * }
+ *
+ *{@literal @}MetadataDefinition
+ *{@literal @}Label("Transaction Id")
+ *{@literal @}Relational
+ *{@literal @}Retention(RetentionPolicy.RUNTIME)
+ *{@literal @}Target({ ElementType.FIELD })
+ * public {@literal @}interface {@literal @}Severity {
+ * }
+ *
+ *{@literal @}Severity(80)
+ *{@literal @}Label("Transaction Blocked");
+ * class TransactionBlocked extends Event {
+ *  {@literal @}TransactionId
+ *  {@literal @}Label("Transaction");
+ *   long transactionId;
+ *
+ *  {@literal @}TransactionId
+ *  {@literal @}Label("Transaction Blocker");
+ *   long transactionId;
+ * }
+ *
+ * </code>
+ * </pre>
+ *
+ * Adding {@code @MetadataDefinition} to the declaration of {@code @Severity} and {@code @TransactionId}
+ * ensures the information is saved by Flight Recorder.
+ *
+ * @since 9
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.TYPE })
+public @interface MetadataDefinition {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/Name.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation that overrides the default name for an element (for example, when
+ * the default package for an event is not appropriate).
+ * <p>
+ * The name must be a valid identifiers in the Java language (for example,
+ * {@code "com.example.MyEvent"} for an event class or {@code "message"} for an
+ * event field).
+ *
+ * @since 9
+ */
+@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@MetadataDefinition
+public @interface Name {
+    /**
+     * Returns the name.
+     *
+     * @return the name
+     */
+    String value();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/Percentage.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Event field annotation to use on fractions, typically between {@code 0.0}
+ * and {@code 1.0}, to specify that the value is a percentage.
+ * <p>
+ * For example, a field with the value {@code 0.5} annotated by this annotation,
+ * should be interpreted as {@code 50%} and rendered in a graphical user
+ * interface with a percentage sign to avoid confusion with {@code 0.005%}.
+ *
+ * @since 9
+ */
+@MetadataDefinition
+@ContentType
+@Label("Percentage")
+@Description("Percentage, represented as a number between 0 and 1")
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})
+public @interface Percentage {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/Period.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Event annotation, specifies the default setting value for a periodic event.
+ *
+ * @since 9
+ */
+@MetadataDefinition
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+@Target(ElementType.TYPE)
+public @interface Period {
+    /**
+     * Settings name {@code "period"} for configuring periodic events
+     */
+    public final static String NAME = "period";
+
+    /**
+     * Returns the default setting value for a periodic setting.
+     * <p>
+     * String representation of a positive {@code Long} value followed by an empty
+     * space and one of the following units:<br>
+     * <br>
+     * {@code "ns"} (nanoseconds)<br>
+     * {@code "us"} (microseconds)<br>
+     * {@code "ms"} (milliseconds)<br>
+     * {@code "s"} (seconds)<br>
+     * {@code "m"} (minutes)<br>
+     * {@code "h"} (hours)<br>
+     * {@code "d"} (days)<br>
+     * <p>
+     * Example values: {@code "0 ns"}, {@code "10 ms"}, and {@code "1 s"}.
+     * <p>
+     * A period may also be <code>"everyChunk"</code> to specify that it occurs at
+     * least once for every recording file. The number of events that are emitted
+     * depends on how many times the file rotations occur when data is recorded.
+     *
+     * @return the default setting value, not {@code null}
+     */
+    String value() default "everyChunk";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/Recording.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,672 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Path;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+import jdk.jfr.internal.PlatformRecording;
+import jdk.jfr.internal.Type;
+import jdk.jfr.internal.Utils;
+import jdk.jfr.internal.WriteableUserPath;
+
+/**
+ * Provides means to configure, start, stop and dump recording data to disk.
+ * <p>
+ * The following example shows how configure, start, stop and dump recording data to disk.
+ *
+ * <pre>
+ * <code>
+ *   Configuration c = Configuration.getConfiguration("default");
+ *   Recording r = new Recording(c);
+ *   r.start();
+ *   System.gc();
+ *   Thread.sleep(5000);
+ *   r.stop();
+ *   r.copyTo(Files.createTempFile("my-recording", ".jfr"));
+ * </code>
+ * </pre>
+ *
+ * @since 9
+ */
+public final class Recording implements Closeable {
+
+    private static class RecordingSettings extends EventSettings {
+
+        private final Recording recording;
+        private final String identifier;
+
+        RecordingSettings(Recording r, String identifier) {
+            this.recording = r;
+            this.identifier = identifier;
+        }
+
+        RecordingSettings(Recording r, Class<? extends Event> eventClass) {
+            Utils.ensureValidEventSubclass(eventClass);
+            this.recording = r;
+            this.identifier = String.valueOf(Type.getTypeId(eventClass));
+        }
+
+        @Override
+        public EventSettings with(String name, String value) {
+            Objects.requireNonNull(value);
+            recording.setSetting(identifier + "#" + name, value);
+            return this;
+        }
+
+        @Override
+        public Map<String, String> toMap() {
+            return recording.getSettings();
+        }
+    }
+
+    private final PlatformRecording internal;
+
+    private Recording(PlatformRecording internal) {
+        this.internal = internal;
+        this.internal.setRecording(this);
+        if (internal.getRecording() != this) {
+            throw new InternalError("Internal recording not properly setup");
+        }
+    }
+
+    /**
+     * Creates a recording without any settings.
+     * <p>
+     * A newly created recording is in the {@link RecordingState#NEW} state. To start
+     * the recording, invoke the {@link Recording#start()} method.
+     *
+     * @throws IllegalStateException if Flight Recorder can't be created (for
+     *         example, if the Java Virtual Machine (JVM) lacks Flight Recorder
+     *         support, or if the file repository can't be created or accessed)
+     *
+     * @throws SecurityException If a security manager is used and
+     *         FlightRecorderPermission "accessFlightRecorder" is not set.
+     */
+    public Recording() {
+        this(FlightRecorder.getFlightRecorder().newInternalRecording(new HashMap<String, String>()));
+    }
+
+    /**
+     * Creates a recording with settings from a configuration.
+     * <p>
+     * The following example shows how create a recording that uses a predefined configuration.
+     *
+     * <pre>
+     * <code>
+     * Recording r = new Recording(Configuration.getConfiguration("default"));
+     * </code>
+     * </pre>
+     *
+     * The newly created recording is in the {@link RecordingState#NEW} state. To
+     * start the recording, invoke the {@link Recording#start()} method.
+     *
+     * @param configuration configuration that contains the settings to be use, not
+     *        {@code null}
+     *
+     * @throws IllegalStateException if Flight Recorder can't be created (for
+     *         example, if the Java Virtual Machine (JVM) lacks Flight Recorder
+     *         support, or if the file repository can't be created or accessed)
+     *
+     * @throws SecurityException if a security manager is used and
+     *         FlightRecorderPermission "accessFlightRecorder" is not set.
+     *
+     * @see Configuration
+     */
+    public Recording(Configuration configuration) {
+        this(FlightRecorder.getFlightRecorder().newInternalRecording(configuration.getSettings()));
+    }
+
+    /**
+     * Starts this recording.
+     * <p>
+     * It's recommended that the recording options and event settings are configured
+     * before calling this method. The benefits of doing so are a more consistent
+     * state when analyzing the recorded data, and improved performance because the
+     * configuration can be applied atomically.
+     * <p>
+     * After a successful invocation of this method, this recording is in the
+     * {@code RUNNING} state.
+     *
+     * @throws IllegalStateException if recording is already started or is in the
+     *         {@code CLOSED} state
+     */
+    public void start() {
+        internal.start();
+    }
+
+    /**
+     * Starts this recording after a delay.
+     * <p>
+     * After a successful invocation of this method, this recording is in the
+     * {@code DELAYED} state.
+     *
+     * @param delay the time to wait before starting this recording, not
+     *        {@code null}
+     * @throws IllegalStateException if the recording is not it the {@code NEW} state
+     */
+    public void scheduleStart(Duration delay) {
+        Objects.requireNonNull(delay);
+        internal.scheduleStart(delay);
+    }
+
+    /**
+     * Stops this recording.
+     * <p>
+     * When a recording is stopped it can't be restarted. If this
+     * recording has a destination, data is written to that destination and
+     * the recording is closed. After a recording is closed, the data is no longer
+     * available.
+     * <p>
+     * After a successful invocation of this method, this recording will be
+     * in the {@code STOPPED} state.
+     *
+     * @return {@code true} if recording is stopped, {@code false} otherwise
+     *
+     * @throws IllegalStateException if the recording is not started or is already stopped
+     *
+     * @throws SecurityException if a security manager exists and the caller
+     *         doesn't have {@code FilePermission} to write to the destination
+     *         path
+     *
+     * @see #setDestination(Path)
+     *
+     */
+    public boolean stop() {
+        return internal.stop("Stopped by user");
+    }
+
+    /**
+     * Returns settings used by this recording.
+     * <p>
+     * Modifying the returned {@code Map} will not change the settings for this recording.
+     * <p>
+     * If no settings are set for this recording, an empty {@code Map} is
+     * returned.
+     *
+     * @return recording settings, not {@code null}
+     */
+    public Map<String, String> getSettings() {
+        return new HashMap<>(internal.getSettings());
+    }
+
+    /**
+     * Returns the current size of this recording in the disk repository,
+     * measured in bytes.
+     * <p>
+     * The size is updated when recording buffers are flushed. If the recording is
+     * not written to the disk repository the returned size is always {@code 0}.
+     *
+     * @return amount of recorded data, measured in bytes, or {@code 0} if the
+     *         recording is not written to the disk repository
+     */
+    public long getSize() {
+        return internal.getSize();
+    }
+
+    /**
+     * Returns the time when this recording was stopped.
+     *
+     * @return the time, or {@code null} if this recording is not stopped
+     */
+    public Instant getStopTime() {
+        return internal.getStopTime();
+    }
+
+    /**
+     * Returns the time when this recording was started.
+     *
+     * @return the the time, or {@code null} if this recording is not started
+     */
+    public Instant getStartTime() {
+        return internal.getStartTime();
+    }
+
+    /**
+     * Returns the maximum size, measured in bytes, at which data is no longer kept in the disk repository.
+     *
+     * @return maximum size in bytes, or {@code 0} if no maximum size is set
+     */
+    public long getMaxSize() {
+        return internal.getMaxSize();
+    }
+
+    /**
+     * Returns the length of time that the data is kept in the disk repository
+     * before it is removed.
+     *
+     * @return maximum length of time, or {@code null} if no maximum length of time
+     *         has been set
+     */
+    public Duration getMaxAge() {
+        return internal.getMaxAge();
+    }
+
+    /**
+     * Returns the name of this recording.
+     * <p>
+     * By default, the name is the same as the recording ID.
+     *
+     * @return the recording name, not {@code null}
+     */
+    public String getName() {
+        return internal.getName();
+    }
+
+    /**
+     * Replaces all settings for this recording.
+     * <p>
+     * The following example shows how to set event settings for a recording.
+     *
+     * <pre>
+     * <code>
+     *     Map{@literal <}String, String{@literal >} settings = new HashMap{@literal <}{@literal >}();
+     *     settings.putAll(EventSettings.enabled("jdk.CPUSample").withPeriod(Duration.ofSeconds(2)).toMap());
+     *     settings.putAll(EventSettings.enabled(MyEvent.class).withThreshold(Duration.ofSeconds(2)).withoutStackTrace().toMap());
+     *     settings.put("jdk.ExecutionSample#period", "10 ms");
+     *     recording.setSettings(settings);
+     * </code>
+     * </pre>
+     *
+     * The following example shows how to merge settings.
+     *
+     * <pre>
+     *     {@code
+     *     Map<String, String> settings = recording.getSettings();
+     *     settings.putAll(additionalSettings);
+     *     recording.setSettings(settings);
+     * }
+     * </pre>
+     *
+     * @param settings the settings to set, not {@code null}
+     */
+    public void setSettings(Map<String, String> settings) {
+        Objects.requireNonNull(settings);
+        Map<String, String> sanitized = Utils.sanitizeNullFreeStringMap(settings);
+        internal.setSettings(sanitized);
+    }
+
+    /**
+     * Returns the recording state that this recording is currently in.
+     *
+     * @return the recording state, not {@code null}
+     *
+     * @see RecordingState
+     */
+    public RecordingState getState() {
+        return internal.getState();
+    }
+
+    /**
+     * Releases all data that is associated with this recording.
+     * <p>
+     * After a successful invocation of this method, this recording is in the
+     * {@code CLOSED} state.
+     */
+    @Override
+    public void close() {
+        internal.close();
+    }
+
+    /**
+     * Returns a clone of this recording, with a new recording ID and name.
+     *
+     * Clones are useful for dumping data without stopping the recording. After
+     * a clone is created, the amount of data to copy is constrained
+     * with the {@link #setMaxAge(Duration)} method and the {@link #setMaxSize(long)}method.
+     *
+     * @param stop {@code true} if the newly created copy should be stopped
+     *        immediately, {@code false} otherwise
+     * @return the recording copy, not {@code null}
+     */
+    public Recording copy(boolean stop) {
+        return internal.newCopy(stop);
+    }
+
+    /**
+     * Writes recording data to a file.
+     * <p>
+     * Recording must be started, but not necessarily stopped.
+     *
+     * @param destination the location where recording data is written, not
+     *        {@code null}
+     *
+     * @throws IOException if the recording can't be copied to the specified
+     *         location
+     *
+     * @throws SecurityException if a security manager exists and the caller doesn't
+     *         have {@code FilePermission} to write to the destination path
+     */
+    public void dump(Path destination) throws IOException {
+        Objects.requireNonNull(destination);
+        internal.copyTo(new WriteableUserPath(destination), "Dumped by user", Collections.emptyMap());
+    }
+
+    /**
+     * Returns {@code true} if this recording uses the disk repository, {@code false} otherwise.
+     * <p>
+     * If no value is set, {@code true} is returned.
+     *
+     * @return {@code true} if the recording uses the disk repository, {@code false}
+     *         otherwise
+     */
+    public boolean isToDisk() {
+        return internal.isToDisk();
+    }
+
+    /**
+     * Determines how much data is kept in the disk repository.
+     * <p>
+     * To control the amount of recording data that is stored on disk, the maximum
+     * amount of data to retain can be specified. When the maximum limit is
+     * exceeded, the Java Virtual Machine (JVM) removes the oldest chunk to make
+     * room for a more recent chunk.
+     * <p>
+     * If neither maximum limit or the maximum age is set, the size of the
+     * recording may grow indefinitely.
+     *
+     * @param maxSize the amount of data to retain, {@code 0} if infinite
+     *
+     * @throws IllegalArgumentException if <code>maxSize</code> is negative
+     *
+     * @throws IllegalStateException if the recording is in {@code CLOSED} state
+     */
+    public void setMaxSize(long maxSize) {
+        if (maxSize < 0) {
+            throw new IllegalArgumentException("Max size of recording can't be negative");
+        }
+        internal.setMaxSize(maxSize);
+    }
+
+    /**
+     * Determines how far back data is kept in the disk repository.
+     * <p>
+     * To control the amount of recording data stored on disk, the maximum length of
+     * time to retain the data can be specified. Data stored on disk that is older
+     * than the specified length of time is removed by the Java Virtual Machine (JVM).
+     * <p>
+     * If neither maximum limit or the maximum age is set, the size of the
+     * recording may grow indefinitely.
+     *
+     * @param maxAge the length of time that data is kept, or {@code null} if infinite
+     *
+     * @throws IllegalArgumentException if <code>maxAge</code> is negative
+     *
+     * @throws IllegalStateException if the recording is in the {@code CLOSED} state
+     */
+    public void setMaxAge(Duration maxAge) {
+        if (maxAge != null && maxAge.isNegative()) {
+            throw new IllegalArgumentException("Max age of recording can't be negative");
+        }
+        internal.setMaxAge(maxAge);
+    }
+
+    /**
+     * Sets a location where data is written on recording stop, or
+     * {@code null} if data is not to be dumped.
+     * <p>
+     * If a destination is set, this recording is automatically closed
+     * after data is successfully copied to the destination path.
+     * <p>
+     * If a destination is <em>not</em> set, Flight Recorder retains the
+     * recording data until this recording is closed. Use the {@link #dump(Path)} method to
+     * manually write data to a file.
+     *
+     * @param destination the destination path, or {@code null} if recording should
+     *        not be dumped at stop
+     *
+     * @throws IllegalStateException if recording is in the {@code STOPPED} or
+     *         {@code CLOSED} state.
+     *
+     * @throws SecurityException if a security manager exists and the caller
+     *         doesn't have {@code FilePermission} to read, write, and delete the
+     *         {@code destination} file
+     *
+     * @throws IOException if the path is not writable
+     */
+    public void setDestination(Path destination) throws IOException {
+        internal.setDestination(destination != null ? new WriteableUserPath(destination) : null);
+    }
+
+    /**
+     * Returns the destination file, where recording data is written when the
+     * recording stops, or {@code null} if no destination is set.
+     *
+     * @return the destination file, or {@code null} if not set.
+     */
+    public Path getDestination() {
+        WriteableUserPath usp = internal.getDestination();
+        if (usp == null) {
+            return null;
+        } else {
+            return usp.getPotentiallyMaliciousOriginal();
+        }
+    }
+
+    /**
+     * Returns a unique ID for this recording.
+     *
+     * @return the recording ID
+     */
+    public long getId() {
+        return internal.getId();
+    }
+
+    /**
+     * Sets a human-readable name (for example, {@code "My Recording"}).
+     *
+     * @param name the recording name, not {@code null}
+     *
+     * @throws IllegalStateException if the recording is in {@code CLOSED} state
+     */
+    public void setName(String name) {
+        Objects.requireNonNull(name);
+        internal.setName(name);
+    }
+
+    /**
+     * Sets whether this recording is dumped to disk when the JVM exits.
+     *
+     * @param dumpOnExit if this recording should be dumped when the JVM exits
+     */
+    public void setDumpOnExit(boolean dumpOnExit) {
+        internal.setDumpOnExit(dumpOnExit);
+    }
+
+    /**
+     * Returns whether this recording is dumped to disk when the JVM exits.
+     * <p>
+     * If dump on exit is not set, {@code false} is returned.
+     *
+     * @return {@code true} if the recording is dumped on exit, {@code false}
+     *         otherwise.
+     */
+    public boolean getDumpOnExit() {
+        return internal.getDumpOnExit();
+    }
+
+    /**
+     * Determines whether this recording is continuously flushed to the disk
+     * repository or data is constrained to what is available in memory buffers.
+     *
+     * @param disk {@code true} if this recording is written to disk,
+     *        {@code false} if in-memory
+     *
+     */
+    public void setToDisk(boolean disk) {
+        internal.setToDisk(disk);
+    }
+
+    /**
+     * Creates a data stream for a specified interval.
+     * <p>
+     * The stream may contain some data outside the specified range.
+     *
+     * @param the start start time for the stream, or {@code null} to get data from
+     *        start time of the recording
+     *
+     * @param the end end time for the stream, or {@code null} to get data until the
+     *        present time.
+     *
+     * @return an input stream, or {@code null} if no data is available in the
+     *         interval.
+     *
+     * @throws IllegalArgumentException if {@code end} happens before
+     *         {@code start}
+     *
+     * @throws IOException if a stream can't be opened
+     */
+    public InputStream getStream(Instant start, Instant end) throws IOException {
+        if (start != null && end != null && end.isBefore(start)) {
+            throw new IllegalArgumentException("End time of requested stream must not be before start time");
+        }
+        return internal.open(start, end);
+    }
+
+    /**
+     * Returns the specified duration for this recording, or {@code null} if no
+     * duration is set.
+     * <p>
+     * The duration can be set only when the recording is in the
+     * {@link RecordingState#NEW} state.
+     *
+     * @return the desired duration of the recording, or {@code null} if no duration
+     *         has been set.
+     */
+    public Duration getDuration() {
+        return internal.getDuration();
+    }
+
+    /**
+     * Sets a duration for how long a recording runs before it stops.
+     * <p>
+     * By default, a recording has no duration ({@code null}).
+     *
+     * @param duration the duration, or {@code null} if no duration is set
+     *
+     * @throws IllegalStateException if recording is in the {@code STOPPED} or {@code CLOSED} state
+     */
+    public void setDuration(Duration duration) {
+        internal.setDuration(duration);
+    }
+
+    /**
+     * Enables the event with the specified name.
+     * <p>
+     * If multiple events have the same name (for example, the same class is loaded
+     * in different class loaders), then all events that match the name are enabled. To
+     * enable a specific class, use the {@link #enable(Class)} method or a {@code String}
+     * representation of the event type ID.
+     *
+     * @param name the settings for the event, not {@code null}
+     *
+     * @return an event setting for further configuration, not {@code null}
+     *
+     * @see EventType
+     */
+    public EventSettings enable(String name) {
+        Objects.requireNonNull(name);
+        RecordingSettings rs = new RecordingSettings(this, name);
+        rs.with("enabled", "true");
+        return rs;
+    }
+
+    /**
+     * Disables event with the specified name.
+     * <p>
+     * If multiple events with same name (for example, the same class is loaded
+     * in different class loaders), then all events that match the
+     * name is disabled. To disable a specific class, use the
+     * {@link #disable(Class)} method or a {@code String} representation of the event
+     * type ID.
+     *
+     * @param name the settings for the event, not {@code null}
+     *
+     * @return an event setting for further configuration, not {@code null}
+     *
+     */
+    public EventSettings disable(String name) {
+        Objects.requireNonNull(name);
+        RecordingSettings rs = new RecordingSettings(this, name);
+        rs.with("enabled", "false");
+        return rs;
+    }
+
+    /**
+     * Enables event.
+     *
+     * @param eventClass the event to enable, not {@code null}
+     *
+     * @throws IllegalArgumentException if {@code eventClass} is an abstract
+     *         class or not a subclass of {@link Event}
+     *
+     * @return an event setting for further configuration, not {@code null}
+     */
+    public EventSettings enable(Class<? extends Event> eventClass) {
+        Objects.requireNonNull(eventClass);
+        RecordingSettings rs = new RecordingSettings(this, eventClass);
+        rs.with("enabled", "true");
+        return rs;
+    }
+
+    /**
+     * Disables event.
+     *
+     * @param eventClass the event to enable, not {@code null}
+     *
+     * @throws IllegalArgumentException if {@code eventClass} is an abstract
+     *         class or not a subclass of {@link Event}
+     *
+     * @return an event setting for further configuration, not {@code null}
+     *
+     */
+    public EventSettings disable(Class<? extends Event> eventClass) {
+        Objects.requireNonNull(eventClass);
+        RecordingSettings rs = new RecordingSettings(this, eventClass);
+        rs.with("enabled", "false");
+        return rs;
+    }
+
+    // package private
+    PlatformRecording getInternal() {
+        return internal;
+    }
+
+    private void setSetting(String id, String value) {
+        Objects.requireNonNull(id);
+        Objects.requireNonNull(value);
+        internal.setSetting(id, value);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/RecordingState.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+/**
+ * Indicates a state in the life cycle of a recording.
+ *
+ * @since 9
+ */
+public enum RecordingState {
+
+    /**
+     * The initial state when a {@code Recording} is created.
+     */
+    NEW,
+
+    /**
+     * The recording is scheduled to start with a start time in the future.
+     * <p>
+     * An invocation of the {@link Recording#start()} method will transition the
+     * recording to the {@code RUNNING} state.
+     */
+    DELAYED,
+
+    /**
+     * The recording is recording data and an invocation of the {@link Recording#stop()}
+     * method will transition the recording to the {@code STOPPED} state.
+     */
+    RUNNING,
+
+    /**
+     * The recording is stopped and is holding recorded data that can be dumped to
+     * disk.
+     * <p>
+     * An invocation of the {@link Recording#close()} method will release the
+     * data and transition the recording to the {@code CLOSED} state.
+     */
+    STOPPED,
+
+    /**
+     * The recording is closed and all resources that are associated with the
+     * recording are released.
+     * <p>
+     * Nothing that can be done with a recording from this point, and it's
+     * no longer retrievable from the {@code FlightRrecorder.getRecordings()} method.
+     */
+    CLOSED;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/Registered.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Event annotation, for programmatic event registration.
+ * <p>
+ * Events are automatically registered when they are first used. This annotation
+ * can be used to override that registration. To register
+ * events programmatically, use {@link FlightRecorder#register(Class)}.
+ *
+ * @since 9
+ */
+@Target({ ElementType.TYPE })
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Registered {
+    /**
+     * Returns {@code true} if the event is to be registered when the event class is
+     * first used, {@code false} otherwise.
+     *
+     * @return {@code true} if the event is to be registered when the event class is
+     *         first used, {@code false} otherwise.
+     */
+    public boolean value() default true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/Relational.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Meta annotation for relational annotations, to be used on an annotation.
+ *
+ * @since 9
+ */
+@MetadataDefinition
+@Label("Relation")
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.ANNOTATION_TYPE)
+public @interface Relational {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/SettingControl.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.security.AccessController;
+import java.util.Set;
+
+import jdk.jfr.internal.Control;
+
+/**
+ * Base class to extend to create setting controls.
+ * <p>
+ * The following example shows a naive implementation of a setting control for
+ * regular expressions:
+ *
+ * <pre>
+ * <code>
+ * final class RegExpControl extends SettingControl {
+ *   private Pattern pattern = Pattern.compile(".*");
+ *
+ *   {@literal @}Override
+ *   public void setValue(String value) {
+ *     this.pattern = Pattern.compile(value);
+ *   }
+ *
+ *   {@literal @}Override
+ *   public String combine(Set{@literal <}String{@literal >} values) {
+ *     return String.join("|", values);
+ *   }
+ *
+ *   {@literal @}Override
+ *   public String getValue() {
+ *     return pattern.toString();
+ *   }
+ *
+ *   public String matches(String s) {
+ *     return pattern.matcher(s).find();
+ *   }
+ * }
+ * </code>
+ * </pre>
+ *
+ * The {@code setValue(String)}, {@code getValue()} and
+ * {@code combine(Set<String>)} methods are invoked when a setting value
+ * changes, which typically happens when a recording is started or stopped. The
+ * {@code combine(Set<String>)} method is invoked to resolve what value to use
+ * when multiple recordings are running at the same time.
+ * <p>
+ * The setting control must have a default constructor that can be invoked when
+ * the event is registered.
+ * <p>
+ * To use a setting control with an event, add a method that returns a
+ * {@code boolean} value and takes the setting control as a parameter. Annotate
+ * the method with the {@code @SettingDefinition} annotation. By default, the
+ * method name is used as the setting name, but the name can be set explicitly
+ * by using the {@code @Name} annotation. If the method returns {@code true},
+ * the event will be committed.
+ * <p>
+ * It is recommended that the {@code setValue(String)} method updates an
+ * efficient data structure that can be quickly checked when the event is
+ * committed.
+ * <p>
+ * The following example shows how to create an event that uses the
+ * regular expression filter defined above.
+ *
+ * <pre>
+ * <code>
+ * abstract class HTTPRequest extends Event {
+ *   {@literal @}Label("Request URI")
+ *   protected String uri;
+ *
+ *   {@literal @}Label("Servlet URI Filter")
+ *   {@literal @}SettingDefinition
+ *   protected boolean uriFilter(RegExpControl regExp) {
+ *     return regExp.matches(uri);
+ *   }
+ * }
+ *
+ * {@literal @}Label("HTTP Get Request")
+ * class HTTPGetRequest extends HTTPRequest {
+ * }
+ *
+ * {@literal @}Label("HTTP Post Request")
+ * class HTTPPostRequest extends HTTPRequest {
+ * }
+ *
+ * class ExampleServlet extends HTTPServlet {
+ *   protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
+ *     HTTPGetRequest request = new HTTPGetRequest();
+ *     request.begin();
+ *     request.uri = req.getRequestURI();
+ *     ...
+ *     request.commit();
+ *   }
+ *
+ *   protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
+ *     HTTPPostRequest request = new HTTPPostRequest();
+ *     request.begin();
+ *     request.uri = req.getRequestURI();
+ *     ...
+ *     request.commit();
+ *   }
+ * }
+ * </code>
+ * </pre>
+ *
+ * The following example shows how an event can be filtered by assigning the
+ * {@code "uriFilter"} setting with the specified regular expressions.
+ *
+ * <pre>
+ * <code>
+ * Recording r = new Recording();
+ * r.enable("HTTPGetRequest").with("uriFilter", "https://www.example.com/list/.*");
+ * r.enable("HTTPPostRequest").with("uriFilter", "https://www.example.com/login/.*");
+ * r.start();
+ * </code>
+ * </pre>
+ *
+ *
+ *
+ * @see SettingDefinition
+ *
+ * @since 9
+ */
+@MetadataDefinition
+public abstract class SettingControl extends Control {
+
+    /**
+     * Constructor for invocation by subclass constructors.
+     */
+    protected SettingControl() {
+        super(AccessController.getContext());
+
+    }
+
+    /**
+     * Combines the setting values for all running recordings into one value when
+     * multiple recordings are running at the same time,
+     * <p>
+     * The semantics of how setting values are combined depends on the setting
+     * control that is implemented, but all recordings should get at least all the
+     * events they request.
+     * <p>
+     * This method should have no side effects, because the caller might cache values.
+     * This method should never return {@code null} or throw an exception. If a
+     * value is not valid for this setting control, the value should be ignored.
+     * <p>
+     * Examples:
+     * <p>
+     * if the setting control represents a threshold and three recordings are
+     * running at the same time with the setting values {@code "10 ms"},
+     * {@code "8 s"}, and {@code  "1 ms"}, this method returns {@code "1 ms"}
+     * because it means that all recordings get at least all the requested data.
+     * <p>
+     * If the setting control represents a set of names and two recordings are
+     * running at the same time with the setting values {@code "Smith, Jones"} and {@code "Jones,
+     * Williams"} the returned value is {@code "Smith, Jones, Williams"} because all names would be accepted.
+     * <p>
+     * If the setting control represents a boolean condition and four recordings are
+     * running at the same time with the following values {@code "true"}, {@code "false"}, {@code "false"}, and
+     * {@code "incorrect"}, this method returns {@code "true"}, because all
+     * recordings get at least all the requested data.
+     *
+     * @param settingValues the set of values, not {@code null}
+     *
+     * @return the value to use, not {@code null}
+     */
+    @Override
+    public abstract String combine(Set<String> settingValues);
+
+    /**
+     * Sets the value for this setting.
+     * <p>
+     * If the setting value is not valid for this setting, this method
+     * does not throw an exception. Instead, the value is ignored.
+     *
+     * @param settingValue the string value, not {@code null}
+     */
+    @Override
+    public abstract void setValue(String settingValue);
+
+    /**
+     * Returns the currently used value for this setting, not {@code null}.
+     * <p>
+     * The value returned by this method is valid as an argument to both
+     * the {@code setValue(String)} method and {@code combine(Set)} method.
+     * <p>
+     * This method is invoked when an event is registered to obtain the
+     * default value. It is therefore important that a valid value can be
+     * returned immediately after an instance of this class is created. It is
+     * not valid to return {@code null}.
+     *
+     * @return the setting value, not {@code null}
+     */
+    @Override
+    public abstract String getValue();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/SettingDefinition.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation that specifies that a method in an event class should be used to
+ * filter out events.
+ * <p>
+ * For the method to be valid it must return a {@code SettingControl} and only have one
+ * parameter, which should be a non-abstract subclass of {@link SettingControl}
+ * <p>
+ * The return value of the method specifies whether the event is to be
+ * written to the Flight Recorder system or not.
+ * <p>
+ * The following example shows how to annotate a method in an event class.
+ *
+ * <pre>
+ * <code>
+ * class HelloWorld extend Event {
+ *
+ *   {@literal @}Label("Message");
+ *   String message;
+ *
+ *   {@literal @}SettingDefinition;
+ *   {@literal @}Label("Message Filter");
+ *   public boolean filter(RegExpControl regExp) {
+ *     return regExp.matches(message);
+ *   }
+ * }
+ * </code>
+ * </pre>
+ *
+ * For an example of how the setting controls are defined, see
+ * {@link SettingControl}.
+ *
+ * @see SettingControl
+ *
+ * @since 9
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.METHOD })
+public @interface SettingDefinition {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/SettingDescriptor.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.lang.annotation.Annotation;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+import jdk.jfr.internal.AnnotationConstruct;
+import jdk.jfr.internal.Type;
+
+/**
+ * Describes an event setting.
+ *
+ * @since 9
+ */
+public final class SettingDescriptor {
+
+    private final AnnotationConstruct annotationConstruct;
+    private final Type type;
+    private final String name;
+    private final String defaultValue;
+
+    // package private, invoked by jdk.internal.
+    SettingDescriptor(Type type, String name, String defaultValue, List<AnnotationElement> annotations) {
+        Objects.requireNonNull(annotations);
+        this.name = Objects.requireNonNull(name, "Name of value descriptor can't be null");
+        this.type = Objects.requireNonNull(type);
+        this.annotationConstruct = new AnnotationConstruct(annotations);
+        this.defaultValue = Objects.requireNonNull(defaultValue);
+    }
+
+    // package private
+    void setAnnotations(List<AnnotationElement> as) {
+        annotationConstruct.setAnnotationElements(as);
+    }
+
+    /**
+     * Returns the name of the setting (for example, {@code "threshold"}).
+     *
+     * @return the name, not {@code null}
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Returns a human-readable name that describes the setting (for example,
+     * {@code "Threshold"}).
+     * <p>
+     * If the setting lacks a label, the label for the type that is associated with this
+     * setting is returned, or {@code null} if doesn't exist
+     *
+     * @return a human-readable name, or {@code null} if doesn't exist
+     */
+    public String getLabel() {
+        String label = annotationConstruct.getLabel();
+        if (label == null) {
+            label = type.getLabel();
+        }
+        return label;
+    }
+
+    /**
+     * Returns a sentence that describes the setting (for example
+     * {@code "Record event with duration
+     * above or equal to threshold"}).
+     * <p>
+     * If the setting lacks a description, the description for the type that is
+     * associated with this setting is returned, or {@code null} if doesn't exist.
+     *
+     * @return the description, or {@code null} if doesn't exist
+     */
+    public String getDescription() {
+        String description = annotationConstruct.getDescription();
+        if (description == null) {
+            description = type.getDescription();
+        }
+        return description;
+    }
+
+    /**
+     * Returns a textual identifier that specifies how a value that is represented by
+     * this {@code SettingDescriptor} object is interpreted or formatted.
+     * <p>
+     * For example, if the setting descriptor represents a percentage, then
+     * {@code "jdk.jfr.Percentage"} hints to a client that a value of "0.5"
+     * is formatted as "50%".
+     * <p>
+     * The JDK provides the following predefined content types:
+     * <ul>
+     * <li>jdk.jfr.Percentage</li>
+     * <li>jdk.jfr.Timespan</li>
+     * <li>jdk.jfr.Timestamp</li>
+     * <li>jdk.jfr.Frequency</li>
+     * <li>jdk.jfr.Flag</li>
+     * <li>jdk.jfr.MemoryAddress</li>
+     * <li>jdk.jfr.DataAmount</li>
+     * <li>jdk.jfr.NetworkAddress</li>
+     * </ul>
+     * <p>
+     * User-defined content types can be created by using {@link ContentType}.
+     * <p>
+     * If the setting lacks a content type, the content type for the type
+     * that is associated with this setting is returned, or {@code null} if not
+     * available.
+     *
+     * @return the content type, or {@code null} if doesn't exist
+     *
+     * @see ContentType
+     */
+    public String getContentType() {
+        for (AnnotationElement anno : getAnnotationElements()) {
+            for (AnnotationElement meta : anno.getAnnotationElements()) {
+                if (meta.getTypeName().equals(ContentType.class.getName())) {
+                    return anno.getTypeName();
+                }
+            }
+        }
+        for (AnnotationElement anno : type.getAnnotationElements()) {
+            for (AnnotationElement meta : anno.getAnnotationElements()) {
+                if (meta.getTypeName().equals(ContentType.class.getName())) {
+                    return anno.getTypeName();
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns the fully qualified class name of the type that is associated with this
+     * setting descriptor.
+     *
+     * @return the type name, not {@code null}
+     *
+     * @see SettingDescriptor#getTypeId()
+     */
+    public String getTypeName() {
+        return type.getName();
+    }
+
+    /**
+     * Returns a unique ID for the type in the Java Virtual Machine (JVM).
+     * <p>
+     * The ID might not be the same between JVM instances.
+     *
+     * @return the type ID, not negative
+     */
+    public long getTypeId() {
+        return type.getId();
+    }
+
+    /**
+     * Returns the first annotation for the specified type if an annotation
+     * element with the same name is available, {@code null} otherwise.
+     *
+     * @param <A> the type of the annotation to query for and return if available
+     * @param annotationType the Class object that corresponds to the annotation
+     *        type, not {@code null}
+     * @return this element's annotation for the specified annotation type if
+     *         available, {@code null} otherwise
+     */
+    public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
+        Objects.requireNonNull(annotationType);
+        return annotationConstruct.getAnnotation(annotationType);
+    }
+
+    /**
+     * Returns an immutable list of annotation elements for this value
+     * descriptor.
+     *
+     * @return a list of annotations, not {@code null}
+     */
+    public List<AnnotationElement> getAnnotationElements() {
+        return Collections.unmodifiableList(annotationConstruct.getUnmodifiableAnnotationElements());
+    }
+
+    /**
+     * Returns the default value for this setting descriptor.
+     *
+     * @return the default value, not {@code null}
+     */
+    public String getDefaultValue() {
+        return defaultValue;
+    }
+
+    // package private
+    Type getType() {
+        return type;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/StackTrace.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Event annotation, determines whether an event by default has a stack trace
+ * or not.
+ *
+ * @since 9
+ */
+@MetadataDefinition
+@Target({ ElementType.TYPE })
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+public @interface StackTrace {
+    /**
+     * Settings name {@code "stackTrace"} to be used for enabling event stack traces.
+     */
+    public final static String NAME = "stackTrace";
+
+    /**
+     * Returns if the stack trace from the {@code Event#commit()} method should be recorded.
+     *
+     * @return {@code true} if the stack trace should be recorded, {@code false}
+     *         otherwise
+     */
+    boolean value() default true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/Threshold.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Event annotation, specifies the default duration below which an event is not
+ * recorded (for example, {@code "20 ms"}).
+ *
+ * @since 9
+ */
+@MetadataDefinition
+@Target({ ElementType.TYPE })
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Threshold {
+    /**
+     * Setting name {@code "threshold"} for configuring event thresholds.
+     */
+    public final static String NAME = "threshold";
+
+    /**
+     * The threshold (for example, {@code "20 ms"}).
+     * <p>
+     * A {@code String} representation of a positive {@code Long} value followed by an
+     * empty space and one of the following units:<br>
+     * <br>
+     * {@code "ns"} (nanoseconds)<br>
+     * {@code "us"} (microseconds)<br>
+     * {@code "ms"} (milliseconds)<br>
+     * {@code "s"} (seconds)<br>
+     * {@code "m"} (minutes)<br>
+     * {@code "h"} (hours)<br>
+     * {@code "d"} (days)<br>
+     * <p>
+     * Example values are {@code "0 ns"}, {@code "10 ms"}, and {@code "1 s"}.
+     *
+     * @return the threshold, default {@code "0 ns"}, not {@code null}
+     */
+    String value() default "0 ns";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/Timespan.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Event field annotation, specifies that the value is a duration.
+ *
+ * @since 9
+ */
+@MetadataDefinition
+@ContentType
+@Label("Timespan")
+@Description("A duration, measured in nanoseconds by default")
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})
+public @interface Timespan {
+    /**
+     * Unit for ticks.
+     */
+    public static final String TICKS = "TICKS";
+    /**
+     * Unit for seconds.
+     */
+    public static final String SECONDS = "SECONDS";
+    /**
+     * Unit for milliseconds.
+     */
+    public static final String MILLISECONDS = "MILLISECONDS";
+    /**
+     * Unit for nanoseconds.
+     */
+    public static final String NANOSECONDS = "NANOSECONDS";
+
+    /**
+     * Unit for microseconds.
+     */
+    public static final String MICROSECONDS = "MICROSECONDS";
+
+    /**
+     * Returns the unit of measure for the time span.
+     * <p>
+     * By default, the unit is nanoseconds.
+     *
+     * @return the time span unit, default {@code #NANOSECONDS}, not {@code null}
+     */
+    String value() default NANOSECONDS;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/Timestamp.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Event field annotation, specifies that the value is a point in time.
+ *
+ * @since 9
+ */
+@MetadataDefinition
+@ContentType
+@Label("Timestamp")
+@Description("A point in time")
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})
+public @interface Timestamp {
+    /**
+     * The unit for the difference, measured in milliseconds, between the current
+     * time and midnight, January 1, 1970 UTC.
+     */
+    public final static String MILLISECONDS_SINCE_EPOCH = "MILLISECONDS_SINCE_EPOCH";
+
+    /**
+     * The unit for the number of ticks that have transpired since some arbitrary
+     * starting date.
+     */
+    public final static String TICKS = "TICKS";
+
+    /**
+     * Unit for the time stamp.
+     *
+     * @return time stamp unit, not {@code null}
+     */
+    String value() default Timestamp.MILLISECONDS_SINCE_EPOCH;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/TransitionFrom.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Event field annotation, specifies that the event transitioned from a thread.
+ *
+ * @since 9
+ */
+@MetadataDefinition
+@Label("Transition From")
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface TransitionFrom {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/TransitionTo.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Event field annotation, specifies that the event will soon transition to a thread.
+ *
+ * @since 9
+ */
+@MetadataDefinition
+@Label("Transition To")
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface TransitionTo {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/Unsigned.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Event field annotation, specifies that the value is of an unsigned data type.
+ *
+ * @since 9
+ */
+@MetadataDefinition
+@ContentType
+@Label("Unsigned Value")
+@Description("Value should be interpreted as unsigned data type")
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.FIELD, ElementType.TYPE })
+public @interface Unsigned {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/ValueDescriptor.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr;
+
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+import jdk.jfr.internal.AnnotationConstruct;
+import jdk.jfr.internal.Type;
+import jdk.jfr.internal.Utils;
+
+/**
+ * Describes the event fields and annotation elements.
+ *
+ * @since 9
+ */
+public final class ValueDescriptor {
+
+    private final AnnotationConstruct annotationConstruct;
+    private final Type type;
+    private final String name;
+    private final boolean isArray;
+    private final boolean constantPool;
+    private final String javaFieldName;
+
+    // package private, invoked by jdk.internal.
+    ValueDescriptor(Type type, String name, List<AnnotationElement> annotations, int dimension, boolean constantPool, String fieldName) {
+        Objects.requireNonNull(annotations);
+        if (dimension < 0) {
+            throw new IllegalArgumentException("Dimension must be positive");
+        }
+        this.name = Objects.requireNonNull(name, "Name of value descriptor can't be null");
+        this.type = Objects.requireNonNull(type);
+        this.isArray = dimension > 0;
+        this.constantPool = constantPool;
+        this.annotationConstruct = new AnnotationConstruct(annotations);
+        this.javaFieldName = fieldName;
+    }
+
+    /**
+     * <p>
+     * Constructs a value descriptor, useful for dynamically creating event types and
+     * annotations.
+     * <P>
+     * The following types are supported:
+     * <ul>
+     * <li>{@code byte.class}
+     * <li>{@code short.class}
+     * <li>{@code int.class}
+     * <li>{@code long.class}
+     * <li>{@code char.class}
+     * <li>{@code float.class}
+     * <li>{@code double.class}
+     * <li>{@code boolean.class}
+     * <li>{@code String.class}
+     * <li>{@code Class.class}
+     * <li>{@code Thread.class}
+     * </ul>
+     *
+     * <p>
+     * The name must be a valid Java identifier (for example, {@code "maxThroughput"}). See 3.8
+     * Java Language Specification for more information.
+     *
+     * @param type the type, not {@code null}
+     * @param name the name, not {@code null}
+     *
+     * @throws SecurityException if a security manager is present and the caller
+     *         doesn't have {@code FlightRecorderPermission("registerEvent")}
+     *
+     */
+    public ValueDescriptor(Class<?> type, String name) {
+        this(type, name, Collections.<AnnotationElement> emptyList());
+    }
+
+    /**
+     * <p>
+     * Constructs a value descriptor, useful for dynamically creating event types and
+     * annotations.
+     * <P>
+     * The following types are supported:
+     * <ul>
+     * <li>{@code byte.class}
+     * <li>{@code short.class}
+     * <li>{@code int.class}
+     * <li>{@code long.class}
+     * <li>{@code char.class}
+     * <li>{@code float.class}
+     * <li>{@code double.class}
+     * <li>{@code boolean.class}
+     * <li>{@code String.class}
+     * <li>{@code Class.class}
+     * <li>{@code Thread.class}
+     * </ul>
+     *
+     * <p>
+     * The name must be a valid Java identifier (for example, {@code "maxThroughput"}). See 3.8
+     * Java Language Specification for more information.
+     *
+     * @param type the type, not {@code null}
+     * @param name the name, not {@code null}
+     * @param annotations the annotations on the value descriptors, not
+     *        {@code null}
+     *
+     * @throws SecurityException if a security manager is present and the caller
+     *         doesn't have {@code FlightRecorderPermission("registerEvent")}
+     */
+    public ValueDescriptor(Class<?> type, String name, List<AnnotationElement> annotations) {
+        this(type, name, new ArrayList<>(annotations), false);
+    }
+
+
+    ValueDescriptor(Class<?> type, String name, List<AnnotationElement> annotations, boolean allowArray) {
+        Objects.requireNonNull(annotations);
+        Utils.checkRegisterPermission();
+        if (!allowArray) {
+            if (type.isArray()) {
+                throw new IllegalArgumentException("Array types are not allowed");
+            }
+        }
+        this.name = Objects.requireNonNull(name, "Name of value descriptor can't be null");
+        this.type = Objects.requireNonNull(Utils.getValidType(Objects.requireNonNull(type), Objects.requireNonNull(name)));
+        this.annotationConstruct = new AnnotationConstruct(annotations);
+        this.javaFieldName = name; // Needed for dynamic events
+        this.isArray = type.isArray();
+        // Assume we always want to store String and Thread in constant pool
+        this.constantPool = type == Class.class || type == Thread.class;
+    }
+
+    /**
+     * Returns a human-readable name that describes the value (for example,
+     * {@code "Maximum Throughput"}).
+     *
+     * @return a human-readable name, or {@code null} if doesn't exist
+     */
+    public String getLabel() {
+        return annotationConstruct.getLabel();
+    }
+
+    /**
+     * Returns the name of the value (for example, {@code "maxThroughput"}).
+     *
+     * @return the name, not {@code null}
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Returns a sentence describing the value (for example, {@code "Maximum
+     * throughput in the transaction system. Value is reset after each new
+     * batch."}).
+     *
+     * @return the description, or {@code null} if doesn't exist
+     */
+    public String getDescription() {
+        return annotationConstruct.getDescription();
+    }
+
+    /**
+     * Returns a textual identifier that specifies how a value represented by
+     * this {@link ValueDescriptor} is interpreted or formatted.
+     * <p>
+     * For example, if the value descriptor's type is {@code float} and the
+     * event value is {@code 0.5f}, a content type of
+     * {@code "jdk.jfr.Percentage"} hints to a client that the value is a
+     * percentage and that it should be rendered as {@code "50%"}.
+     * <p>
+     * The JDK provides the following predefined content types:
+     * <ul>
+     * <li>jdk.jfr.Percentage</li>
+     * <li>jdk.jfr.Timespan</li>
+     * <li>jdk.jfr.Timestamp</li>
+     * <li>jdk.jfr.Frequency</li>
+     * <li>jdk.jfr.Flag</li>
+     * <li>jdk.jfr.MemoryAddress</li>
+     * <li>jdk.jfr.DataAmount</li>
+     * <li>jdk.jfr.NetworkAddress</li>
+     * </ul>
+     * <p>
+     * User-defined content types can be created by using the {@link ContentType} class.
+     *
+     * @return the content type, or {@code null} if doesn't exist
+     *
+     * @see ContentType
+     */
+    public String getContentType() {
+        for (AnnotationElement anno : getAnnotationElements()) {
+            for (AnnotationElement meta : anno.getAnnotationElements()) {
+                if (meta.getTypeName().equals(ContentType.class.getName())) {
+                    return anno.getTypeName();
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns the fully qualified class name of the type that is associated with
+     * this value descriptor.
+     *
+     * @return the type name, not {@code null}
+     *
+     * @see ValueDescriptor#getTypeId()
+     */
+    public String getTypeName() {
+        if (type.isSimpleType()) {
+            return type.getFields().get(0).getTypeName();
+        }
+        return type.getName();
+    }
+
+    /**
+     * Returns a unique ID for the type in the Java virtual Machine (JVM).
+     *
+     * The ID might not be the same between JVM instances.
+     *
+     * @return the type ID, not negative
+     */
+    public long getTypeId() {
+        return type.getId();
+    }
+
+    /**
+     * Returns if this value descriptor is an array type.
+     *
+     * @return {@code true} if it is an array type, {@code false} otherwise
+     */
+    public boolean isArray() {
+        return isArray;
+    }
+
+    /**
+     * Returns the first annotation for the specified type if an annotation
+     * element with the same name is directly present for this value descriptor,
+     * {@code null} otherwise.
+     *
+     * @param <A> the type of the annotation to query for and return if present
+     * @param annotationType the Class object that corresponds to the annotation
+     *        type, not {@code null}
+     * @return this element's annotation for the specified annotation type if
+     *         directly present, else {@code null}
+     */
+    public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
+        Objects.requireNonNull(annotationType);
+        return annotationConstruct.getAnnotation(annotationType);
+    }
+
+    /**
+     * Returns an immutable list of annotation elements for this value
+     * descriptor.
+     *
+     * @return a list of annotations, not {@code null}
+     */
+    public List<AnnotationElement> getAnnotationElements() {
+        return annotationConstruct.getUnmodifiableAnnotationElements();
+    }
+
+    /**
+     * Returns an immutable list of value descriptors if the type is complex,
+     * else an empty list.
+     *
+     * @return a list of value descriptors, not {@code null}
+     */
+    public List<ValueDescriptor> getFields() {
+        if (type.isSimpleType()) {
+            return Collections.emptyList();
+        }
+        return Collections.unmodifiableList(type.getFields());
+    }
+
+    // package private
+    Type getType() {
+        return type;
+    }
+
+    // package private
+    void setAnnotations(List<AnnotationElement> anno) {
+        annotationConstruct.setAnnotationElements(anno);
+    }
+
+    // package private
+    boolean isConstantPool() {
+        return constantPool;
+    }
+
+    // package private
+    String getJavaFieldName() {
+        return javaFieldName;
+    }
+
+    // package private
+    boolean isUnsigned() {
+        return annotationConstruct.hasUnsigned();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/ChunkParser.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.consumer;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.List;
+
+import jdk.jfr.EventType;
+import jdk.jfr.internal.LogLevel;
+import jdk.jfr.internal.LogTag;
+import jdk.jfr.internal.Logger;
+import jdk.jfr.internal.MetadataDescriptor;
+import jdk.jfr.internal.Type;
+import jdk.jfr.internal.consumer.ChunkHeader;
+import jdk.jfr.internal.consumer.RecordingInput;
+
+/**
+ * Parses a chunk.
+ *
+ */
+final class ChunkParser {
+    private static final long CONSTANT_POOL_TYPE_ID = 1;
+    private final RecordingInput input;
+    private final LongMap<Parser> parsers;
+    private final ChunkHeader chunkHeader;
+    private final long absoluteChunkEnd;
+    private final MetadataDescriptor metadata;
+    private final LongMap<Type> typeMap;
+    private final TimeConverter timeConverter;
+
+    public ChunkParser(RecordingInput input) throws IOException {
+      this(new ChunkHeader(input));
+    }
+
+    private ChunkParser(ChunkHeader header) throws IOException {
+        this.input = header.getInput();
+        this.chunkHeader = header;
+        this.metadata = header.readMetadata();
+        this.absoluteChunkEnd = header.getEnd();
+        this.timeConverter =  new TimeConverter(chunkHeader);
+
+        ParserFactory factory = new ParserFactory(metadata, timeConverter);
+        LongMap<ConstantMap> constantPools = factory.getConstantPools();
+        parsers = factory.getParsers();
+        typeMap = factory.getTypeMap();
+
+        fillConstantPools(parsers, constantPools);
+        constantPools.forEach(ConstantMap::setIsResolving);
+        constantPools.forEach(ConstantMap::resolve);
+        constantPools.forEach(ConstantMap::setResolved);
+
+        input.position(chunkHeader.getEventStart());
+    }
+
+    public RecordedEvent readEvent() throws IOException {
+        while (input.position() < absoluteChunkEnd) {
+            long pos = input.position();
+            int size = input.readInt();
+            if (size == 0) {
+                throw new IOException("Event can't have zero size");
+            }
+            long typeId = input.readLong();
+            if (typeId > CONSTANT_POOL_TYPE_ID) { // also skips metadata (id=0)
+                Parser ep = parsers.get(typeId);
+                if (ep instanceof EventParser) {
+                    return (RecordedEvent) ep.parse(input);
+                }
+            }
+            input.position(pos + size);
+        }
+        return null;
+    }
+
+    private void fillConstantPools(LongMap<Parser> typeParser, LongMap<ConstantMap> constantPools) throws IOException {
+        long nextCP = chunkHeader.getAbsoluteChunkStart();
+        long deltaToNext = chunkHeader.getConstantPoolPosition();
+        while (deltaToNext != 0) {
+            nextCP += deltaToNext;
+            input.position(nextCP);
+            final long position = nextCP;
+            int size = input.readInt(); // size
+            long typeId = input.readLong();
+            if (typeId != CONSTANT_POOL_TYPE_ID) {
+                throw new IOException("Expected check point event (id = 1) at position " + nextCP + ", but found type id = " + typeId);
+            }
+            input.readLong(); // timestamp
+            input.readLong(); // duration
+            deltaToNext = input.readLong();
+            final long delta = deltaToNext;
+            boolean flush = input.readBoolean();
+            int poolCount = input.readInt();
+            Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.TRACE, () -> {
+                return "New constant pool: startPosition=" + position +
+                        ", size=" + size + ", deltaToNext=" + delta +
+                        ", flush=" + flush + ", poolCount=" + poolCount;
+            });
+
+            for (int i = 0; i < poolCount; i++) {
+                long id = input.readLong(); // type id
+                ConstantMap pool = constantPools.get(id);
+                Type type = typeMap.get(id);
+                if (pool == null) {
+                    Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Found constant pool(" + id + ") that is never used");
+                    if (type == null) {
+                        throw new IOException("Error parsing constant pool type " + getName(id) + " at position " + input.position() + " at check point between [" + nextCP + ", " + nextCP + size + "]");
+                    }
+                    pool = new ConstantMap(ObjectFactory.create(type, timeConverter), type.getName());
+                    constantPools.put(type.getId(), pool);
+                }
+                Parser parser = typeParser.get(id);
+                if (parser == null) {
+                    throw new IOException("Could not find constant pool type with id = " + id);
+                }
+                try {
+                    int count = input.readInt();
+                    Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.TRACE, () -> "Constant: " + getName(id) + "[" + count + "]");
+                    for (int j = 0; j < count; j++) {
+                        long key = input.readLong();
+                        Object value = parser.parse(input);
+                        pool.put(key, value);
+                    }
+                } catch (Exception e) {
+                    throw new IOException("Error parsing constant pool type " + getName(id) + " at position " + input.position() + " at check point between [" + nextCP + ", " + nextCP + size + "]", e);
+                }
+            }
+            if (input.position() != nextCP + size) {
+                throw new IOException("Size of check point event doesn't match content");
+            }
+        }
+    }
+
+    private String getName(long id) {
+        Type type = typeMap.get(id);
+        return type == null ? ("unknown(" + id +")") : type.getName();
+    }
+
+    public Collection<Type> getTypes() {
+        return metadata.getTypes();
+    }
+
+    public List<EventType> getEventTypes() {
+        return metadata.getEventTypes();
+    }
+
+    public boolean isLastChunk() {
+        return chunkHeader.isLastChunk();
+    }
+
+    public ChunkParser nextChunkParser() throws IOException {
+        return new ChunkParser(chunkHeader.nextHeader());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/ConstantMap.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.consumer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Holds mapping between a set of keys and their corresponding object.
+ *
+ * If the type is a known type, i.e. {@link RecordedThread}, an
+ * {@link ObjectFactory} can be supplied which will instantiate a typed object.
+ */
+final class ConstantMap {
+    private final static class Reference {
+        private final long key;
+        private final ConstantMap pool;
+
+        Reference(ConstantMap pool, long key) {
+            this.pool = pool;
+            this.key = key;
+        }
+
+        Object resolve() {
+            return pool.get(key);
+        }
+    }
+
+    private final ObjectFactory<?> factory;
+    private final LongMap<Object> objects;
+
+    private LongMap<Boolean> isResolving;
+    private boolean allResolved;
+    private String name;
+
+    ConstantMap(ObjectFactory<?> factory, String name) {
+        this.name = name;
+        this.objects = new LongMap<>();
+        this.factory = factory;
+    }
+
+    Object get(long id) {
+        // fast path, all objects in pool resolved
+        if (allResolved) {
+            return objects.get(id);
+        }
+        // referenced from a pool, deal with this later
+        if (isResolving == null) {
+            return new Reference(this, id);
+        }
+
+        Boolean beingResolved = isResolving.get(id);
+
+        // we are resolved (but not the whole pool)
+        if (Boolean.FALSE.equals(beingResolved)) {
+            return objects.get(id);
+        }
+
+        // resolving ourself, abort to avoid infinite recursion
+        if (Boolean.TRUE.equals(beingResolved)) {
+            return null;
+        }
+
+        // resolve me!
+        isResolving.put(id, Boolean.TRUE);
+        Object resolved = resolve(objects.get(id));
+        isResolving.put(id, Boolean.FALSE);
+        if (factory != null) {
+            Object factorized = factory.createObject(id, resolved);
+            objects.put(id, factorized);
+            return factorized;
+        } else {
+            objects.put(id, resolved);
+            return resolved;
+        }
+    }
+
+    private static Object resolve(Object o) {
+        if (o instanceof Reference) {
+            return resolve(((Reference) o).resolve());
+        }
+        if (o != null && o.getClass().isArray()) {
+            final Object[] array = (Object[]) o;
+            for (int i = 0; i < array.length; i++) {
+                array[i] = resolve(array[i]);
+            }
+            return array;
+        }
+        return o;
+    }
+
+    public void resolve() {
+        List<Long> keyList = new ArrayList<>();
+        objects.keys().forEachRemaining(keyList::add);
+        for (Long l : keyList) {
+            get(l);
+        }
+    }
+
+    public void put(long key, Object value) {
+        objects.put(key, value);
+    }
+
+    public void setIsResolving() {
+        isResolving = new LongMap<>();
+    }
+
+    public void setResolved() {
+        allResolved = true;
+        isResolving = null; // pool finished, release memory
+    }
+
+    public String getName() {
+        return name;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/EventParser.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.consumer;
+
+import static jdk.jfr.internal.EventInstrumentation.FIELD_DURATION;
+
+import java.io.IOException;
+import java.util.List;
+
+import jdk.jfr.EventType;
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.internal.consumer.RecordingInput;
+
+/**
+ * Parses an event and returns a {@link RecordedEvent}.
+ *
+ */
+final class EventParser extends Parser {
+    private final Parser[] parsers;
+    private final EventType eventType;
+    private final TimeConverter timeConverter;
+    private final boolean hasDuration;
+    private final List<ValueDescriptor> valueDescriptors;
+
+    EventParser(TimeConverter timeConverter, EventType type, Parser[] parsers) {
+        this.timeConverter = timeConverter;
+        this.parsers = parsers;
+        this.eventType = type;
+        this.hasDuration = type.getField(FIELD_DURATION) != null;
+        this.valueDescriptors = type.getFields();
+    }
+
+    @Override
+    public Object parse(RecordingInput input) throws IOException {
+        Object[] values = new Object[parsers.length];
+        for (int i = 0; i < parsers.length; i++) {
+            values[i] = parsers[i].parse(input);
+        }
+        Long startTicks = (Long) values[0];
+        long startTime = timeConverter.convertTimestamp(startTicks);
+        if (hasDuration) {
+            long durationTicks = (Long) values[1];
+            long endTime = timeConverter.convertTimestamp(startTicks + durationTicks);
+            return new RecordedEvent(eventType, valueDescriptors, values, startTime, endTime, timeConverter);
+        } else {
+            return new RecordedEvent(eventType, valueDescriptors, values, startTime, startTime, timeConverter);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/LongMap.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.consumer;
+
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * Commonly used data structure for looking up objects given an id (long value)
+ *
+ * TODO: Implement without using Map and Long objects, to minimize allocation
+ *
+ * @param <T>
+ */
+final class LongMap<T> implements Iterable<T> {
+    private final HashMap<Long, T> map;
+
+    LongMap() {
+        map = new HashMap<>(101);
+    }
+
+    void put(long id, T object) {
+        map.put(id, object);
+    }
+
+    T get(long id) {
+        return map.get(id);
+    }
+
+    @Override
+    public Iterator<T> iterator() {
+        return map.values().iterator();
+    }
+
+    Iterator<Long> keys() {
+        return map.keySet().iterator();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/ObjectFactory.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.consumer;
+
+import java.util.List;
+
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.internal.Type;
+
+/**
+ * Abstract factory for creating specialized types
+ */
+abstract class ObjectFactory<T> {
+
+    final static String TYPE_PREFIX_VERSION_1 = "com.oracle.jfr.types.";
+    final static String TYPE_PREFIX_VERSION_2 = Type.TYPES_PREFIX;
+    final static String STACK_FRAME_VERSION_1 = TYPE_PREFIX_VERSION_1 + "StackFrame";
+    final static String STACK_FRAME_VERSION_2 = TYPE_PREFIX_VERSION_2 + "StackFrame";
+
+    public static ObjectFactory<?> create(Type type, TimeConverter timeConverter) {
+        switch (type.getName()) {
+        case "java.lang.Thread":
+            return RecordedThread.createFactory(type, timeConverter);
+        case TYPE_PREFIX_VERSION_1 + "StackFrame":
+        case TYPE_PREFIX_VERSION_2 + "StackFrame":
+            return RecordedFrame.createFactory(type, timeConverter);
+        case TYPE_PREFIX_VERSION_1 + "Method":
+        case TYPE_PREFIX_VERSION_2 + "Method":
+            return RecordedMethod.createFactory(type, timeConverter);
+        case TYPE_PREFIX_VERSION_1 + "ThreadGroup":
+        case TYPE_PREFIX_VERSION_2 + "ThreadGroup":
+            return RecordedThreadGroup.createFactory(type, timeConverter);
+        case TYPE_PREFIX_VERSION_1 + "StackTrace":
+        case TYPE_PREFIX_VERSION_2 + "StackTrace":
+            return RecordedStackTrace.createFactory(type, timeConverter);
+        case TYPE_PREFIX_VERSION_1 + "ClassLoader":
+        case TYPE_PREFIX_VERSION_2 + "ClassLoader":
+            return RecordedClassLoader.createFactory(type, timeConverter);
+        case "java.lang.Class":
+            return RecordedClass.createFactory(type, timeConverter);
+        }
+        return null;
+    }
+
+    private final List<ValueDescriptor> valueDescriptors;
+
+    ObjectFactory(Type type) {
+        this.valueDescriptors = type.getFields();
+    }
+
+    T createObject(long id, Object value) {
+        if (value == null) {
+            return null;
+        }
+        if (value instanceof Object[]) {
+            return createTyped(valueDescriptors, id, (Object[]) value);
+        }
+        throw new InternalError("Object factory must have struct type");
+    }
+
+    abstract T createTyped(List<ValueDescriptor> valueDescriptors, long id, Object[] values);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/Parser.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.consumer;
+
+import java.io.IOException;
+
+import jdk.jfr.internal.consumer.RecordingInput;
+
+/**
+ * Base class for parsing data from a {@link RecordingInput}.
+ */
+abstract class Parser {
+    /**
+     * Parses data from a {@link RecordingInput} and return an object.
+     *
+     * @param input input to read from
+     * @return an object
+     * @throws IOException if operation couldn't be completed due to I/O
+     *         problems
+     */
+    abstract Object parse(RecordingInput input) throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/ParserFactory.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.consumer;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+import jdk.jfr.EventType;
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.internal.MetadataDescriptor;
+import jdk.jfr.internal.PrivateAccess;
+import jdk.jfr.internal.Type;
+import jdk.jfr.internal.consumer.RecordingInput;
+
+/**
+ * Class that create parsers suitable for reading events and constant pools
+ */
+final class ParserFactory {
+    private final LongMap<Parser> parsers = new LongMap<>();
+    private final TimeConverter timeConverter;
+    private final LongMap<Type> types = new LongMap<>();
+    private final LongMap<ConstantMap> constantPools;
+
+    public ParserFactory(MetadataDescriptor metadata, TimeConverter timeConverter) throws IOException {
+        this.constantPools = new LongMap<>();
+        this.timeConverter = timeConverter;
+        for (Type t : metadata.getTypes()) {
+            types.put(t.getId(), t);
+        }
+        for (Type t : types) {
+            if (!t.getFields().isEmpty()) { // Avoid primitives
+                CompositeParser cp = createCompositeParser(t);
+                if (t.isSimpleType()) { // Reduce to nested parser
+                   parsers.put(t.getId(), cp.parsers[0]);
+                }
+
+            }
+        }
+        // Override event types with event parsers
+        for (EventType t : metadata.getEventTypes()) {
+            parsers.put(t.getId(), createEventParser(t));
+        }
+    }
+
+    public LongMap<Parser> getParsers() {
+        return parsers;
+    }
+
+    public LongMap<ConstantMap> getConstantPools() {
+        return constantPools;
+    }
+
+    public LongMap<Type> getTypeMap() {
+        return types;
+    }
+
+    private EventParser createEventParser(EventType eventType) throws IOException {
+        List<Parser> parsers = new ArrayList<Parser>();
+        for (ValueDescriptor f : eventType.getFields()) {
+            parsers.add(createParser(f));
+        }
+        return new EventParser(timeConverter, eventType, parsers.toArray(new Parser[0]));
+    }
+
+    private Parser createParser(ValueDescriptor v) throws IOException {
+        boolean constantPool = PrivateAccess.getInstance().isConstantPool(v);
+        if (v.isArray()) {
+            Type valueType = PrivateAccess.getInstance().getType(v);
+            ValueDescriptor element = PrivateAccess.getInstance().newValueDescriptor(v.getName(), valueType, v.getAnnotationElements(), 0, constantPool, null);
+            return new ArrayParser(createParser(element));
+        }
+        long id = v.getTypeId();
+        Type type = types.get(id);
+        if (type == null) {
+            throw new IOException("Type '" + v.getTypeName() + "' is not defined");
+        }
+        if (constantPool) {
+            ConstantMap pool = constantPools.get(id);
+            if (pool == null) {
+                pool = new ConstantMap(ObjectFactory.create(type, timeConverter), type.getName());
+                constantPools.put(id, pool);
+            }
+            return new ConstantMapValueParser(pool);
+        }
+        Parser parser = parsers.get(id);
+        if (parser == null) {
+            if (!v.getFields().isEmpty()) {
+                return createCompositeParser(type);
+            } else {
+                return registerParserType(type, createPrimitiveParser(type));
+            }
+        }
+        return parser;
+    }
+
+    private Parser createPrimitiveParser(Type type) throws IOException {
+        switch (type.getName()) {
+        case "int":
+            return new IntegerParser();
+        case "long":
+            return new LongParser();
+        case "float":
+            return new FloatParser();
+        case "double":
+            return new DoubleParser();
+        case "char":
+            return new CharacterParser();
+        case "boolean":
+            return new BooleanParser();
+        case "short":
+            return new ShortParser();
+        case "byte":
+            return new ByteParser();
+        case "java.lang.String":
+            ConstantMap pool = new ConstantMap(ObjectFactory.create(type, timeConverter), type.getName());
+            constantPools.put(type.getId(), pool);
+            return new StringParser(pool);
+        default:
+            throw new IOException("Unknown primitive type " + type.getName());
+        }
+    }
+
+    private Parser registerParserType(Type t, Parser parser) {
+        Parser p = parsers.get(t.getId());
+        // check if parser exists (known type)
+        if (p != null) {
+            return p;
+        }
+        parsers.put(t.getId(), parser);
+        return parser;
+    }
+
+    private CompositeParser createCompositeParser(Type type) throws IOException {
+        List<ValueDescriptor> vds = type.getFields();
+        Parser[] parsers = new Parser[vds.size()];
+        CompositeParser composite = new CompositeParser(parsers);
+        // need to pre-register so recursive types can be handled
+        registerParserType(type, composite);
+
+        int index = 0;
+        for (ValueDescriptor vd : vds) {
+            parsers[index++] = createParser(vd);
+        }
+        return composite;
+    }
+
+    private static final class BooleanParser extends Parser {
+        @Override
+        public Object parse(RecordingInput input) throws IOException {
+            return input.readBoolean() ? Boolean.TRUE : Boolean.FALSE;
+        }
+    }
+
+    private static final class ByteParser extends Parser {
+        @Override
+        public Object parse(RecordingInput input) throws IOException {
+            return Byte.valueOf(input.readByte());
+        }
+    }
+
+    private static final class LongParser extends Parser {
+        @Override
+        public Object parse(RecordingInput input) throws IOException {
+            return Long.valueOf(input.readLong());
+        }
+    }
+
+    private static final class IntegerParser extends Parser {
+        @Override
+        public Object parse(RecordingInput input) throws IOException {
+            return Integer.valueOf(input.readInt());
+        }
+    }
+
+    private static final class ShortParser extends Parser {
+        @Override
+        public Object parse(RecordingInput input) throws IOException {
+            return Short.valueOf(input.readShort());
+        }
+    }
+
+    private static final class CharacterParser extends Parser {
+        @Override
+        public Object parse(RecordingInput input) throws IOException {
+            return Character.valueOf(input.readChar());
+        }
+    }
+
+    private static final class FloatParser extends Parser {
+        @Override
+        public Object parse(RecordingInput input) throws IOException {
+            return Float.valueOf(input.readFloat());
+        }
+    }
+
+    private static final class DoubleParser extends Parser {
+        @Override
+        public Object parse(RecordingInput input) throws IOException {
+            return Double.valueOf(input.readDouble());
+        }
+    }
+
+    private static final class StringParser extends Parser {
+        private final ConstantMap stringConstantMap;
+        private String last;
+
+        StringParser(ConstantMap stringConstantMap) {
+            this.stringConstantMap = stringConstantMap;
+        }
+
+        @Override
+        public Object parse(RecordingInput input) throws IOException {
+            String s = parseEncodedString(input);
+            if (!Objects.equals(s, last)) {
+                last = s;
+            }
+            return last;
+        }
+
+        private String parseEncodedString(RecordingInput input) throws IOException {
+            byte encoding = input.readByte();
+            if (encoding == RecordingInput.STRING_ENCODING_CONSTANT_POOL) {
+                long id = input.readLong();
+                return (String) stringConstantMap.get(id);
+            } else {
+                return input.readEncodedString(encoding);
+            }
+        }
+    }
+
+    private final static class ArrayParser extends Parser {
+        private final Parser elementParser;
+
+        public ArrayParser(Parser elementParser) {
+            this.elementParser = elementParser;
+        }
+
+        @Override
+        public Object parse(RecordingInput input) throws IOException {
+            final int size = input.readInt();
+            final Object[] array = new Object[size];
+            for (int i = 0; i < size; i++) {
+                array[i] = elementParser.parse(input);
+            }
+            return array;
+        }
+    }
+
+    private final static class CompositeParser extends Parser {
+        private final Parser[] parsers;
+
+        public CompositeParser(Parser[] valueParsers) {
+            this.parsers = valueParsers;
+        }
+
+        @Override
+        public Object parse(RecordingInput input) throws IOException {
+            final Object[] values = new Object[parsers.length];
+            for (int i = 0; i < values.length; i++) {
+                values[i] = parsers[i].parse(input);
+            }
+            return values;
+        }
+    }
+
+    private static final class ConstantMapValueParser extends Parser {
+        private final ConstantMap pool;
+
+        ConstantMapValueParser(ConstantMap pool) {
+            this.pool = pool;
+        }
+
+        @Override
+        public Object parse(RecordingInput input) throws IOException {
+            return pool.get(input.readLong());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedClass.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.consumer;
+
+import java.lang.reflect.Modifier;
+import java.util.List;
+
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.internal.Type;
+
+/**
+ * A recorded Java type, such as a class or an interface.
+ *
+ * @since 9
+ */
+public final class RecordedClass extends RecordedObject {
+
+    static ObjectFactory<RecordedClass> createFactory(Type type, TimeConverter timeConverter) {
+        return new ObjectFactory<RecordedClass>(type) {
+            @Override
+            RecordedClass createTyped(List<ValueDescriptor> desc, long id, Object[] object) {
+                return new RecordedClass(desc, id, object, timeConverter);
+            }
+        };
+    }
+
+    private final long uniqueId;
+
+    // package private
+    private RecordedClass(List<ValueDescriptor> descriptors, long id, Object[] values, TimeConverter timeConverter) {
+        super(descriptors, values, timeConverter);
+        this.uniqueId = id;
+    }
+
+    /**
+     * Returns the modifiers of the class.
+     * <p>
+     * See {@link java.lang.reflect.Modifier}
+     *
+     * @return the modifiers
+     *
+     * @see Modifier
+     */
+    public int getModifiers() {
+        return getTyped("modifiers", Integer.class, -1);
+    }
+
+    /**
+     * Returns the class loader that defined the class.
+     * <P>
+     * If the bootstrap class loader is represented as {@code null} in the Java
+     * Virtual Machine (JVM), then {@code null} is also the return value of this method.
+     *
+     * @return the class loader defining this class, can be {@code null}
+     */
+    public RecordedClassLoader getClassLoader() {
+        return getTyped("classLoader", RecordedClassLoader.class, null);
+    }
+
+    /**
+     * Returns the fully qualified name of the class (for example,
+     * {@code "java.lang.String"}).
+     *
+     * @return the class name, not {@code null}
+     */
+    public String getName() {
+        return getTyped("name", String.class, null).replace("/", ".");
+    }
+
+    /**
+     * Returns a unique ID for the class.
+     * <p>
+     * The ID might not be the same between Java Virtual Machine (JVM) instances.
+     *
+     * @return a unique ID
+     */
+    public long getId() {
+        return uniqueId;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedClassLoader.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.consumer;
+
+import java.util.List;
+
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.internal.Type;
+
+/**
+ * A recorded Java class loader.
+ *
+ * @since 9
+ */
+public final class RecordedClassLoader extends RecordedObject {
+
+    static ObjectFactory<RecordedClassLoader> createFactory(Type type, TimeConverter timeConverter) {
+        return new ObjectFactory<RecordedClassLoader>(type) {
+            @Override
+            RecordedClassLoader createTyped(List<ValueDescriptor> desc, long id, Object[] object) {
+                return new RecordedClassLoader(desc, id, object, timeConverter);
+            }
+        };
+    }
+
+    private final long uniqueId;
+
+    // package private
+    private RecordedClassLoader(List<ValueDescriptor> descriptors, long id, Object[] values, TimeConverter timeConverter) {
+        super(descriptors, values, timeConverter);
+        this.uniqueId = id;
+    }
+
+    /**
+     * Returns the class of the class loader.
+     * <P>
+     * If the bootstrap class loader is represented as {@code null} in the Java
+     * Virtual Machine (JVM), then {@code null} is also the return value of this
+     * method.
+     *
+     * @return class of the class loader, can be {@code null}
+     */
+    public RecordedClass getType() {
+        return getTyped("type", RecordedClass.class, null);
+    }
+
+    /**
+     * Returns the name of the class loader (for example, "boot", "platform", and
+     * "app").
+     *
+     * @return the class loader name, can be {@code null}
+     */
+    public String getName() {
+        return getTyped("name", String.class, null);
+    }
+
+    /**
+     * Returns a unique ID for the class loader.
+     * <p>
+     * The ID might not be the same between Java Virtual Machine (JVM) instances.
+     *
+     * @return a unique ID
+     */
+    public long getId() {
+        return uniqueId;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.consumer;
+
+import java.time.Duration;
+import java.time.Instant;
+import java.util.List;
+
+import jdk.jfr.EventType;
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.internal.EventInstrumentation;
+
+/**
+ * A recorded event.
+ *
+ * @since 9
+ */
+public final class RecordedEvent extends RecordedObject {
+    private final EventType eventType;
+    private final long startTime;
+    private final long endTime;
+
+    // package private
+    RecordedEvent(EventType type, List<ValueDescriptor> vds, Object[] values, long startTime, long endTime, TimeConverter timeConverter) {
+        super(vds, values, timeConverter);
+        this.eventType = type;
+        this.startTime = startTime;
+        this.endTime = endTime;
+    }
+
+    /**
+     * Returns the stack trace that was created when the event was committed, or
+     * {@code null} if the event lacks a stack trace.
+     *
+     * @return stack trace, or {@code null} if doesn't exist for the event
+     */
+    public RecordedStackTrace getStackTrace() {
+        return getTyped(EventInstrumentation.FIELD_STACK_TRACE, RecordedStackTrace.class, null);
+    }
+
+    /**
+     * Returns the thread from which the event was committed, or {@code null} if
+     * the thread was not recorded.
+     *
+     * @return thread, or {@code null} if doesn't exist for the event
+     */
+    public RecordedThread getThread() {
+        return getTyped(EventInstrumentation.FIELD_EVENT_THREAD, RecordedThread.class, null);
+    }
+
+    /**
+     * Returns the event type that describes the event.
+     *
+     * @return the event type, not {@code null}
+     */
+    public EventType getEventType() {
+        return eventType;
+    }
+
+    /**
+     * Returns the start time of the event.
+     * <p>
+     * If the event is an instant event, then the start time and end time are the same.
+     *
+     * @return the start time, not {@code null}
+     */
+    public Instant getStartTime() {
+        return Instant.ofEpochSecond(0, startTime);
+    }
+
+    /**
+     * Returns the end time of the event.
+     * <p>
+     * If the event is an instant event, then the start time and end time are the same.
+     *
+     * @return the end time, not {@code null}
+     */
+    public Instant getEndTime() {
+        return Instant.ofEpochSecond(0, endTime);
+    }
+
+    /**
+     * Returns the duration of the event, measured in nanoseconds.
+     *
+     * @return the duration in nanoseconds, not {@code null}
+     */
+    public Duration getDuration() {
+        return Duration.ofNanos(endTime - startTime);
+    }
+
+    /**
+     * Returns the list of descriptors that describes the fields of the event.
+     *
+     * @return descriptors, not {@code null}
+     */
+    @Override
+    public List<ValueDescriptor> getFields() {
+        return getEventType().getFields();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedFrame.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.consumer;
+
+import java.lang.reflect.Modifier;
+import java.util.List;
+
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.internal.Type;
+
+/**
+ * A recorded frame in a stack trace.
+ *
+ * @since 9
+ */
+public final class RecordedFrame extends RecordedObject {
+
+    static ObjectFactory<RecordedFrame> createFactory(Type type, TimeConverter timeConverter) {
+        return new ObjectFactory<RecordedFrame>(type) {
+            @Override
+            RecordedFrame createTyped(List<ValueDescriptor> desc, long id, Object[] object) {
+                return new RecordedFrame(desc, object, timeConverter);
+            }
+        };
+    }
+
+    // package private
+    RecordedFrame(List<ValueDescriptor> desc, Object[] objects, TimeConverter timeConverter) {
+        super(desc, objects, timeConverter);
+    }
+
+    /**
+     * Returns {@code true} if this is a Java frame, {@code false} otherwise.
+     * <p>
+     * A Java method that has a native modifier is considered a Java frame.
+     *
+     * @return {@code true} if this is a Java frame, {@code false} otherwise
+     *
+     * @see Modifier#isNative(int)
+     */
+    public boolean isJavaFrame() {
+        // Only Java frames exist today, but this allows
+        // API to be extended for native frame in the future.
+        if (hasField("javaFrame")) {
+            return getTyped("javaFrame", Boolean.class, Boolean.TRUE);
+        }
+        return true;
+    }
+
+    /**
+     * Returns the bytecode index for the execution point that is represented by
+     * this recorded frame.
+     *
+     * @return byte code index, or {@code -1} if doesn't exist
+     */
+    public int getBytecodeIndex() {
+        return getTyped("bytecodeIndex", Integer.class, Integer.valueOf(-1));
+    }
+
+    /**
+     * Returns the line number for the execution point that is represented by this
+     * recorded frame, or {@code -1} if doesn't exist
+     *
+     * @return the line number, or {@code -1} if doesn't exist
+     */
+    public int getLineNumber() {
+        return getTyped("lineNumber", Integer.class, Integer.valueOf(-1));
+    }
+
+    /**
+     * Returns the frame type for the execution point that is represented by this
+     * recorded frame (for example, {@code "Interpreted"}, {@code "JIT compiled"} or
+     * {@code "Inlined"}).
+     *
+     * @return the frame type, or {@code null} if doesn't exist
+     */
+    public String getType() {
+        return getTyped("type", String.class, null);
+    }
+
+    /**
+     * Returns the method for the execution point that is represented by this
+     * recorded frame.
+     *
+     * @return the method, not {@code null}
+     */
+    public RecordedMethod getMethod() {
+        return getTyped("method", RecordedMethod.class, null);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedMethod.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.consumer;
+
+import java.lang.reflect.Modifier;
+import java.util.List;
+
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.internal.Type;
+
+/**
+ * A recorded method.
+ *
+ * @since 9
+ */
+public final class RecordedMethod extends RecordedObject {
+
+    static ObjectFactory<RecordedMethod> createFactory(Type type, TimeConverter timeConverter) {
+        return new ObjectFactory<RecordedMethod>(type) {
+            @Override
+            RecordedMethod createTyped(List<ValueDescriptor> desc, long id, Object[] object) {
+                return new RecordedMethod(desc, object, timeConverter);
+            }
+        };
+    }
+
+    private RecordedMethod(List<ValueDescriptor> descriptors, Object[] objects, TimeConverter timeConverter) {
+        super(descriptors, objects, timeConverter);
+    }
+
+    /**
+     * Returns the class this method belongs to, if it belong to a Java frame.
+     * <p>
+     * To ensure this is a Java frame, use the {@link RecordedFrame#isJavaFrame()}
+     * method.
+     *
+     * @return the class, may be {@code null} if not a Java frame
+     *
+     * @see RecordedFrame#isJavaFrame()
+     */
+    public RecordedClass getType() {
+        return getTyped("type", RecordedClass.class, null);
+    }
+
+    /**
+     * Returns the name of this method, for example {@code "toString"}.
+     * <p>
+     * If this method doesn't belong to a Java frame the result is undefined.
+     *
+     * @return method name, or {@code null} if doesn't exist
+     *
+     * @see RecordedFrame#isJavaFrame()
+     */
+    public String getName() {
+        return getTyped("name", String.class, null);
+    }
+
+    /**
+     * Returns the method descriptor for this method (for example,
+     * {@code "(Ljava/lang/String;)V"}).
+     * <p>
+     * See Java Virtual Machine Specification, 4.3
+     * <p>
+     * If this method doesn't belong to a Java frame then the the result is undefined.
+     *
+     * @return method descriptor.
+     *
+     * @see RecordedFrame#isJavaFrame()
+     */
+    public String getDescriptor() {
+        return getTyped("descriptor", String.class, null);
+    }
+
+    /**
+     * Returns the modifiers for this method.
+     * <p>
+     * If this method doesn't belong to a Java frame, then the result is undefined.
+     *
+     * @return the modifiers
+     *
+     * @see Modifier
+     * @see RecordedFrame#isJavaFrame
+     */
+    public int getModifiers() {
+        return getTyped("modifiers", Integer.class, Integer.valueOf(0));
+    }
+
+    /**
+     * Returns whether this method is hidden (for example, wrapper code in a lambda
+     * expressions).
+     *
+     * @return {@code true} if method is hidden, {@code false} otherwise
+     */
+    public boolean isHidden() {
+        return getTyped("hidden", Boolean.class, Boolean.FALSE);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,892 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.consumer;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.List;
+import java.util.Objects;
+
+import jdk.jfr.Timespan;
+import jdk.jfr.Timestamp;
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.internal.PrivateAccess;
+import jdk.jfr.internal.cmd.PrettyWriter;
+
+/**
+ * A complex data type that consists of one or more fields.
+ * <p>
+ * This class provides methods to select and query nested objects by passing a
+ * dot {@code "."} delimited {@code String} object (for instance,
+ * {@code "aaa.bbb"}). A method evaluates a nested object from left to right,
+ * and if a part is {@code null}, it throws {@code NullPointerException}.
+ *
+ * @since 9
+ */
+public class RecordedObject {
+
+    private final static class UnsignedValue {
+        private final Object o;
+
+        UnsignedValue(Object o) {
+            this.o = o;
+        }
+
+        Object value() {
+            return o;
+        }
+    }
+
+    private final Object[] objects;
+    private final List<ValueDescriptor> descriptors;
+    private final TimeConverter timeConverter;
+
+    // package private, not to be subclassed outside this package
+    RecordedObject(List<ValueDescriptor> descriptors, Object[] objects, TimeConverter timeConverter) {
+        this.descriptors = descriptors;
+        this.objects = objects;
+        this.timeConverter = timeConverter;
+    }
+
+    // package private
+    final <T> T getTyped(String name, Class<T> clazz, T defaultValue) {
+        // Unnecessary to check field presence twice, but this
+        // will do for now.
+        if (!hasField(name)) {
+            return defaultValue;
+        }
+        T object = getValue(name);
+        if (object == null || object.getClass().isAssignableFrom(clazz)) {
+            return object;
+        } else {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * Returns {@code true} if a field with the given name exists, {@code false}
+     * otherwise.
+     *
+     * @param name name of the field to get, not {@code null}
+     *
+     * @return {@code true} if the field exists, {@code false} otherwise.
+     *
+     * @see #getFields()
+     */
+    public boolean hasField(String name) {
+        Objects.requireNonNull(name);
+        for (ValueDescriptor v : descriptors) {
+            if (v.getName().equals(name)) {
+                return true;
+            }
+        }
+        int dotIndex = name.indexOf(".");
+        if (dotIndex > 0) {
+            String structName = name.substring(0, dotIndex);
+            for (ValueDescriptor v : descriptors) {
+                if (!v.getFields().isEmpty() && v.getName().equals(structName)) {
+                    RecordedObject child = getValue(structName);
+                    if (child != null) {
+                        return child.hasField(name.substring(dotIndex + 1));
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns the value of the field with the given name.
+     * <p>
+     * The return type may be a primitive type or a subclass of
+     * {@link RecordedObject}.
+     * <p>
+     * It's possible to index into a nested object by using {@code "."} (for
+     * instance {@code "thread.group.parent.name}").
+     * <p>
+     * A field might change or be removed in a future JDK release. A best practice
+     * for callers of this method is to validate the field before attempting access.
+     * <p>
+     * Example
+     *
+     * <pre>
+     * <code>
+     * if (event.hasField("intValue")) {
+     *   int intValue = event.getValue("intValue");
+     *   System.out.println("Int value: " + intValue);
+     * }
+     *
+     * if (event.hasField("objectClass")) {
+     *   RecordedClass clazz = event.getValue("objectClass");
+     *   System.out.println("Class name: " + clazz.getName());
+     * }
+     *
+     * if (event.hasField("sampledThread")) {
+     *   RecordedThread sampledThread = event.getValue("sampledThread");
+     *   System.out.println("Sampled thread: " + sampledThread.getName());
+     * }
+     * </code>
+     * </pre>
+     *
+     * @param <T> the return type
+     * @param  name of the field to get, not {@code null}
+     * @throws IllegalArgumentException if no field called {@code name} exists
+     *
+     * @return the value, can be {@code null}
+     *
+     * @see #hasField(String)
+     *
+     */
+    final public <T> T getValue(String name) {
+        @SuppressWarnings("unchecked")
+        T t = (T) getValue(name, false);
+        return t;
+    }
+
+    private Object getValue(String name, boolean allowUnsigned) {
+        Objects.requireNonNull(name);
+        int index = 0;
+        for (ValueDescriptor v : descriptors) {
+            if (name.equals(v.getName())) {
+                Object object = objects[index];
+                if (object == null) {
+                    // error or missing
+                    return null;
+                }
+                if (v.getFields().isEmpty()) {
+                    if (allowUnsigned && PrivateAccess.getInstance().isUnsigned(v)) {
+                        // Types that are meaningless to widen
+                        if (object instanceof Character || object instanceof Long) {
+                            return object;
+                        }
+                        return new UnsignedValue(object);
+                    }
+                    return object; // primitives and primitive arrays
+                } else {
+                    if (object instanceof RecordedObject) {
+                        // known types from factory
+                        return object;
+                    }
+                    // must be array type
+                    Object[] array = (Object[]) object;
+                    if (v.isArray()) {
+                        // struct array
+                        return structifyArray(v, array, 0);
+                    }
+                    // struct
+                    return new RecordedObject(v.getFields(), (Object[]) object, timeConverter);
+                }
+            }
+            index++;
+        }
+
+        int dotIndex = name.indexOf(".");
+        if (dotIndex > 0) {
+            String structName = name.substring(0, dotIndex);
+            for (ValueDescriptor v : descriptors) {
+                if (!v.getFields().isEmpty() && v.getName().equals(structName)) {
+                    RecordedObject child = getValue(structName);
+                    String subName = name.substring(dotIndex + 1);
+                    if (child != null) {
+                        return child.getValue(subName, allowUnsigned);
+                    } else {
+                        // Call getValueDescriptor to trigger IllegalArgumentException if the name is
+                        // incorrect. Type can't be validate due to type erasure
+                        getValueDescriptor(v.getFields(), subName, null);
+                        throw new NullPointerException("Field value for \"" + structName + "\" was null. Can't access nested field \"" + subName + "\"");
+                    }
+                }
+            }
+        }
+        throw new IllegalArgumentException("Could not find field with name " + name);
+    }
+
+    // Returns the leaf value descriptor matches both name or value, or throws an
+    // IllegalArgumentException
+    private ValueDescriptor getValueDescriptor(List<ValueDescriptor> descriptors, String name, String leafType) {
+        int dotIndex = name.indexOf(".");
+        if (dotIndex > 0) {
+            String first = name.substring(0, dotIndex);
+            String second = name.substring(dotIndex + 1);
+            for (ValueDescriptor v : descriptors) {
+                if (v.getName().equals(first)) {
+                    List<ValueDescriptor> fields = v.getFields();
+                    if (!fields.isEmpty()) {
+                        return getValueDescriptor(v.getFields(), second, leafType);
+                    }
+                }
+            }
+            throw new IllegalArgumentException("Attempt to get unknown field \"" + first + "\"");
+        }
+        for (ValueDescriptor v : descriptors) {
+            if (v.getName().equals(name)) {
+                if (leafType != null && !v.getTypeName().equals(leafType)) {
+                    throw new IllegalArgumentException("Attempt to get " + v.getTypeName() + " field \"" + name + "\" with illegal data type conversion " + leafType);
+                }
+                return v;
+            }
+        }
+        throw new IllegalArgumentException("\"Attempt to get unknown field \"" + name + "\"");
+    }
+
+    // Gets a value, but checks that type and name is correct first
+    // This is to prevent a call to getString on a thread field, that is
+    // null to succeed.
+    private <T> T getTypedValue(String name, String typeName) {
+        Objects.requireNonNull(name);
+        // Validate name and type first
+        getValueDescriptor(descriptors, name, typeName);
+        return getValue(name);
+    }
+
+    private Object[] structifyArray(ValueDescriptor v, Object[] array, int dimension) {
+        if (array == null) {
+            return null;
+        }
+        Object[] structArray = new Object[array.length];
+        for (int i = 0; i < structArray.length; i++) {
+            Object arrayElement = array[i];
+            if (dimension == 0) {
+                // No general way to handle structarrays
+                // without invoking ObjectFactory for every instance (which may require id)
+                if (isStackFrameType(v.getTypeName())) {
+                    structArray[i] = new RecordedFrame(v.getFields(), (Object[]) arrayElement, timeConverter);
+                } else {
+                    structArray[i] = new RecordedObject(v.getFields(), (Object[]) arrayElement, timeConverter);
+                }
+            } else {
+                structArray[i] = structifyArray(v, (Object[]) arrayElement, dimension - 1);
+            }
+        }
+        return structArray;
+    }
+
+    private boolean isStackFrameType(String typeName) {
+        if (ObjectFactory.STACK_FRAME_VERSION_1.equals(typeName)) {
+            return true;
+        }
+        if (ObjectFactory.STACK_FRAME_VERSION_2.equals(typeName)) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Returns an immutable list of the fields for this object.
+     *
+     * @return the fields, not {@code null}
+     */
+    public List<ValueDescriptor> getFields() {
+        return descriptors;
+    }
+
+    /**
+     * Returns the value of a field of type {@code boolean}.
+     * <p>
+     * It's possible to index into a nested object using {@code "."} (for example,
+     * {@code "aaa.bbb"}).
+     * <p>
+     * A field might change or be removed in a future JDK release. A best practice
+     * for callers of this method is to validate the field before attempting access.
+     *
+     * @param name name of the field to get, not {@code null}
+     *
+     * @return the value of the field, {@code true} or {@code false}
+     *
+     * @throws IllegalArgumentException if the field doesn't exist, or the field is
+     *         not of type {@code boolean}
+     *
+     * @see #hasField(String)
+     * @see #getValue(String)
+     */
+    public final boolean getBoolean(String name) {
+        Object o = getValue(name);
+        if (o instanceof Boolean) {
+            return ((Boolean) o).booleanValue();
+        }
+        throw newIllegalArgumentException(name, "boolean");
+    }
+
+    /**
+     * Returns the value of a field of type {@code byte}.
+     * <p>
+     * It's possible to index into a nested object using {@code "."} (for example,
+     * {@code "foo.bar"}).
+     * <p>
+     * A field might change or be removed in a future JDK release. A best practice
+     * for callers of this method is to validate the field before attempting access.
+     *
+     * @param name of the field to get, not {@code null}
+     *
+     * @return the value of the field
+     *
+     * @throws IllegalArgumentException if the field doesn't exist, or the field is
+     *         not of type {@code byte}
+     *
+     * @see #hasField(String)
+     * @see #getValue(String)
+     */
+    public final byte getByte(String name) {
+        Object o = getValue(name);
+        if (o instanceof Byte) {
+            return ((Byte) o).byteValue();
+        }
+        throw newIllegalArgumentException(name, "byte");
+    }
+
+    /**
+     * Returns the value of a field of type {@code char}.
+     * <p>
+     * It's possible to index into a nested object using {@code "."} (for example,
+     * {@code "aaa.bbb"}).
+     * <p>
+     * A field might change or be removed in a future JDK release. A best practice
+     * for callers of this method is to validate the field before attempting access.
+     *
+     * @param name of the field to get, not {@code null}
+     *
+     * @return the value of the field as a {@code char}
+     *
+     * @throws IllegalArgumentException if the field doesn't exist, or the field is
+     *         not of type {@code char}
+     *
+     * @see #hasField(String)
+     * @see #getValue(String)
+     */
+    public final char getChar(String name) {
+        Object o = getValue(name);
+        if (o instanceof Character) {
+            return ((Character) o).charValue();
+        }
+
+        throw newIllegalArgumentException(name, "char");
+    }
+
+    /**
+     * Returns the value of a field of type {@code short} or of another primitive
+     * type convertible to type {@code short} by a widening conversion.
+     * <p>
+     * This method can be used on the following types: {@code short} and {@code byte}.
+     * <p>
+     * If the field has the {@code @Unsigned} annotation and is of a narrower type
+     * than {@code short}, then the value is returned as an unsigned.
+     * <p>
+     * It's possible to index into a nested object using {@code "."} (for example,
+     * {@code "aaa.bbb"}).
+     * <p>
+     * A field might change or be removed in a future JDK release. A best practice
+     * for callers of this method is to validate the field before attempting access.
+     *
+     * @param name of the field to get, not {@code null}
+     *
+     * @return the value of the field converted to type {@code short}
+     *
+     * @throws IllegalArgumentException if the field doesn't exist, or the field
+     *         value can't be converted to the type {@code short} by a widening
+     *         conversion
+     *
+     * @see #hasField(String)
+     * @set #getValue(String)
+     */
+    public final short getShort(String name) {
+        Object o = getValue(name, true);
+        if (o instanceof Short) {
+            return ((Short) o).shortValue();
+        }
+        if (o instanceof Byte) {
+            return ((Byte) o).byteValue();
+        }
+        if (o instanceof UnsignedValue) {
+            Object u = ((UnsignedValue) o).value();
+            if (u instanceof Short) {
+                return ((Short) u).shortValue();
+            }
+            if (u instanceof Byte) {
+                return (short) Byte.toUnsignedInt(((Byte) u));
+            }
+        }
+        throw newIllegalArgumentException(name, "short");
+    }
+
+    /**
+     * Returns the value of a field of type {@code int} or of another primitive type
+     * that is convertible to type {@code int} by a widening conversion.
+     * <p>
+     * This method can be used on fields of the following types: {@code int},
+     * {@code short}, {@code char}, and {@code byte}.
+     * <p>
+     * If the field has the {@code @Unsigned} annotation and is of a narrower type
+     * than {@code int}, then the value will be returned as an unsigned.
+     * <p>
+     * It's possible to index into a nested object using {@code "."} (for example,
+     * {@code "aaa.bbb"}).
+     * <p>
+     * A field might change or be removed in a future JDK release. A best practice
+     * for callers of this method is to validate the field before attempting access.
+     *
+     * @param name of the field to get, not {@code null}
+     *
+     * @return the value of the field converted to type {@code int}
+     *
+     * @throws IllegalArgumentException if the field doesn't exist, or the field
+     *         value can't be converted to the type {@code int} by a widening
+     *         conversion
+     *
+     * @see #hasField(String)
+     * @set #getValue(String)
+     */
+    public final int getInt(String name) {
+        Object o = getValue(name, true);
+        if (o instanceof Integer) {
+            return ((Integer) o).intValue();
+        }
+        if (o instanceof Short) {
+            return ((Short) o).intValue();
+        }
+        if (o instanceof Character) {
+            return ((Character) o).charValue();
+        }
+        if (o instanceof Byte) {
+            return ((Byte) o).intValue();
+        }
+        if (o instanceof UnsignedValue) {
+            Object u = ((UnsignedValue) o).value();
+            if (u instanceof Integer) {
+                return ((Integer) u).intValue();
+            }
+            if (u instanceof Short) {
+                return Short.toUnsignedInt(((Short) u));
+            }
+            if (u instanceof Byte) {
+                return Byte.toUnsignedInt(((Byte) u));
+            }
+        }
+        throw newIllegalArgumentException(name, "int");
+    }
+
+    /**
+     * Returns the value of a field of type {@code float} or of another primitive
+     * type convertible to type {@code float} by a widening conversion.
+     * <p>
+     * This method can be used on fields of the following types: {@code float},
+     * {@code long}, {@code int}, {@code short}, {@code char}, and {@code byte}.
+     * <p>
+     * It's possible to index into a nested object using {@code "."} (for example,
+     * {@code "aaa.bbb"}).
+     * <p>
+     * A field might change or be removed in a future JDK release. A best practice
+     * for callers of this method is to validate the field before attempting access.
+     *
+     * @param name of the field to get, not {@code null}
+     *
+     * @return the value of the field converted to type {@code float}
+     *
+     * @throws IllegalArgumentException if the field doesn't exist, or the field
+     *         value can't be converted to the type {@code float} by a widening
+     *         conversion
+     *
+     * @see #hasField(String)
+     * @set #getValue(String)
+     */
+    public final float getFloat(String name) {
+        Object o = getValue(name);
+        if (o instanceof Float) {
+            return ((Float) o).floatValue();
+        }
+        if (o instanceof Long) {
+            return ((Long) o).floatValue();
+        }
+        if (o instanceof Integer) {
+            return ((Integer) o).floatValue();
+        }
+        if (o instanceof Short) {
+            return ((Short) o).floatValue();
+        }
+        if (o instanceof Byte) {
+            return ((Byte) o).byteValue();
+        }
+        if (o instanceof Character) {
+            return ((Character) o).charValue();
+        }
+        throw newIllegalArgumentException(name, "float");
+    }
+
+    /**
+     * Returns the value of a field of type {@code long} or of another primitive
+     * type that is convertible to type {@code long} by a widening conversion.
+     * <p>
+     * This method can be used on fields of the following types: {@code long},
+     * {@code int}, {@code short}, {@code char}, and {@code byte}.
+     * <p>
+     * If the field has the {@code @Unsigned} annotation and is of a narrower type
+     * than {@code long}, then the value will be returned as an unsigned.
+     * <p>
+     * It's possible to index into a nested object using {@code "."} (for example,
+     * {@code "aaa.bbb"}).
+     * <p>
+     * A field might change or be removed in a future JDK release. A best practice
+     * for callers of this method is to validate the field before attempting access.
+     *
+     * @param name of the field to get, not {@code null}
+     *
+     * @return the value of the field converted to type {@code long}
+     *
+     * @throws IllegalArgumentException if the field doesn't exist, or the field
+     *         value can't be converted to the type {@code long} via a widening
+     *         conversion
+     *
+     * @see #hasField(String)
+     * @set #getValue(String)
+     */
+    public final long getLong(String name) {
+        Object o = getValue(name, true);
+        if (o instanceof Long) {
+            return ((Long) o).longValue();
+        }
+        if (o instanceof Integer) {
+            return ((Integer) o).longValue();
+        }
+        if (o instanceof Short) {
+            return ((Short) o).longValue();
+        }
+        if (o instanceof Character) {
+            return ((Character) o).charValue();
+        }
+        if (o instanceof Byte) {
+            return ((Byte) o).longValue();
+        }
+        if (o instanceof UnsignedValue) {
+            Object u = ((UnsignedValue) o).value();
+            if (u instanceof Integer) {
+                return Integer.toUnsignedLong(((Integer) u));
+            }
+            if (u instanceof Short) {
+                return Short.toUnsignedLong(((Short) u));
+            }
+            if (u instanceof Byte) {
+                return Byte.toUnsignedLong(((Byte) u));
+            }
+        }
+        throw newIllegalArgumentException(name, "long");
+    }
+
+    /**
+     * Returns the value of a field of type {@code double} or of another primitive
+     * type that is convertible to type {@code double} by a widening conversion.
+     * <p>
+     * This method can be used on fields of the following types: {@code double}, {@code float},
+     * {@code long}, {@code int}, {@code short}, {@code char}, and {@code byte}.
+     * <p>
+     * It's possible to index into a nested object using {@code "."} (for example,
+     * {@code "aaa.bbb"}).
+     * <p>
+     * A field might change or be removed in a future JDK release. A best practice
+     * for callers of this method is to validate the field before attempting access.
+     *
+     * @param name of the field to get, not {@code null}
+     *
+     * @return the value of the field converted to type {@code double}
+     *
+     * @throws IllegalArgumentException if the field doesn't exist, or the field
+     *         value can't be converted to the type {@code double} by a widening
+     *         conversion
+     *
+     * @see #hasField(String)
+     * @set #getValue(String)
+     */
+    public final double getDouble(String name) {
+        Object o = getValue(name);
+        if (o instanceof Double) {
+            return ((Double) o).doubleValue();
+        }
+        if (o instanceof Float) {
+            return ((Float) o).doubleValue();
+        }
+        if (o instanceof Long) {
+            return ((Long) o).doubleValue();
+        }
+        if (o instanceof Integer) {
+            return ((Integer) o).doubleValue();
+        }
+        if (o instanceof Short) {
+            return ((Short) o).doubleValue();
+        }
+        if (o instanceof Byte) {
+            return ((Byte) o).byteValue();
+        }
+        if (o instanceof Character) {
+            return ((Character) o).charValue();
+        }
+        throw newIllegalArgumentException(name, "double");
+    }
+
+    /**
+     * Returns the value of a field of type {@code String}.
+     * <p>
+     * It's possible to index into a nested object using {@code "."} (for example,
+     * {@code "foo.bar"}).
+     * <p>
+     * A field might change or be removed in a future JDK release. A best practice
+     * for callers of this method is to validate the field before attempting access.
+     *
+     * @param name of the field to get, not {@code null}
+     *
+     * @return the value of the field as a {@code String}, can be {@code null}
+     *
+     * @throws IllegalArgumentException if the field doesn't exist, or the field
+     *         isn't of type {@code String}
+     *
+     * @see #hasField(String)
+     * @set #getValue(String)
+     */
+    public final String getString(String name) {
+        return getTypedValue(name, "java.lang.String");
+    }
+
+    /**
+     * Returns the value of a timespan field.
+     * <p>
+     * This method can be used on fields annotated with {@code @Timespan}, and of
+     * the following types: {@code long}, {@code int}, {@code short}, {@code char},
+     * and {@code byte}.
+     * <p>
+     * It's possible to index into a nested object using {@code "."} (for example,
+     * {@code "aaa.bbb"}).
+     * <p>
+     * A field might change or be removed in a future JDK release. A best practice
+     * for callers of this method is to validate the field before attempting access.
+     *
+     * @param name of the field to get, not {@code null}
+     *
+     * @return a time span represented as a {@code Duration}, not {@code null}
+     *
+     * @throws IllegalArgumentException if the field doesn't exist, or the field
+     *         value can't be converted to a {@code Duration} object
+     *
+     * @see #hasField(String)
+     * @set #getValue(String)
+     */
+    public final Duration getDuration(String name) {
+        Object o = getValue(name);
+        if (o instanceof Long) {
+            return getDuration(((Long) o).longValue(), name);
+        }
+        if (o instanceof Integer) {
+            return getDuration(((Integer) o).longValue(), name);
+        }
+        if (o instanceof Short) {
+            return getDuration(((Short) o).longValue(), name);
+        }
+        if (o instanceof Character) {
+            return getDuration(((Character) o).charValue(), name);
+        }
+        if (o instanceof Byte) {
+            return getDuration(((Byte) o).longValue(), name);
+        }
+        if (o instanceof UnsignedValue) {
+            Object u = ((UnsignedValue) o).value();
+            if (u instanceof Integer) {
+                return getDuration(Integer.toUnsignedLong((Integer) u), name);
+            }
+            if (u instanceof Short) {
+                return getDuration(Short.toUnsignedLong((Short) u), name);
+            }
+            if (u instanceof Byte) {
+                return getDuration(Short.toUnsignedLong((Byte) u), name);
+            }
+        }
+        throw newIllegalArgumentException(name, "java,time.Duration");
+    }
+
+    private Duration getDuration(long timespan, String name) throws InternalError {
+        ValueDescriptor v = getValueDescriptor(descriptors, name, null);
+        Timespan ts = v.getAnnotation(Timespan.class);
+        if (ts != null) {
+            switch (ts.value()) {
+            case Timespan.MICROSECONDS:
+                return Duration.ofNanos(1000 * timespan);
+            case Timespan.SECONDS:
+                return Duration.ofSeconds(timespan);
+            case Timespan.MILLISECONDS:
+                return Duration.ofMillis(timespan);
+            case Timespan.NANOSECONDS:
+                return Duration.ofNanos(timespan);
+            case Timespan.TICKS:
+                return Duration.ofNanos(timeConverter.convertTimespan(timespan));
+            }
+            throw new IllegalArgumentException("Attempt to get " + v.getTypeName() + " field \"" + name + "\" with illegal timespan unit " + ts.value());
+        }
+        throw new IllegalArgumentException("Attempt to get " + v.getTypeName() + " field \"" + name + "\" with missing @Timespan");
+    }
+
+    /**
+     * Returns the value of a timestamp field.
+     * <p>
+     * This method can be used on fields annotated with {@code @Timestamp}, and of
+     * the following types: {@code long}, {@code int}, {@code short}, {@code char}
+     * and {@code byte}.
+     * <p>
+     * It's possible to index into a nested object using {@code "."} (for example,
+     * {@code "aaa.bbb"}).
+     * <p>
+     * A field might change or be removed in a future JDK release. A best practice
+     * for callers of this method is to validate the field before attempting access.
+     *
+     * @param name of the field to get, not {@code null}
+     *
+     * @return a timstamp represented as an {@code Instant}, not {@code null}
+     *
+     * @throws IllegalArgumentException if the field doesn't exist, or the field
+     *         value can't be converted to an {@code Instant} object
+     *
+     * @see #hasField(String)
+     * @set #getValue(String)
+     */
+    public final Instant getInstant(String name) {
+        Object o = getValue(name, true);
+        if (o instanceof Long) {
+            return getInstant(((Long) o).longValue(), name);
+        }
+        if (o instanceof Integer) {
+            return getInstant(((Integer) o).longValue(), name);
+        }
+        if (o instanceof Short) {
+            return getInstant(((Short) o).longValue(), name);
+        }
+        if (o instanceof Character) {
+            return getInstant(((Character) o).charValue(), name);
+        }
+        if (o instanceof Byte) {
+            return getInstant(((Byte) o).longValue(), name);
+        }
+        if (o instanceof UnsignedValue) {
+            Object u = ((UnsignedValue) o).value();
+            if (u instanceof Integer) {
+                return getInstant(Integer.toUnsignedLong((Integer) u), name);
+            }
+            if (u instanceof Short) {
+                return getInstant(Short.toUnsignedLong((Short) u), name);
+            }
+            if (u instanceof Byte) {
+                return getInstant(Short.toUnsignedLong((Byte) u), name);
+            }
+        }
+        throw newIllegalArgumentException(name, "java,time.Instant");
+    }
+
+    private Instant getInstant(long timestamp, String name) {
+        ValueDescriptor v = getValueDescriptor(descriptors, name, null);
+        Timestamp ts = v.getAnnotation(Timestamp.class);
+        if (ts != null) {
+            switch (ts.value()) {
+            case Timestamp.MILLISECONDS_SINCE_EPOCH:
+                return Instant.ofEpochMilli(timestamp);
+            case Timestamp.TICKS:
+                return Instant.ofEpochSecond(0, timeConverter.convertTimestamp(timestamp));
+            }
+            throw new IllegalArgumentException("Attempt to get " + v.getTypeName() + " field \"" + name + "\" with illegal timestamp unit " + ts.value());
+        }
+        throw new IllegalArgumentException("Attempt to get " + v.getTypeName() + " field \"" + name + "\" with missing @Timestamp");
+    }
+
+    /**
+     * Returns the value of a field of type {@code Class}.
+     * <p>
+     * It's possible to index into a nested object using {@code "."} (for example,
+     * {@code "aaa.bbb"}).
+     * <p>
+     * A field might change or be removed in a future JDK release. A best practice
+     * for callers of this method is to validate the field before attempting access.
+     *
+     * @param name of the field to get, not {@code null}
+     *
+     * @return the value of the field as a {@code RecordedClass}, can be
+     *         {@code null}
+     *
+     * @throws IllegalArgumentException if the field doesn't exist, or the field
+     *         isn't of type {@code Class}
+     *
+     * @see #hasField(String)
+     * @set #getValue(String)
+     */
+    public final RecordedClass getClass(String name) {
+        return getTypedValue(name, "java.lang.Class");
+    }
+
+    /**
+     * Returns the value of a field of type {@code Thread}.
+     * <p>
+     * It's possible to index into a nested object using {@code "."} (for example,
+     * {@code "foo.bar"}).
+     * <p>
+     * A field might change or be removed in a future JDK release. A best practice
+     * for callers of this method is to validate the field before attempting access.
+     *
+     * @param name of the field to get, not {@code null}
+     *
+     * @return the value of the field as a {@code RecordedThread} object, can be
+     *         {@code null}
+     *
+     * @throws IllegalArgumentException if the field doesn't exist, or the field
+     *         isn't of type {@code Thread}
+     *
+     * @see #hasField(String)
+     * @set #getValue(String)
+     */
+    public final RecordedThread getThread(String name) {
+        return getTypedValue(name, "java.lang.Thread");
+    }
+
+    /**
+     * Returns a textual representation of this object.
+     *
+     * @return textual description of this object
+     */
+    @Override
+    final public String toString() {
+        StringWriter s = new StringWriter();
+        PrettyWriter p = new PrettyWriter(new PrintWriter(s));
+        try {
+            if (this instanceof RecordedEvent) {
+                p.print((RecordedEvent) this);
+            } else {
+                p.print(this, "");
+            }
+
+        } catch (IOException e) {
+            // Ignore, should not happen with StringWriter
+        }
+        p.flush();
+        return s.toString();
+    }
+
+    private static IllegalArgumentException newIllegalArgumentException(String name, String typeName) {
+        return new IllegalArgumentException("Attempt to get field \"" + name + "\" with illegal data type conversion " + typeName);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedStackTrace.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.consumer;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.internal.Type;
+
+/**
+ * A recorded stack trace.
+ *
+ * @since 9
+ */
+public final class RecordedStackTrace extends RecordedObject {
+
+    static ObjectFactory<RecordedStackTrace> createFactory(Type type, TimeConverter timeConverter) {
+        return new ObjectFactory<RecordedStackTrace>(type) {
+            @Override
+            RecordedStackTrace createTyped(List<ValueDescriptor> desc, long id, Object[] object) {
+                return new RecordedStackTrace(desc, object, timeConverter);
+            }
+        };
+    }
+
+    private RecordedStackTrace(List<ValueDescriptor> desc, Object[] values, TimeConverter timeConverter) {
+        super(desc, values, timeConverter);
+    }
+
+    /**
+     * Returns the frames in the stack trace.
+     *
+     * @return a list of Java stack frames, not {@code null}
+     */
+    @SuppressWarnings("unchecked")
+    public List<RecordedFrame> getFrames() {
+        Object[] array = getTyped("frames", Object[].class, null);
+        if (array == null) {
+            return Collections.EMPTY_LIST;
+        }
+        List<?> list = Arrays.asList(array);
+        return (List<RecordedFrame>) list;
+    }
+
+    /**
+     * Returns {@code true} if the stack trace is truncated due to its size,
+     * {@code false} otherwise.
+     *
+     * @return {@code true} if the stack trace is truncated, {@code false}
+     *         otherwise
+     */
+    public boolean isTruncated() {
+        return getTyped("truncated", Boolean.class, true);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedThread.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.consumer;
+
+import java.util.List;
+
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.internal.Type;
+
+/**
+ * A recorded thread.
+ *
+ * @since 9
+ */
+public final class RecordedThread extends RecordedObject {
+
+    static ObjectFactory<RecordedThread> createFactory(Type type, TimeConverter timeConverter) {
+        return new ObjectFactory<RecordedThread>(type) {
+            @Override
+            RecordedThread createTyped(List<ValueDescriptor> desc, long id, Object[] object) {
+                return new RecordedThread(desc, id, object, timeConverter);
+            }
+        };
+    }
+
+    private final long uniqueId;
+
+    private RecordedThread(List<ValueDescriptor> descriptors, long id, Object[] values,  TimeConverter timeConverter) {
+        super(descriptors, values, timeConverter);
+        this.uniqueId = id;
+    }
+
+    /**
+     * Returns the thread name used by the operating system.
+     *
+     * @return the OS thread name, or {@code null} if doesn't exist
+     */
+    public String getOSName() {
+        return getTyped("osName", String.class, null);
+    }
+
+    /**
+     * Returns the thread ID used by the operating system.
+     *
+     * @return The Java thread ID, or {@code -1} if doesn't exist
+     */
+    public long getOSThreadId() {
+        Long l = getTyped("osThreadId", Long.class, -1L);
+        return l.longValue();
+    }
+
+    /**
+     * Returns the Java thread group, if available.
+     *
+     * @return the thread group, or {@code null} if doesn't exist
+     */
+    public RecordedThreadGroup getThreadGroup() {
+        return getTyped("group", RecordedThreadGroup.class, null);
+    }
+
+    /**
+     * Returns the Java thread name, or {@code null} if if doesn't exist.
+     * <p>
+     * Returns {@code java.lang.Thread.getName()} if the thread has a Java
+     * representation. {@code null} otherwise.
+     *
+     * @return the Java thread name, or {@code null} if doesn't exist
+     */
+    public String getJavaName() {
+        return getTyped("javaName", String.class, null);
+    }
+
+    /**
+     * Returns the Java thread ID, or {@code -1} if it's not a Java thread.
+     *
+     * @return the Java thread ID, or {@code -1} if it's not a Java thread
+     */
+    public long getJavaThreadId() {
+        Long l = getTyped("javaThreadId", Long.class, -1L);
+        return l.longValue();
+    }
+
+    /**
+     * Returns a unique ID for both native threads and Java threads that can't be
+     * reused within the lifespan of the JVM.
+     * <p>
+     * See {@link #getJavaThreadId()} for the ID that is returned by
+     * {@code java.lang.Thread.getId()}
+     *
+     * @return a unique ID for the thread
+     */
+    public long getId() {
+        return uniqueId;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedThreadGroup.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.consumer;
+
+import java.util.List;
+
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.internal.Type;
+
+/**
+ * A recorded Java thread group.
+ *
+ * @since 9
+ */
+public final class RecordedThreadGroup extends RecordedObject {
+
+    static ObjectFactory<RecordedThreadGroup> createFactory(Type type, TimeConverter timeConverter) {
+        return new ObjectFactory<RecordedThreadGroup>(type) {
+            @Override
+            RecordedThreadGroup createTyped(List<ValueDescriptor> desc, long id, Object[] object) {
+                return new RecordedThreadGroup(desc, object, timeConverter);
+            }
+        };
+    }
+
+    private RecordedThreadGroup(List<ValueDescriptor> descriptors, Object[] objects, TimeConverter timeConverter) {
+        super(descriptors, objects, timeConverter);
+    }
+
+    /**
+     * Returns the name of the thread group, or {@code null} if doesn't exist.
+     *
+     * @return the thread group name, or {@code null} if doesn't exist
+     */
+    public String getName() {
+        return getTyped("name", String.class, null);
+    }
+
+    /**
+     * Returns the parent thread group, or {@code null} if it doesn't exist.
+     *
+     * @return parent thread group, or {@code null} if it doesn't exist.
+     */
+    public RecordedThreadGroup getParent() {
+        return getTyped("parent", RecordedThreadGroup.class, null);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingFile.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.consumer;
+
+import java.io.Closeable;
+import java.io.EOFException;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
+import jdk.jfr.EventType;
+import jdk.jfr.internal.MetadataDescriptor;
+import jdk.jfr.internal.consumer.ChunkHeader;
+import jdk.jfr.internal.consumer.RecordingInput;
+
+/**
+ * A recording file.
+ * <p>
+ * The following example shows how read and print all events in a recording file.
+ *
+ * <pre>
+ * <code>
+ * try (RecordingFile recordingFile = new RecordingFile(Paths.get("recording.jfr"))) {
+ *   while (recordingFile.hasMoreEvents()) {
+ *     RecordedEvent event = recordingFile.readEvent();
+ *     System.out.println(event);
+ *   }
+ * }
+ * </code>
+ * </pre>
+ *
+ * @since 9
+ */
+public final class RecordingFile implements Closeable {
+
+    private final File file;
+    private RecordingInput input;
+    private ChunkParser chunkParser;
+    private RecordedEvent nextEvent;
+    private boolean eof;
+
+    /**
+     * Creates a recording file.
+     *
+     * @param file the path of the file to open, not {@code null}
+     * @throws IOException if it's not a valid recording file, or an I/O error
+     *         occurred
+     * @throws NoSuchFileException if the {@code file} can't be located
+     *
+     * @throws SecurityException if a security manager exists and its
+     *         {@code checkRead} method denies read access to the file.
+     */
+    public RecordingFile(Path file) throws IOException {
+        this.file = file.toFile();
+        this.input = new RecordingInput(this.file);
+        findNext();
+    }
+
+    /**
+     * Reads the next event in the recording.
+     *
+     * @return the next event, not {@code null}
+     *
+     * @throws EOFException if no more events exist in the recording file
+     * @throws IOException if an I/O error occurs.
+     *
+     * @see #hasMoreEvents()
+     */
+    public RecordedEvent readEvent() throws IOException {
+        if (eof) {
+            ensureOpen();
+            throw new EOFException();
+        }
+        RecordedEvent event = nextEvent;
+        nextEvent = chunkParser.readEvent();
+        if (nextEvent == null) {
+            findNext();
+        }
+        return event;
+    }
+
+    /**
+     * Returns {@code true} if unread events exist in the recording file,
+     * {@code false} otherwise.
+     *
+     * @return {@code true} if unread events exist in the recording, {@code false}
+     *         otherwise.
+     */
+    public boolean hasMoreEvents() {
+        return !eof;
+    }
+
+    /**
+     * Returns a list of all event types in this recording.
+     *
+     * @return a list of event types, not {@code null}
+     * @throws IOException if an I/O error occurred while reading from the file
+     *
+     * @see #hasMoreEvents()
+     */
+    public List<EventType> readEventTypes() throws IOException {
+        ensureOpen();
+        List<EventType> types = new ArrayList<>();
+        HashSet<Long> foundIds = new HashSet<>();
+        try (RecordingInput ri = new RecordingInput(file)) {
+            ChunkHeader ch = new ChunkHeader(ri);
+            aggregateTypeForChunk(ch, types, foundIds);
+            while (!ch.isLastChunk()) {
+                ch = ch.nextHeader();
+                aggregateTypeForChunk(ch, types, foundIds);
+            }
+        }
+        return types;
+    }
+
+    private static void aggregateTypeForChunk(ChunkHeader ch, List<EventType> types, HashSet<Long> foundIds) throws IOException {
+        MetadataDescriptor m = ch.readMetadata();
+        for (EventType t : m.getEventTypes()) {
+            if (!foundIds.contains(t.getId())) {
+                types.add(t);
+                foundIds.add(t.getId());
+            }
+        }
+    }
+
+    /**
+     * Closes this recording file and releases any system resources that are
+     * associated with it.
+     *
+     * @throws IOException if an I/O error occurred
+     */
+    public void close() throws IOException {
+        if (input != null) {
+            eof = true;
+            input.close();
+            chunkParser = null;
+            input = null;
+            nextEvent = null;
+        }
+    }
+
+    /**
+     * Returns a list of all events in a file.
+     * <p>
+     * This method is intended for simple cases where it's convenient to read all
+     * events in a single operation. It isn't intended for reading large files.
+     *
+     * @param path the path to the file, not {@code null}
+     *
+     * @return the events from the file as a {@code List} object; whether the
+     *         {@code List} is modifiable or not is implementation dependent and
+     *         therefore not specified, not {@code null}
+     *
+     * @throws IOException if an I/O error occurred, it's not a Flight Recorder
+     *         file or a version of a JFR file that can't be parsed
+     *
+     * @throws SecurityException if a security manager exists and its
+     *         {@code checkRead} method denies read access to the file.
+     */
+    public static List<RecordedEvent> readAllEvents(Path path) throws IOException {
+        try (RecordingFile r = new RecordingFile(path)) {
+            List<RecordedEvent> list = new ArrayList<>();
+            while (r.hasMoreEvents()) {
+                list.add(r.readEvent());
+            }
+            return list;
+        }
+    }
+
+    // either sets next to an event or sets eof to true
+    private void findNext() throws IOException {
+        while (nextEvent == null) {
+            if (chunkParser == null) {
+                chunkParser = new ChunkParser(input);
+            } else if (!chunkParser.isLastChunk()) {
+                chunkParser = chunkParser.nextChunkParser();
+            } else {
+                eof = true;
+                return;
+            }
+            nextEvent = chunkParser.readEvent();
+        }
+    }
+
+    private void ensureOpen() throws IOException {
+        if (input == null) {
+            throw new IOException("Stream Closed");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/TimeConverter.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.consumer;
+
+import jdk.jfr.internal.consumer.ChunkHeader;
+
+/**
+ * Converts ticks to nanoseconds
+ */
+final class TimeConverter {
+    private final long startTicks;
+    private final long startNanos;
+    private final double divisor;
+
+    TimeConverter(ChunkHeader chunkHeader) {
+        this.startTicks = chunkHeader.getStartTicks();
+        this.startNanos = chunkHeader.getStartNanos();
+        this.divisor = chunkHeader.getTicksPerSecond() / 1000_000_000L;
+    }
+
+    public long convertTimestamp(long ticks) {
+        return startNanos + (long) ((ticks - startTicks) / divisor);
+    }
+
+    public long convertTimespan(long ticks) {
+        return (long) (ticks / divisor);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/package-info.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * This package contains classes for consuming Flight Recorder data.
+ * <p>
+ * In the following example, the program prints a histogram of all method samples in a recording.
+ * <pre>
+ * <code>
+ *   public static void main(String[] args) {
+ *     if (args.length != 0) {
+ *       System.out.println("Must specify recording file.");
+ *       return;
+ *     }
+ *     try (RecordingFile f = new RecordingFile(Paths.get(args[0]))) {
+ *       Map{@literal <}String, SimpleEntry{@literal <}String, Integer{@literal >}{@literal >} histogram = new HashMap{@literal <}{@literal >}();
+ *       int total = 0;
+ *       while (f.hasMoreEvents()) {
+ *         RecordedEvent event = f.readEvent();
+ *         if (event.getEventType().getName().equals("jdk.ExecutionSample")) {
+ *           RecordedStackTrace s = event.getStackTrace();
+ *           if (s != null) {
+ *             RecordedFrame topFrame= s.getFrames().get(0);
+ *             if (topFrame.isJavaFrame())  {
+ *               RecordedMethod method = topFrame.getMethod();
+ *               String methodName = method.getType().getName() + "#" + method.getName() + " " + method.getDescriptor();
+ *               Entry entry = histogram.computeIfAbsent(methodName, u -{@literal >} new SimpleEntry{@literal <}String, Integer{@literal >}(methodName, 0));
+ *               entry.setValue(entry.getValue() + 1);
+ *               total++;
+ *             }
+ *           }
+ *         }
+ *       }
+ *       List{@literal <}SimpleEntry{@literal <}String, Integer{@literal >}{@literal >} entries = new ArrayList{@literal <}{@literal >}(histogram.values());
+ *       entries.sort((u, v) -{@literal >} v.getValue().compareTo(u.getValue()));
+ *       for (SimpleEntry{@literal <}String, Integer{@literal >} c : entries) {
+ *         System.out.printf("%2.0f%% %s\n", 100 * (float) c.getValue() / total, c.getKey());
+ *       }
+ *       System.out.println("\nSample count: " + total);
+ *     } catch (IOException ioe) {
+ *       System.out.println("Error reading file " + args[0] + ". " + ioe.getMessage());
+ *     }
+ *   }
+ * </code>
+ * </pre>
+ * <p>
+ * <b>Null-handling</b>
+ * <p>
+ * All methods define whether they accept or return {@code null} in the Javadoc.
+ * Typically this is expressed as {@code "not null"}. If a {@code null}
+ * parameter is used where it is not allowed, a
+ * {@code java.lang.NullPointerException} is thrown. If a {@code null}
+ * parameters is passed to a method that throws other exceptions, such as
+ * {@code java.io.IOException}, the {@code java.lang.NullPointerException} takes
+ * precedence, unless the Javadoc for the method explicitly states how
+ * {@code null} is handled, i.e. by throwing {@code java.lang.IllegalArgumentException}.
+ *
+ * @since 9
+ */
+package jdk.jfr.consumer;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/events/AbstractJDKEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.events;
+
+import jdk.jfr.Enabled;
+import jdk.jfr.Event;
+import jdk.jfr.Registered;
+import jdk.jfr.StackTrace;
+
+@Registered(false)
+@Enabled(false)
+@StackTrace(false)
+abstract class AbstractJDKEvent extends Event {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/events/ActiveRecordingEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.events;
+
+import jdk.jfr.Category;
+import jdk.jfr.Label;
+import jdk.jfr.DataAmount;
+import jdk.jfr.Name;
+import jdk.jfr.StackTrace;
+import jdk.jfr.Timespan;
+import jdk.jfr.Timestamp;
+import jdk.jfr.internal.Type;
+
+@Name(Type.EVENT_NAME_PREFIX + "ActiveRecording")
+@Label("Flight Recording")
+@Category("Flight Recorder")
+@StackTrace(false)
+public final class ActiveRecordingEvent extends AbstractJDKEvent {
+
+    @Label("Id")
+    public long id;
+
+    @Label("Name")
+    public String name;
+
+    @Label("Destination")
+    public String destination;
+
+    @Label("Max Age")
+    @Timespan(Timespan.MILLISECONDS)
+    public long maxAge;
+
+    @Label("Max Size")
+    @DataAmount
+    public long maxSize;
+
+    @Label("Start Time")
+    @Timestamp(Timestamp.MILLISECONDS_SINCE_EPOCH)
+    public long recordingStart;
+
+    @Label("Recording Duration")
+    @Timespan(Timespan.MILLISECONDS)
+    public long recordingDuration;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/events/ActiveSettingEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.events;
+
+import jdk.jfr.Category;
+import jdk.jfr.Label;
+import jdk.jfr.Name;
+import jdk.jfr.StackTrace;
+import jdk.jfr.internal.Type;
+
+@Name(Type.EVENT_NAME_PREFIX + "ActiveSetting")
+@Label("Recording Setting")
+@Category("Flight Recorder")
+@StackTrace(false)
+public final class ActiveSettingEvent extends AbstractJDKEvent {
+
+    @Label("Event Id")
+    public long id;
+
+    @Label("Setting Name")
+    public String name;
+
+    @Label("Setting Value")
+    public String value;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/events/ErrorThrownEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.events;
+
+import jdk.jfr.Category;
+import jdk.jfr.Description;
+import jdk.jfr.Label;
+import jdk.jfr.Name;
+import jdk.jfr.internal.Type;
+
+@Name(Type.EVENT_NAME_PREFIX + "JavaErrorThrow")
+@Label("Java Error")
+@Category("Java Application")
+@Description("An object derived from java.lang.Error has been created. OutOfMemoryErrors are ignored")
+public final class ErrorThrownEvent extends AbstractJDKEvent {
+
+    @Label("Message")
+    public String message;
+
+    @Label("Class")
+    public Class<?> thrownClass;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/events/ExceptionStatisticsEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.events;
+
+import jdk.jfr.Category;
+import jdk.jfr.Description;
+import jdk.jfr.Label;
+import jdk.jfr.Name;
+import jdk.jfr.StackTrace;
+import jdk.jfr.internal.Type;
+
+@Name(Type.EVENT_NAME_PREFIX + "ExceptionStatistics")
+@Label("Exception Statistics")
+@Category({ "Java Application", "Statistics" })
+@Description("Number of objects derived from java.lang.Throwable that have been created")
+@StackTrace(false)
+public final class ExceptionStatisticsEvent extends AbstractJDKEvent {
+
+    @Label("Exceptions Created")
+    public long throwables;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/events/ExceptionThrownEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.events;
+
+import jdk.jfr.Category;
+import jdk.jfr.Description;
+import jdk.jfr.Label;
+import jdk.jfr.Name;
+import jdk.jfr.internal.Type;
+
+@Name(Type.EVENT_NAME_PREFIX + "JavaExceptionThrow")
+@Label("Java Exception")
+@Category("Java Application")
+@Description("An object derived from java.lang.Exception has been created")
+public final class ExceptionThrownEvent extends AbstractJDKEvent {
+
+    @Label("Message")
+    public String message;
+
+    @Label("Class")
+    public Class<?> thrownClass;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/events/FileForceEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.events;
+
+import jdk.jfr.Category;
+import jdk.jfr.Description;
+import jdk.jfr.Label;
+import jdk.jfr.Name;
+import jdk.jfr.internal.Type;
+
+@Name(Type.EVENT_NAME_PREFIX + "FileForce")
+@Label("File Force")
+@Category("Java Application")
+@Description("Force updates to be written to file")
+public final class FileForceEvent extends AbstractJDKEvent {
+
+    public static final ThreadLocal<FileForceEvent> EVENT =
+        new ThreadLocal<>() {
+            @Override protected FileForceEvent initialValue() {
+                return new FileForceEvent();
+            }
+        };
+
+    @Label("Path")
+    @Description("Full path of the file")
+    public String path;
+
+    @Label("Update Metadata")
+    @Description("Whether the file metadata is updated")
+    public boolean metaData;
+
+    public void reset() {
+        path = null;
+        metaData = false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/events/FileReadEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.events;
+
+import jdk.jfr.Category;
+import jdk.jfr.Description;
+import jdk.jfr.Label;
+import jdk.jfr.DataAmount;
+import jdk.jfr.Name;
+import jdk.jfr.internal.Type;
+
+@Name(Type.EVENT_NAME_PREFIX + "FileRead")
+@Label("File Read")
+@Category("Java Application")
+@Description("Reading data from a file")
+public final class FileReadEvent extends AbstractJDKEvent {
+
+    public static final ThreadLocal<FileReadEvent> EVENT =
+        new ThreadLocal<>() {
+            @Override protected FileReadEvent initialValue() {
+                return new FileReadEvent();
+            }
+        };
+
+    @Label("Path")
+    @Description("Full path of the file")
+    public String path;
+
+    @Label("Bytes Read")
+    @Description("Number of bytes read from the file (possibly 0)")
+    @DataAmount
+    public long bytesRead;
+
+    @Label("End of File")
+    @Description("If end of file was reached")
+    public boolean endOfFile;
+
+    public void reset() {
+        path = null;
+        endOfFile = false;
+        bytesRead = 0;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/events/FileWriteEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.events;
+
+import jdk.jfr.Category;
+import jdk.jfr.Description;
+import jdk.jfr.Label;
+import jdk.jfr.DataAmount;
+import jdk.jfr.Name;
+import jdk.jfr.internal.Type;
+
+@Name(Type.EVENT_NAME_PREFIX + "FileWrite")
+@Label("File Write")
+@Category("Java Application")
+@Description("Writing data to a file")
+public final class FileWriteEvent extends AbstractJDKEvent {
+
+    public static final ThreadLocal<FileWriteEvent> EVENT =
+        new ThreadLocal<>() {
+            @Override protected FileWriteEvent initialValue() {
+                return new FileWriteEvent();
+            }
+        };
+
+    @Label("Path")
+    @Description("Full path of the file")
+    public String path;
+
+    @Label("Bytes Written")
+    @Description("Number of bytes written to the file")
+    @DataAmount
+    public long bytesWritten;
+
+    public void reset() {
+        path = null;
+        bytesWritten = 0;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/events/SocketReadEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.events;
+
+import jdk.jfr.Category;
+import jdk.jfr.Description;
+import jdk.jfr.Label;
+import jdk.jfr.DataAmount;
+import jdk.jfr.Name;
+import jdk.jfr.Timespan;
+import jdk.jfr.internal.Type;
+
+@Name(Type.EVENT_NAME_PREFIX + "SocketRead")
+@Label("Socket Read")
+@Category("Java Application")
+@Description("Reading data from a socket")
+public final class SocketReadEvent extends AbstractJDKEvent {
+
+    public static final ThreadLocal<SocketReadEvent> EVENT =
+        new ThreadLocal<>() {
+            @Override protected SocketReadEvent initialValue() {
+                return new SocketReadEvent();
+            }
+        };
+
+    @Label("Remote Host")
+    public String host;
+
+    @Label("Remote Address")
+    public String address;
+
+    @Label("Remote Port")
+    public int port;
+
+    @Label("Timeout Value")
+    @Timespan(Timespan.MILLISECONDS)
+    public long timeout;
+
+    @Label("Bytes Read")
+    @Description("Number of bytes read from the socket")
+    @DataAmount
+    public long bytesRead;
+
+    @Label("End of Stream")
+    @Description("If end of stream was reached")
+    public boolean endOfStream;
+
+    public void reset() {
+        host = null;
+        address = null;
+        port = 0;
+        timeout = 0;
+        bytesRead = 0L;
+        endOfStream = false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/events/SocketWriteEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.events;
+
+import jdk.jfr.Category;
+import jdk.jfr.Description;
+import jdk.jfr.Label;
+import jdk.jfr.DataAmount;
+import jdk.jfr.Name;
+import jdk.jfr.internal.Type;
+
+@Name(Type.EVENT_NAME_PREFIX + "SocketWrite")
+@Label("Socket Write")
+@Category("Java Application")
+@Description("Writing data to a socket")
+public final class SocketWriteEvent extends AbstractJDKEvent {
+
+    public static final ThreadLocal<SocketWriteEvent> EVENT =
+        new ThreadLocal<>() {
+            @Override protected SocketWriteEvent initialValue() {
+                return new SocketWriteEvent();
+            }
+        };
+
+    @Label("Remote Host")
+    public String host;
+
+    @Label("Remote Address")
+    public String address;
+
+    @Label("Remote Port")
+    public int port;
+
+    @Label("Bytes Written")
+    @Description("Number of bytes written to the socket")
+    @DataAmount
+    public long bytesWritten;
+
+    public void reset() {
+        host = null;
+        address = null;
+        port = 0;
+        bytesWritten = 0;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/ASMToolkit.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintWriter;
+import java.util.List;
+
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.internal.org.objectweb.asm.Type;
+import jdk.internal.org.objectweb.asm.commons.Method;
+import jdk.internal.org.objectweb.asm.util.TraceClassVisitor;
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.internal.EventInstrumentation.FieldInfo;
+
+final class ASMToolkit {
+    private static Type TYPE_STRING = Type.getType(String.class);
+    private static Type Type_THREAD = Type.getType(Thread.class);
+    private static Type TYPE_CLASS = Type.getType(Class.class);
+
+    public static void invokeSpecial(MethodVisitor methodVisitor, String className, Method m) {
+        methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, className, m.getName(), m.getDescriptor(), false);
+    }
+
+    public static void invokeStatic(MethodVisitor methodVisitor, String className, Method m) {
+        methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, className, m.getName(), m.getDescriptor(), false);
+    }
+
+    public static void invokeVirtual(MethodVisitor methodVisitor, String className, Method m) {
+        methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, className, m.getName(), m.getDescriptor(), false);
+    }
+
+
+    public static Type toType(ValueDescriptor v) {
+        String typeName = v.getTypeName();
+
+        switch (typeName) {
+        case "byte":
+            return Type.BYTE_TYPE;
+        case "short":
+            return Type.SHORT_TYPE;
+        case "int":
+            return Type.INT_TYPE;
+        case "long":
+            return Type.LONG_TYPE;
+        case "double":
+            return Type.DOUBLE_TYPE;
+        case "float":
+            return Type.FLOAT_TYPE;
+        case "char":
+            return Type.CHAR_TYPE;
+        case "boolean":
+            return Type.BOOLEAN_TYPE;
+        case "java.lang.String":
+            return TYPE_STRING;
+        case "java.lang.Thread":
+            return Type_THREAD;
+        case "java.lang.Class":
+            return TYPE_CLASS;
+        }
+        // Add support for SettingControl?
+       throw new Error("Not a valid type " + v.getTypeName());
+    }
+
+    /**
+     * Converts "int" into "I" and "java.lang.String" into "Ljava/lang/String;"
+     *
+     * @param typeName
+     *            type
+     *
+     * @return descriptor
+     */
+    public static String getDescriptor(String typeName) {
+        if ("int".equals(typeName)) {
+            return "I";
+        }
+        if ("long".equals(typeName)) {
+            return "J";
+        }
+        if ("boolean".equals(typeName)) {
+            return "Z";
+        }
+        if ("float".equals(typeName)) {
+            return "F";
+        }
+        if ("double".equals(typeName)) {
+            return "D";
+        }
+        if ("short".equals(typeName)) {
+            return "S";
+        }
+        if ("char".equals(typeName)) {
+            return "C";
+        }
+        if ("byte".equals(typeName)) {
+            return "B";
+        }
+        String internal = getInternalName(typeName);
+        return Type.getObjectType(internal).getDescriptor();
+    }
+
+    /**
+     * Converts java.lang.String into java/lang/String
+     *
+     * @param className
+     *
+     * @return internal name
+     */
+    public static String getInternalName(String className) {
+        return className.replace(".", "/");
+    }
+
+    public static Method makeWriteMethod(List<FieldInfo> fields) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("(");
+        for (FieldInfo v : fields) {
+            if (!v.fieldName.equals(EventInstrumentation.FIELD_EVENT_THREAD) && !v.fieldName.equals(EventInstrumentation.FIELD_STACK_TRACE)) {
+                sb.append(v.fieldDescriptor);
+            }
+        }
+        sb.append(")V");
+        return new Method("write", sb.toString());
+    }
+
+    public static void logASM(String className, byte[] bytes) {
+        Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.INFO, "Generated bytecode for class " + className);
+        Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.TRACE, () -> {
+            ClassReader cr = new ClassReader(bytes);
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            PrintWriter w = new PrintWriter(baos);
+            w.println("Bytecode:");
+            cr.accept(new TraceClassVisitor(w), 0);
+            return baos.toString();
+        });
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/AnnotationConstruct.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Collections;
+import java.util.List;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.Description;
+import jdk.jfr.Label;
+import jdk.jfr.Unsigned;
+
+public final class AnnotationConstruct {
+
+    private static final class AnnotationInvokationHandler implements InvocationHandler {
+
+        private final AnnotationElement annotationElement;
+
+        AnnotationInvokationHandler(AnnotationElement a) {
+            this.annotationElement = a;
+        }
+
+        @Override
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+            String methodName = method.getName();
+            int parameters = method.getTypeParameters().length;
+            if (parameters == 0 && annotationElement.hasValue(methodName)) {
+                return annotationElement.getValue(methodName);
+            }
+            throw new UnsupportedOperationException("Flight Recorder proxy only supports members declared in annotation interfaces, i.e. not toString, equals etc.");
+        }
+    }
+
+    private List<AnnotationElement> annotationElements = Collections.emptyList();
+    private byte unsignedFlag = -1;
+    public AnnotationConstruct(List<AnnotationElement> ann) {
+        this.annotationElements = ann;
+    }
+
+    public AnnotationConstruct() {
+    }
+
+    public void setAnnotationElements(List<AnnotationElement> elements) {
+        annotationElements = Utils.smallUnmodifiable(elements);
+    }
+
+    public String getLabel() {
+        Label label = getAnnotation(Label.class);
+        if (label == null) {
+            return null;
+        }
+        return label.value();
+    }
+
+    public String getDescription() {
+        Description description = getAnnotation(Description.class);
+        if (description == null) {
+            return null;
+        }
+        return description.value();
+    }
+
+    @SuppressWarnings("unchecked")
+    public final <T> T getAnnotation(Class<? extends Annotation> clazz) {
+        AnnotationElement ae = getAnnotationElement(clazz);
+        if (ae != null) {
+            return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class<?>[] { clazz }, new AnnotationInvokationHandler(ae));
+        }
+        return null;
+    }
+
+    public List<AnnotationElement> getUnmodifiableAnnotationElements() {
+        return annotationElements;
+    }
+
+    // package private
+    boolean remove(AnnotationElement annotation) {
+        return annotationElements.remove(annotation);
+    }
+
+    private AnnotationElement getAnnotationElement(Class<? extends Annotation> clazz) {
+        // if multiple annotation elements with the same name exists, prioritize
+        // the one with the same id. Note, id alone is not a guarantee, since it
+        // may differ between JVM instances.
+        long id = Type.getTypeId(clazz);
+        String className = clazz.getName();
+        for (AnnotationElement a : getUnmodifiableAnnotationElements()) {
+            if (a.getTypeId() == id && a.getTypeName().equals(className)) {
+                return a;
+            }
+        }
+        for (AnnotationElement a : getUnmodifiableAnnotationElements()) {
+            if (a.getTypeName().equals(className)) {
+                return a;
+            }
+        }
+        return null;
+    }
+
+    public boolean hasUnsigned() {
+        // Must be initialized lazily since some annotation elements
+        // are added after construction
+        if (unsignedFlag < 0) {
+            Unsigned unsigned = getAnnotation(Unsigned.class);
+            unsignedFlag = (byte) (unsigned == null ? 0 :1);
+        }
+        return unsignedFlag == (byte)1 ? true : false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/Bits.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import jdk.internal.misc.Unsafe;
+
+final class Bits {                            // package-private
+
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+    private static final boolean unalignedAccess = unsafe.unalignedAccess();
+    private static final boolean bigEndian = unsafe.isBigEndian();
+
+    private Bits() { }
+
+    // -- Swapping --
+
+    private static short swap(short x) {
+        return Short.reverseBytes(x);
+    }
+
+    private static char swap(char x) {
+        return Character.reverseBytes(x);
+    }
+
+    private static int swap(int x) {
+        return Integer.reverseBytes(x);
+    }
+
+    private static long swap(long x) {
+        return Long.reverseBytes(x);
+    }
+
+    private static float swap(float x) {
+        return Float.intBitsToFloat(swap(Float.floatToIntBits(x)));
+    }
+
+    private static double swap(double x) {
+        return Double.longBitsToDouble(swap(Double.doubleToLongBits(x)));
+    }
+
+    // -- Alignment --
+
+    private static boolean isAddressAligned(long a, int datumSize) {
+        return (a & datumSize - 1) == 0;
+    }
+
+    // -- Primitives stored per byte
+
+    private static byte char1(char x) { return (byte)(x >> 8); }
+    private static byte char0(char x) { return (byte)(x     ); }
+
+    private static byte short1(short x) { return (byte)(x >> 8); }
+    private static byte short0(short x) { return (byte)(x     ); }
+
+    private static byte int3(int x) { return (byte)(x >> 24); }
+    private static byte int2(int x) { return (byte)(x >> 16); }
+    private static byte int1(int x) { return (byte)(x >>  8); }
+    private static byte int0(int x) { return (byte)(x      ); }
+
+    private static byte long7(long x) { return (byte)(x >> 56); }
+    private static byte long6(long x) { return (byte)(x >> 48); }
+    private static byte long5(long x) { return (byte)(x >> 40); }
+    private static byte long4(long x) { return (byte)(x >> 32); }
+    private static byte long3(long x) { return (byte)(x >> 24); }
+    private static byte long2(long x) { return (byte)(x >> 16); }
+    private static byte long1(long x) { return (byte)(x >>  8); }
+    private static byte long0(long x) { return (byte)(x      ); }
+
+    private static void putCharBigEndianUnaligned(long a, char x) {
+        putByte_(a    , char1(x));
+        putByte_(a + 1, char0(x));
+    }
+
+    private static void putShortBigEndianUnaligned(long a, short x) {
+        putByte_(a    , short1(x));
+        putByte_(a + 1, short0(x));
+    }
+
+    private static void putIntBigEndianUnaligned(long a, int x) {
+        putByte_(a    , int3(x));
+        putByte_(a + 1, int2(x));
+        putByte_(a + 2, int1(x));
+        putByte_(a + 3, int0(x));
+    }
+
+    private static void putLongBigEndianUnaligned(long a, long x) {
+        putByte_(a    , long7(x));
+        putByte_(a + 1, long6(x));
+        putByte_(a + 2, long5(x));
+        putByte_(a + 3, long4(x));
+        putByte_(a + 4, long3(x));
+        putByte_(a + 5, long2(x));
+        putByte_(a + 6, long1(x));
+        putByte_(a + 7, long0(x));
+    }
+
+    private static void putFloatBigEndianUnaligned(long a, float x) {
+        putIntBigEndianUnaligned(a, Float.floatToRawIntBits(x));
+    }
+
+    private static void putDoubleBigEndianUnaligned(long a, double x) {
+        putLongBigEndianUnaligned(a, Double.doubleToRawLongBits(x));
+    }
+
+    private static void putByte_(long a, byte b) {
+        unsafe.putByte(a, b);
+    }
+
+    private static void putBoolean_(long a, boolean x) {
+        unsafe.putBoolean(null, a, x);
+    }
+
+    private static void putChar_(long a, char x) {
+        unsafe.putChar(a, bigEndian ? x : swap(x));
+    }
+
+    private static void putShort_(long a, short x) {
+        unsafe.putShort(a, bigEndian ? x : swap(x));
+    }
+
+    private static void putInt_(long a, int x) {
+        unsafe.putInt(a, bigEndian ? x : swap(x));
+    }
+
+    private static void putLong_(long a, long x) {
+        unsafe.putLong(a, bigEndian ? x : swap(x));
+    }
+
+    private static void putFloat_(long a, float x) {
+        unsafe.putFloat(a, bigEndian ? x : swap(x));
+    }
+
+    private static void putDouble_(long a, double x) {
+        unsafe.putDouble(a, bigEndian ? x : swap(x));
+    }
+
+    // external api
+    static int putByte(long a, byte x) {
+        putByte_(a, x);
+        return Byte.BYTES;
+    }
+
+    static int putBoolean(long a, boolean x) {
+        putBoolean_(a, x);
+        return Byte.BYTES;
+    }
+
+    static int putChar(long a, char x) {
+        if (unalignedAccess || isAddressAligned(a, Character.BYTES)) {
+            putChar_(a, x);
+            return Character.BYTES;
+        }
+        putCharBigEndianUnaligned(a, x);
+        return Character.BYTES;
+    }
+
+    static int putShort(long a, short x) {
+        if (unalignedAccess || isAddressAligned(a, Short.BYTES)) {
+            putShort_(a, x);
+            return Short.BYTES;
+        }
+        putShortBigEndianUnaligned(a, x);
+        return Short.BYTES;
+    }
+
+    static int putInt(long a, int x) {
+        if (unalignedAccess || isAddressAligned(a, Integer.BYTES)) {
+            putInt_(a, x);
+            return Integer.BYTES;
+        }
+        putIntBigEndianUnaligned(a, x);
+        return Integer.BYTES;
+    }
+
+    static int putLong(long a, long x) {
+         if (unalignedAccess || isAddressAligned(a, Long.BYTES)) {
+            putLong_(a, x);
+            return Long.BYTES;
+        }
+        putLongBigEndianUnaligned(a, x);
+        return Long.BYTES;
+    }
+
+    static int putFloat(long a, float x) {
+        if (unalignedAccess || isAddressAligned(a, Float.BYTES)) {
+            putFloat_(a, x);
+            return Float.BYTES;
+        }
+        putFloatBigEndianUnaligned(a, x);
+        return Float.BYTES;
+    }
+
+    static int putDouble(long a, double x) {
+        if (unalignedAccess || isAddressAligned(a, Double.BYTES)) {
+            putDouble_(a, x);
+            return Double.BYTES;
+        }
+        putDoubleBigEndianUnaligned(a, x);
+        return Double.BYTES;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/ChunkInputStream.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+final class ChunkInputStream extends InputStream {
+    private final Iterator<RepositoryChunk> chunks;
+    private RepositoryChunk currentChunk;
+    private InputStream stream;
+
+    ChunkInputStream(List<RepositoryChunk> chunks) throws IOException {
+        List<RepositoryChunk> l = new ArrayList<>(chunks.size());
+        for (RepositoryChunk c : chunks) {
+            c.use(); // keep alive while we're reading.
+            l.add(c);
+        }
+
+        this.chunks = l.iterator();
+        nextStream();
+    }
+
+    @Override
+    public int available() throws IOException {
+        if (stream != null) {
+            return stream.available();
+        }
+        return 0;
+    }
+
+    private boolean nextStream() throws IOException {
+        if (!nextChunk()) {
+            return false;
+        }
+
+        stream = new BufferedInputStream(SecuritySupport.newFileInputStream(currentChunk.getFile()));
+        return true;
+    }
+
+    private boolean nextChunk() {
+        if (!chunks.hasNext()) {
+            return false;
+        }
+        currentChunk = chunks.next();
+        return true;
+    }
+
+    @Override
+    public int read() throws IOException {
+        while (true) {
+            if (stream != null) {
+                int r = stream.read();
+                if (r != -1) {
+                    return r;
+                }
+                stream.close();
+                currentChunk.release();
+                stream = null;
+                currentChunk = null;
+            }
+            if (!nextStream()) {
+                return -1;
+            }
+        }
+    }
+
+    @Override
+    public void close() throws IOException {
+        if (stream != null) {
+            stream.close();
+            stream = null;
+        }
+        while (currentChunk != null) {
+            currentChunk.release();
+            currentChunk = null;
+            if (!nextChunk()) {
+                return;
+            }
+        }
+    }
+
+    @Override
+    @SuppressWarnings("deprecation")
+    protected void finalize() throws Throwable {
+        super.finalize();
+        close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/ChunksChannel.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.ReadableByteChannel;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+final class ChunksChannel implements ReadableByteChannel {
+    private final Iterator<RepositoryChunk> chunks;
+    private RepositoryChunk                 current;
+    private ReadableByteChannel             channel;
+
+    public ChunksChannel(List<RepositoryChunk> chunks) throws IOException {
+        if (chunks.isEmpty()) {
+            throw new FileNotFoundException("No chunks");
+        }
+        List<RepositoryChunk> l = new ArrayList<>(chunks.size());
+        for (RepositoryChunk c : chunks) {
+            c.use(); // keep alive while we're reading.
+            l.add(c);
+        }
+        this.chunks = l.iterator();
+        nextChannel();
+    }
+
+    private boolean nextChunk() {
+        if (!chunks.hasNext()) {
+            return false;
+        }
+        current = chunks.next();
+        return true;
+    }
+
+    private boolean nextChannel() throws IOException {
+        if (!nextChunk()) {
+            return false;
+        }
+
+        channel = current.newChannel();
+        return true;
+    }
+
+    @Override
+    public int read(ByteBuffer dst) throws IOException {
+        for (;;) {
+            if (channel != null) {
+                assert current != null;
+                int r = channel.read(dst);
+                if (r != -1) {
+                    return r;
+                }
+                channel.close();
+                current.release();
+                channel = null;
+                current = null;
+            }
+            if (!nextChannel()) {
+                return -1;
+            }
+        }
+    }
+
+    public long transferTo(FileChannel out) throws IOException {
+        long pos = 0;
+        for (;;) {
+            if (channel != null) {
+                assert current != null;
+
+                long rem = current.getSize();
+
+                while (rem > 0) {
+                    long n = Math.min(rem, 1024 * 1024);
+                    long w = out.transferFrom(channel, pos, n);
+                    pos += w;
+                    rem -= w;
+                }
+
+                channel.close();
+                current.release();
+
+                channel = null;
+                current = null;
+            }
+            if (!nextChannel()) {
+                return pos;
+            }
+        }
+    }
+
+    @Override
+    public void close() throws IOException {
+        if (channel != null) {
+            channel.close();
+            channel = null;
+        }
+        while (current != null) {
+            current.release();
+            current = null;
+            if (!nextChunk()) {
+                return;
+            }
+        }
+    }
+
+    @Override
+    public boolean isOpen() {
+        return channel != null;
+    }
+
+    @Override
+    @SuppressWarnings("deprecation")
+    protected void finalize() throws Throwable {
+        super.finalize();
+        close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/Control.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+
+// User must never be able to subclass directly.
+//
+// Never put Control or Setting Control in a collections
+// so overridable versions of hashCode or equals are
+// executed in the wrong context. TODO: wrap this class
+// in SsecureControl directly when it is instantiated and
+// forward calls using AccessControlContext
+abstract public class Control {
+    private final AccessControlContext context;
+    private final static int CACHE_SIZE = 5;
+    private final Set<?>[] cachedUnions = new HashSet<?>[CACHE_SIZE];
+    private final String[] cachedValues = new String[CACHE_SIZE];
+    private String defaultValue;
+    private String lastValue;
+
+    // called by exposed subclass in external API
+    public Control(AccessControlContext acc) {
+        Objects.requireNonNull(acc);
+        this.context = acc;
+
+    }
+
+    // only to be called by trusted VM code
+    public Control(String defaultValue) {
+        this.defaultValue = defaultValue;
+        this.context = null;
+    }
+
+    // For user code to override, must never be called from jdk.jfr.internal
+    // for user defined settings
+    public abstract String combine(Set<String> values);
+
+    // For user code to override, must never be called from jdk.jfr.internal
+    // for user defined settings
+    public abstract void setValue(String value);
+
+    // For user code to override, must never be called from jdk.jfr.internal
+    // for user defined settings
+    public abstract String getValue();
+
+      // Package private, user code should not have access to this method
+    final void apply(Set<String> values) {
+        setValueSafe(findCombineSafe(values));
+    }
+
+    // Package private, user code should not have access to this method.
+    // Only called during event registration
+    final void setDefault() {
+        if (defaultValue == null) {
+            defaultValue = getValueSafe();
+        }
+        apply(defaultValue);
+    }
+
+    final String getValueSafe() {
+        if (context == null) {
+            // VM events requires no access control context
+            return getValue();
+        } else {
+            return AccessController.doPrivileged(new PrivilegedAction<String>() {
+                @Override
+                public String run() {
+                    try {
+                        return getValue();
+                    } catch (Throwable t) {
+                        // Prevent malicious user to propagate exception callback in the wrong context
+                        Logger.log(LogTag.JFR_SETTING, LogLevel.WARN, "Exception occured when trying to get value for " + getClass());
+                    }
+                    return defaultValue != null ? defaultValue : ""; // Need to return something
+                }
+            }, context);
+        }
+    }
+
+    private void apply(String value) {
+        if (lastValue != null && Objects.equals(value, lastValue)) {
+            return;
+        }
+        setValueSafe(value);
+    }
+
+    final void setValueSafe(String value) {
+        if (context == null) {
+            // VM events requires no access control context
+            try {
+                setValue(value);
+            } catch (Throwable t) {
+                Logger.log(LogTag.JFR_SETTING, LogLevel.WARN, "Exception occured when setting value \"" + value + "\" for " + getClass());
+            }
+        } else {
+            AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                @Override
+                public Void run() {
+                    try {
+                        setValue(value);
+                    } catch (Throwable t) {
+                        // Prevent malicious user to propagate exception callback in the wrong context
+                        Logger.log(LogTag.JFR_SETTING, LogLevel.WARN, "Exception occured when setting value \"" + value + "\" for " + getClass());
+                    }
+                    return null;
+                }
+            }, context);
+        }
+        lastValue = value;
+    }
+
+
+    private String combineSafe(Set<String> values) {
+        if (context == null) {
+            // VM events requires no access control context
+            return combine(values);
+        }
+        return AccessController.doPrivileged(new PrivilegedAction<String>() {
+            @Override
+            public String run() {
+                try {
+                    combine(Collections.unmodifiableSet(values));
+                } catch (Throwable t) {
+                    // Prevent malicious user to propagate exception callback in the wrong context
+                    Logger.log(LogTag.JFR_SETTING, LogLevel.WARN, "Exception occured when combining " + values + " for " + getClass());
+                }
+                return null;
+            }
+        }, context);
+    }
+
+    private final String findCombineSafe(Set<String> values) {
+        if (values.size() == 1) {
+            return values.iterator().next();
+        }
+        for (int i = 0; i < CACHE_SIZE; i++) {
+            if (Objects.equals(cachedUnions[i], values)) {
+                return cachedValues[i];
+            }
+        }
+        String result = combineSafe(values);
+        for (int i = 0; i < CACHE_SIZE - 1; i++) {
+            cachedUnions[i + 1] = cachedUnions[i];
+            cachedValues[i + 1] = cachedValues[i];
+        }
+        cachedValues[0] = result;
+        cachedUnions[0] = values;
+        return result;
+    }
+
+
+    // package private, user code should not have access to this method
+    final String getDefaultValue() {
+        return defaultValue;
+    }
+
+    // package private, user code should not have access to this method
+    final String getLastValue() {
+        return lastValue;
+    }
+
+    // Precaution to prevent a malicious user from instantiating instances
+    // of a control where the context has not been set up.
+    @Override
+    public final Object clone() throws java.lang.CloneNotSupportedException {
+        throw new CloneNotSupportedException();
+    }
+
+    private final void writeObject(ObjectOutputStream out) throws IOException {
+        throw new IOException("Object cannot be serialized");
+    }
+
+    private final void readObject(ObjectInputStream in) throws IOException {
+        throw new IOException("Class cannot be deserialized");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/Cutoff.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import jdk.jfr.MetadataDefinition;
+
+/**
+ * Event annotation, determines the cutoff above which an event should not be
+ * recorded, i.e. {@code "20 ms"}.
+ *
+ * This settings is only supported for JVM events,
+ *
+ * @since 9
+ */
+@MetadataDefinition
+@Target({ ElementType.TYPE })
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Cutoff {
+    /**
+     * Settings name {@code "cutoff"} for configuring event cutoffs.
+     */
+    public final static String NAME = "cutoff";
+    public final static String INIFITY = "infinity";
+
+    /**
+     * Cutoff, for example {@code "20 ms"}.
+     * <p>
+     * String representation of a positive {@code Long} value followed by an empty
+     * space and one of the following units<br>
+     * <br>
+     * {@code "ns"} (nanoseconds)<br>
+     * {@code "us"} (microseconds)<br>
+     * {@code "ms"} (milliseconds)<br>
+     * {@code "s"} (seconds)<br>
+     * {@code "m"} (minutes)<br>
+     * {@code "h"} (hours)<br>
+     * {@code "d"} (days)<br>
+     * <p>
+     * Example values, {@code "0 ns"}, {@code "10 ms"} and {@code "1 s"}. If the
+     * events has an infinite timespan, the text {@code"infinity"} should be used.
+     *
+     * @return the threshold, default {@code "0 ns"} not {@code null}
+     */
+    String value() default "inifity";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventClassBuilder.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
+
+import jdk.internal.org.objectweb.asm.AnnotationVisitor;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.Label;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.internal.org.objectweb.asm.Type;
+import jdk.internal.org.objectweb.asm.commons.GeneratorAdapter;
+import jdk.internal.org.objectweb.asm.commons.Method;
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.Event;
+import jdk.jfr.ValueDescriptor;
+
+
+// Helper class for building dynamic events
+public final class EventClassBuilder {
+
+    private static final Type TYPE_EVENT = Type.getType(Event.class);
+    private static final Type TYPE_IOBE = Type.getType(IndexOutOfBoundsException.class);
+    private static final Method DEFAULT_CONSTRUCTOR = Method.getMethod("void <init> ()");
+    private static final Method SET_METHOD = Method.getMethod("void set (int, java.lang.Object)");
+    private static final AtomicLong idCounter = new AtomicLong();
+    private final ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
+    private final String fullClassName;
+    private final Type type;
+    private final List<ValueDescriptor> fields;
+    private final List<AnnotationElement> annotationElements;
+
+    public EventClassBuilder(List<AnnotationElement> annotationElements, List<ValueDescriptor> fields) {
+        this.fullClassName = "jdk.jfr.DynamicEvent" + idCounter.incrementAndGet();
+        this.type = Type.getType(fullClassName.replace(".", "/"));
+        this.fields = fields;
+        this.annotationElements = annotationElements;
+    }
+
+    public Class<? extends Event> build() {
+        buildClassInfo();
+        buildConstructor();
+        buildFields();
+        buildSetMethod();
+        endClass();
+        byte[] bytes = classWriter.toByteArray();
+        ASMToolkit.logASM(fullClassName, bytes);
+        return SecuritySupport.defineClass(type.getInternalName(), bytes, Event.class.getClassLoader()).asSubclass(Event.class);
+    }
+
+    private void endClass() {
+        classWriter.visitEnd();
+    }
+
+    private void buildSetMethod() {
+        GeneratorAdapter ga = new GeneratorAdapter(Opcodes.ACC_PUBLIC, SET_METHOD, null, null, classWriter);
+        int index = 0;
+        for (ValueDescriptor v : fields) {
+            ga.loadArg(0);
+            ga.visitLdcInsn(index);
+            Label notEqual = new Label();
+            ga.ifICmp(GeneratorAdapter.NE, notEqual);
+            ga.loadThis();
+            ga.loadArg(1);
+            Type fieldType = ASMToolkit.toType(v);
+            ga.unbox(ASMToolkit.toType(v));
+            ga.putField(type, v.getName(), fieldType);
+            ga.visitInsn(Opcodes.RETURN);
+            ga.visitLabel(notEqual);
+            index++;
+        }
+        ga.throwException(TYPE_IOBE, "Index must between 0 and " + fields.size());
+        ga.endMethod();
+    }
+
+    private void buildConstructor() {
+        MethodVisitor mv = classWriter.visitMethod(Opcodes.ACC_PUBLIC, DEFAULT_CONSTRUCTOR.getName(), DEFAULT_CONSTRUCTOR.getDescriptor(), null, null);
+        mv.visitIntInsn(Opcodes.ALOAD, 0);
+        ASMToolkit.invokeSpecial(mv, TYPE_EVENT.getInternalName(), DEFAULT_CONSTRUCTOR);
+        mv.visitInsn(Opcodes.RETURN);
+        mv.visitMaxs(0, 0);
+    }
+
+    private void buildClassInfo() {
+        String internalSuperName = ASMToolkit.getInternalName(Event.class.getName());
+        String internalClassName = type.getInternalName();
+        classWriter.visit(52, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER, internalClassName, null, internalSuperName, null);
+
+        for (AnnotationElement a : annotationElements) {
+            String descriptor = ASMToolkit.getDescriptor(a.getTypeName());
+            AnnotationVisitor av = classWriter.visitAnnotation(descriptor, true);
+            for (ValueDescriptor v : a.getValueDescriptors()) {
+                Object value = a.getValue(v.getName());
+                String name = v.getName();
+                if (v.isArray()) {
+                    AnnotationVisitor arrayVisitor = av.visitArray(name);
+                    Object[] array = (Object[]) value;
+                    for (int i = 0; i < array.length; i++) {
+                        arrayVisitor.visit(null, array[i]);
+                    }
+                    arrayVisitor.visitEnd();
+                } else {
+                    av.visit(name, value);
+                }
+            }
+            av.visitEnd();
+        }
+    }
+
+    private void buildFields() {
+        for (ValueDescriptor v : fields) {
+            String internal = ASMToolkit.getDescriptor(v.getTypeName());
+            classWriter.visitField(Opcodes.ACC_PRIVATE, v.getName(), internal, null, null);
+            // No need to store annotations on field since they will be replaced anyway.
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventControl.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import jdk.internal.module.Modules;
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.Enabled;
+import jdk.jfr.Event;
+import jdk.jfr.Name;
+import jdk.jfr.Period;
+import jdk.jfr.SettingControl;
+import jdk.jfr.SettingDefinition;
+import jdk.jfr.StackTrace;
+import jdk.jfr.Threshold;
+import jdk.jfr.events.ActiveSettingEvent;
+import jdk.jfr.internal.EventInstrumentation.SettingInfo;
+import jdk.jfr.internal.settings.CutoffSetting;
+import jdk.jfr.internal.settings.EnabledSetting;
+import jdk.jfr.internal.settings.PeriodSetting;
+import jdk.jfr.internal.settings.StackTraceSetting;
+import jdk.jfr.internal.settings.ThresholdSetting;
+
+// This class can't have a hard reference from PlatformEventType, since it
+// holds SettingControl instances that need to be released
+// when a class is unloaded (to avoid memory leaks).
+public final class EventControl {
+
+    static final String FIELD_SETTING_PREFIX = "setting";
+    private static final Type TYPE_ENABLED = TypeLibrary.createType(EnabledSetting.class);
+    private static final Type TYPE_THRESHOLD = TypeLibrary.createType(ThresholdSetting.class);
+    private static final Type TYPE_STACK_TRACE = TypeLibrary.createType(StackTraceSetting.class);
+    private static final Type TYPE_PERIOD = TypeLibrary.createType(PeriodSetting.class);
+    private static final Type TYPE_CUTOFF = TypeLibrary.createType(CutoffSetting.class);
+
+    private final List<SettingInfo> settingInfos = new ArrayList<>();
+    private final Map<String, Control> eventControls = new HashMap<>(5);
+    private final PlatformEventType type;
+    private final String idName;
+
+    EventControl(PlatformEventType eventType) {
+        eventControls.put(Enabled.NAME, defineEnabled(eventType));
+        if (eventType.hasDuration()) {
+            eventControls.put(Threshold.NAME, defineThreshold(eventType));
+        }
+        if (eventType.hasStackTrace()) {
+            eventControls.put(StackTrace.NAME, defineStackTrace(eventType));
+        }
+        if (eventType.hasPeriod()) {
+            eventControls.put(Period.NAME, definePeriod(eventType));
+        }
+        if (eventType.hasCutoff()) {
+            eventControls.put(Cutoff.NAME, defineCutoff(eventType));
+        }
+
+        ArrayList<AnnotationElement> aes = new ArrayList<>(eventType.getAnnotationElements());
+        remove(eventType, aes, Threshold.class);
+        remove(eventType, aes, Period.class);
+        remove(eventType, aes, Enabled.class);
+        remove(eventType, aes, StackTrace.class);
+        remove(eventType, aes, Cutoff.class);
+        aes.trimToSize();
+        eventType.setAnnotations(aes);
+        this.type = eventType;
+        this.idName = String.valueOf(eventType.getId());
+    }
+
+    static void remove(PlatformEventType type, List<AnnotationElement> aes, Class<? extends java.lang.annotation.Annotation> clazz) {
+        long id = Type.getTypeId(clazz);
+        for (AnnotationElement a : type.getAnnotationElements()) {
+            if (a.getTypeId() == id && a.getTypeName().equals(clazz.getName())) {
+                aes.remove(a);
+            }
+        }
+    }
+
+    EventControl(PlatformEventType es, Class<? extends Event> eventClass) {
+        this(es);
+        defineSettings(eventClass);
+    }
+
+    @SuppressWarnings("unchecked")
+    private void defineSettings(Class<?> eventClass) {
+        // Iterate up the class hierarchy and let
+        // subclasses shadow base classes.
+        boolean allowPrivateMethod = true;
+        while (eventClass != null) {
+            for (Method m : eventClass.getDeclaredMethods()) {
+                boolean isPrivate = Modifier.isPrivate(m.getModifiers());
+                if (m.getReturnType() == Boolean.TYPE && m.getParameterCount() == 1 && (!isPrivate || allowPrivateMethod)) {
+                    SettingDefinition se = m.getDeclaredAnnotation(SettingDefinition.class);
+                    if (se != null) {
+                        Class<?> settingClass = m.getParameters()[0].getType();
+                        if (!Modifier.isAbstract(settingClass.getModifiers()) && SettingControl.class.isAssignableFrom(settingClass)) {
+                            String name = m.getName();
+                            Name n = m.getAnnotation(Name.class);
+                            if (n != null) {
+                                name = n.value();
+                            }
+                            if (!eventControls.containsKey(name)) {
+                                defineSetting((Class<? extends SettingControl>) settingClass, m, type, name);
+                            }
+                        }
+                    }
+                }
+            }
+            eventClass = eventClass.getSuperclass();
+            allowPrivateMethod = false;
+        }
+    }
+
+    private void defineSetting(Class<? extends SettingControl> settingsClass, Method method, PlatformEventType eventType, String settingName) {
+        try {
+            Module settingModule = settingsClass.getModule();
+            Modules.addReads(settingModule, EventControl.class.getModule());
+            int index = settingInfos.size();
+            SettingInfo si = new SettingInfo(FIELD_SETTING_PREFIX + index, index);
+            si.settingControl = instantiateSettingControl(settingsClass);
+            Control c = si.settingControl;
+            c.setDefault();
+            String defaultValue = c.getValueSafe();
+            if (defaultValue != null) {
+                Type settingType = TypeLibrary.createType(settingsClass);
+                ArrayList<AnnotationElement> aes = new ArrayList<>();
+                for (Annotation a : method.getDeclaredAnnotations()) {
+                    AnnotationElement ae = TypeLibrary.createAnnotation(a);
+                    if (ae != null) {
+                        aes.add(ae);
+                    }
+                }
+                aes.trimToSize();
+                eventControls.put(settingName, si.settingControl);
+                eventType.add(PrivateAccess.getInstance().newSettingDescriptor(settingType, settingName, defaultValue, aes));
+                settingInfos.add(si);
+            }
+        } catch (InstantiationException e) {
+            // Programming error by user, fail fast
+            throw new InstantiationError("Could not instantiate setting " + settingsClass.getName() + " for event " + eventType.getLogName() + ". " + e.getMessage());
+        } catch (IllegalAccessException e) {
+            // Programming error by user, fail fast
+            throw new IllegalAccessError("Could not access setting " + settingsClass.getName() + " for event " + eventType.getLogName() + ". " + e.getMessage());
+        }
+    }
+
+    private SettingControl instantiateSettingControl(Class<? extends SettingControl> settingControlClass) throws IllegalAccessException, InstantiationException {
+        SecuritySupport.makeVisibleToJFR(settingControlClass);
+        final Constructor<?> cc;
+        try {
+            cc = settingControlClass.getDeclaredConstructors()[0];
+        } catch (Exception e) {
+            throw (Error) new InternalError("Could not get constructor for " + settingControlClass.getName()).initCause(e);
+        }
+        SecuritySupport.setAccessible(cc);
+        try {
+            return (SettingControl) cc.newInstance();
+        } catch (IllegalArgumentException | InvocationTargetException e) {
+            throw (Error) new InternalError("Could not instantiate setting for class " + settingControlClass.getName());
+        }
+    }
+
+    private static Control defineEnabled(PlatformEventType type) {
+        Enabled enabled = type.getAnnotation(Enabled.class);
+        // Java events are enabled by default,
+        // JVM events are not, maybe they should be? Would lower learning curve
+        // there too.
+        String def = type.isJVM() ? "false" : "true";
+        if (enabled != null) {
+            def = Boolean.toString(enabled.value());
+        }
+        type.add(PrivateAccess.getInstance().newSettingDescriptor(TYPE_ENABLED, Enabled.NAME, def, Collections.emptyList()));
+        return new EnabledSetting(type, def);
+    }
+
+    private static Control defineThreshold(PlatformEventType type) {
+        Threshold threshold = type.getAnnotation(Threshold.class);
+        String def = "0 ns";
+        if (threshold != null) {
+            def = threshold.value();
+        }
+        type.add(PrivateAccess.getInstance().newSettingDescriptor(TYPE_THRESHOLD, Threshold.NAME, def, Collections.emptyList()));
+        return new ThresholdSetting(type, def);
+    }
+
+    private static Control defineStackTrace(PlatformEventType type) {
+        StackTrace stackTrace = type.getAnnotation(StackTrace.class);
+        String def = "true";
+        if (stackTrace != null) {
+            def = Boolean.toString(stackTrace.value());
+        }
+        type.add(PrivateAccess.getInstance().newSettingDescriptor(TYPE_STACK_TRACE, StackTrace.NAME, def, Collections.emptyList()));
+        return new StackTraceSetting(type, def);
+    }
+
+    private static Control defineCutoff(PlatformEventType type) {
+        Cutoff cutoff = type.getAnnotation(Cutoff.class);
+        String def = Cutoff.INIFITY;
+        if (cutoff != null) {
+            def = cutoff.value();
+        }
+        type.add(PrivateAccess.getInstance().newSettingDescriptor(TYPE_CUTOFF, Cutoff.NAME, def, Collections.emptyList()));
+        return new CutoffSetting(type, def);
+    }
+
+
+    private static Control definePeriod(PlatformEventType type) {
+        Period period = type.getAnnotation(Period.class);
+        String def = "everyChunk";
+        if (period != null) {
+            def = period.value();
+        }
+        type.add(PrivateAccess.getInstance().newSettingDescriptor(TYPE_PERIOD, PeriodSetting.NAME, def, Collections.emptyList()));
+        return new PeriodSetting(type, def);
+    }
+
+    void disable() {
+        for (Control c : eventControls.values()) {
+            if (c instanceof EnabledSetting) {
+                c.setValueSafe("false");
+                return;
+            }
+        }
+    }
+
+    void writeActiveSettingEvent() {
+        if (!type.isRegistered()) {
+            return;
+        }
+        for (Map.Entry<String, Control> entry : eventControls.entrySet()) {
+            Control c = entry.getValue();
+            if (Utils.isSettingVisible(c, type.hasEventHook())) {
+                String value = c.getLastValue();
+                if (value == null) {
+                    value = c.getDefaultValue();
+                }
+                ActiveSettingEvent ase = new ActiveSettingEvent();
+                ase.id = type.getId();
+                ase.name = entry.getKey();
+                ase.value = value;
+                ase.commit();
+            }
+        }
+    }
+
+    public Set<Entry<String, Control>> getEntries() {
+        return eventControls.entrySet();
+    }
+
+    public PlatformEventType getEventType() {
+        return type;
+    }
+
+    public String getSettingsId() {
+        return idName;
+    }
+
+    public List<SettingInfo> getSettingInfos() {
+        return settingInfos;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventHandlerCreator.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringJoiner;
+
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.Label;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.internal.org.objectweb.asm.Type;
+import jdk.internal.org.objectweb.asm.commons.Method;
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.SettingControl;
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.internal.EventInstrumentation.FieldInfo;
+import jdk.jfr.internal.EventInstrumentation.SettingInfo;
+import jdk.jfr.internal.handlers.EventHandler;
+
+final class EventHandlerCreator {
+    // TODO:
+    // How can we find out class version without loading a
+    // class as resource in a privileged block and use ASM to inspect
+    // the contents. Using '52' even though we know later versions
+    // are available. The reason for this is compatibility aspects
+    // with for example WLS.
+    private static final int CLASS_VERSION = 52;
+
+    // This is needed so a new EventHandler is automatically generated in MetadataRespoistory
+    // if a user Event class is loaded using APPCDS/CDS.
+    private static final String SUFFIX  = "_" + System.currentTimeMillis() + "-" + JVM.getJVM().getPid();
+
+    private static final String FIELD_EVENT_TYPE = "platformEventType";
+    private static final String FIELD_PREFIX_STRING_POOL = "stringPool";
+
+    private final static Type TYPE_STRING_POOL = Type.getType(StringPool.class);
+    private final static Type TYPE_EVENT_WRITER = Type.getType(EventWriter.class);
+    private final static Type TYPE_PLATFORM_EVENT_TYPE = Type.getType(PlatformEventType.class);
+    private final static Type TYPE_EVENT_HANDLER = Type.getType(EventHandler.class);
+    private final static Type TYPE_SETTING_CONTROL = Type.getType(SettingControl.class);
+    private final static Type TYPE_EVENT_TYPE = Type.getType(EventType.class);
+    private final static Type TYPE_EVENT_CONTROL = Type.getType(EventControl.class);
+    private final static String DESCRIPTOR_EVENT_HANDLER = "(" + Type.BOOLEAN_TYPE.getDescriptor() + TYPE_EVENT_TYPE.getDescriptor() + TYPE_EVENT_CONTROL.getDescriptor() + ")V";
+    private final static Method METHOD_GET_EVENT_WRITER = new Method("getEventWriter", "()" + TYPE_EVENT_WRITER.getDescriptor());
+    private final static Method METHOD_EVENT_HANDLER_CONSTRUCTOR = new Method("<init>", DESCRIPTOR_EVENT_HANDLER);
+    private final static Method METHOD_RESET = new Method("reset", "()V");
+
+    private final ClassWriter classWriter;
+    private final String className;
+    private final String internalClassName;
+    private final List<SettingInfo> settingInfos;
+    private final List<FieldInfo> fields;
+
+    public EventHandlerCreator(long id, List<SettingInfo> settingInfos, List<FieldInfo> fields) {
+        this.classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
+        this.className = makeEventHandlerName(id);
+        this.internalClassName = ASMToolkit.getInternalName(className);
+        this.settingInfos = settingInfos;
+        this.fields = fields;
+    }
+
+    public static String makeEventHandlerName(long id) {
+        return EventHandler.class.getName() + id + SUFFIX;
+    }
+
+    public EventHandlerCreator(long id, List<SettingInfo> settingInfos, EventType type, Class<? extends Event> eventClass) {
+        this(id, settingInfos, createFieldInfos(eventClass, type));
+    }
+
+    private static List<FieldInfo> createFieldInfos(Class<? extends Event> eventClass, EventType type) throws Error {
+        List<FieldInfo> fieldInfos = new ArrayList<>();
+        for (ValueDescriptor v : type.getFields()) {
+            // Only value descriptors that are not fields on the event class.
+            if (v != TypeLibrary.STACK_TRACE_FIELD && v != TypeLibrary.THREAD_FIELD) {
+                String fieldName = PrivateAccess.getInstance().getFieldName(v);
+                String fieldDescriptor = ASMToolkit.getDescriptor(v.getTypeName());
+                Class<?> c = eventClass;
+                String internalName = null;
+                while (c != Event.class) {
+                    try {
+                        Field field = c.getDeclaredField(fieldName);
+                        if (c == eventClass || !Modifier.isPrivate(field.getModifiers())) {
+                            internalName = ASMToolkit.getInternalName(c.getName());
+                            break;
+                        }
+                    } catch (NoSuchFieldException | SecurityException e) {
+                        // ignore
+                    }
+                    c = c.getSuperclass();
+                }
+                if (internalName != null) {
+                    fieldInfos.add(new FieldInfo(fieldName, fieldDescriptor, internalName));
+                } else {
+                    throw new InternalError("Could not locate field " + fieldName + " for event type" + type.getName());
+                }
+            }
+        }
+        return fieldInfos;
+    }
+
+    public Class<? extends EventHandler> makeEventHandlerClass() {
+        buildClassInfo();
+        buildConstructor();
+        buildWriteMethod();
+        byte[] bytes = classWriter.toByteArray();
+        ASMToolkit.logASM(className, bytes);
+        return SecuritySupport.defineClass(className, bytes, Event.class.getClassLoader()).asSubclass(EventHandler.class);
+    }
+
+    public static EventHandler instantiateEventHandler(Class<? extends EventHandler> handlerClass, boolean registered, EventType eventType, EventControl eventControl) throws Error {
+        final Constructor<?> cc;
+        try {
+            cc = handlerClass.getDeclaredConstructors()[0];
+        } catch (Exception e) {
+            throw (Error) new InternalError("Could not get handler constructor for " + eventType.getName()).initCause(e);
+        }
+        // Users should not be allowed to create instances of the event handler
+        // so we need to unlock it here.
+        SecuritySupport.setAccessible(cc);
+        try {
+            List<SettingInfo> settingInfos = eventControl.getSettingInfos();
+            Object[] arguments = new Object[3 + settingInfos.size()];
+            arguments[0] = registered;
+            arguments[1] = eventType;
+            arguments[2] = eventControl;
+            for (SettingInfo si : settingInfos) {
+                arguments[si.index + 3] = si.settingControl;
+            }
+            return (EventHandler) cc.newInstance(arguments);
+        } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+            throw (Error) new InternalError("Could not instantiate event handler for " + eventType.getName() + ". " + e.getMessage()).initCause(e);
+        }
+    }
+
+    private void buildConstructor() {
+        MethodVisitor mv = classWriter.visitMethod(Opcodes.ACC_PRIVATE, METHOD_EVENT_HANDLER_CONSTRUCTOR.getName(), makeConstructorDescriptor(settingInfos), null, null);
+        mv.visitVarInsn(Opcodes.ALOAD, 0); // this
+        mv.visitVarInsn(Opcodes.ILOAD, 1); // registered
+        mv.visitVarInsn(Opcodes.ALOAD, 2); // event type
+        mv.visitVarInsn(Opcodes.ALOAD, 3); // event control
+        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(EventHandler.class), METHOD_EVENT_HANDLER_CONSTRUCTOR.getName(), METHOD_EVENT_HANDLER_CONSTRUCTOR.getDescriptor(), false);
+        for (SettingInfo si : settingInfos) {
+            mv.visitVarInsn(Opcodes.ALOAD, 0); // this
+            mv.visitVarInsn(Opcodes.ALOAD, si.index + 4); // Setting Control
+            mv.visitFieldInsn(Opcodes.PUTFIELD, internalClassName, si.fieldName, TYPE_SETTING_CONTROL.getDescriptor());
+        }
+        // initialized string field writers
+        int fieldIndex = 0;
+        for (FieldInfo field : fields) {
+            if (field.isString()) {
+                mv.visitVarInsn(Opcodes.ALOAD, 0);
+                mv.visitVarInsn(Opcodes.ALOAD, 0);
+                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(EventHandler.class), "createStringFieldWriter", "()" + TYPE_STRING_POOL.getDescriptor(), false);
+                mv.visitFieldInsn(Opcodes.PUTFIELD, internalClassName, FIELD_PREFIX_STRING_POOL + fieldIndex, TYPE_STRING_POOL.getDescriptor());
+            }
+            fieldIndex++;
+        }
+        mv.visitInsn(Opcodes.RETURN);
+        mv.visitMaxs(0, 0);
+        mv.visitEnd();
+    }
+
+    private void buildClassInfo() {
+        String internalSuperName = ASMToolkit.getInternalName(EventHandler.class.getName());
+        classWriter.visit(CLASS_VERSION, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER, internalClassName, null, internalSuperName, null);
+        for (SettingInfo si : settingInfos) {
+            classWriter.visitField(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL, si.fieldName, TYPE_SETTING_CONTROL.getDescriptor(), null, null);
+        }
+        int fieldIndex = 0;
+        for (FieldInfo field : fields) {
+            if (field.isString()) {
+                classWriter.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, FIELD_PREFIX_STRING_POOL+ fieldIndex, TYPE_STRING_POOL.getDescriptor(), null, null);
+            }
+            fieldIndex++;
+        }
+    }
+
+    private void visitMethod(final MethodVisitor mv, final int opcode, final Type type, final Method method) {
+        mv.visitMethodInsn(opcode, type.getInternalName(), method.getName(), method.getDescriptor(), false);
+    }
+
+    private void buildWriteMethod() {
+        int argIndex = 0; // // indexes the argument type array, the argument type array does not include 'this'
+        int slotIndex = 1; // indexes the proper slot in the local variable table, takes type size into account, therefore sometimes argIndex != slotIndex
+        int fieldIndex = 0;
+        Method desc = ASMToolkit.makeWriteMethod(fields);
+        Type[] argumentTypes = Type.getArgumentTypes(desc.getDescriptor());
+        MethodVisitor mv = classWriter.visitMethod(Opcodes.ACC_PUBLIC, desc.getName(), desc.getDescriptor(), null, null);
+        mv.visitCode();
+        Label start = new Label();
+        Label endTryBlock = new Label();
+        Label exceptionHandler = new Label();
+        mv.visitTryCatchBlock(start, endTryBlock, exceptionHandler, "java/lang/Throwable");
+        mv.visitLabel(start);
+        visitMethod(mv, Opcodes.INVOKESTATIC, TYPE_EVENT_WRITER, METHOD_GET_EVENT_WRITER);
+        // stack: [BW]
+        mv.visitInsn(Opcodes.DUP);
+        // stack: [BW], [BW]
+        // write begin event
+        mv.visitVarInsn(Opcodes.ALOAD, 0);
+        // stack: [BW], [BW], [this]
+        mv.visitFieldInsn(Opcodes.GETFIELD, TYPE_EVENT_HANDLER.getInternalName(), FIELD_EVENT_TYPE, TYPE_PLATFORM_EVENT_TYPE.getDescriptor());
+        // stack: [BW], [BW], [BS]
+        visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.BEGIN_EVENT.asASM());
+        // stack: [BW], [integer]
+        Label recursive = new Label();
+        mv.visitJumpInsn(Opcodes.IFEQ, recursive);
+        // stack: [BW]
+        // write startTime
+        mv.visitInsn(Opcodes.DUP);
+        // stack: [BW], [BW]
+        mv.visitVarInsn(argumentTypes[argIndex].getOpcode(Opcodes.ILOAD), slotIndex);
+        // stack: [BW], [BW], [long]
+        slotIndex += argumentTypes[argIndex++].getSize();
+        visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.PUT_LONG.asASM());
+        // stack: [BW]
+        fieldIndex++;
+        // write duration
+        mv.visitInsn(Opcodes.DUP);
+        // stack: [BW], [BW]
+        mv.visitVarInsn(argumentTypes[argIndex].getOpcode(Opcodes.ILOAD), slotIndex);
+        // stack: [BW], [BW], [long]
+        slotIndex += argumentTypes[argIndex++].getSize();
+        visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.PUT_LONG.asASM());
+        // stack: [BW]
+        fieldIndex++;
+        // write eventThread
+        mv.visitInsn(Opcodes.DUP);
+        // stack: [BW], [BW]
+        visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.PUT_EVENT_THREAD.asASM());
+        // stack: [BW]
+        // write stackTrace
+        mv.visitInsn(Opcodes.DUP);
+        // stack: [BW], [BW]
+        visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.PUT_STACK_TRACE.asASM());
+        // stack: [BW]
+        // write custom fields
+        while (fieldIndex < fields.size()) {
+            mv.visitInsn(Opcodes.DUP);
+            // stack: [BW], [BW]
+            mv.visitVarInsn(argumentTypes[argIndex].getOpcode(Opcodes.ILOAD), slotIndex);
+            // stack:[BW], [BW], [field]
+            slotIndex += argumentTypes[argIndex++].getSize();
+            FieldInfo field = fields.get(fieldIndex);
+            if (field.isString()) {
+                mv.visitVarInsn(Opcodes.ALOAD, 0);
+                // stack:[BW], [BW], [field], [this]
+                mv.visitFieldInsn(Opcodes.GETFIELD, this.internalClassName, FIELD_PREFIX_STRING_POOL + fieldIndex, TYPE_STRING_POOL.getDescriptor());
+                // stack:[BW], [BW], [field], [string]
+            }
+            EventWriterMethod eventMethod = EventWriterMethod.lookupMethod(field);
+            visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, eventMethod.asASM());
+            // stack: [BW]
+            fieldIndex++;
+        }
+        // stack: [BW]
+        // write end event (writer already on stack)
+        visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.END_EVENT.asASM());
+        // stack [integer]
+        // notified -> restart event write attempt
+        mv.visitJumpInsn(Opcodes.IFEQ, start);
+        // stack:
+        mv.visitLabel(endTryBlock);
+        Label end = new Label();
+        mv.visitJumpInsn(Opcodes.GOTO, end);
+        mv.visitLabel(exceptionHandler);
+        // stack: [ex]
+        mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/lang/Throwable"});
+        visitMethod(mv, Opcodes.INVOKESTATIC, TYPE_EVENT_WRITER, METHOD_GET_EVENT_WRITER);
+        // stack: [ex] [BW]
+        mv.visitInsn(Opcodes.DUP);
+        // stack: [ex] [BW] [BW]
+        Label rethrow = new Label();
+        mv.visitJumpInsn(Opcodes.IFNULL, rethrow);
+        // stack: [ex] [BW]
+        mv.visitInsn(Opcodes.DUP);
+        // stack: [ex] [BW] [BW]
+        visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, METHOD_RESET);
+        mv.visitLabel(rethrow);
+        // stack:[ex] [BW]
+        mv.visitFrame(Opcodes.F_SAME, 0, null, 2, new Object[] {"java/lang/Throwable", TYPE_EVENT_WRITER.getInternalName()});
+        mv.visitInsn(Opcodes.POP);
+        // stack:[ex]
+        mv.visitInsn(Opcodes.ATHROW);
+        mv.visitLabel(recursive);
+        // stack: [BW]
+        mv.visitFrame(Opcodes.F_SAME, 0, null, 1, new Object[] { TYPE_EVENT_WRITER.getInternalName()} );
+        mv.visitInsn(Opcodes.POP);
+        mv.visitLabel(end);
+        // stack:
+        mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
+        mv.visitInsn(Opcodes.RETURN);
+        mv.visitMaxs(0, 0);
+        mv.visitEnd();
+    }
+
+    private static String makeConstructorDescriptor(List<SettingInfo> settingsInfos) {
+        StringJoiner constructordescriptor = new StringJoiner("", "(", ")V");
+        constructordescriptor.add(Type.BOOLEAN_TYPE.getDescriptor());
+        constructordescriptor.add(Type.getType(EventType.class).getDescriptor());
+        constructordescriptor.add(Type.getType(EventControl.class).getDescriptor());
+        for (int i = 0; i < settingsInfos.size(); i++) {
+            constructordescriptor.add(TYPE_SETTING_CONTROL.getDescriptor());
+        }
+        return constructordescriptor.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,527 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Parameter;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Consumer;
+
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.Label;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.internal.org.objectweb.asm.Type;
+import jdk.internal.org.objectweb.asm.commons.Method;
+import jdk.internal.org.objectweb.asm.tree.AnnotationNode;
+import jdk.internal.org.objectweb.asm.tree.ClassNode;
+import jdk.internal.org.objectweb.asm.tree.FieldNode;
+import jdk.internal.org.objectweb.asm.tree.MethodNode;
+import jdk.jfr.Enabled;
+import jdk.jfr.Event;
+import jdk.jfr.Name;
+import jdk.jfr.Registered;
+import jdk.jfr.SettingControl;
+import jdk.jfr.SettingDefinition;
+import jdk.jfr.internal.handlers.EventHandler;
+
+/**
+ * Class responsible for adding instrumentation to a subclass of {@link Event}.
+ *
+ */
+public final class EventInstrumentation {
+    static final class SettingInfo {
+        private String methodName;
+        private String internalSettingName;
+        private String settingDescriptor;
+        final String fieldName;
+        final int index;
+        // Used when instantiating Setting
+        SettingControl settingControl;
+
+        public SettingInfo(String fieldName, int index) {
+            this.fieldName = fieldName;
+            this.index = index;
+        }
+    }
+
+    static final class FieldInfo {
+        private final static Type STRING = Type.getType(String.class);
+        final String fieldName;
+        final String fieldDescriptor;
+        final String internalClassName;
+
+        public FieldInfo(String fieldName, String fieldDescriptor, String internalClassName) {
+            this.fieldName = fieldName;
+            this.fieldDescriptor = fieldDescriptor;
+            this.internalClassName = internalClassName;
+        }
+
+        public boolean isString() {
+            return STRING.getDescriptor().equals(fieldDescriptor);
+        }
+    }
+
+    public static final String FIELD_EVENT_THREAD = "eventThread";
+    public static final String FIELD_STACK_TRACE = "stackTrace";
+    public static final String FIELD_DURATION = "duration";
+
+    static final String FIELD_EVENT_HANDLER = "eventHandler";
+    static final String FIELD_START_TIME = "startTime";
+
+    private static final Type ANNOTATION_TYPE_NAME = Type.getType(Name.class);
+    private static final Type ANNOTATION_TYPE_REGISTERED = Type.getType(Registered.class);
+    private static final Type ANNOTATION_TYPE_ENABLED = Type.getType(Enabled.class);
+    private static final Type TYPE_EVENT_HANDLER = Type.getType(EventHandler.class);
+    private static final Type TYPE_SETTING_CONTROL = Type.getType(SettingControl.class);
+    private static final Method METHOD_COMMIT = new Method("commit", Type.VOID_TYPE, new Type[0]);
+    private static final Method METHOD_BEGIN = new Method("begin", Type.VOID_TYPE, new Type[0]);
+    private static final Method METHOD_END = new Method("end", Type.VOID_TYPE, new Type[0]);
+    private static final Method METHOD_IS_ENABLED = new Method("isEnabled", Type.BOOLEAN_TYPE, new Type[0]);
+    private static final Method METHOD_TIME_STAMP = new Method("timestamp", Type.LONG_TYPE, new Type[0]);
+    private static final Method METHOD_EVENT_SHOULD_COMMIT = new Method("shouldCommit", Type.BOOLEAN_TYPE, new Type[0]);
+    private static final Method METHOD_EVENT_HANDLER_SHOULD_COMMIT = new Method("shouldCommit", Type.BOOLEAN_TYPE, new Type[] { Type.LONG_TYPE });
+    private static final Method METHOD_DURATION = new Method("duration", Type.LONG_TYPE, new Type[] { Type.LONG_TYPE });
+
+    private final ClassNode classNode;
+    private final List<SettingInfo> settingInfos;
+    private final List<FieldInfo> fieldInfos;;
+    private final Method writeMethod;
+    private final String eventHandlerXInternalName;
+    private final String eventName;
+    private boolean guardHandlerReference;
+    private Class<?> superClass;
+
+    EventInstrumentation(Class<?> superClass, byte[] bytes, long id) {
+        this.superClass = superClass;
+        this.classNode = createClassNode(bytes);
+        this.settingInfos = buildSettingInfos(superClass, classNode);
+        this.fieldInfos = buildFieldInfos(superClass, classNode);
+        this.writeMethod = makeWriteMethod(fieldInfos);
+        this.eventHandlerXInternalName = ASMToolkit.getInternalName(EventHandlerCreator.makeEventHandlerName(id));
+        String n =  annotationValue(classNode, ANNOTATION_TYPE_NAME.getDescriptor(), String.class);
+        this.eventName = n == null ? classNode.name.replace("/", ".") : n;
+
+    }
+
+    public String getClassName() {
+      return classNode.name.replace("/",".");
+    }
+
+    private ClassNode createClassNode(byte[] bytes) {
+        ClassNode classNode = new ClassNode();
+        ClassReader classReader = new ClassReader(bytes);
+        classReader.accept(classNode, 0);
+        return classNode;
+    }
+
+    boolean isRegistered() {
+        Boolean result = annotationValue(classNode, ANNOTATION_TYPE_REGISTERED.getDescriptor(), Boolean.class);
+        if (result != null) {
+            return result.booleanValue();
+        }
+        if (superClass != null) {
+            Registered r = superClass.getAnnotation(Registered.class);
+            if (r != null) {
+                return r.value();
+            }
+        }
+        return true;
+    }
+
+    boolean isEnabled() {
+        Boolean result = annotationValue(classNode, ANNOTATION_TYPE_ENABLED.getDescriptor(), Boolean.class);
+        if (result != null) {
+            return result.booleanValue();
+        }
+        if (superClass != null) {
+            Enabled e = superClass.getAnnotation(Enabled.class);
+            if (e != null) {
+                return e.value();
+            }
+        }
+        return true;
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T> T annotationValue(ClassNode classNode, String typeDescriptor, Class<?> type) {
+        if (classNode.visibleAnnotations != null) {
+            for (AnnotationNode a : classNode.visibleAnnotations) {
+                if (typeDescriptor.equals(a.desc)) {
+                    List<Object> values = a.values;
+                    if (values != null && values.size() == 2) {
+                        Object key = values.get(0);
+                        Object value = values.get(1);
+                        if (key instanceof String && value != null) {
+                            if (type == value.getClass()) {
+                                String keyName = (String) key;
+                                if ("value".equals(keyName)) {
+                                   return (T) value;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    private static List<SettingInfo> buildSettingInfos(Class<?> superClass, ClassNode classNode) {
+        Set<String> methodSet = new HashSet<>();
+        List<SettingInfo> settingInfos = new ArrayList<>();
+        String settingDescriptor = Type.getType(SettingDefinition.class).getDescriptor();
+        for (MethodNode m : classNode.methods) {
+            if (m.visibleAnnotations != null) {
+                for (AnnotationNode an : m.visibleAnnotations) {
+                    // We can't really validate the method at this
+                    // stage. We would need to check that the parameter
+                    // is an instance of SettingControl.
+                    if (settingDescriptor.equals(an.desc)) {
+                        Type returnType = Type.getReturnType(m.desc);
+                        if (returnType.equals(Type.getType(Boolean.TYPE))) {
+                            Type[] args = Type.getArgumentTypes(m.desc);
+                            if (args.length == 1) {
+                                Type paramType = args[0];
+                                String fieldName = EventControl.FIELD_SETTING_PREFIX + settingInfos.size();
+                                int index = settingInfos.size();
+                                SettingInfo si = new SettingInfo(fieldName, index);
+                                si.methodName = m.name;
+                                si.settingDescriptor = paramType.getDescriptor();
+                                si.internalSettingName = paramType.getInternalName();
+                                methodSet.add(m.name);
+                                settingInfos.add(si);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        for (Class<?> c = superClass; c != Event.class; c = c.getSuperclass()) {
+            for (java.lang.reflect.Method method : c.getDeclaredMethods()) {
+                if (!methodSet.contains(method.getName())) {
+                    // skip private method in base classes
+                    if (!Modifier.isPrivate(method.getModifiers())) {
+                        if (method.getReturnType().equals(Boolean.TYPE)) {
+                            if (method.getParameterCount() == 1) {
+                                Parameter param = method.getParameters()[0];
+                                Type paramType = Type.getType(param.getType());
+                                String fieldName = EventControl.FIELD_SETTING_PREFIX + settingInfos.size();
+                                int index = settingInfos.size();
+                                SettingInfo si = new SettingInfo(fieldName, index);
+                                si.methodName = method.getName();
+                                si.settingDescriptor = paramType.getDescriptor();
+                                si.internalSettingName = paramType.getInternalName();
+                                methodSet.add(method.getName());
+                                settingInfos.add(si);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return settingInfos;
+
+    }
+
+    private static List<FieldInfo> buildFieldInfos(Class<?> superClass, ClassNode classNode) {
+        Set<String> fieldSet = new HashSet<>();
+        List<FieldInfo> fieldInfos = new ArrayList<>(classNode.fields.size());
+        // These two field are added by native as transient so they will be
+        // ignored by the loop below.
+        // The benefit of adding them manually is that we can
+        // control in which order they occur and we can add @Name, @Description
+        // in Java, instead of in native. It also means code for adding implicit
+        // fields for native can be reused by Java.
+        fieldInfos.add(new FieldInfo("startTime", Type.LONG_TYPE.getDescriptor(), classNode.name));
+        fieldInfos.add(new FieldInfo("duration", Type.LONG_TYPE.getDescriptor(), classNode.name));
+        for (FieldNode field : classNode.fields) {
+            String className = Type.getType(field.desc).getClassName();
+            if (!fieldSet.contains(field.name) && isValidField(field.access, className)) {
+                FieldInfo fi = new FieldInfo(field.name, field.desc, classNode.name);
+                fieldInfos.add(fi);
+                fieldSet.add(field.name);
+            }
+        }
+        for (Class<?> c = superClass; c != Event.class; c = c.getSuperclass()) {
+            for (Field field : c.getDeclaredFields()) {
+                // skip private field in base classes
+                if (!Modifier.isPrivate(field.getModifiers())) {
+                    if (isValidField(field.getModifiers(), field.getType().getName())) {
+                        String fieldName = field.getName();
+                        if (!fieldSet.contains(fieldName)) {
+                            Type fieldType = Type.getType(field.getType());
+                            String internalClassName = ASMToolkit.getInternalName(c.getName());
+                            fieldInfos.add(new FieldInfo(fieldName, fieldType.getDescriptor(), internalClassName));
+                            fieldSet.add(fieldName);
+                        }
+                    }
+                }
+            }
+        }
+        return fieldInfos;
+    }
+
+    public static boolean isValidField(int access, String className) {
+        if (Modifier.isTransient(access) || Modifier.isStatic(access)) {
+            return false;
+        }
+        return jdk.jfr.internal.Type.isValidJavaFieldType(className);
+    }
+
+    public byte[] buildInstrumented() {
+        makeInstrumented();
+        return toByteArray();
+    }
+
+    private byte[] toByteArray() {
+        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
+        classNode.accept(cw);
+        cw.visitEnd();
+        byte[] result = cw.toByteArray();
+        Utils.writeGeneratedASM(classNode.name, result);
+        return result;
+    }
+
+    public byte[] builUninstrumented() {
+        makeUninstrumented();
+        return toByteArray();
+    }
+
+    private void makeInstrumented() {
+        // MyEvent#isEnabled()
+        updateMethod(METHOD_IS_ENABLED, methodVisitor -> {
+            Label nullLabel = new Label();
+            if (guardHandlerReference) {
+                methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, TYPE_EVENT_HANDLER.getDescriptor());
+                methodVisitor.visitJumpInsn(Opcodes.IFNULL, nullLabel);
+            }
+            methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, TYPE_EVENT_HANDLER.getDescriptor());
+            ASMToolkit.invokeVirtual(methodVisitor, TYPE_EVENT_HANDLER.getInternalName(), METHOD_IS_ENABLED);
+            methodVisitor.visitInsn(Opcodes.IRETURN);
+            if (guardHandlerReference) {
+                methodVisitor.visitLabel(nullLabel);
+                methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
+                methodVisitor.visitInsn(Opcodes.ICONST_0);
+                methodVisitor.visitInsn(Opcodes.IRETURN);
+            }
+        });
+
+        // MyEvent#begin()
+        updateMethod(METHOD_BEGIN, methodVisitor -> {
+            methodVisitor.visitIntInsn(Opcodes.ALOAD, 0);
+            ASMToolkit.invokeStatic(methodVisitor, TYPE_EVENT_HANDLER.getInternalName(), METHOD_TIME_STAMP);
+            methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, getInternalClassName(), FIELD_START_TIME, "J");
+            methodVisitor.visitInsn(Opcodes.RETURN);
+        });
+
+        // MyEvent#end()
+        updateMethod(METHOD_END, methodVisitor -> {
+            methodVisitor.visitIntInsn(Opcodes.ALOAD, 0);
+            methodVisitor.visitIntInsn(Opcodes.ALOAD, 0);
+            methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_START_TIME, "J");
+            ASMToolkit.invokeStatic(methodVisitor, TYPE_EVENT_HANDLER.getInternalName(), METHOD_DURATION);
+            methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, getInternalClassName(), FIELD_DURATION, "J");
+            methodVisitor.visitInsn(Opcodes.RETURN);
+            methodVisitor.visitMaxs(0, 0);
+        });
+
+        // MyEvent#commit() - Java event writer
+        updateMethod(METHOD_COMMIT, methodVisitor -> {
+                // if (!isEnable()) {
+                // return;
+                // }
+                methodVisitor.visitCode();
+                methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
+                methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, getInternalClassName(), METHOD_IS_ENABLED.getName(), METHOD_IS_ENABLED.getDescriptor(), false);
+                Label l0 = new Label();
+                methodVisitor.visitJumpInsn(Opcodes.IFNE, l0);
+                methodVisitor.visitInsn(Opcodes.RETURN);
+                methodVisitor.visitLabel(l0);
+                methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
+                // if (startTime == 0) {
+                // startTime = EventWriter.timestamp();
+                // } else {
+                methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
+                methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_START_TIME, "J");
+                methodVisitor.visitInsn(Opcodes.LCONST_0);
+                methodVisitor.visitInsn(Opcodes.LCMP);
+                Label durationalEvent = new Label();
+                methodVisitor.visitJumpInsn(Opcodes.IFNE, durationalEvent);
+                methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
+                methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, TYPE_EVENT_HANDLER.getInternalName(), METHOD_TIME_STAMP.getName(),
+                        METHOD_TIME_STAMP.getDescriptor(), false);
+                methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, getInternalClassName(), FIELD_START_TIME, "J");
+                Label commit = new Label();
+                methodVisitor.visitJumpInsn(Opcodes.GOTO, commit);
+                // if (duration == 0) {
+                // duration = EventWriter.timestamp() - startTime;
+                // }
+                // }
+                methodVisitor.visitLabel(durationalEvent);
+                methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
+                methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
+                methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_DURATION, "J");
+                methodVisitor.visitInsn(Opcodes.LCONST_0);
+                methodVisitor.visitInsn(Opcodes.LCMP);
+                methodVisitor.visitJumpInsn(Opcodes.IFNE, commit);
+                methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
+                methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, TYPE_EVENT_HANDLER.getInternalName(), METHOD_TIME_STAMP.getName(), METHOD_TIME_STAMP.getDescriptor(), false);
+                methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
+                methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_START_TIME, "J");
+                methodVisitor.visitInsn(Opcodes.LSUB);
+                methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, getInternalClassName(), FIELD_DURATION, "J");
+                methodVisitor.visitLabel(commit);
+                // if (shouldCommit()) {
+                methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
+                methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
+                methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, getInternalClassName(), METHOD_EVENT_SHOULD_COMMIT.getName(), METHOD_EVENT_SHOULD_COMMIT.getDescriptor(), false);
+                Label end = new Label();
+                // eventHandler.write(...);
+                // }
+                methodVisitor.visitJumpInsn(Opcodes.IFEQ, end);
+                methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, Type.getDescriptor(EventHandler.class));
+
+                methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, eventHandlerXInternalName);
+                for (FieldInfo fi : fieldInfos) {
+                    methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
+                    methodVisitor.visitFieldInsn(Opcodes.GETFIELD, fi.internalClassName, fi.fieldName, fi.fieldDescriptor);
+                }
+
+                methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, eventHandlerXInternalName, writeMethod.getName(), writeMethod.getDescriptor(), false);
+                methodVisitor.visitLabel(end);
+                methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
+                methodVisitor.visitInsn(Opcodes.RETURN);
+                methodVisitor.visitEnd();
+            });
+
+        // MyEvent#shouldCommit()
+        updateMethod(METHOD_EVENT_SHOULD_COMMIT, methodVisitor -> {
+            Label fail = new Label();
+            // if (!eventHandler.shoouldCommit(duration) goto fail;
+            methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, Type.getDescriptor(EventHandler.class));
+            methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
+            methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_DURATION, "J");
+            ASMToolkit.invokeVirtual(methodVisitor, TYPE_EVENT_HANDLER.getInternalName(), METHOD_EVENT_HANDLER_SHOULD_COMMIT);
+            methodVisitor.visitJumpInsn(Opcodes.IFEQ, fail);
+            for (SettingInfo si : settingInfos) {
+                // if (!settingsMethod(eventHandler.settingX)) goto fail;
+                methodVisitor.visitIntInsn(Opcodes.ALOAD, 0);
+                methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, Type.getDescriptor(EventHandler.class));
+                methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, eventHandlerXInternalName);
+                methodVisitor.visitFieldInsn(Opcodes.GETFIELD, eventHandlerXInternalName, si.fieldName, TYPE_SETTING_CONTROL.getDescriptor());
+                methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, si.internalSettingName);
+                methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, getInternalClassName(), si.methodName, "(" + si.settingDescriptor + ")Z", false);
+                methodVisitor.visitJumpInsn(Opcodes.IFEQ, fail);
+            }
+            // return true
+            methodVisitor.visitInsn(Opcodes.ICONST_1);
+            methodVisitor.visitInsn(Opcodes.IRETURN);
+            // return false
+            methodVisitor.visitLabel(fail);
+            methodVisitor.visitInsn(Opcodes.ICONST_0);
+            methodVisitor.visitInsn(Opcodes.IRETURN);
+        });
+    }
+
+    private void makeUninstrumented() {
+        updateExistingWithReturnFalse(METHOD_EVENT_SHOULD_COMMIT);
+        updateExistingWithReturnFalse(METHOD_IS_ENABLED);
+        updateExistingWithEmptyVoidMethod(METHOD_COMMIT);
+        updateExistingWithEmptyVoidMethod(METHOD_BEGIN);
+        updateExistingWithEmptyVoidMethod(METHOD_END);
+    }
+
+    private final void updateExistingWithEmptyVoidMethod(Method voidMethod) {
+        updateMethod(voidMethod, methodVisitor -> {
+            methodVisitor.visitInsn(Opcodes.RETURN);
+        });
+    }
+
+    private final void updateExistingWithReturnFalse(Method voidMethod) {
+        updateMethod(voidMethod, methodVisitor -> {
+            methodVisitor.visitInsn(Opcodes.ICONST_0);
+            methodVisitor.visitInsn(Opcodes.IRETURN);
+        });
+    }
+
+    private MethodNode getMethodNode(Method method) {
+        for (MethodNode m : classNode.methods) {
+            if (m.name.equals(method.getName()) && m.desc.equals(method.getDescriptor())) {
+                return m;
+            }
+        }
+        return null;
+    }
+
+    private final void updateMethod(Method method, Consumer<MethodVisitor> code) {
+        MethodNode old = getMethodNode(method);
+        int index = classNode.methods.indexOf(old);
+        classNode.methods.remove(old);
+        MethodVisitor mv = classNode.visitMethod(old.access, old.name, old.desc, null, null);
+        mv.visitCode();
+        code.accept(mv);
+        mv.visitMaxs(0, 0);
+        MethodNode newMethod = getMethodNode(method);
+        classNode.methods.remove(newMethod);
+        classNode.methods.add(index, newMethod);
+    }
+
+    public static Method makeWriteMethod(List<FieldInfo> fields) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("(");
+        for (FieldInfo v : fields) {
+            sb.append(v.fieldDescriptor);
+        }
+        sb.append(")V");
+        return new Method("write", sb.toString());
+    }
+
+    private String getInternalClassName() {
+        return classNode.name;
+    }
+
+    public List<SettingInfo> getSettingInfos() {
+        return settingInfos;
+    }
+
+    public List<FieldInfo> getFieldInfos() {
+        return fieldInfos;
+    }
+
+    public String getEventName() {
+        return eventName;
+    }
+
+    public void setGuardHandler(boolean guardHandlerReference) {
+        this.guardHandlerReference = guardHandlerReference;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventWriter.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,355 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import jdk.internal.misc.Unsafe;
+import jdk.jfr.internal.consumer.RecordingInput;
+
+/**
+ * Class must reside in a package with package restriction.
+ *
+ * Users should not have direct access to underlying memory.
+ *
+ */
+public final class EventWriter {
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+    private final static JVM jvm = JVM.getJVM();
+
+    private long startPosition;
+    private long startPositionAddress;
+    private long currentPosition;
+    private long maxPosition;
+    private final long threadID;
+    private PlatformEventType eventType;
+    private int maxEventSize;
+    private boolean started;
+    private boolean valid;
+    private boolean flushOnEnd;
+    // set by the JVM, not private to avoid being optimized out
+    boolean notified;
+
+    public static EventWriter getEventWriter() {
+        EventWriter ew = (EventWriter)JVM.getEventWriter();
+        return ew != null ? ew : JVM.newEventWriter();
+    }
+
+    public void putBoolean(boolean i) {
+        if (isValidForSize(Byte.BYTES)) {
+            currentPosition += Bits.putBoolean(currentPosition, i);
+        }
+    }
+
+    public void putByte(byte i) {
+        if (isValidForSize(Byte.BYTES)) {
+            unsafe.putByte(currentPosition, i);
+            ++currentPosition;
+        }
+    }
+
+    public void putChar(char v) {
+        if (isValidForSize(Character.BYTES + 1)) {
+            putUncheckedLong(v);
+        }
+    }
+
+    private void putUncheckedChar(char v) {
+        putUncheckedLong(v);
+    }
+
+    public void putShort(short v) {
+        if (isValidForSize(Short.BYTES + 1)) {
+            putUncheckedLong(v & 0xFFFF);
+        }
+    }
+
+    public void putInt(int v) {
+        if (isValidForSize(Integer.BYTES + 1)) {
+            putUncheckedLong(v & 0x00000000ffffffffL);
+        }
+    }
+
+    private void putUncheckedInt(int v) {
+        putUncheckedLong(v & 0x00000000ffffffffL);
+    }
+
+    public void putFloat(float i) {
+        if (isValidForSize(Float.BYTES)) {
+            currentPosition += Bits.putFloat(currentPosition, i);
+        }
+    }
+
+    public void putLong(long v) {
+        if (isValidForSize(Long.BYTES + 1)) {
+            putUncheckedLong(v);
+        }
+    }
+
+    public void putDouble(double i) {
+        if (isValidForSize(Double.BYTES)) {
+            currentPosition += Bits.putDouble(currentPosition, i);
+        }
+    }
+
+    public void putString(String s, StringPool pool) {
+        if (s == null) {
+            putByte(RecordingInput.STRING_ENCODING_NULL);
+            return;
+        }
+        int length = s.length();
+        if (length == 0) {
+            putByte(RecordingInput.STRING_ENCODING_EMPTY_STRING);
+            return;
+        }
+        if (length > StringPool.MIN_LIMIT && length < StringPool.MAX_LIMIT) {
+            long l = StringPool.addString(s);
+            if (l > 0) {
+                putByte(RecordingInput.STRING_ENCODING_CONSTANT_POOL);
+                putLong(l);
+                return;
+            }
+        }
+        putStringValue(s);
+        return;
+    }
+
+    private void putStringValue(String s) {
+        int length = s.length();
+        if (isValidForSize(1 + 5 + 3 * length)) {
+            putUncheckedByte(RecordingInput.STRING_ENCODING_CHAR_ARRAY); // 1 byte
+            putUncheckedInt(length); // max 5 bytes
+            for (int i = 0; i < length; i++) {
+                putUncheckedChar(s.charAt(i)); // max 3 bytes
+            }
+        }
+    }
+
+    public void putEventThread() {
+        putLong(threadID);
+    }
+
+    public void putThread(Thread athread) {
+        if (athread == null) {
+            putLong(0L);
+        } else {
+            putLong(jvm.getThreadId(athread));
+        }
+    }
+
+    public void putClass(Class<?> aClass) {
+        if (aClass == null) {
+            putLong(0L);
+        } else {
+            putLong(JVM.getClassIdNonIntrinsic(aClass));
+        }
+    }
+
+    public void putStackTrace() {
+        if (eventType.getStackTraceEnabled()) {
+            putLong(jvm.getStackTraceId(eventType.getStackTraceOffset()));
+        } else {
+            putLong(0L);
+        }
+    }
+
+    private void reserveEventSizeField() {
+        // move currentPosition Integer.Bytes offset from start position
+        if (isValidForSize(Integer.BYTES)) {
+            currentPosition += Integer.BYTES;
+        }
+    }
+
+    private void reset() {
+        currentPosition = startPosition;
+        if (flushOnEnd) {
+            flushOnEnd = flush();
+        }
+        valid = true;
+        started = false;
+    }
+
+    private boolean isValidForSize(int requestedSize) {
+        if (!valid) {
+            return false;
+        }
+        if (currentPosition + requestedSize > maxPosition) {
+            flushOnEnd = flush(usedSize(), requestedSize);
+            // retry
+            if (currentPosition + requestedSize > maxPosition) {
+                Logger.log(LogTag.JFR_SYSTEM,
+                           LogLevel.WARN, () ->
+                               "Unable to commit. Requested size " + requestedSize + " too large");
+                valid = false;
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private boolean isNotified() {
+        return notified;
+    }
+
+    private void resetNotified() {
+        notified = false;
+    }
+
+    private int usedSize() {
+        return (int) (currentPosition - startPosition);
+    }
+
+    private boolean flush() {
+        return flush(usedSize(), 0);
+    }
+
+    private boolean flush(int usedSize, int requestedSize) {
+        return JVM.flush(this, usedSize, requestedSize);
+    }
+
+    public boolean beginEvent(PlatformEventType eventType) {
+        if (started) {
+            // recursive write attempt
+            return false;
+        }
+        started = true;
+        this.eventType = eventType;
+        reserveEventSizeField();
+        putLong(eventType.getId());
+        return true;
+    }
+
+    public boolean endEvent() {
+        if (!valid) {
+            reset();
+            return true;
+        }
+        final int eventSize = usedSize();
+        if (eventSize > maxEventSize) {
+            reset();
+            return true;
+        }
+        Bits.putInt(startPosition, makePaddedInt(eventSize));
+        if (isNotified()) {
+            resetNotified();
+            reset();
+            // returning false will trigger restart of the event write attempt
+            return false;
+        }
+        startPosition = currentPosition;
+        unsafe.putAddress(startPositionAddress, startPosition);
+        // the event is now committed
+        if (flushOnEnd) {
+            flushOnEnd = flush();
+        }
+        started = false;
+        return true;
+    }
+
+    private EventWriter(long startPos, long maxPos, long startPosAddress, long threadID, boolean valid) {
+        startPosition = currentPosition = startPos;
+        maxPosition = maxPos;
+        startPositionAddress = startPosAddress;
+        this.threadID = threadID;
+        started = false;
+        flushOnEnd = false;
+        this.valid = valid;
+        notified = false;
+        // event may not exceed size for a padded integer
+        maxEventSize = (1 << 28) -1;
+    }
+
+    private static int makePaddedInt(int v) {
+        // bit  0-6 + pad => bit 24 - 31
+        long b1 = (((v >>> 0) & 0x7F) | 0x80) << 24;
+
+        // bit  7-13 + pad => bit 16 - 23
+        long b2 = (((v >>> 7) & 0x7F) | 0x80) << 16;
+
+        // bit 14-20 + pad => bit  8 - 15
+        long b3 = (((v >>> 14) & 0x7F) | 0x80) << 8;
+
+        // bit 21-28       => bit  0 -  7
+        long b4 = (((v >>> 21) & 0x7F)) << 0;
+
+        return (int) (b1 + b2 + b3 + b4);
+    }
+
+    private void putUncheckedLong(long v) {
+        if ((v & ~0x7FL) == 0L) {
+            putUncheckedByte((byte) v); // 0-6
+            return;
+        }
+        putUncheckedByte((byte) (v | 0x80L)); // 0-6
+        v >>>= 7;
+        if ((v & ~0x7FL) == 0L) {
+            putUncheckedByte((byte) v); // 7-13
+            return;
+        }
+        putUncheckedByte((byte) (v | 0x80L)); // 7-13
+        v >>>= 7;
+        if ((v & ~0x7FL) == 0L) {
+            putUncheckedByte((byte) v); // 14-20
+            return;
+        }
+        putUncheckedByte((byte) (v | 0x80L)); // 14-20
+        v >>>= 7;
+        if ((v & ~0x7FL) == 0L) {
+            putUncheckedByte((byte) v); // 21-27
+            return;
+        }
+        putUncheckedByte((byte) (v | 0x80L)); // 21-27
+        v >>>= 7;
+        if ((v & ~0x7FL) == 0L) {
+            putUncheckedByte((byte) v); // 28-34
+            return;
+        }
+        putUncheckedByte((byte) (v | 0x80L)); // 28-34
+        v >>>= 7;
+        if ((v & ~0x7FL) == 0L) {
+            putUncheckedByte((byte) v); // 35-41
+            return;
+        }
+        putUncheckedByte((byte) (v | 0x80L)); // 35-41
+        v >>>= 7;
+        if ((v & ~0x7FL) == 0L) {
+            putUncheckedByte((byte) v); // 42-48
+            return;
+        }
+        putUncheckedByte((byte) (v | 0x80L)); // 42-48
+        v >>>= 7;
+
+        if ((v & ~0x7FL) == 0L) {
+            putUncheckedByte((byte) v); // 49-55
+            return;
+        }
+        putUncheckedByte((byte) (v | 0x80L)); // 49-55
+        putUncheckedByte((byte) (v >>> 7)); // 56-63, last byte as is.
+    }
+
+    private void putUncheckedByte(byte i) {
+        unsafe.putByte(currentPosition, i);
+        ++currentPosition;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventWriterMethod.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import jdk.internal.org.objectweb.asm.commons.Method;
+import jdk.jfr.internal.EventInstrumentation.FieldInfo;
+
+public enum EventWriterMethod {
+
+    BEGIN_EVENT("(" + jdk.internal.org.objectweb.asm.Type.getType(PlatformEventType.class).getDescriptor() + ")Z", "???", "beginEvent"),
+    END_EVENT("()Z", "???", "endEvent"),
+    PUT_BYTE("(B)V", "byte", "putByte"),
+    PUT_SHORT("(S)V", "short", "putShort"),
+    PUT_INT("(I)V", "int", "putInt"),
+    PUT_LONG("(J)V", "long", "putLong"),
+    PUT_FLOAT("(F)V", "float", "putFloat"),
+    PUT_DOUBLE("(D)V", "double", "putDouble"),
+    PUT_CHAR("(C)V", "char", "putChar"),
+    PUT_BOOLEAN("(Z)V", "boolean", "putBoolean"),
+    PUT_THREAD("(Ljava/lang/Thread;)V", Type.THREAD.getName(), "putThread"),
+    PUT_CLASS("(Ljava/lang/Class;)V", Type.CLASS.getName(), "putClass"),
+    PUT_STRING("(Ljava/lang/String;Ljdk/jfr/internal/StringPool;)V", Type.STRING.getName(), "putString"),
+    PUT_EVENT_THREAD("()V", Type.THREAD.getName(), "putEventThread"),
+    PUT_STACK_TRACE("()V", Type.TYPES_PREFIX + "StackTrace", "putStackTrace");
+
+    private final Method asmMethod;
+    private final String typeDescriptor;
+
+    EventWriterMethod(String paramSignature, String typeName, String methodName) {
+        this.typeDescriptor = ASMToolkit.getDescriptor(typeName);
+        this.asmMethod = new Method(methodName, paramSignature);
+    }
+
+    public Method asASM() {
+        return asmMethod;
+    }
+
+    /**
+     * Return method in {@link EventWriter} class to use when writing event of
+     * a certain type.
+     *
+     * @param v field info
+     *
+     * @return the method
+     */
+    public static EventWriterMethod lookupMethod(FieldInfo v) {
+        // event thread
+        if (v.fieldName.equals(EventInstrumentation.FIELD_EVENT_THREAD)) {
+            return EventWriterMethod.PUT_EVENT_THREAD;
+        }
+        for (EventWriterMethod m : EventWriterMethod.values()) {
+            if (v.fieldDescriptor.equals(m.typeDescriptor)) {
+                return m;
+            }
+        }
+        throw new Error("Unknown type " + v.fieldDescriptor);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,519 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import java.io.IOException;
+import java.util.List;
+
+import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.jfr.Event;
+
+/**
+ * Interface against the JVM.
+ *
+ */
+public final class JVM {
+    private static final JVM jvm = new JVM();
+
+    // JVM signals file changes by doing Object#notifu on this object
+    static final Object FILE_DELTA_CHANGE = new Object();
+
+    static final long RESERVED_CLASS_ID_LIMIT = 400;
+
+    private volatile boolean recording;
+    private volatile boolean nativeOK;
+
+    private static native void registerNatives();
+
+    static {
+        registerNatives();
+        for (LogTag tag : LogTag.values()) {
+            subscribeLogLevel(tag, tag.id);
+        }
+        Options.ensureInitialized();
+    }
+
+    /**
+     * Get the one and only JVM.
+     *
+     * @return the JVM
+     */
+    public static JVM getJVM() {
+        return jvm;
+    }
+
+    private JVM() {
+    }
+
+    /**
+     * Begin recording events
+     *
+     * Requires that JFR has been started with {@link #createNativeJFR()}
+     */
+    public native void beginRecording();
+
+    /**
+     * Return ticks
+     *
+     * @return the time, in ticks
+     *
+     */
+    @HotSpotIntrinsicCandidate
+    public static native long counterTime();
+
+
+    /**
+     * Emits native periodic event.
+     *
+     * @param eventTypeId type id
+     *
+     * @param timestamp commit time for event
+     * @param when when it is being done {@link Periodic.When}
+     *
+     * @return true if the event was committed
+     */
+    public native boolean emitEvent(long eventTypeId, long timestamp, long when);
+
+    /**
+     * End recording events, which includes flushing data in thread buffers
+     *
+     * Requires that JFR has been started with {@link #createNativeJFR()}
+     *
+     */
+    public native void endRecording();
+
+    /**
+     * Return a list of all classes deriving from {@link Event}
+     *
+     * @return list of event classes.
+     */
+    public native List<Class<? extends Event>> getAllEventClasses();
+
+    /**
+     * Return a count of the number of unloaded classes deriving from {@link Event}
+     *
+     * @return number of unloaded event classes.
+     */
+    public native long getUnloadedEventClassCount();
+
+    /**
+     * Return a unique identifier for a class. The class is marked as being
+     * "in use" in JFR.
+     *
+     * @param clazz clazz
+     *
+     * @return a unique class identifier
+     */
+   @HotSpotIntrinsicCandidate
+    public static native long getClassId(Class<?> clazz);
+
+    // temporary workaround until we solve intrinsics supporting epoch shift tagging
+    public static native long getClassIdNonIntrinsic(Class<?> clazz);
+
+    /**
+     * Return process identifier.
+     *
+     * @return process identifier
+     */
+    public native String getPid();
+
+    /**
+     * Return unique identifier for stack trace.
+     *
+     * Requires that JFR has been started with {@link #createNativeJFR()}
+     *
+     * @param skipCount number of frames to skip
+     * @return a unique stack trace identifier
+     */
+    public native long getStackTraceId(int skipCount);
+
+    /**
+     * Return identifier for thread
+     *
+     * @param t thread
+     * @return a unique thread identifier
+     */
+    public native long getThreadId(Thread t);
+
+    /**
+     * Frequency, ticks per second
+     *
+     * @return frequency
+     */
+    public native long getTicksFrequency();
+
+    /**
+     * Write message to log. Should swallow null or empty message, and be able
+     * to handle any Java character and not crash with very large message
+     *
+     * @param tagSetId the tagset id
+     * @param level on level
+     * @param message log message
+     *
+     */
+    public static native void log(int tagSetId, int level, String message);
+
+    /**
+     * Subscribe to LogLevel updates for LogTag
+     *
+     * @param lt the log tag to subscribe
+     * @param tagSetId the tagset id
+     */
+    public static native void subscribeLogLevel(LogTag lt, int tagSetId);
+
+    /**
+     * Call to invoke event tagging and retransformation of the passed classes
+     *
+     * @param classes
+     */
+    public native synchronized void retransformClasses(Class<?>[] classes);
+
+    /**
+     * Enable event
+     *
+     * @param eventTypeId event type id
+     *
+     * @param enabled enable event
+     */
+    public native void setEnabled(long eventTypeId, boolean enabled);
+
+    /**
+     * Interval at which the JVM should notify on {@link #FILE_DELTA_CHANGE}
+     *
+     * @param delta number of bytes, reset after file rotation
+     */
+    public native void setFileNotification(long delta);
+
+    /**
+     * Set the number of global buffers to use
+     *
+     * @param count
+     *
+     * @throws IllegalArgumentException if count is not within a valid range
+     * @throws IllegalStateException if value can't be changed
+     */
+    public native void setGlobalBufferCount(long count) throws IllegalArgumentException, IllegalStateException;
+
+    /**
+     * Set size of a global buffer
+     *
+     * @param size
+     *
+     * @throws IllegalArgumentException if buffer size is not within a valid
+     *         range
+     */
+    public native void setGlobalBufferSize(long size) throws IllegalArgumentException;
+
+    /**
+     * Set overall memory size
+     *
+     * @param size
+     *
+     * @throws IllegalArgumentException if memory size is not within a valid
+     *         range
+     */
+    public native void setMemorySize(long size) throws IllegalArgumentException;
+
+    /**
+
+    /**
+     * Set interval for method samples, in milliseconds.
+     *
+     * Setting interval to 0 turns off the method sampler.
+     *
+     * @param intervalMillis the sampling interval
+     */
+    public native void setMethodSamplingInterval(long type, long intervalMillis);
+
+      /**
+     * Sets the file where data should be written.
+     *
+     * Requires that JFR has been started with {@link #createNativeJFR()}
+     *
+     * <pre>
+     * Recording  Previous  Current  Action
+     * ==============================================
+     *    true     null      null     Ignore, keep recording in-memory
+     *    true     null      file1    Start disk recording
+     *    true     file      null     Copy out metadata to disk and continue in-memory recording
+     *    true     file1     file2    Copy out metadata and start with new File (file2)
+     *    false     *        null     Ignore, but start recording to memory with {@link #beginRecording()}
+     *    false     *        file     Ignore, but start recording to disk with {@link #beginRecording()}
+     *
+     * </pre>
+     *
+     * recording can be set to true/false with {@link #beginRecording()}
+     * {@link #endRecording()}
+     *
+     * @param file the file where data should be written, or null if it should
+     *        not be copied out (in memory).
+     *
+     * @throws IOException
+     */
+    public native void setOutput(String file);
+
+    /**
+     * Controls if a class deriving from jdk.jfr.Event should
+     * always be instrumented on class load.
+     *
+     * @param force, true to force initialization, false otherwise
+     */
+    public native void setForceInstrumentation(boolean force);
+
+    /**
+     * Turn on/off thread sampling.
+     *
+     * @param sampleThreads true if threads should be sampled, false otherwise.
+     *
+     * @throws IllegalStateException if state can't be changed.
+     */
+    public native void setSampleThreads(boolean sampleThreads) throws IllegalStateException;
+
+    /**
+     * Turn on/off compressed integers.
+     *
+     * @param compressed true if compressed integers should be used, false
+     *        otherwise.
+     *
+     * @throws IllegalStateException if state can't be changed.
+     */
+    public native void setCompressedIntegers(boolean compressed) throws IllegalStateException;
+
+    /**
+     * Set stack depth.
+     *
+     * @param depth
+     *
+     * @throws IllegalArgumentException if not within a valid range
+     * @throws IllegalStateException if depth can't be changed
+     */
+    public native void setStackDepth(int depth) throws IllegalArgumentException, IllegalStateException;
+
+    /**
+     * Turn on stack trace for an event
+     *
+     * @param eventTypeId the event id
+     *
+     * @param enabled if stack traces should be enabled
+     */
+    public native void setStackTraceEnabled(long eventTypeId, boolean enabled);
+
+    /**
+     * Set thread buffer size.
+     *
+     * @param size
+     *
+     * @throws IllegalArgumentException if size is not within a valid range
+     * @throws IllegalStateException if size can't be changed
+     */
+    public native void setThreadBufferSize(long size) throws IllegalArgumentException, IllegalStateException;
+
+    /**
+     * Set threshold for event,
+     *
+     * Long.MAXIMUM_VALUE = no limit
+     *
+     * @param eventTypeId the id of the event type
+     * @param ticks threshold in ticks,
+     * @return true, if it could be set
+     */
+    public native boolean setThreshold(long eventTypeId, long ticks);
+
+    /**
+     * Store the metadata descriptor that is to be written at the end of a
+     * chunk, data should be written after GMT offset and size of metadata event
+     * should be adjusted
+     *
+     * Requires that JFR has been started with {@link #createNativeJFR()}
+     *
+     * @param bytes binary representation of metadata descriptor
+     *
+     * @param binary representation of descriptor
+     */
+    public native void storeMetadataDescriptor(byte[] bytes);
+
+    public void endRecording_() {
+        endRecording();
+        recording = false;
+    }
+
+    public void beginRecording_() {
+        beginRecording();
+        recording = true;
+    }
+
+    public boolean isRecording() {
+        return recording;
+    }
+
+    /**
+     * If the JVM supports JVM TI and retransformation has not been disabled this
+     * method will return true. This flag can not change during the lifetime of
+     * the JVM.
+     *
+     * @return if transform is allowed
+     */
+    public native boolean getAllowedToDoEventRetransforms();
+
+    /**
+     * Set up native resources, data structures, threads etc. for JFR
+     *
+     * @param simulateFailure simulate a initialization failure and rollback in
+     *        native, used for testing purposes
+     *
+     * @throws IllegalStateException if native part of JFR could not be created.
+     *
+     */
+    private native boolean createJFR(boolean simulateFailure) throws IllegalStateException;
+
+    /**
+     * Destroys native part of JFR. If already destroy, call is ignored.
+     *
+     * Requires that JFR has been started with {@link #createNativeJFR()}
+     *
+     * @return if an instance was actually destroyed.
+     *
+     */
+    private native boolean destroyJFR();
+
+    public boolean createFailedNativeJFR() throws IllegalStateException {
+        return createJFR(true);
+    }
+
+    public void createNativeJFR() {
+        nativeOK = createJFR(false);
+    }
+
+    public boolean destroyNativeJFR() {
+        boolean result = destroyJFR();
+        nativeOK = !result;
+        return result;
+    }
+
+    public boolean hasNativeJFR() {
+        return nativeOK;
+    }
+
+    /**
+     * Cheap test to check if JFR functionality is available.
+     *
+     * @return
+     */
+    public native boolean isAvailable();
+
+    /**
+     * To convert ticks to wall clock time.
+     */
+    public native double getTimeConversionFactor();
+
+    /**
+     * Return a unique identifier for a class. Compared to {@link #getClassId()}
+     * , this method does not tag the class as being "in-use".
+     *
+     * @param clazz class
+     *
+     * @return a unique class identifier
+     */
+    public native long getTypeId(Class<?> clazz);
+
+    /**
+     * Fast path fetching the EventWriter using VM intrinsics
+     *
+     * @return thread local EventWriter
+     */
+    @HotSpotIntrinsicCandidate
+    public static native Object getEventWriter();
+
+    /**
+     * Create a new EventWriter
+     *
+     * @return thread local EventWriter
+     */
+    public static native EventWriter newEventWriter();
+
+    /**
+     * Flushes the EventWriter for this thread.
+     */
+    public static native boolean flush(EventWriter writer, int uncommittedSize, int requestedSize);
+
+    /**
+     * Sets the location of the disk repository, to be used at an emergency
+     * dump.
+     *
+     * @param dirText
+     */
+    public native void setRepositoryLocation(String dirText);
+
+    /**
+    * Access to VM termination support.
+    *
+    *@param errorMsg descriptive message to be include in VM termination sequence
+    */
+    public native void abort(String errorMsg);
+
+    /**
+     * Adds a string to the string constant pool.
+     *
+     * If the same string is added twice, two entries will be created.
+     *
+     * @param id identifier associated with the string, not negative
+     *
+     * @param s string constant to be added, not null
+     *
+     * @return the current epoch of this insertion attempt
+     */
+    public static native boolean addStringConstant(boolean epoch, long id, String s);
+    /**
+     * Gets the address of the jboolean epoch.
+     *
+     * The epoch alternates every checkpoint.
+     *
+     * @return The address of the jboolean.
+     */
+    public native long getEpochAddress();
+
+    public native void uncaughtException(Thread thread, Throwable t);
+    /**
+     * Sets cutoff for event.
+     *
+     * Determines how long the event should be allowed to run.
+     *
+     * Long.MAXIMUM_VALUE = no limit
+     *
+     * @param eventTypeId the id of the event type
+     * @param cutoffTicks cutoff in ticks,
+     * @return true, if it could be set
+     */
+    public native boolean setCutoff(long eventTypeId, long cutoffTicks);
+
+    /**
+     * Emit old object sample events.
+     *
+     * @param cutoff the cutoff in ticks
+     * @param emitAll emit all samples in old object queue
+     */
+    public native void emitOldObjectSamples(long cutoff, boolean emitAll);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMSupport.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.internal;
+
+import java.io.IOException;
+
+/**
+ * Checks if the running VM supports Flight Recorder.
+ *
+ * Purpose of this helper class is to detect early and cleanly if the VM has
+ * support for Flight Recorder, i.e. not throw {@link UnsatisfiedLinkError} in
+ * unexpected places.
+ * <p>
+ * This is needed so a disabled-jfr.jar can be built for non Oracle JDKs.
+ */
+public final class JVMSupport {
+
+    private static final String UNSUPPORTED_VM_MESSAGE = "Flight Recorder is not supported on this VM";
+    private static final boolean notAvailable = !checkAvailability();
+
+    private static boolean checkAvailability() {
+        // set jfr.unsupported.vm to true to test API on an unsupported VM
+        try {
+            if (SecuritySupport.getBooleanProperty("jfr.unsupported.vm")) {
+                return false;
+            }
+        } catch (NoClassDefFoundError cnfe) {
+            // May happen on JDK 8, where jdk.internal.misc.Unsafe can't be found
+            return false;
+        }
+        try {
+            // Will typically throw UnsatisfiedLinkError if
+            // there is no native implementation
+            JVM.getJVM().isAvailable();
+            return true;
+        } catch (Throwable t) {
+            return false;
+        }
+    }
+
+    public static void ensureWithInternalError() {
+        if (notAvailable) {
+            throw new InternalError(UNSUPPORTED_VM_MESSAGE);
+        }
+    }
+
+    public static void ensureWithIOException() throws IOException {
+        if (notAvailable) {
+            throw new IOException(UNSUPPORTED_VM_MESSAGE);
+        }
+    }
+
+    public static void ensureWithIllegalStateException() {
+        if (notAvailable) {
+            throw new IllegalStateException(UNSUPPORTED_VM_MESSAGE);
+        }
+    }
+
+    public static boolean isNotAvailable() {
+        return notAvailable;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMUpcalls.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.internal;
+
+import java.lang.reflect.Modifier;
+
+import jdk.jfr.Event;
+import jdk.jfr.internal.handlers.EventHandler;
+import jdk.jfr.internal.instrument.JDKEvents;
+
+/**
+ * All upcalls from the JVM should go through this class.
+ *
+ */
+// Called by native
+final class JVMUpcalls {
+    /**
+     * Called by the JVM when a retransform happens on a tagged class
+     *
+     * @param traceId
+     *            Id of the class
+     * @param dummy
+     *            (not used but needed since invoke infrastructure in native
+     *            uses same signature bytesForEagerInstrumentation)
+     * @param clazz
+     *            class being retransformed
+     * @param oldBytes
+     *            byte code
+     * @return byte code to use
+     * @throws Throwable
+     */
+    static byte[] onRetransform(long traceId, boolean dummy, Class<?> clazz, byte[] oldBytes) throws Throwable {
+        try {
+            if (Event.class.isAssignableFrom(clazz) && !Modifier.isAbstract(clazz.getModifiers())) {
+                EventHandler handler = Utils.getHandler(clazz.asSubclass(Event.class));
+                if (handler == null) {
+                    Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "No event handler found for " + clazz.getName() + ". Ignoring instrumentation request.");
+                    // Probably triggered by some other agent
+                    return oldBytes;
+                }
+                Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "Adding instrumentation to event class " + clazz.getName() + " using retransform");
+                EventInstrumentation ei = new EventInstrumentation(clazz.getSuperclass(), oldBytes, traceId);
+                byte[] bytes = ei.buildInstrumented();
+                ASMToolkit.logASM(clazz.getName(), bytes);
+                return bytes;
+            }
+            return JDKEvents.retransformCallback(clazz, oldBytes);
+        } catch (Throwable t) {
+            Logger.log(LogTag.JFR_SYSTEM, LogLevel.WARN, "Unexpected error when adding instrumentation to event class " + clazz.getName());
+        }
+        return oldBytes;
+
+    }
+
+    /**
+     * Called by the JVM when requested to do an "eager" instrumentation. Would
+     * normally happen when JVMTI retransform capabilities are not available.
+     *
+     * @param traceId
+     *            Id of the class
+     * @param forceInstrumentation
+     *            add instrumentation regardless if event is enabled or not.
+     * @param superClazz
+     *            the super class of the class being processed
+     * @param oldBytes
+     *            byte code
+     * @return byte code to use
+     * @throws Throwable
+     */
+    static byte[] bytesForEagerInstrumentation(long traceId, boolean forceInstrumentation, Class<?> superClass, byte[] oldBytes) throws Throwable {
+        if (JVMSupport.isNotAvailable()) {
+            return oldBytes;
+        }
+        String eventName = "<Unknown>";
+        try {
+            EventInstrumentation ei = new EventInstrumentation(superClass, oldBytes, traceId);
+            eventName = ei.getEventName();
+            if (!forceInstrumentation) {
+                // Assume we are recording
+                MetadataRepository mr = MetadataRepository.getInstance();
+                // No need to generate bytecode if:
+                // 1) Event class is disabled, and there is not an external configuration that overrides.
+                // 2) Event class has @Registered(false)
+                if (!mr.isEnabled(ei.getEventName()) && !ei.isEnabled() || !ei.isRegistered()) {
+                    Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "Skipping instrumentation for event type " + eventName + " since event was disabled on class load");
+                    return oldBytes;
+                }
+            }
+            // Corner case when we are forced to generate bytecode. We can't reference the event
+            // handler in #isEnabled() before event class has been registered, so we add a
+            // guard against a null reference.
+            ei.setGuardHandler(true);
+            Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "Adding " + (forceInstrumentation ? "forced " : "") + "instrumentation for event type " + eventName + " during initial class load");
+            EventHandlerCreator eh = new EventHandlerCreator(traceId, ei.getSettingInfos(), ei.getFieldInfos());
+            // Handler class must be loaded before instrumented event class can
+            // be used
+            eh.makeEventHandlerClass();
+            byte[] bytes = ei.buildInstrumented();
+            ASMToolkit.logASM(ei.getClassName() + "(" + traceId + ")", bytes);
+            return bytes;
+        } catch (Throwable t) {
+            Logger.log(LogTag.JFR_SYSTEM, LogLevel.WARN, "Unexpected error when adding instrumentation for event type " + eventName);
+            return oldBytes;
+        }
+    }
+
+    /**
+     * Called by the JVM to create the recorder thread.
+     *
+     * @param systemThreadGroup
+     *            the system thread group
+     *
+     * @param contextClassLoader
+     *            the context class loader.
+     *
+     * @return a new thread
+     */
+    static Thread createRecorderThread(ThreadGroup systemThreadGroup, ClassLoader contextClassLoader) {
+        return SecuritySupport.createRecorderThread(systemThreadGroup, contextClassLoader);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/LogLevel.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+public enum LogLevel {
+    TRACE(1),
+    DEBUG(2),
+    INFO(3),
+    WARN(4),
+    ERROR(5);
+    // must be in sync with JVM levels.
+
+    final int level;
+
+    LogLevel(int level) {
+        this.level = level;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/LogTag.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+/* Mapped against c++ enum in jfrLogTagSet.hpp */
+public enum LogTag {
+    /**
+     * Covers
+     * <ul>
+     * <li>Initialization of Flight Recorder
+     * <li> recording life cycle (start, stop and dump)
+     * <li> repository life cycle
+     * <li>loading of configuration files.
+     * </ul>
+     * Target audience: operations
+     */
+    JFR(0),
+    /**
+     * Covers general implementation aspects of JFR (for Hotspot developers)
+     */
+    JFR_SYSTEM(1),
+    /**
+     * Covers JVM/JDK events (for Hotspot developers)
+     */
+    JFR_SYSTEM_EVENT(2),
+    /**
+     * Covers setting for the JVM/JDK  (for Hotspot developers)
+     */
+    JFR_SYSTEM_SETTING(3),
+    /**
+     * Covers generated bytecode (for Hotspot developers)
+     */
+    JFR_SYSTEM_BYTECODE(4),
+    /**
+     * Covers XML parsing (for Hotspot developers)
+     */
+    JFR_SYSTEM_PARSER(5),
+    /**
+     * Covers metadata for JVM/JDK (for Hotspot developers)
+     */
+    JFR_SYSTEM_METADATA(6),
+    /**
+     *  Covers metadata for Java user (for Hotspot developers)
+     */
+    JFR_METADATA(7),
+    /**
+     * Covers events (for users of the JDK)
+     */
+    JFR_EVENT(8),
+    /**
+     * Covers setting (for users of the JDK)
+     */
+    JFR_SETTING(9);
+    /* set from native side */
+    private volatile int tagSetLevel = 100; // prevent logging if JVM log system has not been initialized
+
+    final int id;
+
+    LogTag(int tagId) {
+        id = tagId;
+    }
+
+    public boolean shouldLog(int level) {
+        return level >= tagSetLevel;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/Logger.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import java.util.function.Supplier;
+
+/**
+ * JFR logger
+ *
+ */
+
+public final class Logger {
+
+    private final static int MAX_SIZE = 10000;
+
+    public static void log(LogTag logTag, LogLevel logLevel, String message) {
+        if (logTag.shouldLog(logLevel.level)) {
+            logInternal(logTag, logLevel, message);
+        }
+    }
+
+    public static void log(LogTag logTag, LogLevel logLevel, Supplier<String> messageSupplier) {
+        if (logTag.shouldLog(logLevel.level)) {
+            logInternal(logTag, logLevel, messageSupplier.get());
+        }
+    }
+
+    private static void logInternal(LogTag logTag, LogLevel logLevel, String message) {
+        if (message == null || message.length() < MAX_SIZE) {
+            JVM.log(logTag.id, logLevel.level, message);
+        } else {
+            JVM.log(logTag.id, logLevel.level, message.substring(0, MAX_SIZE));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataDescriptor.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import jdk.jfr.EventType;
+
+/**
+ * Metadata about a chunk
+ */
+public final class MetadataDescriptor {
+
+    static final class Attribute {
+        final String name;
+        final String value;
+
+        private Attribute(String name, String value) {
+            this.name = name;
+            this.value = value;
+        }
+    }
+
+    static final class Element {
+        final String name;
+        final List<Element> elements = new ArrayList<>();
+        final List<Attribute> attributes = new ArrayList<>();
+
+        Element(String name) {
+            this.name = name;
+        }
+
+        long longValue(String name) {
+            String v = attribute(name);
+            if (v != null)
+                return Long.parseLong(v);
+            else
+                throw new IllegalArgumentException(name);
+        }
+
+        String attribute(String name) {
+            for (Attribute a : attributes) {
+                if (a.name.equals(name)) {
+                    return a.value;
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            try {
+                prettyPrintXML(sb, "", this);
+            } catch (IOException e) {
+                // should not happen
+            }
+            return sb.toString();
+        }
+
+        long attribute(String name, long defaultValue) {
+            String text = attribute(name);
+            if (text == null) {
+                return defaultValue;
+            }
+            return Long.parseLong(text);
+        }
+
+        String attribute(String name, String defaultValue) {
+            String text = attribute(name);
+            if (text == null) {
+                return defaultValue;
+            }
+            return text;
+        }
+
+        List<Element> elements(String... names) {
+            List<Element> filteredElements = new ArrayList<>();
+            for (String name : names) {
+                for (Element e : elements) {
+                    if (e.name.equals(name)) {
+                        filteredElements.add(e);
+                    }
+                }
+            }
+            return filteredElements;
+        }
+
+        void add(Element element) {
+            elements.add(element);
+        }
+
+        void addAttribute(String name, Object value) {
+            attributes.add(new Attribute(name, String.valueOf(value)));
+        }
+
+        Element newChild(String name) {
+            Element e = new Element(name);
+            elements.add(e);
+            return e;
+        }
+
+        public void addArrayAttribute(Element element, String name, Object value) {
+            String typeName = value.getClass().getComponentType().getName();
+            switch (typeName) {
+            case "int":
+                int[] ints = (int[]) value;
+                for (int i = 0; i < ints.length; i++) {
+                    addAttribute(name  + "-" + i , ints[i]);
+                }
+                break;
+            case "long":
+                long[] longs = (long[]) value;
+                for (int i = 0; i < longs.length; i++) {
+                    addAttribute(name  + "-" + i , longs[i]);
+                }
+                break;
+            case "float":
+                float[] floats = (float[]) value;
+                for (int i = 0; i < floats.length; i++) {
+                    addAttribute(name  + "-" + i , floats[i]);
+                }
+                break;
+
+            case "double":
+                double[] doubles = (double[]) value;
+                for (int i = 0; i < doubles.length; i++) {
+                    addAttribute(name  + "-" + i , doubles[i]);
+                }
+                break;
+            case "short":
+                short[] shorts = (short[]) value;
+                for (int i = 0; i < shorts.length; i++) {
+                    addAttribute(name  + "-" + i , shorts[i]);
+                }
+                break;
+            case "char":
+                char[] chars = (char[]) value;
+                for (int i = 0; i < chars.length; i++) {
+                    addAttribute(name  + "-" + i , chars[i]);
+                }
+                break;
+            case "byte":
+                byte[] bytes = (byte[]) value;
+                for (int i = 0; i < bytes.length; i++) {
+                    addAttribute(name  + "-" + i , bytes[i]);
+                }
+                break;
+            case "boolean":
+                boolean[] booleans = (boolean[]) value;
+                for (int i = 0; i < booleans.length; i++) {
+                    addAttribute(name  + "-" + i , booleans[i]);
+                }
+                break;
+            case "java.lang.String":
+                String[] strings = (String[]) value;
+                for (int i = 0; i < strings.length; i++) {
+                    addAttribute(name  + "-" + i , strings[i]);
+                }
+                break;
+            default:
+                throw new InternalError("Array type of " + typeName + " is not supported");
+            }
+        }
+    }
+
+    static final String ATTRIBUTE_ID = "id";
+    static final String ATTRIBUTE_SIMPLE_TYPE = "simpleType";
+    static final String ATTRIBUTE_GMT_OFFSET = "gmtOffset";
+    static final String ATTRIBUTE_LOCALE = "locale";
+    static final String ELEMENT_TYPE = "class";
+    static final String ELEMENT_SETTING = "setting";
+    static final String ELEMENT_ANNOTATION = "annotation";
+    static final String ELEMENT_FIELD = "field";
+    static final String ATTRIBUTE_SUPER_TYPE = "superType";
+    static final String ATTRIBUTE_TYPE_ID = "class";
+    static final String ATTRIBUTE_DIMENSION = "dimension";
+    static final String ATTRIBUTE_NAME = "name";
+    static final String ATTRIBUTE_CONSTANT_POOL = "constantPool";
+    static final String ATTRIBUTE_DEFAULT_VALUE = "defaultValue";
+
+    final List<EventType> eventTypes = new ArrayList<>();
+    final Collection<Type> types = new ArrayList<>();
+    long gmtOffset;
+    String locale;
+    Element root;
+
+    // package private
+    MetadataDescriptor() {
+    }
+
+    private static void prettyPrintXML(Appendable sb, String indent, Element e) throws IOException {
+        sb.append(indent + "<" + e.name);
+        for (Attribute a : e.attributes) {
+            sb.append(" ").append(a.name).append("=\"").append(a.value).append("\"");
+        }
+        if (e.elements.size() == 0) {
+            sb.append("/");
+        }
+        sb.append(">\n");
+        for (Element child : e.elements) {
+            prettyPrintXML(sb, indent + "  ", child);
+        }
+        if (e.elements.size() != 0) {
+            sb.append(indent).append("</").append(e.name).append(">\n");
+        }
+    }
+
+    public Collection<Type> getTypes() {
+        return types;
+    }
+
+    public List<EventType> getEventTypes() {
+        return eventTypes;
+    }
+
+    public int getGMTOffset() {
+        return (int) gmtOffset;
+    }
+
+    public String getLocale() {
+        return locale;
+    }
+
+    public static MetadataDescriptor read(DataInput input) throws IOException {
+        MetadataReader r = new MetadataReader(input);
+        return r.getDescriptor();
+    }
+
+    static void write(List<Type> types, DataOutput output) throws IOException {
+        MetadataDescriptor m = new MetadataDescriptor();
+        m.locale = Locale.getDefault().toString();
+        m.gmtOffset = TimeZone.getDefault().getRawOffset();
+        m.types.addAll(types);
+        MetadataWriter w = new MetadataWriter(m);
+        w.writeBinary(output);
+    }
+
+    @Override
+    public String toString() {
+        return root.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataHandler.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,403 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import jdk.internal.org.xml.sax.Attributes;
+import jdk.internal.org.xml.sax.EntityResolver;
+import jdk.internal.org.xml.sax.SAXException;
+import jdk.internal.org.xml.sax.helpers.DefaultHandler;
+import jdk.internal.util.xml.SAXParser;
+import jdk.internal.util.xml.impl.SAXParserImpl;
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.Category;
+import jdk.jfr.Description;
+import jdk.jfr.Enabled;
+import jdk.jfr.Experimental;
+import jdk.jfr.Label;
+import jdk.jfr.Period;
+import jdk.jfr.Relational;
+import jdk.jfr.StackTrace;
+import jdk.jfr.Threshold;
+import jdk.jfr.TransitionFrom;
+import jdk.jfr.TransitionTo;
+import jdk.jfr.Unsigned;
+
+final class MetadataHandler extends DefaultHandler implements EntityResolver {
+
+    static class TypeElement {
+        List<FieldElement> fields = new ArrayList<>();
+        String name;
+        String label;
+        String description;
+        String category;
+        String superType;
+        String period;
+        boolean thread;
+        boolean startTime;
+        boolean stackTrace;
+        boolean cutoff;
+        boolean isEvent;
+        boolean experimental;
+        boolean valueType;
+    }
+
+    static class FieldElement {
+        TypeElement referenceType;
+        String name;
+        String label;
+        String description;
+        String contentType;
+        String typeName;
+        String transition;
+        String relation;
+        boolean struct;
+        boolean array;
+        boolean experimental;
+        boolean unsigned;
+    }
+
+    static class XmlType {
+        String name;
+        String javaType;
+        String contentType;
+        boolean unsigned;
+    }
+
+    final Map<String, TypeElement> types = new LinkedHashMap<>(200);
+    final Map<String, XmlType> xmlTypes = new HashMap<>(20);
+    final Map<String, AnnotationElement> xmlContentTypes = new HashMap<>(20);
+    final List<String> relations = new ArrayList<>();
+    long eventTypeId = 255;
+    long structTypeId = 33;
+    FieldElement currentField;
+    TypeElement currentType;
+
+    @Override
+    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+        switch (qName) {
+        case "XmlType":
+            XmlType xmlType = new XmlType();
+            xmlType.name = attributes.getValue("name");
+            xmlType.javaType = attributes.getValue("javaType");
+            xmlType.contentType = attributes.getValue("contentType");
+            xmlType.unsigned = Boolean.valueOf(attributes.getValue("unsigned"));
+            xmlTypes.put(xmlType.name, xmlType);
+            break;
+        case "Type":
+        case "Event":
+            currentType = new TypeElement();
+            currentType.name = attributes.getValue("name");
+            currentType.label = attributes.getValue("label");
+            currentType.description = attributes.getValue("description");
+            currentType.category = attributes.getValue("category");
+            currentType.thread = getBoolean(attributes, "thread", false);
+            currentType.stackTrace = getBoolean(attributes, "stackTrace", false);
+            currentType.startTime = getBoolean(attributes, "startTime", true);
+            currentType.period = attributes.getValue("period");
+            currentType.cutoff = getBoolean(attributes, "cutoff", false);
+            currentType.experimental = getBoolean(attributes, "experimental", false);
+            currentType.isEvent = qName.equals("Event");
+            break;
+        case "Field":
+            currentField = new FieldElement();
+            currentField.struct = getBoolean(attributes, "struct", false);
+            currentField.array = getBoolean(attributes, "array", false);
+            currentField.name = attributes.getValue("name");
+            currentField.label = attributes.getValue("label");
+            currentField.typeName = attributes.getValue("type");
+            currentField.description = attributes.getValue("description");
+            currentField.experimental = getBoolean(attributes, "experimental", false);
+            currentField.contentType = attributes.getValue("contentType");
+            currentField.relation = attributes.getValue("relation");
+            currentField.transition = attributes.getValue("transition");
+            break;
+        case "XmlContentType":
+            String name = attributes.getValue("name");
+            String type = attributes.getValue("annotationType");
+            String value = attributes.getValue("annotationValue");
+            Class<? extends Annotation> annotationType = createAnnotationClass(type);
+            AnnotationElement ae = value == null ? new AnnotationElement(annotationType) : new AnnotationElement(annotationType, value);
+            xmlContentTypes.put(name, ae);
+            break;
+        case "Relation":
+            String n = attributes.getValue("name");
+            relations.add(n);
+            break;
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private Class<? extends Annotation> createAnnotationClass(String type) {
+        try {
+            if (!type.startsWith("jdk.jfr.")) {
+                throw new IllegalStateException("Incorrect type " + type + ". Annotation class must be located in jdk.jfr package.");
+            }
+            Class<?> c = Class.forName(type, true, null);
+            return (Class<? extends Annotation>) c;
+        } catch (ClassNotFoundException cne) {
+            throw new IllegalStateException(cne);
+        }
+    }
+
+    private boolean getBoolean(Attributes attributes, String name, boolean defaultValue) {
+        String value = attributes.getValue(name);
+        return value == null ? defaultValue : Boolean.valueOf(value);
+    }
+
+    @Override
+    public void endElement(String uri, String localName, String qName) {
+        switch (qName) {
+        case "Type":
+        case "Event":
+            types.put(currentType.name, currentType);
+            currentType = null;
+            break;
+        case "Field":
+            currentType.fields.add(currentField);
+            currentField = null;
+            break;
+        }
+    }
+
+    public static List<Type> createTypes() throws IOException {
+        SAXParser parser = new SAXParserImpl();
+        MetadataHandler t = new MetadataHandler();
+        try (InputStream is = new BufferedInputStream(SecuritySupport.getResourceAsStream("/jdk/jfr/internal/types/metadata.xml"))) {
+            Logger.log(LogTag.JFR_SYSTEM, LogLevel.DEBUG, () -> "Parsing metadata.xml");
+            try {
+                parser.parse(is, t);
+                return t.buildTypes();
+            } catch (Exception e) {
+                e.printStackTrace();
+                throw new IOException(e);
+            }
+        }
+    }
+
+    private List<Type> buildTypes() {
+        removeXMLConvenience();
+        Map<String, Type> typeMap = buildTypeMap();
+        Map<String, AnnotationElement> relationMap = buildRelationMap(typeMap);
+        addFields(typeMap, relationMap);
+        return trimTypes(typeMap);
+    }
+
+    private Map<String, AnnotationElement> buildRelationMap(Map<String, Type> typeMap) {
+        Map<String, AnnotationElement> relationMap = new HashMap<>();
+        for (String relation : relations) {
+            Type relationType = new Type(Type.TYPES_PREFIX + relation, Type.SUPER_TYPE_ANNOTATION, eventTypeId++);
+            relationType.setAnnotations(Collections.singletonList(new AnnotationElement(Relational.class)));
+            AnnotationElement ae = PrivateAccess.getInstance().newAnnotation(relationType, Collections.emptyList(), true);
+            relationMap.put(relation, ae);
+            typeMap.put(relationType.getName(), relationType);
+        }
+        return relationMap;
+    }
+
+    private List<Type> trimTypes(Map<String, Type> lookup) {
+        List<Type> trimmedTypes = new ArrayList<>(lookup.size());
+        for (Type t : lookup.values()) {
+            t.trimFields();
+            trimmedTypes.add(t);
+        }
+        return trimmedTypes;
+    }
+
+    private void addFields(Map<String, Type> lookup, Map<String, AnnotationElement> relationMap) {
+        for (TypeElement te : types.values()) {
+            Type type = lookup.get(te.name);
+            if (te.isEvent) {
+                boolean periodic = te.period!= null;
+                TypeLibrary.addImplicitFields(type, periodic, te.startTime && !periodic, te.thread, te.stackTrace && !periodic, te.cutoff);
+            }
+            for (FieldElement f : te.fields) {
+                Type fieldType = Type.getKnownType(f.typeName);
+                if (fieldType == null) {
+                    fieldType = Objects.requireNonNull(lookup.get(f.referenceType.name));
+                }
+                List<AnnotationElement> aes = new ArrayList<>();
+                if (f.unsigned) {
+                    aes.add(new AnnotationElement(Unsigned.class));
+                }
+                if (f.contentType != null) {
+                    aes.add(Objects.requireNonNull(xmlContentTypes.get(f.contentType)));
+                }
+                if (f.relation != null) {
+                    aes.add(Objects.requireNonNull(relationMap.get(f.relation)));
+                }
+                if (f.label != null) {
+                    aes.add(new AnnotationElement(Label.class, f.label));
+                }
+                if (f.experimental) {
+                    aes.add(new AnnotationElement(Experimental.class));
+                }
+                if (f.description != null) {
+                    aes.add(new AnnotationElement(Description.class, f.description));
+                }
+                if ("from".equals(f.transition)) {
+                    aes.add(new AnnotationElement(TransitionFrom.class));
+                }
+                if ("to".equals(f.transition)) {
+                    aes.add(new AnnotationElement(TransitionTo.class));
+                }
+                boolean constantPool = !f.struct && f.referenceType != null;
+                type.add(PrivateAccess.getInstance().newValueDescriptor(f.name, fieldType, aes, f.array ? 1 : 0, constantPool, null));
+            }
+        }
+    }
+
+    private Map<String, Type> buildTypeMap() {
+        Map<String, Type> typeMap = new HashMap<>();
+        for (Type type : Type.getKnownTypes()) {
+            typeMap.put(type.getName(), type);
+        }
+
+        for (TypeElement t : types.values()) {
+            List<AnnotationElement> aes = new ArrayList<>();
+            if (t.category != null) {
+                aes.add(new AnnotationElement(Category.class, buildCategoryArray(t.category)));
+            }
+            if (t.label != null) {
+                aes.add(new AnnotationElement(Label.class, t.label));
+            }
+            if (t.description != null) {
+                aes.add(new AnnotationElement(Description.class, t.description));
+            }
+            if (t.isEvent) {
+                if (t.period != null) {
+                    aes.add(new AnnotationElement(Period.class, t.period));
+                } else {
+                    if (t.startTime) {
+                        aes.add(new AnnotationElement(Threshold.class, "0 ns"));
+                    }
+                    if (t.stackTrace) {
+                        aes.add(new AnnotationElement(StackTrace.class, true));
+                    }
+                }
+                if (t.cutoff) {
+                    aes.add(new AnnotationElement(Cutoff.class, Cutoff.INIFITY));
+                }
+            }
+            if (t.experimental) {
+                aes.add(new AnnotationElement(Experimental.class));
+            }
+            Type type;
+            if (t.isEvent) {
+                aes.add(new AnnotationElement(Enabled.class, false));
+                type = new PlatformEventType(t.name,  eventTypeId++, false, true);
+            } else {
+                // Struct types had their own XML-element in the past. To have id assigned in the
+                // same order as generated .hpp file do some tweaks here.
+                boolean valueType = t.name.endsWith("StackFrame") || t.valueType;
+                type = new Type(t.name, null, valueType ?  eventTypeId++ : nextTypeId(t.name), false);
+            }
+            type.setAnnotations(aes);
+            typeMap.put(t.name, type);
+        }
+        return typeMap;
+    }
+
+    private long nextTypeId(String name) {
+        if (Type.THREAD.getName().equals(name)) {
+            return Type.THREAD.getId();
+        }
+        if (Type.STRING.getName().equals(name)) {
+            return Type.STRING.getId();
+        }
+        if (Type.CLASS.getName().equals(name)) {
+            return Type.CLASS.getId();
+        }
+        for (Type type : Type.getKnownTypes()) {
+            if (type.getName().equals(name)) {
+                return type.getId();
+            }
+        }
+        return structTypeId++;
+    }
+
+    private String[] buildCategoryArray(String category) {
+        List<String> categories = new ArrayList<>();
+        StringBuilder sb = new StringBuilder();
+        for (char c : category.toCharArray()) {
+            if (c == ',') {
+                categories.add(sb.toString().trim());
+                sb.setLength(0);
+            } else {
+                sb.append(c);
+            }
+        }
+        categories.add(sb.toString().trim());
+        return categories.toArray(new String[0]);
+    }
+
+    private void removeXMLConvenience() {
+        for (TypeElement t : types.values()) {
+            XmlType xmlType = xmlTypes.get(t.name);
+            if (xmlType != null && xmlType.javaType != null) {
+                t.name = xmlType.javaType; // known type, i.e primitive
+            } else {
+                if (t.isEvent) {
+                    t.name = Type.EVENT_NAME_PREFIX + t.name;
+                } else {
+                    t.name = Type.TYPES_PREFIX + t.name;
+                }
+            }
+        }
+
+        for (TypeElement t : types.values()) {
+            for (FieldElement f : t.fields) {
+                f.referenceType = types.get(f.typeName);
+                XmlType xmlType = xmlTypes.get(f.typeName);
+                if (xmlType != null) {
+                    if (xmlType.javaType != null) {
+                        f.typeName = xmlType.javaType;
+                    }
+                    if (xmlType.contentType != null) {
+                        f.contentType = xmlType.contentType;
+                    }
+                    if (xmlType.unsigned) {
+                        f.unsigned = true;
+                    }
+                }
+                if (f.struct && f.referenceType != null) {
+                    f.referenceType.valueType = true;
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataReader.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_CONSTANT_POOL;
+import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_DIMENSION;
+import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_ID;
+import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_NAME;
+import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_SIMPLE_TYPE;
+import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_SUPER_TYPE;
+import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_TYPE_ID;
+import static jdk.jfr.internal.MetadataDescriptor.ELEMENT_ANNOTATION;
+import static jdk.jfr.internal.MetadataDescriptor.ELEMENT_FIELD;
+import static jdk.jfr.internal.MetadataDescriptor.ELEMENT_SETTING;
+import static jdk.jfr.internal.MetadataDescriptor.ELEMENT_TYPE;
+
+import java.io.DataInput;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.SettingDescriptor;
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.internal.MetadataDescriptor.Element;
+
+/**
+ * Parses metadata.
+ *
+ */
+final class MetadataReader {
+
+    private final DataInput input;
+    private final List<String> pool;
+    private final MetadataDescriptor descriptor;
+    private final Map<Long, Type> types = new HashMap<>();
+
+    public MetadataReader(DataInput input) throws IOException {
+        this.input = input;
+        int size = input.readInt();
+        this.pool = new ArrayList<>(size);
+        for (int i = 0; i < size; i++) {
+            this.pool.add(input.readUTF());
+        }
+        descriptor = new MetadataDescriptor();
+        Element root = createElement();
+        Element metadata = root.elements("metadata").get(0);
+        declareTypes(metadata);
+        defineTypes(metadata);
+        annotateTypes(metadata);
+        buildEvenTypes();
+        Element time = root.elements("region").get(0);
+        descriptor.gmtOffset = time.attribute(MetadataDescriptor.ATTRIBUTE_GMT_OFFSET, 1);
+        descriptor.locale = time.attribute(MetadataDescriptor.ATTRIBUTE_LOCALE, "");
+        descriptor.root = root;
+        if (LogTag.JFR_SYSTEM_PARSER.shouldLog(LogLevel.TRACE.level)) {
+             List<Type> ts = new ArrayList<>(types.values());
+             Collections.sort(ts, (x,y) -> x.getName().compareTo(y.getName()));
+             for (Type t : ts) {
+                 t.log("Found", LogTag.JFR_SYSTEM_PARSER, LogLevel.TRACE);
+             }
+        }
+    }
+
+    private String readString() throws IOException {
+        return pool.get(readInt());
+    }
+
+    private int readInt() throws IOException {
+        return input.readInt();
+    }
+
+    private Element createElement() throws IOException {
+        String name = readString();
+        Element e = new Element(name);
+        int attributeCount = readInt();
+        for (int i = 0; i < attributeCount; i++) {
+            e.addAttribute(readString(), readString());
+        }
+        int childrenCount = readInt();
+        for (int i = 0; i < childrenCount; i++) {
+            e.add(createElement());
+        }
+        return e;
+    }
+
+    private void annotateTypes(Element metadata) throws IOException {
+        for (Element typeElement : metadata.elements(ELEMENT_TYPE)) {
+            Type type = getType(ATTRIBUTE_ID, typeElement);
+            ArrayList<AnnotationElement> aes = new ArrayList<>();
+            for (Element annotationElement : typeElement.elements(ELEMENT_ANNOTATION)) {
+                aes.add(makeAnnotation(annotationElement));
+            }
+            aes.trimToSize();
+            type.setAnnotations(aes);
+
+            int index = 0;
+            if (type instanceof PlatformEventType) {
+                List<SettingDescriptor> settings = ((PlatformEventType) type).getAllSettings();
+                for (Element settingElement : typeElement.elements(ELEMENT_SETTING)) {
+                    ArrayList<AnnotationElement> annotations = new ArrayList<>();
+                    for (Element annotationElement : settingElement.elements(ELEMENT_ANNOTATION)) {
+                        annotations.add(makeAnnotation(annotationElement));
+                    }
+                    annotations.trimToSize();
+                    PrivateAccess.getInstance().setAnnotations(settings.get(index), annotations);
+                    index++;
+                }
+            }
+            index = 0;
+            List<ValueDescriptor> fields = type.getFields();
+            for (Element fieldElement : typeElement.elements(ELEMENT_FIELD)) {
+                ArrayList<AnnotationElement> annotations = new ArrayList<>();
+                for (Element annotationElement : fieldElement.elements(ELEMENT_ANNOTATION)) {
+                    annotations.add(makeAnnotation(annotationElement));
+                }
+                annotations.trimToSize();
+                PrivateAccess.getInstance().setAnnotations(fields.get(index), annotations);
+                index++;
+            }
+        }
+    }
+
+    private AnnotationElement makeAnnotation(Element annotationElement) throws IOException {
+        Type annotationType = getType(ATTRIBUTE_TYPE_ID, annotationElement);
+        List<Object> values = new ArrayList<>();
+        for (ValueDescriptor v : annotationType.getFields()) {
+            if (v.isArray()) {
+                List<Object> list = new ArrayList<>();
+                int index = 0;
+                while (true) {
+                    String text = annotationElement.attribute(v.getName() + "-" + index);
+                    if (text == null) {
+                        break;
+                    }
+                    list.add(objectify(v.getTypeName(), text));
+                    index++;
+                }
+                Object object = Utils.makePrimitiveArray(v.getTypeName(), list);
+                if (object == null) {
+                    throw new IOException("Unsupported type " + list + " in array");
+                }
+                values.add(object);
+            } else {
+                String text = annotationElement.attribute(v.getName());
+                values.add(objectify(v.getTypeName(), text));
+            }
+        }
+        return PrivateAccess.getInstance().newAnnotation(annotationType, values, false);
+    }
+
+    private Object objectify(String typeName, String text) throws IOException {
+        try {
+            switch (typeName) {
+            case "int":
+                return Integer.valueOf(text);
+            case "long":
+                return Long.valueOf(text);
+            case "double":
+                return Double.valueOf(text);
+            case "float":
+                return Float.valueOf(text);
+            case "short":
+                return Short.valueOf(text);
+            case "char":
+                if (text.length() != 1) {
+                    throw new IOException("Unexpected size of char");
+                }
+                return text.charAt(0);
+            case "byte":
+                return Byte.valueOf(text);
+            case "boolean":
+                return Boolean.valueOf(text);
+            case "java.lang.String":
+                return text;
+            }
+        } catch (IllegalArgumentException iae) {
+            throw new IOException("Could not parse text representation of " + typeName);
+        }
+        throw new IOException("Unsupported type for annotation " + typeName);
+    }
+
+    private Type getType(String attribute, Element element) {
+        long id = element.longValue(attribute);
+        Type type = types.get(id);
+        if (type == null) {
+            String name = element.attribute("type");
+            throw new IllegalStateException("Type '" + id + "' is not defined for " + name);
+        }
+        return type;
+    }
+
+    private void buildEvenTypes() {
+        for (Type type : descriptor.types) {
+            if (type instanceof PlatformEventType) {
+                descriptor.eventTypes.add(PrivateAccess.getInstance().newEventType((PlatformEventType) type));
+            }
+        }
+    }
+
+    private void defineTypes(Element metadata) {
+        for (Element typeElement : metadata.elements(ELEMENT_TYPE)) {
+            long id = typeElement.attribute(ATTRIBUTE_ID, -1);
+            Type t = types.get(id);
+            for (Element fieldElement : typeElement.elements(ELEMENT_SETTING)) {
+                String name = fieldElement.attribute(ATTRIBUTE_NAME);
+                String defaultValue = fieldElement.attribute(ATTRIBUTE_NAME);
+                Type settingType = getType(ATTRIBUTE_TYPE_ID, fieldElement);
+                PlatformEventType eventType = (PlatformEventType) t;
+                eventType.add(PrivateAccess.getInstance().newSettingDescriptor(settingType, name, defaultValue, new ArrayList<>(2)));
+            }
+            for (Element fieldElement : typeElement.elements(ELEMENT_FIELD)) {
+                String name = fieldElement.attribute(ATTRIBUTE_NAME);
+                Type fieldType = getType(ATTRIBUTE_TYPE_ID, fieldElement);
+                long dimension = fieldElement.attribute(ATTRIBUTE_DIMENSION, 0);
+                boolean constantPool = fieldElement.attribute(ATTRIBUTE_CONSTANT_POOL) != null;
+                // Add annotation later, because they may refer to undefined
+                // types at this stage
+                t.add(PrivateAccess.getInstance().newValueDescriptor(name, fieldType, new ArrayList<>(), (int) dimension, constantPool, null));
+            }
+            t.trimFields();
+        }
+    }
+
+    private void declareTypes(Element metadata) {
+        for (Element typeElement : metadata.elements(ELEMENT_TYPE)) {
+            String typeName = typeElement.attribute(ATTRIBUTE_NAME);
+            String superType = typeElement.attribute(ATTRIBUTE_SUPER_TYPE);
+            boolean simpleType = typeElement.attribute(ATTRIBUTE_SIMPLE_TYPE) != null;
+            long id = typeElement.attribute(ATTRIBUTE_ID, -1);
+            Type t;
+            if (Type.SUPER_TYPE_EVENT.equals(superType)) {
+                t = new PlatformEventType(typeName, id, false, false);
+            } else {
+                t = new Type(typeName, superType, id, false, simpleType);
+            }
+            types.put(id, t);
+            descriptor.types.add(t);
+        }
+    }
+
+    public MetadataDescriptor getDescriptor() {
+        return descriptor;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import static jdk.jfr.internal.LogLevel.DEBUG;
+import static jdk.jfr.internal.LogTag.JFR_SYSTEM;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.Period;
+import jdk.jfr.StackTrace;
+import jdk.jfr.Threshold;
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.internal.RequestEngine.RequestHook;
+import jdk.jfr.internal.handlers.EventHandler;
+
+public final class MetadataRepository {
+
+    private static final JVM jvm = JVM.getJVM();
+    private static final MetadataRepository instace = new MetadataRepository();
+
+    private final List<EventType> nativeEventTypes = new ArrayList<>(100);
+    private final List<EventControl> nativeControls = new ArrayList<EventControl>(100);
+    private final TypeLibrary typeLibrary = TypeLibrary.getInstance();
+    private final SettingsManager settingsManager = new SettingsManager();
+    private boolean staleMetadata = true;
+    private boolean unregistered;
+    private long lastUnloaded = -1;
+
+    public MetadataRepository() {
+        initializeJVMEventTypes();
+    }
+
+    private void initializeJVMEventTypes() {
+        List<RequestHook> requestHooks = new ArrayList<>();
+        for (Type type : typeLibrary.getTypes()) {
+            if (type instanceof PlatformEventType) {
+                PlatformEventType pEventType = (PlatformEventType) type;
+                EventType eventType = PrivateAccess.getInstance().newEventType(pEventType);
+                pEventType.setHasDuration(eventType.getAnnotation(Threshold.class) != null);
+                pEventType.setHasStackTrace(eventType.getAnnotation(StackTrace.class) != null);
+                pEventType.setHasCutoff(eventType.getAnnotation(Cutoff.class) != null);
+                pEventType.setHasPeriod(eventType.getAnnotation(Period.class) != null);
+                // Must add hook before EventControl is created as it removes
+                // annotations, such as Period and Threshold.
+                if (pEventType.hasPeriod()) {
+                    pEventType.setEventHook(true);
+                    if (!(Type.EVENT_NAME_PREFIX + "ExecutionSample").equals(type.getName())) {
+                        requestHooks.add(new RequestHook(pEventType));
+                    }
+                }
+                nativeControls.add(new EventControl(pEventType));
+                nativeEventTypes.add(eventType);
+            }
+        }
+        RequestEngine.addHooks(requestHooks);
+    }
+
+    public static MetadataRepository getInstance() {
+        return instace;
+    }
+
+    public synchronized List<EventType> getRegisteredEventTypes() {
+        List<EventHandler> handlers = getEventHandlers();
+        List<EventType> eventTypes = new ArrayList<>(handlers.size() + nativeEventTypes.size());
+        for (EventHandler h : handlers) {
+            if (h.isRegistered()) {
+                eventTypes.add(h.getEventType());
+            }
+        }
+        eventTypes.addAll(nativeEventTypes);
+        return eventTypes;
+    }
+
+    public synchronized EventType getEventType(Class<? extends Event> eventClass) {
+        EventHandler h = getHandler(eventClass);
+        if (h != null && h.isRegistered()) {
+            return h.getEventType();
+        }
+        throw new IllegalStateException("Event class " + eventClass.getName() + " is not registered");
+    }
+
+    public synchronized void unregister(Class<? extends Event> eventClass) {
+        Utils.checkRegisterPermission();
+        EventHandler handler = getHandler(eventClass);
+        if (handler != null) {
+            handler.setRegistered(false);
+        }
+        // never registered, ignore call
+    }
+    public synchronized EventType register(Class<? extends Event> eventClass) {
+        return register(eventClass, Collections.emptyList(), Collections.emptyList());
+    }
+
+    public synchronized EventType register(Class<? extends Event> eventClass, List<AnnotationElement> dynamicAnnotations, List<ValueDescriptor> dynamicFields) {
+        Utils.checkRegisterPermission();
+        EventHandler handler = getHandler(eventClass);
+        if (handler == null) {
+            handler = makeHandler(eventClass, dynamicAnnotations, dynamicFields);
+        }
+        handler.setRegistered(true);
+        typeLibrary.addType(handler.getPlatformEventType());
+        if (jvm.isRecording()) {
+            storeDescriptorInJVM(); // needed for emergency dump
+            settingsManager.setEventControl(handler.getEventControl());
+            settingsManager.updateRetransform(Collections.singletonList((eventClass)));
+        } else {
+            setStaleMetadata();
+        }
+        return handler.getEventType();
+    }
+
+    private EventHandler getHandler(Class<? extends Event> eventClass) {
+        Utils.ensureValidEventSubclass(eventClass);
+        SecuritySupport.makeVisibleToJFR(eventClass);
+        Utils.ensureInitialized(eventClass);
+        return Utils.getHandler(eventClass);
+    }
+
+    private EventHandler makeHandler(Class<? extends Event> eventClass, List<AnnotationElement> dynamicAnnotations, List<ValueDescriptor> dynamicFields) throws InternalError {
+        SecuritySupport.addHandlerExport(eventClass);
+        PlatformEventType pEventType = (PlatformEventType) TypeLibrary.createType(eventClass, dynamicAnnotations, dynamicFields);
+        EventType eventType = PrivateAccess.getInstance().newEventType(pEventType);
+        EventControl ec = new EventControl(pEventType, eventClass);
+        Class<? extends EventHandler> handlerClass = null;
+        try {
+            String eventHandlerName = EventHandlerCreator.makeEventHandlerName(eventType.getId());
+            handlerClass = Class.forName(eventHandlerName, false, Event.class.getClassLoader()).asSubclass(EventHandler.class);
+            // Created eagerly on class load, tag as instrumented
+            pEventType.setInstrumented();
+            Logger.log(JFR_SYSTEM, DEBUG, "Found existing event handler for " + eventType.getName());
+       } catch (ClassNotFoundException cne) {
+           EventHandlerCreator ehc = new EventHandlerCreator(eventType.getId(),  ec.getSettingInfos(), eventType, eventClass);
+           handlerClass = ehc.makeEventHandlerClass();
+           Logger.log(LogTag.JFR_SYSTEM, DEBUG, "Created event handler for " + eventType.getName());
+       }
+        EventHandler handler = EventHandlerCreator.instantiateEventHandler(handlerClass, true, eventType, ec);
+        Utils.setHandler(eventClass, handler);
+        return handler;
+    }
+
+
+    public synchronized void setSettings(List<Map<String, String>> list) {
+        settingsManager.setSettings(list);
+    }
+
+    synchronized void disableEvents() {
+        for (EventControl c : getEventControls()) {
+            c.disable();
+        }
+    }
+
+    public synchronized List<EventControl> getEventControls() {
+        List<EventControl> controls = new ArrayList<>();
+        controls.addAll(nativeControls);
+        for (EventHandler eh : getEventHandlers()) {
+            controls.add(eh.getEventControl());
+        }
+        return controls;
+    }
+
+    private void storeDescriptorInJVM() throws InternalError {
+        jvm.storeMetadataDescriptor(getBinaryRepresentation());
+        staleMetadata = false;
+    }
+
+    private static List<EventHandler> getEventHandlers() {
+        List<Class<? extends Event>> allEventClasses = jvm.getAllEventClasses();
+        List<EventHandler> eventHandlers = new ArrayList<>(allEventClasses.size());
+        for (Class<? extends Event> clazz : allEventClasses) {
+            EventHandler eh = Utils.getHandler(clazz);
+            if (eh != null) {
+                eventHandlers.add(eh);
+            }
+        }
+        return eventHandlers;
+    }
+
+    private byte[] getBinaryRepresentation() {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream(40000);
+        DataOutputStream daos = new DataOutputStream(baos);
+        try {
+            List<Type> types = typeLibrary.getTypes();
+            Collections.sort(types);
+            MetadataDescriptor.write(types, daos);
+            daos.flush();
+            return baos.toByteArray();
+        } catch (IOException e) {
+            // should not happen
+            throw new InternalError(e);
+        }
+    }
+
+    synchronized boolean isEnabled(String eventName) {
+        return settingsManager.isEnabled(eventName);
+    }
+
+    synchronized void setStaleMetadata() {
+        staleMetadata = true;
+    }
+
+    // Lock around setOutput ensures that other threads dosn't
+    // emit event after setOutput and unregister the event class, before a call
+    // to storeDescriptorInJVM
+    synchronized void setOutput(String filename) {
+        jvm.setOutput(filename);
+
+        unregisterUnloaded();
+        if (unregistered) {
+            staleMetadata = typeLibrary.clearUnregistered();
+            unregistered = false;
+        }
+        if (staleMetadata) {
+            storeDescriptorInJVM();
+        }
+    }
+
+    private void unregisterUnloaded() {
+        long unloaded = jvm.getUnloadedEventClassCount();
+        if (this.lastUnloaded != unloaded) {
+            this.lastUnloaded = unloaded;
+            List<Class<? extends Event>> eventClasses = jvm.getAllEventClasses();
+            HashSet<Long> knownIds = new HashSet<>(eventClasses.size());
+            for (Class<? extends Event>  ec: eventClasses) {
+                knownIds.add(Type.getTypeId(ec));
+            }
+            for (Type type : typeLibrary.getTypes()) {
+                if (type instanceof PlatformEventType) {
+                    if (!knownIds.contains(type.getId())) {
+                        PlatformEventType pe = (PlatformEventType) type;
+                        if (!pe.isJVM()) {
+                            pe.setRegistered(false);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    synchronized public void setUnregistered() {
+       unregistered = true;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataWriter.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_CONSTANT_POOL;
+import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_DEFAULT_VALUE;
+import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_DIMENSION;
+import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_GMT_OFFSET;
+import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_ID;
+import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_LOCALE;
+import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_NAME;
+import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_SIMPLE_TYPE;
+import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_SUPER_TYPE;
+import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_TYPE_ID;
+import static jdk.jfr.internal.MetadataDescriptor.ELEMENT_ANNOTATION;
+import static jdk.jfr.internal.MetadataDescriptor.ELEMENT_FIELD;
+import static jdk.jfr.internal.MetadataDescriptor.ELEMENT_SETTING;
+import static jdk.jfr.internal.MetadataDescriptor.ELEMENT_TYPE;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Set;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.SettingDescriptor;
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.internal.MetadataDescriptor.Attribute;
+import jdk.jfr.internal.MetadataDescriptor.Element;
+import jdk.jfr.internal.consumer.RecordingInput;
+
+/**
+ * Class responsible for converting a list of types into a format that can be
+ * parsed by a client.
+ *
+ */
+final class MetadataWriter {
+
+    private final Element metadata = new Element("metadata");
+    private final Element root = new Element("root");
+
+    public MetadataWriter(MetadataDescriptor descriptor) {
+        descriptor.getTypes().forEach(type -> makeTypeElement(metadata, type));
+
+        root.add(metadata);
+        Element region = new Element("region");
+        region.addAttribute(ATTRIBUTE_LOCALE, descriptor.locale);
+        region.addAttribute(ATTRIBUTE_GMT_OFFSET, descriptor.gmtOffset);
+        root.add(region);
+    }
+
+    public void writeBinary(DataOutput output) throws IOException {
+        Set<String> stringPool = new HashSet<>(1000);
+        // Possible improvement, sort string by how often they occur.
+        // and assign low number to the most frequently used.
+        buildStringPool(root, stringPool);
+        HashMap<String, Integer> lookup = new LinkedHashMap<>(stringPool.size());
+        int index = 0;
+        int poolSize = stringPool.size();
+        writeInt(output, poolSize);
+        for (String s : stringPool) {
+            lookup.put(s, index);
+            writeString(output, s);
+            index++;
+        }
+        write(output, root, lookup);
+    }
+
+    private void writeString(DataOutput out, String s) throws IOException {
+        if (s == null ) {
+            out.writeByte(RecordingInput.STRING_ENCODING_NULL);
+            return;
+        }
+        out.writeByte(RecordingInput.STRING_ENCODING_CHAR_ARRAY); // encoding UTF-16
+        int length = s.length();
+        writeInt(out, length);
+            for (int i = 0; i < length; i++) {
+                writeInt(out, s.charAt(i));
+            }
+    }
+
+    private void writeInt(DataOutput out, int v) throws IOException {
+
+        long s = v & 0xffffffffL;
+        if (s < 1 << 7) {
+            out.write((byte) (s));
+            return;
+        }
+        out.write((byte) (s | 0x80)); // first byte written
+        s >>= 7;
+        if (s < 1 << 7) {
+            out.write((byte) (s));
+            return;
+        }
+        out.write((byte) (s | 0x80)); // second byte written
+        s >>= 7;
+        if (s < 1 << 7) {
+            out.write((byte) (s));
+            return;
+        }
+        out.write((byte) (s | 0x80)); // third byte written
+        s >>= 7;
+        if (s < 1 << 7) {
+            out.write((byte) (s));
+            return;
+        }
+        s >>= 7;
+        out.write((byte) (s));// fourth byte written
+    }
+
+    private void buildStringPool(Element element, Set<String> pool) {
+        pool.add(element.name);
+        for (Attribute a : element.attributes) {
+            pool.add(a.name);
+            pool.add(a.value);
+        }
+        for (Element child : element.elements) {
+            buildStringPool(child, pool);
+        }
+    }
+
+    private void write(DataOutput output,Element element, HashMap<String, Integer> lookup) throws IOException {
+        writeInt(output, lookup.get(element.name));
+        writeInt(output, element.attributes.size());
+        for (Attribute a : element.attributes) {
+            writeInt(output, lookup.get(a.name));
+            writeInt(output, lookup.get(a.value));
+        }
+        writeInt(output, element.elements.size());
+        for (Element child : element.elements) {
+            write(output, child, lookup);
+        }
+    }
+
+    private void makeTypeElement(Element root, Type type) {
+        Element element = root.newChild(ELEMENT_TYPE);
+        element.addAttribute(ATTRIBUTE_NAME, type.getName());
+        String superType = type.getSuperType();
+        if (superType != null) {
+            element.addAttribute(ATTRIBUTE_SUPER_TYPE, superType);
+        }
+        if (type.isSimpleType()) {
+            element.addAttribute(ATTRIBUTE_SIMPLE_TYPE, true);
+        }
+        element.addAttribute(ATTRIBUTE_ID, type.getId());
+        if (type instanceof PlatformEventType) {
+            for (SettingDescriptor v : ((PlatformEventType)type).getSettings()) {
+                makeSettingElement(element, v);
+            }
+        }
+        for (ValueDescriptor v : type.getFields()) {
+            makeFieldElement(element, v);
+        }
+        for (AnnotationElement a : type.getAnnotationElements()) {
+            makeAnnotation(element, a);
+        }
+    }
+
+    private void makeSettingElement(Element typeElement, SettingDescriptor s) {
+        Element element = typeElement.newChild(ELEMENT_SETTING);
+        element.addAttribute(ATTRIBUTE_NAME, s.getName());
+        element.addAttribute(ATTRIBUTE_TYPE_ID, s.getTypeId());
+        element.addAttribute(ATTRIBUTE_DEFAULT_VALUE, s.getDefaultValue());
+        for (AnnotationElement a : s.getAnnotationElements()) {
+            makeAnnotation(element, a);
+        }
+    }
+
+    private void makeFieldElement(Element typeElement, ValueDescriptor v) {
+        Element element = typeElement.newChild(ELEMENT_FIELD);
+        element.addAttribute(ATTRIBUTE_NAME, v.getName());
+        element.addAttribute(ATTRIBUTE_TYPE_ID, v.getTypeId());
+        if (v.isArray()) {
+            element.addAttribute(ATTRIBUTE_DIMENSION, 1);
+        }
+        if (PrivateAccess.getInstance().isConstantPool(v)) {
+            element.addAttribute(ATTRIBUTE_CONSTANT_POOL, true);
+        }
+        for (AnnotationElement a : v.getAnnotationElements()) {
+            makeAnnotation(element, a);
+        }
+    }
+
+    private void makeAnnotation(Element entity, AnnotationElement annotation) {
+        Element element = entity.newChild(ELEMENT_ANNOTATION);
+        element.addAttribute(ATTRIBUTE_TYPE_ID, annotation.getTypeId());
+        List<Object> values = annotation.getValues();
+        int index = 0;
+        for (ValueDescriptor v : annotation.getValueDescriptors()) {
+            Object value = values.get(index++);
+            if (v.isArray()) {
+                element.addArrayAttribute(element, v.getName(), value);
+            } else {
+                element.addAttribute(v.getName(), value);
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/Options.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import jdk.jfr.internal.SecuritySupport.SafePath;
+import jdk.internal.misc.Unsafe;
+
+/**
+ * Options that control Flight Recorder.
+ *
+ * Can be set using JFR.configure
+ *
+ */
+public final class Options {
+
+    private final static JVM jvm = JVM.getJVM();
+    private final static long WAIT_INTERVAL = 1000; // ms;
+
+    private final static long MIN_MAX_CHUNKSIZE = 1024 * 1024;
+
+    private static final long DEFAULT_GLOBAL_BUFFER_COUNT = 20;
+    private static final long DEFAULT_GLOBAL_BUFFER_SIZE = 524288;
+    private static final long DEFAULT_MEMORY_SIZE = DEFAULT_GLOBAL_BUFFER_COUNT * DEFAULT_GLOBAL_BUFFER_SIZE;
+    private static long DEFAULT_THREAD_BUFFER_SIZE;
+    private static final int DEFAULT_STACK_DEPTH = 64;
+    private static final boolean DEFAULT_SAMPLE_THREADS = true;
+    private static final long DEFAULT_MAX_CHUNK_SIZE = 12 * 1024 * 1024;
+    private static final SafePath DEFAULT_DUMP_PATH = SecuritySupport.USER_HOME;
+
+    private static long memorySize;
+    private static long globalBufferSize;
+    private static long globalBufferCount;
+    private static long threadBufferSize;
+    private static int stackDepth;
+    private static boolean sampleThreads;
+    private static long maxChunkSize;
+    private static SafePath dumpPath;
+
+    static {
+        final long pageSize = Unsafe.getUnsafe().pageSize();
+        DEFAULT_THREAD_BUFFER_SIZE = pageSize > 8 * 1024 ? pageSize : 8 * 1024;
+        reset();
+    }
+
+    public static synchronized void setMaxChunkSize(long max) {
+        if (max < MIN_MAX_CHUNKSIZE) {
+            throw new IllegalArgumentException("Max chunk size must be at least " + MIN_MAX_CHUNKSIZE);
+        }
+        jvm.setFileNotification(max);
+        maxChunkSize = max;
+    }
+
+    public static synchronized long getMaxChunkSize() {
+        return maxChunkSize;
+    }
+
+    public static synchronized void setMemorySize(long memSize) {
+        jvm.setMemorySize(memSize);
+        memorySize = memSize;
+    }
+
+    public static synchronized long getMemorySize() {
+        return memorySize;
+    }
+
+    public static synchronized void setThreadBufferSize(long threadBufSize) {
+        jvm.setThreadBufferSize(threadBufSize);
+        threadBufferSize = threadBufSize;
+    }
+
+    public static synchronized long getThreadBufferSize() {
+        return threadBufferSize;
+    }
+
+    public static synchronized long getGlobalBufferSize() {
+        return globalBufferSize;
+    }
+
+    public static synchronized void setGlobalBufferCount(long globalBufCount) {
+        jvm.setGlobalBufferCount(globalBufCount);
+        globalBufferCount = globalBufCount;
+    }
+
+    public static synchronized long getGlobalBufferCount() {
+        return globalBufferCount;
+    }
+
+    public static synchronized void setGlobalBufferSize(long globalBufsize) {
+        jvm.setGlobalBufferSize(globalBufsize);
+        globalBufferSize = globalBufsize;
+    }
+
+    public static synchronized void setDumpPath(SafePath path) {
+        dumpPath = path;
+    }
+
+    public static synchronized SafePath getDumpPath() {
+        return dumpPath;
+    }
+
+    public static synchronized void setStackDepth(Integer stackTraceDepth) {
+        jvm.setStackDepth(stackTraceDepth);
+        stackDepth = stackTraceDepth;
+    }
+
+    public static synchronized int getStackDepth() {
+        return stackDepth;
+    }
+
+    public static synchronized void setSampleThreads(Boolean sample) {
+        jvm.setSampleThreads(sample);
+        sampleThreads = sample;
+    }
+
+    public static synchronized boolean getSampleThreads() {
+        return sampleThreads;
+    }
+
+    private static synchronized void reset() {
+        setMaxChunkSize(DEFAULT_MAX_CHUNK_SIZE);
+        setMemorySize(DEFAULT_MEMORY_SIZE);
+        setGlobalBufferSize(DEFAULT_GLOBAL_BUFFER_SIZE);
+        setGlobalBufferCount(DEFAULT_GLOBAL_BUFFER_COUNT);
+        setDumpPath(DEFAULT_DUMP_PATH);
+        setSampleThreads(DEFAULT_SAMPLE_THREADS);
+        setStackDepth(DEFAULT_STACK_DEPTH);
+        setThreadBufferSize(DEFAULT_THREAD_BUFFER_SIZE);
+    }
+
+    static synchronized long getWaitInterval() {
+        return WAIT_INTERVAL;
+    }
+
+    static void ensureInitialized() {
+        // trigger clinit which will setup JVM defaults.
+    }
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformEventType.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+import jdk.jfr.SettingDescriptor;
+
+/**
+ * Implementation of event type.
+ *
+ * To avoid memory leaks, this class must not hold strong reference to an event
+ * class or a setting class
+ */
+public final class PlatformEventType extends Type {
+    private final boolean isJVM;
+    private final boolean  isJDK;
+    private final boolean isMethodSampling;
+    private final List<SettingDescriptor> settings = new ArrayList<>(5);
+    private final boolean dynamicSettings;
+    private final int stackTraceOffset;
+
+    // default values
+    private boolean enabled = false;
+    private boolean stackTraceEnabled = true;
+    private long thresholdTicks = 0;
+    private long period = 0;
+    private boolean hasHook;
+
+    private boolean beginChunk;
+    private boolean endChunk;
+    private boolean hasStackTrace = true;
+    private boolean hasDuration = true;
+    private boolean hasPeriod = true;
+    private boolean hasCutoff = false;
+    private boolean isInstrumented;
+    private boolean markForInstrumentation;
+    private boolean registered = true;
+    private boolean commitable = enabled && registered;
+
+
+    // package private
+    PlatformEventType(String name, long id, boolean isJDK, boolean dynamicSettings) {
+        super(name, Type.SUPER_TYPE_EVENT, id);
+        this.dynamicSettings = dynamicSettings;
+        this.isJVM = Type.isDefinedByJVM(id);
+        this.isMethodSampling = name.equals(Type.EVENT_NAME_PREFIX + "ExecutionSample") || name.equals(Type.EVENT_NAME_PREFIX + "NativeMethodSample");
+        this.isJDK = isJDK;
+        this.stackTraceOffset = stackTraceOffset(name, isJDK);
+    }
+
+    private static int stackTraceOffset(String name, boolean isJDK) {
+        if (isJDK) {
+            if (name.equals(Type.EVENT_NAME_PREFIX + "JavaExceptionThrow")) {
+                return 5;
+            }
+            if (name.equals(Type.EVENT_NAME_PREFIX + "JavaErrorThrow")) {
+                return 5;
+            }
+        }
+        return 4;
+    }
+
+    public void add(SettingDescriptor settingDescriptor) {
+        Objects.requireNonNull(settingDescriptor);
+        settings.add(settingDescriptor);
+    }
+
+    public List<SettingDescriptor> getSettings() {
+        if (dynamicSettings) {
+            List<SettingDescriptor> list = new ArrayList<>(settings.size());
+            for (SettingDescriptor s : settings) {
+                if (Utils.isSettingVisible(s.getTypeId(), hasHook)) {
+                    list.add(s);
+                }
+            }
+            return list;
+        }
+        return settings;
+    }
+
+    public List<SettingDescriptor> getAllSettings() {
+        return settings;
+    }
+
+    public void setHasStackTrace(boolean hasStackTrace) {
+        this.hasStackTrace = hasStackTrace;
+    }
+
+    public void setHasDuration(boolean hasDuration) {
+        this.hasDuration = hasDuration;
+    }
+
+    public void setHasCutoff(boolean hasCutoff) {
+       this.hasCutoff = hasCutoff;
+    }
+
+    public void setCutoff(long cutoffNanos) {
+        if (isJVM) {
+            long cutoffTicks = Utils.nanosToTicks(cutoffNanos);
+            JVM.getJVM().setCutoff(getId(), cutoffTicks);
+        }
+    }
+
+    public void setHasPeriod(boolean hasPeriod) {
+        this.hasPeriod = hasPeriod;
+    }
+
+    public boolean hasStackTrace() {
+        return this.hasStackTrace;
+    }
+
+    public boolean hasDuration() {
+        return this.hasDuration;
+    }
+
+    public boolean hasPeriod() {
+        return this.hasPeriod;
+    }
+
+    public boolean hasCutoff() {
+        return this.hasCutoff;
+    }
+
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    public boolean isJVM() {
+        return isJVM;
+    }
+
+    public boolean isJDK() {
+        return isJDK;
+    }
+
+    public void setEnabled(boolean enabled) {
+        this.enabled = enabled;
+        updateCommitable();
+        if (isJVM) {
+            if (isMethodSampling) {
+                long p = enabled ? period : 0;
+                JVM.getJVM().setMethodSamplingInterval(getId(), p);
+            } else {
+                JVM.getJVM().setEnabled(getId(), enabled);
+            }
+        }
+    }
+
+    public void setPeriod(long periodMillis, boolean beginChunk, boolean endChunk) {
+        if (isMethodSampling) {
+            long p = enabled ? periodMillis : 0;
+            JVM.getJVM().setMethodSamplingInterval(getId(), p);
+        }
+        this.beginChunk = beginChunk;
+        this.endChunk = endChunk;
+        this.period = periodMillis;
+    }
+
+    public void setStackTraceEnabled(boolean stackTraceEnabled) {
+        this.stackTraceEnabled = stackTraceEnabled;
+        if (isJVM) {
+            JVM.getJVM().setStackTraceEnabled(getId(), stackTraceEnabled);
+        }
+    }
+
+    public void setThreshold(long thresholdNanos) {
+        this.thresholdTicks = Utils.nanosToTicks(thresholdNanos);
+        if (isJVM) {
+            JVM.getJVM().setThreshold(getId(), thresholdTicks);
+        }
+    }
+
+    public boolean isEveryChunk() {
+        return period == 0;
+    }
+
+    public boolean getStackTraceEnabled() {
+        return stackTraceEnabled;
+    }
+
+    public long getThresholdTicks() {
+        return thresholdTicks;
+    }
+
+    public long getPeriod() {
+        return period;
+    }
+
+    public boolean hasEventHook() {
+        return hasHook;
+    }
+
+    public void setEventHook(boolean hasHook) {
+        this.hasHook = hasHook;
+    }
+
+    public boolean isBeginChunk() {
+        return beginChunk;
+    }
+
+    public boolean isEndChunk() {
+        return endChunk;
+    }
+
+    public boolean isInstrumented() {
+        return isInstrumented;
+    }
+
+    public void setInstrumented() {
+        isInstrumented = true;
+    }
+
+    public void markForInstrumentation(boolean markForInstrumentation) {
+        this.markForInstrumentation = markForInstrumentation;
+    }
+
+    public boolean isMarkedForInstrumentation() {
+        return markForInstrumentation;
+    }
+
+    public boolean setRegistered(boolean registered) {
+        if (this.registered != registered) {
+            this.registered = registered;
+            updateCommitable();
+            LogTag logTag = isJVM() || isJDK() ? LogTag.JFR_SYSTEM_EVENT : LogTag.JFR_EVENT;
+            if (registered) {
+                Logger.log(logTag, LogLevel.INFO, "Registered " + getLogName());
+            } else {
+                Logger.log(logTag, LogLevel.INFO, "Unregistered " + getLogName());
+            }
+            if (!registered) {
+                MetadataRepository.getInstance().setUnregistered();
+            }
+            return true;
+        }
+        return false;
+    }
+
+    private void updateCommitable() {
+        this.commitable = enabled && registered;
+    }
+
+    public final boolean isRegistered() {
+        return registered;
+    }
+
+    // Efficient check of enabled && registered
+    public boolean isCommitable() {
+        return commitable;
+    }
+
+    public int getStackTraceOffset() {
+        return stackTraceOffset;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecorder.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,563 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import static jdk.jfr.internal.LogLevel.INFO;
+import static jdk.jfr.internal.LogLevel.TRACE;
+import static jdk.jfr.internal.LogLevel.WARN;
+import static jdk.jfr.internal.LogTag.JFR;
+import static jdk.jfr.internal.LogTag.JFR_SYSTEM;
+
+import java.io.IOException;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import jdk.jfr.Enabled;
+import jdk.jfr.EventType;
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.FlightRecorderListener;
+import jdk.jfr.Recording;
+import jdk.jfr.RecordingState;
+import jdk.jfr.events.ActiveRecordingEvent;
+import jdk.jfr.events.ActiveSettingEvent;
+import jdk.jfr.internal.SecuritySupport.SecureRecorderListener;
+import jdk.jfr.internal.instrument.JDKEvents;
+import jdk.jfr.internal.settings.CutoffSetting;
+import jdk.jfr.internal.test.WhiteBox;
+
+public final class PlatformRecorder {
+
+    private final List<PlatformRecording> recordings = new ArrayList<>();
+    private final static List<SecureRecorderListener> changeListeners = new ArrayList<>();
+    private final Repository repository;
+    private final Timer timer;
+    private final static JVM jvm = JVM.getJVM();
+    private final EventType activeRecordingEvent;
+    private final EventType activeSettingEvent;
+    private final Thread shutdownHook;
+
+    private long recordingCounter = 0;
+    private RepositoryChunk currentChunk;
+
+    public PlatformRecorder() throws Exception {
+        repository = Repository.getRepository();
+        Logger.log(JFR_SYSTEM, INFO, "Initialized disk repository");
+        repository.ensureRepository();
+        jvm.createNativeJFR();
+        Logger.log(JFR_SYSTEM, INFO, "Created native");
+        JDKEvents.initialize();
+        Logger.log(JFR_SYSTEM, INFO, "Registered JDK events");
+        JDKEvents.addInstrumentation();
+        startDiskMonitor();
+        SecuritySupport.registerEvent(ActiveRecordingEvent.class);
+        activeRecordingEvent = EventType.getEventType(ActiveRecordingEvent.class);
+        SecuritySupport.registerEvent(ActiveSettingEvent.class);
+        activeSettingEvent = EventType.getEventType(ActiveSettingEvent.class);
+        shutdownHook = SecuritySupport.createThreadWitNoPermissions("JFR: Shutdown Hook", new ShutdownHook(this));
+        SecuritySupport.setUncaughtExceptionHandler(shutdownHook, new ShutdownHook.ExceptionHandler());
+        SecuritySupport.registerShutdownHook(shutdownHook);
+        timer = createTimer();
+    }
+
+    private static Timer createTimer() {
+        try {
+            List<Timer> result = new CopyOnWriteArrayList<>();
+            Thread t = SecuritySupport.createThreadWitNoPermissions("Permissionless thread", ()-> {
+                result.add(new Timer("JFR Recording Scheduler", true));
+            });
+            t.start();
+            t.join();
+            return result.get(0);
+        } catch (InterruptedException e) {
+            throw new IllegalStateException("Not able to create timer task. " + e.getMessage(), e);
+        }
+    }
+
+    public synchronized PlatformRecording newRecording(Map<String, String> settings) {
+        PlatformRecording recording = new PlatformRecording(this, ++recordingCounter);
+        if (!settings.isEmpty()) {
+            recording.setSettings(settings);
+        }
+        recordings.add(recording);
+        return recording;
+    }
+
+    synchronized void finish(PlatformRecording recording) {
+        if (recording.getState() == RecordingState.RUNNING) {
+            recording.stop("Recording closed");
+        }
+        recordings.remove(recording);
+    }
+
+    public synchronized List<PlatformRecording> getRecordings() {
+        return Collections.unmodifiableList(new ArrayList<PlatformRecording>(recordings));
+    }
+
+    public synchronized static void addListener(FlightRecorderListener changeListener) {
+        AccessControlContext context = AccessController.getContext();
+        SecureRecorderListener sl = new SecureRecorderListener(context, changeListener);
+        boolean runInitialized;
+        synchronized (PlatformRecorder.class) {
+            runInitialized = FlightRecorder.isInitialized();
+            changeListeners.add(sl);
+        }
+        if (runInitialized) {
+            sl.recorderInitialized(FlightRecorder.getFlightRecorder());
+        }
+    }
+
+    public synchronized static boolean removeListener(FlightRecorderListener changeListener) {
+        for (SecureRecorderListener s : new ArrayList<>(changeListeners)) {
+            if (s.getChangeListener() == changeListener) {
+                changeListeners.remove(s);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    static synchronized List<FlightRecorderListener> getListeners() {
+        return new ArrayList<>(changeListeners);
+    }
+
+    Timer getTimer() {
+        return timer;
+    }
+
+    public static void notifyRecorderInitialized(FlightRecorder recorder) {
+        Logger.log(JFR_SYSTEM, TRACE, "Notifying listeners that Flight Recorder is initialized");
+        for (FlightRecorderListener r : getListeners()) {
+            r.recorderInitialized(recorder);
+        }
+    }
+
+    // called by shutdown hook
+    synchronized void destroy() {
+        try {
+            timer.cancel();
+        } catch (Exception ex) {
+            Logger.log(JFR_SYSTEM, WARN, "Shutdown hook could not cancel timer");
+        }
+
+        for (PlatformRecording p : getRecordings()) {
+            if (p.getState() == RecordingState.RUNNING) {
+                try {
+                    p.stop("Shutdown");
+                } catch (Exception ex) {
+                    Logger.log(JFR, WARN, "Recording " + p.getName() + ":" + p.getId() + " could not be stopped");
+                }
+            }
+        }
+
+        JDKEvents.remove();
+
+        if (jvm.hasNativeJFR()) {
+            if (jvm.isRecording()) {
+                jvm.endRecording_();
+            }
+            jvm.destroyNativeJFR();
+        }
+        repository.clear();
+    }
+
+    synchronized void start(PlatformRecording recording) {
+        // State can only be NEW or DELAYED because of previous checks
+        Instant now = Instant.now();
+        recording.setStartTime(now);
+        recording.updateTimer();
+        Duration duration = recording.getDuration();
+        if (duration != null) {
+            recording.setStopTime(now.plus(duration));
+        }
+        boolean toDisk = recording.isToDisk();
+        boolean beginPhysical = true;
+        for (PlatformRecording s : getRecordings()) {
+            if (s.getState() == RecordingState.RUNNING) {
+                beginPhysical = false;
+                if (s.isToDisk()) {
+                    toDisk = true;
+                }
+            }
+        }
+        if (beginPhysical) {
+            RepositoryChunk newChunk = null;
+            if (toDisk) {
+                newChunk = repository.newChunk(now);
+                MetadataRepository.getInstance().setOutput(newChunk.getUnfishedFile().toString());
+            } else {
+                MetadataRepository.getInstance().setOutput(null);
+            }
+            currentChunk = newChunk;
+            jvm.beginRecording_();
+            recording.setState(RecordingState.RUNNING);
+            updateSettings();
+            writeMetaEvents();
+        } else {
+            RepositoryChunk newChunk = null;
+            if (toDisk) {
+                newChunk = repository.newChunk(now);
+                RequestEngine.doChunkEnd();
+                MetadataRepository.getInstance().setOutput(newChunk.getUnfishedFile().toString());
+            }
+            recording.setState(RecordingState.RUNNING);
+            updateSettings();
+            writeMetaEvents();
+            if (currentChunk != null) {
+                finishChunk(currentChunk, now, recording);
+            }
+            currentChunk = newChunk;
+        }
+
+        RequestEngine.doChunkBegin();
+    }
+
+    synchronized void stop(PlatformRecording recording) {
+        RecordingState state = recording.getState();
+
+        if (Utils.isAfter(state, RecordingState.RUNNING)) {
+            throw new IllegalStateException("Can't stop an already stopped recording.");
+        }
+        if (Utils.isBefore(state, RecordingState.RUNNING)) {
+            throw new IllegalStateException("Recording must be started before it can be stopped.");
+        }
+        Instant now = Instant.now();
+        boolean toDisk = false;
+        boolean endPhysical = true;
+        for (PlatformRecording s : getRecordings()) {
+            RecordingState rs = s.getState();
+            if (s != recording && RecordingState.RUNNING == rs) {
+                endPhysical = false;
+                if (s.isToDisk()) {
+                    toDisk = true;
+                }
+            }
+        }
+        emitOldObjectSamples(recording);
+
+        if (endPhysical) {
+            RequestEngine.doChunkEnd();
+            if (recording.isToDisk()) {
+                if (currentChunk != null) {
+                    MetadataRepository.getInstance().setOutput(null);
+                    finishChunk(currentChunk, now, null);
+                    currentChunk = null;
+                }
+            } else {
+                // last memory
+                dumpMemoryToDestination(recording);
+            }
+            jvm.endRecording_();
+            disableEvents();
+        } else {
+            RepositoryChunk newChunk = null;
+            RequestEngine.doChunkEnd();
+            updateSettingsButIgnoreRecording(recording);
+            if (toDisk) {
+                newChunk = repository.newChunk(now);
+                MetadataRepository.getInstance().setOutput(newChunk.getUnfishedFile().toString());
+            } else {
+                MetadataRepository.getInstance().setOutput(null);
+            }
+            writeMetaEvents();
+            if (currentChunk != null) {
+                finishChunk(currentChunk, now, null);
+            }
+            currentChunk = newChunk;
+            RequestEngine.doChunkBegin();
+        }
+        recording.setState(RecordingState.STOPPED);
+    }
+
+    // Only dump event if the recording that is being stopped
+    // has OldObjectSample enabled + cutoff from recording, not global value
+    private void emitOldObjectSamples(PlatformRecording recording) {
+        Map<String, String> settings = recording.getSettings();
+        String s = settings.get(Type.EVENT_NAME_PREFIX + "OldObjectSample#" + Enabled.NAME);
+        if ("true".equals(s)) {
+            long nanos = CutoffSetting.parseValueSafe(settings.get(Type.EVENT_NAME_PREFIX + "OldObjectSample#" + Cutoff.NAME));
+            long ticks = Utils.nanosToTicks(nanos);
+            JVM.getJVM().emitOldObjectSamples(ticks, WhiteBox.getWriteAllObjectSamples());
+        }
+    }
+
+    private void dumpMemoryToDestination(PlatformRecording recording) {
+        WriteableUserPath dest = recording.getDestination();
+        if (dest != null) {
+            MetadataRepository.getInstance().setOutput(dest.getText());
+            recording.clearDestination();
+        }
+    }
+
+    private void disableEvents() {
+        MetadataRepository.getInstance().disableEvents();
+    }
+
+    void updateSettings() {
+        updateSettingsButIgnoreRecording(null);
+    }
+
+    void updateSettingsButIgnoreRecording(PlatformRecording ignoreMe) {
+        List<PlatformRecording> recordings = getRunningRecordings();
+        List<Map<String, String>> list = new ArrayList<>(recordings.size());
+        for (PlatformRecording r : recordings) {
+            if (r != ignoreMe) {
+                list.add(r.getSettings());
+            }
+        }
+        MetadataRepository.getInstance().setSettings(list);
+    }
+
+    synchronized void rotateDisk() {
+        Instant now = Instant.now();
+        RepositoryChunk newChunk = repository.newChunk(now);
+        RequestEngine.doChunkEnd();
+        MetadataRepository.getInstance().setOutput(newChunk.getUnfishedFile().toString());
+        writeMetaEvents();
+        if (currentChunk != null) {
+            finishChunk(currentChunk, now, null);
+        }
+        currentChunk = newChunk;
+        RequestEngine.doChunkBegin();
+    }
+
+    private List<PlatformRecording> getRunningRecordings() {
+        List<PlatformRecording> runningRecordings = new ArrayList<>();
+        for (PlatformRecording recording : getRecordings()) {
+            if (recording.getState() == RecordingState.RUNNING) {
+                runningRecordings.add(recording);
+            }
+        }
+        return runningRecordings;
+    }
+
+    private List<RepositoryChunk> makeChunkList(Instant startTime, Instant endTime) {
+        Set<RepositoryChunk> chunkSet = new HashSet<>();
+        for (PlatformRecording r : getRecordings()) {
+            chunkSet.addAll(r.getChunks());
+        }
+        if (chunkSet.size() > 0) {
+            List<RepositoryChunk> chunks = new ArrayList<>(chunkSet.size());
+            for (RepositoryChunk rc : chunkSet) {
+                if (rc.inInterval(startTime, endTime)) {
+                    chunks.add(rc);
+                }
+            }
+            // n*log(n), should be able to do n*log(k) with a priority queue,
+            // where k = number of recordings, n = number of chunks
+            Collections.sort(chunks, RepositoryChunk.END_TIME_COMPARATOR);
+            return chunks;
+        }
+
+        return Collections.emptyList();
+    }
+
+    private void startDiskMonitor() {
+        Thread t = SecuritySupport.createThreadWitNoPermissions("JFR Periodic Tasks", () -> periodicTask());
+        SecuritySupport.setDaemonThread(t, true);
+        t.start();
+    }
+
+    private void finishChunk(RepositoryChunk chunk, Instant time, PlatformRecording ignoreMe) {
+        chunk.finish(time);
+        for (PlatformRecording r : getRecordings()) {
+            if (r != ignoreMe && r.getState() == RecordingState.RUNNING) {
+                r.appendChunk(chunk);
+            }
+        }
+    }
+
+    private void writeMetaEvents() {
+
+        if (activeRecordingEvent.isEnabled()) {
+            for (PlatformRecording r : getRecordings()) {
+                if (r.getState() == RecordingState.RUNNING && r.shouldWriteMetadataEvent()) {
+                    ActiveRecordingEvent event = new ActiveRecordingEvent();
+                    event.id = r.getId();
+                    event.name = r.getName();
+                    WriteableUserPath p = r.getDestination();
+                    event.destination = p == null ? null : p.getText();
+                    Duration d = r.getDuration();
+                    event.recordingDuration = d == null ? Long.MAX_VALUE : d.toMillis();
+                    Duration age = r.getMaxAge();
+                    event.maxAge = age == null ? Long.MAX_VALUE : age.toMillis();
+                    Long size = r.getMaxSize();
+                    event.maxSize = size == null ? Long.MAX_VALUE : size;
+                    Instant start = r.getStartTime();
+                    event.recordingStart = start == null ? Long.MAX_VALUE : start.toEpochMilli();
+                    event.commit();
+                }
+            }
+        }
+        if (activeSettingEvent.isEnabled()) {
+            for (EventControl ec : MetadataRepository.getInstance().getEventControls()) {
+                ec.writeActiveSettingEvent();
+            }
+        }
+    }
+
+    private void periodicTask() {
+        while (true) {
+            synchronized (this) {
+                if (!jvm.hasNativeJFR()) {
+                    return;
+                }
+                if (currentChunk != null) {
+                    try {
+                        if (SecuritySupport.getFileSize(currentChunk.getUnfishedFile()) > Options.getMaxChunkSize()) {
+                            rotateDisk();
+                        }
+                    } catch (IOException e) {
+                        Logger.log(JFR_SYSTEM, WARN, "Could not check file size to determine chunk rotation");
+                    }
+                }
+            }
+            long minDelta = RequestEngine.doPeriodic();
+            long wait = Math.min(minDelta, Options.getWaitInterval());
+            takeNap(wait);
+        }
+    }
+
+    private void takeNap(long duration) {
+        try {
+            synchronized (JVM.FILE_DELTA_CHANGE) {
+                JVM.FILE_DELTA_CHANGE.wait(duration < 10 ? 10 : duration);
+            }
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+    }
+
+    synchronized Recording newCopy(PlatformRecording r, boolean stop) {
+        Recording newRec = new Recording();
+        PlatformRecording copy = PrivateAccess.getInstance().getPlatformRecording(newRec);
+        copy.setSettings(r.getSettings());
+        copy.setMaxAge(r.getMaxAge());
+        copy.setMaxSize(r.getMaxSize());
+        copy.setDumpOnExit(r.getDumpOnExit());
+        copy.setName("Clone of " + r.getName());
+        copy.setToDisk(r.isToDisk());
+        copy.setInternalDuration(r.getDuration());
+        copy.setStartTime(r.getStartTime());
+        copy.setStopTime(r.getStopTime());
+
+        if (r.getState() == RecordingState.NEW) {
+            return newRec;
+        }
+        if (r.getState() == RecordingState.DELAYED) {
+            copy.scheduleStart(r.getStartTime());
+            return newRec;
+        }
+        copy.setState(r.getState());
+        // recording has started, copy chunks
+        for (RepositoryChunk c : r.getChunks()) {
+            copy.add(c);
+        }
+        if (r.getState() == RecordingState.RUNNING) {
+            if (stop) {
+                copy.stop("Stopped when cloning recording '" + r.getName() + "'");
+            } else {
+                if (r.getStopTime() != null) {
+                    TimerTask stopTask = copy.createStopTask();
+                    copy.setStopTask(copy.createStopTask());
+                    getTimer().schedule(stopTask, r.getStopTime().toEpochMilli());
+                }
+            }
+        }
+        return newRec;
+    }
+
+    public synchronized Recording newSnapshot() {
+        boolean running = false;
+        boolean toDisk = false;
+        for (PlatformRecording r : recordings) {
+            if (r.getState() == RecordingState.RUNNING) {
+                running = true;
+            }
+            if (r.isToDisk()) {
+                toDisk = true;
+            }
+
+        }
+        // If needed, flush data from memory
+        if (running) {
+            if (toDisk) {
+                rotateDisk();
+            } else {
+                try (Recording snapshot = new Recording()) {
+                    PlatformRecording internal = PrivateAccess.getInstance().getPlatformRecording(snapshot);
+                    internal.setShouldWriteActiveRecordingEvent(false);
+                    snapshot.start();
+                    snapshot.stop();
+                    return makeRecordingWithDiskChunks();
+                }
+            }
+        }
+        return makeRecordingWithDiskChunks();
+    }
+
+    private Recording makeRecordingWithDiskChunks() {
+        Recording snapshot = new Recording();
+        snapshot.setName("Snapshot");
+        PlatformRecording internal = PrivateAccess.getInstance().getPlatformRecording(snapshot);
+        for (RepositoryChunk c : makeChunkList(null, null)) {
+            internal.add(c);
+        }
+        internal.setState(RecordingState.STOPPED);
+        Instant startTime = null;
+        Instant endTime = null;
+
+        for (RepositoryChunk c : makeChunkList(null, null)) {
+            if (startTime == null || c.getStartTime().isBefore(startTime)) {
+                startTime = c.getStartTime();
+            }
+            if (endTime == null || c.getEndTime().isAfter(endTime)) {
+                endTime = c.getEndTime();
+            }
+        }
+        Instant now = Instant.now();
+        if (startTime == null) {
+            startTime = now;
+        }
+        if (endTime == null) {
+            endTime = now;
+        }
+        internal.setStartTime(startTime);
+        internal.setStopTime(endTime);
+        internal.setInternalDuration(Duration.between(startTime, endTime));
+        return snapshot;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,696 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import static jdk.jfr.internal.LogLevel.DEBUG;
+import static jdk.jfr.internal.LogLevel.WARN;
+import static jdk.jfr.internal.LogTag.JFR;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.channels.FileChannel;
+import java.nio.file.StandardOpenOption;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.StringJoiner;
+import java.util.TimerTask;
+import java.util.TreeMap;
+
+import jdk.jfr.Configuration;
+import jdk.jfr.FlightRecorderListener;
+import jdk.jfr.Recording;
+import jdk.jfr.RecordingState;
+
+public final class PlatformRecording implements AutoCloseable {
+
+    private final PlatformRecorder recorder;
+    private final long id;
+    // Recording settings
+    private Map<String, String> settings = new LinkedHashMap<>();
+    private Duration duration;
+    private Duration maxAge;
+    private long maxSize;
+
+    private WriteableUserPath destination;
+
+    private boolean toDisk = true;
+    private String name;
+    private boolean dumpOnExit;
+    // Timestamp information
+    private Instant stopTime;
+    private Instant startTime;
+
+    // Misc, information
+    private RecordingState state = RecordingState.NEW;
+    private long size;
+    private final LinkedList<RepositoryChunk> chunks = new LinkedList<>();
+    private volatile Recording recording;
+    private TimerTask stopTask;
+    private TimerTask startTask;
+    private AccessControlContext noDestinationDumpOnExitAccessControlContext;
+    private boolean shuoldWriteActiveRecordingEvent = true;
+
+    PlatformRecording(PlatformRecorder recorder, long id) {
+        // Typically the access control context is taken
+        // when you call dump(Path) or setDdestination(Path),
+        // but if no destination is set and dumponexit=true
+        // the control context of the recording is taken when the
+        // Recording object is constructed.  This works well for
+        // -XX:StartFlightRecording and JFR.dump
+        this.noDestinationDumpOnExitAccessControlContext = AccessController.getContext();
+        this.id = id;
+        this.recorder = recorder;
+        this.name = String.valueOf(id);
+    }
+
+    public void start() {
+        RecordingState oldState;
+        RecordingState newState;
+        synchronized (recorder) {
+            oldState = recording.getState();
+            if (!Utils.isBefore(state, RecordingState.RUNNING)) {
+                throw new IllegalStateException("Recording can only be started once.");
+            }
+            if (startTask != null) {
+                startTask.cancel();
+                startTask = null;
+                startTime = null;
+            }
+            recorder.start(this);
+            Logger.log(LogTag.JFR, LogLevel.INFO, () -> {
+                // Only print non-default values so it easy to see
+                // which options were added
+                    StringJoiner options = new StringJoiner(", ");
+                    if (!toDisk) {
+                        options.add("disk=false");
+                    }
+                    if (maxAge != null) {
+                        options.add("maxage=" + Utils.formatTimespan(maxAge, ""));
+                    }
+                    if (maxSize != 0) {
+                        options.add("maxsize=" + Utils.formatBytes(maxSize, ""));
+                    }
+                    if (dumpOnExit) {
+                        options.add("dumponexit=true");
+                    }
+                    if (duration != null) {
+                        options.add("duration=" + Utils.formatTimespan(duration, ""));
+                    }
+                    if (destination != null) {
+                        options.add("filename=" + destination.getText());
+                    }
+                    String optionText = options.toString();
+                    if (optionText.length() != 0) {
+                        optionText = "{" + optionText + "}";
+                    }
+                    return "Started recording \"" + getName() + "\" (" + getId() + ") " + optionText;
+                });
+            newState = recording.getState();
+        }
+        notifyIfStateChanged(oldState, newState);
+    }
+
+    public boolean stop(String reason) {
+        return stop(reason, null);
+    }
+
+    public boolean stop(String reason, WriteableUserPath alternativePath) {
+        return stop(reason, alternativePath, Collections.emptyMap());
+    }
+
+    boolean stop(String reason, WriteableUserPath alternativePath, Map<String, String> overlaySettings) {
+        RecordingState oldState;
+        RecordingState newState;
+        synchronized (recorder) {
+            oldState = recording.getState();
+            if (stopTask != null) {
+                stopTask.cancel();
+                stopTask = null;
+            }
+            recorder.stop(this);
+            String endTExt = reason == null ? "" : ". Reason \"" + reason + "\".";
+            Logger.log(LogTag.JFR, LogLevel.INFO, "Stopped recording \"" + recording.getName() + "\" (" + recording.getId()+ ")" + endTExt);
+            this.stopTime = Instant.now();
+            newState = recording.getState();
+        }
+        WriteableUserPath dest = getDestination();
+        if (dest == null && alternativePath != null) {
+            dest = alternativePath;
+        }
+        if (dest != null) {
+            try {
+                copyTo(dest, reason, overlaySettings);
+                Logger.log(LogTag.JFR, LogLevel.INFO, "Wrote recording \"" + recording.getName() + "\" (" + recording.getId()+ ") to " + dest.getText());
+                notifyIfStateChanged(newState, oldState);
+                close(); // remove if copied out
+            } catch (IOException e) {
+                // throw e; // BUG8925030
+            }
+        } else {
+            notifyIfStateChanged(newState, oldState);
+        }
+        return true;
+    }
+
+    public void scheduleStart(Duration delay) {
+        synchronized (recorder) {
+            ensureOkForSchedule();
+
+            startTime = Instant.now().plus(delay);
+            LocalDateTime now = LocalDateTime.now().plus(delay);
+            setState(RecordingState.DELAYED);
+            startTask = createStartTask();
+            recorder.getTimer().schedule(startTask, delay.toMillis());
+            Logger.log(LogTag.JFR, LogLevel.INFO, "Scheduled recording \"" + recording.getName() + "\" (" + recording.getId()+ ") to start at " + now);
+        }
+    }
+
+    private void ensureOkForSchedule() {
+        if (getState() != RecordingState.NEW) {
+            throw new IllegalStateException("Only a new recoridng can be scheduled for start");
+        }
+    }
+
+    private TimerTask createStartTask() {
+        // Taking ref. to recording here.
+        // Opens up for memory leaks.
+        return new TimerTask() {
+            @Override
+            public void run() {
+                synchronized (recorder) {
+                    if (getState() != RecordingState.DELAYED) {
+                        return;
+                    }
+                    start();
+                }
+            }
+        };
+    }
+
+    void scheduleStart(Instant startTime) {
+        synchronized (recorder) {
+            ensureOkForSchedule();
+            this.startTime = startTime;
+            setState(RecordingState.DELAYED);
+            startTask = createStartTask();
+            recorder.getTimer().schedule(startTask, startTime.toEpochMilli());
+        }
+    }
+
+    public Map<String, String> getSettings() {
+        synchronized (recorder) {
+            return settings;
+        }
+    }
+
+    public long getSize() {
+        return size;
+    }
+
+    public Instant getStopTime() {
+        synchronized (recorder) {
+            return stopTime;
+        }
+    }
+
+    public Instant getStartTime() {
+        synchronized (recorder) {
+            return startTime;
+        }
+    }
+
+    public Long getMaxSize() {
+        synchronized (recorder) {
+            return maxSize;
+        }
+    }
+
+    public Duration getMaxAge() {
+        synchronized (recorder) {
+            return maxAge;
+        }
+    }
+
+    public String getName() {
+        synchronized (recorder) {
+            return name;
+        }
+    }
+
+
+    public RecordingState getState() {
+        synchronized (recorder) {
+            return state;
+        }
+    }
+
+    @Override
+    public void close() {
+        RecordingState oldState;
+        RecordingState newState;
+
+        synchronized (recorder) {
+            oldState = getState();
+            if (RecordingState.CLOSED != getState()) {
+                if (startTask != null) {
+                    startTask.cancel();
+                    startTask = null;
+                }
+                recorder.finish(this);
+                for (RepositoryChunk c : chunks) {
+                    removed(c);
+                }
+                chunks.clear();
+                setState(RecordingState.CLOSED);
+                Logger.log(LogTag.JFR, LogLevel.INFO, "Closed recording \"" + getName() + "\" (" + getId()+ ")");
+            }
+            newState = getState();
+        }
+        notifyIfStateChanged(newState, oldState);
+    }
+
+    public void copyTo(WriteableUserPath path, String reason, Map<String, String> dumpSettings) throws IOException {
+        synchronized (recorder) {
+            RecordingState state = getState();
+            if (state == RecordingState.CLOSED) {
+                throw new IOException("Recording \"" + name + "\" (id=" + id + ") has been closed, no contents to write");
+            }
+            if (state == RecordingState.DELAYED || state == RecordingState.NEW) {
+                throw new IOException("Recording \"" + name + "\" (id=" + id + ") has not started, no contents to write");
+            }
+            if (state == RecordingState.STOPPED) {
+                // have all we need, just write it
+                dumpToFile(path, reason, getId());
+                return;
+            }
+
+            // Recording is RUNNING, create a clone
+            try(Recording r = new Recording()) {
+                PlatformRecording clone = PrivateAccess.getInstance().getPlatformRecording(r);
+                clone.setShouldWriteActiveRecordingEvent(false);
+                clone.setName(getName());
+                clone.setDestination(path);
+                clone.setToDisk(true);
+                // We purposely don't clone settings, since
+                // a union a == a
+                if (!isToDisk()) {
+                    // force memory contents to disk
+                    clone.start();
+                } else {
+                    // using existing chunks on disk
+                    for (RepositoryChunk c : chunks) {
+                        clone.add(c);
+                    }
+                    clone.setState(RecordingState.RUNNING);
+                    clone.setStartTime(getStartTime());
+                }
+                if (dumpSettings.isEmpty()) {
+                    clone.setSettings(getSettings());
+                    clone.stop(reason); // dumps to destination path here
+                } else {
+                    // Risk of violating lock order here, since
+                    // clone.stop() will take recorder lock inside
+                    // metadata lock, but OK if we already
+                    // have recorder lock when we entered metadata lock
+                    Thread.holdsLock(recorder);
+                    synchronized(MetadataRepository.getInstance()) {
+                        Thread.holdsLock(recorder);
+                        Map<String, String> oldSettings = getSettings();
+                        Map<String, String> newSettings = new HashMap<>(oldSettings);
+                        // replace with dump settings
+                        newSettings.putAll(dumpSettings);
+                        clone.setSettings(newSettings);
+                        clone.stop(reason);
+                    }
+                }
+            }
+            return;
+        }
+    }
+
+    private void dumpToFile(WriteableUserPath userPath, String reason, long id) throws IOException {
+        userPath.doPriviligedIO(() -> {
+            try (ChunksChannel cc = new ChunksChannel(chunks); FileChannel fc = FileChannel.open(userPath.getReal(), StandardOpenOption.WRITE, StandardOpenOption.APPEND)) {
+                cc.transferTo(fc);
+                fc.force(true);
+            }
+            return null;
+        });
+    }
+
+    public boolean isToDisk() {
+        synchronized (recorder) {
+            return toDisk;
+        }
+    }
+
+    public void setMaxSize(long maxSize) {
+        synchronized (recorder) {
+            if (getState() == RecordingState.CLOSED) {
+                throw new IllegalStateException("Can't set max age when recording is closed");
+            }
+            this.maxSize = maxSize;
+            trimToSize();
+        }
+    }
+
+   public void setDestination(WriteableUserPath userSuppliedPath) throws IOException {
+        synchronized (recorder) {
+            if (Utils.isState(getState(), RecordingState.STOPPED, RecordingState.CLOSED)) {
+                throw new IllegalStateException("Destination can't be set on a recording that has been stopped/closed");
+            }
+            this.destination = userSuppliedPath;
+        }
+    }
+
+    public WriteableUserPath getDestination() {
+        synchronized (recorder) {
+            return destination;
+        }
+    }
+
+    void setState(RecordingState state) {
+        synchronized (recorder) {
+            this.state = state;
+        }
+    }
+
+    void setStartTime(Instant startTime) {
+        synchronized (recorder) {
+            this.startTime = startTime;
+        }
+    }
+
+    void setStopTime(Instant timeStamp) {
+        synchronized (recorder) {
+            stopTime = timeStamp;
+        }
+    }
+
+    public long getId() {
+        synchronized (recorder) {
+            return id;
+        }
+    }
+
+    public void setName(String name) {
+        synchronized (recorder) {
+            ensureNotClosed();
+            this.name = name;
+        }
+    }
+
+    private void ensureNotClosed() {
+        if (getState() == RecordingState.CLOSED) {
+            throw new IllegalStateException("Can't change name on a closed recording");
+        }
+    }
+
+    public void setDumpOnExit(boolean dumpOnExit) {
+        synchronized (recorder) {
+            this.dumpOnExit = dumpOnExit;
+        }
+    }
+
+    public boolean getDumpOnExit() {
+        synchronized (recorder) {
+            return dumpOnExit;
+        }
+    }
+
+    public void setToDisk(boolean toDisk) {
+        synchronized (recorder) {
+            if (Utils.isState(getState(), RecordingState.NEW, RecordingState.DELAYED)) {
+                this.toDisk = toDisk;
+            } else {
+                throw new IllegalStateException("Recording option disk can't be changed after recording has started");
+            }
+        }
+    }
+
+    public void setSetting(String id, String value) {
+        synchronized (recorder) {
+            this.settings.put(id, value);
+            if (getState() == RecordingState.RUNNING) {
+                recorder.updateSettings();
+            }
+        }
+    }
+
+    public void setSettings(Map<String, String> settings) {
+        setSettings(settings, true);
+    }
+
+    private void setSettings(Map<String, String> settings, boolean update) {
+        if (LogTag.JFR_SETTING.shouldLog(LogLevel.INFO.level) && update) {
+            TreeMap<String, String> ordered = new TreeMap<>(settings);
+            Logger.log(LogTag.JFR_SETTING, LogLevel.INFO, "New settings for recording \"" + getName() + "\" (" + getId() + ")");
+            for (Map.Entry<String, String> entry : ordered.entrySet()) {
+                String text =  entry.getKey() + "=\"" + entry.getValue() + "\"";
+                Logger.log(LogTag.JFR_SETTING, LogLevel.INFO, text);
+            }
+        }
+        synchronized (recorder) {
+            this.settings = new LinkedHashMap<>(settings);
+            if (getState() == RecordingState.RUNNING && update) {
+                recorder.updateSettings();
+            }
+        }
+    }
+
+
+    private void notifyIfStateChanged(RecordingState newState, RecordingState oldState) {
+        if (oldState == newState) {
+            return;
+        }
+        for (FlightRecorderListener cl : PlatformRecorder.getListeners()) {
+            try {
+                cl.recordingStateChanged(getRecording());
+            } catch (RuntimeException re) {
+                Logger.log(JFR, WARN, "Error notifying recorder listener:" + re.getMessage());
+            }
+        }
+    }
+
+    public void setRecording(Recording recording) {
+        this.recording = recording;
+    }
+
+    public Recording getRecording() {
+        return recording;
+    }
+
+    @Override
+    public String toString() {
+        return getName() + " (id=" + getId() + ") " + getState();
+    }
+
+    public void setConfiguration(Configuration c) {
+        setSettings(c.getSettings());
+    }
+
+    public void setMaxAge(Duration maxAge) {
+        synchronized (recorder) {
+            if (getState() == RecordingState.CLOSED) {
+                throw new IllegalStateException("Can't set max age when recording is closed");
+            }
+            this.maxAge = maxAge;
+            if (maxAge != null) {
+                trimToAge(Instant.now().minus(maxAge));
+            }
+        }
+    }
+
+    void appendChunk(RepositoryChunk chunk) {
+        if (!chunk.isFinished()) {
+            throw new Error("not finished chunk " + chunk.getStartTime());
+        }
+        synchronized (recorder) {
+            if (!toDisk) {
+                return;
+            }
+            if (maxAge != null) {
+                trimToAge(chunk.getEndTime().minus(maxAge));
+            }
+            chunks.addLast(chunk);
+            added(chunk);
+            trimToSize();
+        }
+    }
+
+    private void trimToSize() {
+        if (maxSize == 0) {
+            return;
+        }
+        while (size > maxSize && chunks.size() > 1) {
+            RepositoryChunk c = chunks.removeFirst();
+            removed(c);
+        }
+    }
+
+    private void trimToAge(Instant oldest) {
+        while (!chunks.isEmpty()) {
+            RepositoryChunk oldestChunk = chunks.peek();
+            if (oldestChunk.getEndTime().isAfter(oldest)) {
+                return;
+            }
+            chunks.removeFirst();
+            removed(oldestChunk);
+        }
+    }
+
+    void add(RepositoryChunk c) {
+        chunks.add(c);
+        added(c);
+    }
+
+    private void added(RepositoryChunk c) {
+        c.use();
+        size += c.getSize();
+        Logger.log(JFR, DEBUG,  ()-> "Recording \"" + name + "\" (" + id + ") added chunk " + c.toString() + ", current size=" + size);
+    }
+
+    private void removed(RepositoryChunk c) {
+        size -= c.getSize();
+        Logger.log(JFR, DEBUG,  ()->  "Recording \"" + name + "\" (" + id + ") removed chunk " + c.toString() + ", current size=" + size);
+        c.release();
+    }
+
+    public List<RepositoryChunk> getChunks() {
+        return chunks;
+    }
+
+    public InputStream open(Instant start, Instant end) throws IOException {
+        synchronized (recorder) {
+            if (getState() != RecordingState.STOPPED) {
+                throw new IOException("Recording must be stopped before it can be read.");
+            }
+            List<RepositoryChunk> chunksToUse = new ArrayList<RepositoryChunk>();
+            for (RepositoryChunk chunk : chunks) {
+                if (chunk.isFinished()) {
+                    Instant chunkStart = chunk.getStartTime();
+                    Instant chunkEnd = chunk.getEndTime();
+                    if (start == null || !chunkEnd.isBefore(start)) {
+                        if (end == null || !chunkStart.isAfter(end)) {
+                            chunksToUse.add(chunk);
+                        }
+                    }
+                }
+            }
+            if (chunksToUse.isEmpty()) {
+                return null;
+            }
+            return new ChunkInputStream(chunksToUse);
+        }
+    }
+
+    public Duration getDuration() {
+        synchronized (recorder) {
+            return duration;
+        }
+    }
+
+    void setInternalDuration(Duration duration) {
+        this.duration = duration;
+    }
+
+    public void setDuration(Duration duration) {
+        synchronized (recorder) {
+            if (Utils.isState(getState(), RecordingState.STOPPED, RecordingState.CLOSED)) {
+                throw new IllegalStateException("Duration can't be set after a recording has been stopped/closed");
+            }
+            setInternalDuration(duration);
+            if (getState() != RecordingState.NEW) {
+                updateTimer();
+            }
+        }
+    }
+
+    void updateTimer() {
+        if (stopTask != null) {
+            stopTask.cancel();
+            stopTask = null;
+        }
+        if (getState() == RecordingState.CLOSED) {
+            return;
+        }
+        if (duration != null) {
+            stopTask = createStopTask();
+            recorder.getTimer().schedule(stopTask, new Date(startTime.plus(duration).toEpochMilli()));
+        }
+    }
+
+    TimerTask createStopTask() {
+        return new TimerTask() {
+            @Override
+            public void run() {
+                try {
+                    stop("End of duration reached");
+                } catch (Throwable t) {
+                    // Prevent malicious user to propagate exception callback in the wrong context
+                    Logger.log(LogTag.JFR, LogLevel.ERROR, "Could not stop recording. " + t.getMessage());
+                }
+            }
+        };
+    }
+
+    public Recording newCopy(boolean stop) {
+        return recorder.newCopy(this, stop);
+    }
+
+    void setStopTask(TimerTask stopTask) {
+        synchronized (recorder) {
+            this.stopTask = stopTask;
+        }
+    }
+
+    void clearDestination() {
+       destination = null;
+    }
+
+    public AccessControlContext getNoDestinationDumpOnExitAccessControlContext() {
+        return noDestinationDumpOnExitAccessControlContext;
+    }
+
+    void setShouldWriteActiveRecordingEvent(boolean shouldWrite) {
+       this.shuoldWriteActiveRecordingEvent = shouldWrite;
+    }
+
+    boolean shouldWriteMetadataEvent() {
+        return shuoldWriteActiveRecordingEvent;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/PrivateAccess.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import java.util.List;
+import java.util.Map;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.Configuration;
+import jdk.jfr.EventType;
+import jdk.jfr.FlightRecorderPermission;
+import jdk.jfr.Recording;
+import jdk.jfr.SettingDescriptor;
+import jdk.jfr.ValueDescriptor;
+
+/**
+ * Provides access to package private function in jdk.jfr.
+ * <p>
+ * The static initializer in this class loads the Settings class, which will
+ * call {@link #setPrivateAccess(PrivateAccess)} on this class, which can be
+ * used call to package protected methods.
+ *
+ * This is similar to how java.lang accesses package private methods in
+ * java.lang.reflect.
+ */
+public abstract class PrivateAccess {
+    private volatile static PrivateAccess instance;
+
+    public static PrivateAccess getInstance() {
+        // Can't be initialized in <clinit> because it may
+        // deadlock with FlightRecordeerPermission.<clinit>
+        if (instance == null) {
+            // Will trigger
+            // FlightRecordeerPermission.<clinit>
+            // which will call PrivateAccess.setPrivateAccess
+            new FlightRecorderPermission(Utils.REGISTER_EVENT);
+        }
+        return instance;
+    }
+
+    public static void setPrivateAccess(PrivateAccess pa) {
+        instance = pa;
+    }
+
+    public abstract Type getType(Object o);
+
+    public abstract Configuration newConfiguration(String name, String label, String description, String provider, Map<String,String> settings, String contents);
+
+    public abstract EventType newEventType(PlatformEventType eventTypes);
+
+    public abstract AnnotationElement newAnnotation(Type annotationType, List<Object> values, boolean boot);
+
+    public abstract ValueDescriptor newValueDescriptor(String name, Type fieldType, List<AnnotationElement> annotations, int dimension, boolean constantPool, String fieldName);
+
+    public abstract PlatformRecording getPlatformRecording(Recording r);
+
+    public abstract PlatformEventType getPlatformEventType(EventType eventType);
+
+    public abstract boolean isConstantPool(ValueDescriptor v);
+
+    public abstract String getFieldName(ValueDescriptor v);
+
+    public abstract ValueDescriptor newValueDescriptor(Class<?> type, String name);
+
+    public abstract SettingDescriptor newSettingDescriptor(Type type, String name, String def, List<AnnotationElement> aes);
+
+    public abstract void setAnnotations(ValueDescriptor v, List<AnnotationElement> a);
+
+    public abstract void setAnnotations(SettingDescriptor s, List<AnnotationElement> a);
+
+    public abstract boolean isUnsigned(ValueDescriptor v);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/Repository.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.HashSet;
+import java.util.Set;
+
+import jdk.jfr.internal.SecuritySupport.SafePath;
+
+public final class Repository {
+
+    private static final int MAX_REPO_CREATION_RETRIES = 1000;
+    private static final JVM jvm = JVM.getJVM();
+    private static final Repository instance = new Repository();
+
+    static DateTimeFormatter REPO_DATE_FORMAT = DateTimeFormatter
+            .ofPattern("yyyy_MM_dd_HH_mm_ss");
+
+    private final Set<SafePath> cleanupDirectories = new HashSet<>();
+    private SafePath baseLocation;
+    private SafePath repository;
+
+    private Repository() {
+    }
+
+    public static Repository getRepository() {
+        return instance;
+    }
+
+    public synchronized void setBasePath(SafePath baseLocation) throws Exception {
+        // Probe to see if repository can be created, needed for fail fast
+        // during JVM startup or JFR.configure
+        this.repository = createRepository(baseLocation);
+        try {
+            // Remove so we don't "leak" repositories, if JFR is never started
+            // and shutdown hook not added.
+            SecuritySupport.delete(repository);
+        } catch (IOException ioe) {
+            Logger.log(LogTag.JFR, LogLevel.INFO, "Could not delete disk repository " + repository);
+        }
+        this.baseLocation = baseLocation;
+    }
+
+    synchronized void ensureRepository() throws Exception {
+        if (baseLocation == null) {
+            setBasePath(SecuritySupport.JAVA_IO_TMPDIR);
+        }
+    }
+
+    synchronized RepositoryChunk newChunk(Instant timestamp) {
+        try {
+            if (!SecuritySupport.existDirectory(repository)) {
+                this.repository = createRepository(baseLocation);
+                jvm.setRepositoryLocation(repository.toString());
+                cleanupDirectories.add(repository);
+            }
+            return new RepositoryChunk(repository, timestamp);
+        } catch (Exception e) {
+            String errorMsg = String.format("Could not create chunk in repository %s, %s", repository, e.getMessage());
+            Logger.log(LogTag.JFR, LogLevel.ERROR, errorMsg);
+            jvm.abort(errorMsg);
+            throw new InternalError("Could not abort after JFR disk creation error");
+        }
+    }
+
+    private static SafePath createRepository(SafePath basePath) throws Exception {
+        SafePath canonicalBaseRepositoryPath = createRealBasePath(basePath);
+        SafePath f = null;
+
+        String basename = REPO_DATE_FORMAT.format(LocalDateTime.now()) + "_" + JVM.getJVM().getPid();
+        String name = basename;
+
+        int i = 0;
+        for (; i < MAX_REPO_CREATION_RETRIES; i++) {
+            f = new SafePath(canonicalBaseRepositoryPath.toPath().resolve(name));
+            if (tryToUseAsRepository(f)) {
+                break;
+            }
+            name = basename + "_" + i;
+        }
+
+        if (i == MAX_REPO_CREATION_RETRIES) {
+            throw new Exception("Unable to create JFR repository directory using base location (" + basePath + ")");
+        }
+        SafePath canonicalRepositoryPath = SecuritySupport.toRealPath(f);
+        return canonicalRepositoryPath;
+    }
+
+    private static SafePath createRealBasePath(SafePath safePath) throws Exception {
+        if (SecuritySupport.exists(safePath)) {
+            if (!SecuritySupport.isWritable(safePath)) {
+                throw new IOException("JFR repository directory (" + safePath.toString() + ") exists, but isn't writable");
+            }
+            return SecuritySupport.toRealPath(safePath);
+        }
+        SafePath p = SecuritySupport.createDirectories(safePath);
+        return SecuritySupport.toRealPath(p);
+    }
+
+    private static boolean tryToUseAsRepository(final SafePath path) {
+        Path parent = path.toPath().getParent();
+        if (parent == null) {
+            return false;
+        }
+        try {
+            try {
+                SecuritySupport.createDirectories(path);
+            } catch (Exception e) {
+                // file already existed or some other problem occurred
+            }
+            if (!SecuritySupport.exists(path)) {
+                return false;
+            }
+            if (!SecuritySupport.isDirectory(path)) {
+                return false;
+            }
+            return true;
+        } catch (IOException io) {
+            return false;
+        }
+    }
+
+    synchronized void clear() {
+        for (SafePath p : cleanupDirectories) {
+            try {
+                SecuritySupport.clearDirectory(p);
+                Logger.log(LogTag.JFR, LogLevel.INFO, "Removed repository " + p);
+            } catch (IOException e) {
+                Logger.log(LogTag.JFR, LogLevel.ERROR, "Repository " + p + " could not be removed at shutdown: " + e.getMessage());
+            }
+        }
+    }
+
+    public synchronized SafePath getRepositoryPath() {
+        return repository;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/RepositoryChunk.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.file.Path;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZonedDateTime;
+import java.util.Comparator;
+import java.util.Objects;
+
+import jdk.jfr.internal.SecuritySupport.SafePath;
+
+final class RepositoryChunk {
+    private static final int MAX_CHUNK_NAMES = 100;
+
+    static final Comparator<RepositoryChunk> END_TIME_COMPARATOR = new Comparator<RepositoryChunk>() {
+        @Override
+        public int compare(RepositoryChunk c1, RepositoryChunk c2) {
+            return c1.endTime.compareTo(c2.endTime);
+        }
+    };
+
+    private final SafePath repositoryPath;
+    private final SafePath unFinishedFile;
+    private final SafePath file;
+    private final Instant startTime;
+    private final RandomAccessFile unFinishedRAF;
+
+    private Instant endTime = null; // unfinished
+    private int refCount = 0;
+    private long size;
+
+    RepositoryChunk(SafePath path, Instant startTime) throws Exception {
+        ZonedDateTime z = ZonedDateTime.now();
+        String fileName = Repository.REPO_DATE_FORMAT.format(
+                LocalDateTime.ofInstant(startTime, z.getZone()));
+        this.startTime = startTime;
+        this.repositoryPath = path;
+        this.unFinishedFile = findFileName(repositoryPath, fileName, ".part");
+        this.file = findFileName(repositoryPath, fileName, ".jfr");
+        this.unFinishedRAF = SecuritySupport.createRandomAccessFile(unFinishedFile);
+        SecuritySupport.touch(file);
+    }
+
+    private static SafePath findFileName(SafePath directory, String name, String extension) throws Exception {
+        Path p = directory.toPath().resolve(name + extension);
+        for (int i = 1; i < MAX_CHUNK_NAMES; i++) {
+            SafePath s = new SafePath(p);
+            if (!SecuritySupport.exists(s)) {
+                return s;
+            }
+            String extendedName = String.format("%s_%02d%s", name, i, extension);
+            p = directory.toPath().resolve(extendedName);
+        }
+        p = directory.toPath().resolve(name + "_" + System.currentTimeMillis() + extension);
+        return SecuritySupport.toRealPath(new SafePath(p));
+    }
+
+    public SafePath getUnfishedFile() {
+        return unFinishedFile;
+    }
+
+    void finish(Instant endTime) {
+        try {
+            finishWithException(endTime);
+        } catch (IOException e) {
+            Logger.log(LogTag.JFR, LogLevel.ERROR, "Could not finish chunk. " + e.getMessage());
+        }
+    }
+
+    private void finishWithException(Instant endTime) throws IOException {
+        unFinishedRAF.close();
+        this.size = finish(unFinishedFile, file);
+        this.endTime = endTime;
+        Logger.log(LogTag.JFR_SYSTEM, LogLevel.DEBUG, () -> "Chunk finished: " + file);
+    }
+
+    private static long finish(SafePath unFinishedFile, SafePath file) throws IOException {
+        Objects.requireNonNull(unFinishedFile);
+        Objects.requireNonNull(file);
+        SecuritySupport.delete(file);
+        SecuritySupport.moveReplace(unFinishedFile, file);
+        return SecuritySupport.getFileSize(file);
+    }
+
+    public Instant getStartTime() {
+        return startTime;
+    }
+
+    public Instant getEndTime() {
+        return endTime;
+    }
+
+    private void delete(SafePath f) {
+        try {
+            SecuritySupport.delete(f);
+            Logger.log(LogTag.JFR, LogLevel.DEBUG, () -> "Repository chunk " + f + " deleted");
+        } catch (IOException e) {
+            Logger.log(LogTag.JFR, LogLevel.ERROR, ()  -> "Repository chunk " + f + " could not be deleted: " + e.getMessage());
+            if (f != null) {
+                SecuritySupport.deleteOnExit(f);
+            }
+        }
+    }
+
+    private void destroy() {
+        if (!isFinished()) {
+            finish(Instant.MIN);
+        }
+        if (file != null) {
+            delete(file);
+        }
+        try {
+            unFinishedRAF.close();
+        } catch (IOException e) {
+            Logger.log(LogTag.JFR, LogLevel.ERROR, () -> "Could not close random access file: " + unFinishedFile.toString() + ". File will not be deleted due to: " + e.getMessage());
+        }
+    }
+
+    public synchronized void use() {
+        ++refCount;
+        Logger.log(LogTag.JFR_SYSTEM, LogLevel.DEBUG, () -> "Use chunk " + toString() + " ref count now " + refCount);
+    }
+
+    public synchronized void release() {
+        --refCount;
+        Logger.log(LogTag.JFR_SYSTEM, LogLevel.DEBUG, () -> "Release chunk " + toString() + " ref count now " + refCount);
+        if (refCount == 0) {
+            destroy();
+        }
+    }
+
+    @Override
+    @SuppressWarnings("deprecation")
+    protected void finalize() {
+        boolean destroy = false;
+        synchronized (this) {
+            if (refCount > 0) {
+                destroy = true;
+            }
+        }
+        if (destroy) {
+            destroy();
+        }
+    }
+
+    public long getSize() {
+        return size;
+    }
+
+    public boolean isFinished() {
+        return endTime != null;
+    }
+
+    @Override
+    public String toString() {
+        if (isFinished()) {
+            return file.toString();
+        }
+        return unFinishedFile.toString();
+    }
+
+    ReadableByteChannel newChannel() throws IOException {
+        if (!isFinished()) {
+            throw new IOException("Chunk not finished");
+        }
+        return ((SecuritySupport.newFileChannelToRead(file)));
+    }
+
+    public boolean inInterval(Instant startTime, Instant endTime) {
+        if (startTime != null && getEndTime().isBefore(startTime)) {
+            return false;
+        }
+        if (endTime != null && getStartTime().isAfter(endTime)) {
+            return false;
+        }
+        return true;
+    }
+
+    public SafePath getFile() {
+        return file;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/RequestEngine.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.Predicate;
+
+public final class RequestEngine {
+
+    private final static JVM jvm = JVM.getJVM();
+
+    final static class RequestHook {
+        private final Runnable hook;
+        private final PlatformEventType type;
+        private final AccessControlContext accessControllerContext;
+        private long delta;
+
+        // Java events
+        private RequestHook(AccessControlContext acc, PlatformEventType eventType, Runnable hook) {
+            this.hook = hook;
+            this.type = eventType;
+            this.accessControllerContext = acc;
+        }
+
+        // native events
+        RequestHook(PlatformEventType eventType) {
+            this(null, eventType, null);
+        }
+
+        private void execute() {
+            try {
+                if (accessControllerContext == null) { // native
+                    jvm.emitEvent(type.getId(), JVM.counterTime(), 0);
+                    Logger.log(LogTag.JFR_SYSTEM_EVENT, LogLevel.DEBUG, ()-> "Executed periodic hook for " + type.getLogName());
+                } else {
+                    executeSecure();
+                }
+            } catch (Throwable e) {
+                // Prevent malicious user to propagate exception callback in the wrong context
+                Logger.log(LogTag.JFR_SYSTEM_EVENT, LogLevel.WARN, "Exception occured during execution of period hook for " + type.getLogName());
+            }
+        }
+
+        private void executeSecure() {
+            AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                @Override
+                public Void run() {
+                    try {
+                        hook.run();
+                        Logger.log(LogTag.JFR_EVENT, LogLevel.DEBUG, ()-> "Executed periodic hook for " + type.getLogName());
+                    } catch (Throwable t) {
+                        // Prevent malicious user to propagate exception callback in the wrong context
+                        Logger.log(LogTag.JFR_EVENT, LogLevel.WARN, "Exception occured during execution of period hook for " + type.getLogName());
+                    }
+                    return null;
+                }
+            }, accessControllerContext);
+        }
+    }
+
+    private final static List<RequestHook> entries = new CopyOnWriteArrayList<>();
+    private static long lastTimeMillis;
+
+    // Insertion takes O(2*n), could be O(1) with HashMap, but
+    // thinking is that CopyOnWriteArrayList is faster
+    // to iterate over, which will happen more over time.
+    public static void addHook(AccessControlContext acc, PlatformEventType type, Runnable hook) {
+        Objects.requireNonNull(acc);
+        RequestHook he = new RequestHook(acc, type, hook);
+        for (RequestHook e : entries) {
+            if (e.hook == hook) {
+                throw new IllegalArgumentException("Hook has already been added");
+            }
+        }
+        he.type.setEventHook(true);
+        entries.add(he);
+        logHook("Added", type);
+    }
+
+
+    private static void logHook(String action, PlatformEventType type) {
+        if (type.isJDK() || type.isJVM()) {
+            Logger.log(LogTag.JFR_SYSTEM_EVENT, LogLevel.INFO, action + " periodic hook for " + type.getLogName());
+        } else {
+            Logger.log(LogTag.JFR_EVENT, LogLevel.INFO, action + " periodic hook for " + type.getLogName());
+        }
+    }
+
+    // Takes O(2*n), see addHook.
+    public static boolean removeHook(Runnable hook) {
+        for (RequestHook rh : entries) {
+            if (rh.hook == hook) {
+                entries.remove(rh);
+                rh.type.setEventHook(false);
+                logHook("Removed", rh.type);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    // Only to be used for JVM events. No access control contest
+    // or check if hook already exists
+    static void addHooks(List<RequestHook> newEntries) {
+        List<RequestHook> addEntries = new ArrayList<>();
+        for (RequestHook rh : newEntries) {
+            rh.type.setEventHook(true);
+            addEntries.add(rh);
+            logHook("Added", rh.type);
+        }
+        entries.addAll(newEntries);
+    }
+
+    static void doChunkEnd() {
+        doChunk(x -> x.isEndChunk());
+    }
+
+    static void doChunkBegin() {
+        doChunk(x -> x.isBeginChunk());
+    }
+
+    private static void doChunk(Predicate<PlatformEventType> predicate) {
+        for (RequestHook requestHook : entries) {
+            PlatformEventType s = requestHook.type;
+            if (s.isEnabled() && predicate.test(s)) {
+                requestHook.execute();
+            }
+        }
+    }
+
+    static long doPeriodic() {
+        return run_requests(entries);
+    }
+
+    // code copied from native impl.
+    private static long run_requests(Collection<RequestHook> entries) {
+        long last = lastTimeMillis;
+        // Bug 9000556 - current time millis has rather lame resolution
+        // The use of os::elapsed_counter() is deliberate here, we don't
+        // want it exchanged for os::ft_elapsed_counter().
+        // Keeping direct call os::elapsed_counter() here for reliable
+        // real time values in order to decide when registered requestable
+        // events are due.
+        long now = System.currentTimeMillis();
+        long min = 0;
+        long delta = 0;
+
+        if (last == 0) {
+            last = now;
+        }
+
+        // time from then to now
+        delta = now - last;
+
+        if (delta < 0) {
+            // to handle time adjustments
+            // for example Daylight Savings
+            lastTimeMillis = now;
+            return 0;
+        }
+        for (RequestHook he : entries) {
+            long left = 0;
+            PlatformEventType es = he.type;
+            // Not enabled, skip.
+            if (!es.isEnabled() || es.isEveryChunk()) {
+                continue;
+            }
+            long r_period = es.getPeriod();
+            long r_delta = he.delta;
+
+            // add time elapsed.
+            r_delta += delta;
+
+            // above threshold?
+            if (r_delta >= r_period) {
+                // Bug 9000556 - don't try to compensate
+                // for wait > period
+                r_delta = 0;
+                he.execute();
+                ;
+            }
+
+            // calculate time left
+            left = (r_period - r_delta);
+
+            /**
+             * nothing outside checks that a period is >= 0, so left can end up
+             * negative here. ex. (r_period =(-1)) - (r_delta = 0) if it is,
+             * handle it.
+             */
+            if (left < 0) {
+                left = 0;
+            }
+
+            // assign delta back
+            he.delta = r_delta;
+
+            if (min == 0 || left < min) {
+                min = left;
+            }
+        }
+        lastTimeMillis = now;
+        return min;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/SecuritySupport.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,399 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.RandomAccessFile;
+import java.io.Reader;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.ReflectPermission;
+import java.nio.channels.FileChannel;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.StandardOpenOption;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.Permission;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+import java.util.PropertyPermission;
+import java.util.concurrent.Callable;
+
+import jdk.internal.misc.Unsafe;
+import jdk.internal.module.Modules;
+import jdk.jfr.Event;
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.FlightRecorderListener;
+import jdk.jfr.FlightRecorderPermission;
+import jdk.jfr.Recording;
+
+/**
+ * Contains JFR code that does
+ * {@link AccessController#doPrivileged(PrivilegedAction)}
+ */
+public final class SecuritySupport {
+    private final static Unsafe unsafe = Unsafe.getUnsafe();
+    private final static Module JFR_MODULE = Event.class.getModule();
+    public  final static SafePath JFC_DIRECTORY = getPathInProperty("java.home", "lib/jfr");
+
+    static final SafePath USER_HOME = getPathInProperty("user.home", null);
+    static final SafePath JAVA_IO_TMPDIR = getPathInProperty("java.io.tmpdir", null);
+
+    final static class SecureRecorderListener implements FlightRecorderListener {
+
+        private final AccessControlContext context;
+        private final FlightRecorderListener changeListener;
+
+        SecureRecorderListener(AccessControlContext context, FlightRecorderListener changeListener) {
+            this.context = Objects.requireNonNull(context);
+            this.changeListener = Objects.requireNonNull(changeListener);
+        }
+
+        @Override
+        public void recordingStateChanged(Recording recording) {
+            AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
+                try {
+                    changeListener.recordingStateChanged(recording);
+                } catch (Throwable t) {
+                    // Prevent malicious user to propagate exception callback in the wrong context
+                    Logger.log(LogTag.JFR, LogLevel.WARN, "Unexpected exception in listener " + changeListener.getClass()+ " at recording state change");
+                }
+                return null;
+            }, context);
+        }
+
+        @Override
+        public void recorderInitialized(FlightRecorder recorder) {
+            AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
+                try  {
+                    changeListener.recorderInitialized(recorder);
+                } catch (Throwable t) {
+                    // Prevent malicious user to propagate exception callback in the wrong context
+                    Logger.log(LogTag.JFR, LogLevel.WARN, "Unexpected exception in listener " + changeListener.getClass()+ " when initializing FlightRecorder");
+                }
+                return null;
+            }, context);
+        }
+
+        public FlightRecorderListener getChangeListener() {
+            return changeListener;
+        }
+    }
+
+    private static final class DirectoryCleaner extends SimpleFileVisitor<Path> {
+        @Override
+        public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException {
+            Files.delete(path);
+            return FileVisitResult.CONTINUE;
+        }
+
+        @Override
+        public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+            if (exc != null) {
+                throw exc;
+            }
+            Files.delete(dir);
+            return FileVisitResult.CONTINUE;
+        }
+    }
+
+    /**
+     * Path created by the default file provider,and not
+     * a malicious provider.
+     *
+     */
+    public static final class SafePath {
+        private final Path path;
+        private final String text;
+
+        public SafePath(Path p) {
+            // sanitize
+            text = p.toString();
+            path = Paths.get(text);
+        }
+
+        public SafePath(String path) {
+            this(Paths.get(path));
+        }
+
+        public Path toPath() {
+            return path;
+        }
+
+        public String toString() {
+            return text;
+        }
+    }
+
+    private interface RunnableWithCheckedException {
+        public void run() throws Exception;
+    }
+
+    private interface CallableWithoutCheckException<T> {
+        public T call();
+    }
+
+    private static <U> U doPrivilegedIOWithReturn(Callable<U> function) throws IOException {
+        try {
+            return AccessController.doPrivileged(new PrivilegedExceptionAction<U>() {
+                @Override
+                public U run() throws Exception {
+                    return function.call();
+                }
+            }, null);
+        } catch (PrivilegedActionException e) {
+            Throwable t = e.getCause();
+            if (t instanceof IOException) {
+                throw (IOException) t;
+            }
+            throw new IOException("Unexpected error during I/O operation. " + t.getMessage(), t);
+        }
+    }
+
+    private static void doPriviligedIO(RunnableWithCheckedException function) throws IOException {
+        doPrivilegedIOWithReturn(() -> {
+            function.run();
+            return null;
+        });
+    }
+
+    private static void doPrivileged(Runnable function, Permission... perms) {
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            @Override
+            public Void run() {
+                function.run();
+                return null;
+            }
+        }, null, perms);
+    }
+
+    private static void doPrivileged(Runnable function) {
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            @Override
+            public Void run() {
+                function.run();
+                return null;
+            }
+        });
+    }
+
+    private static <T> T doPrivilegedWithReturn(CallableWithoutCheckException<T> function, Permission... perms) {
+        return AccessController.doPrivileged(new PrivilegedAction<T>() {
+            @Override
+            public T run() {
+                return function.call();
+            }
+        }, null, perms);
+    }
+
+    public static List<SafePath> getPredefinedJFCFiles() {
+        List<SafePath> list = new ArrayList<>();
+        try {
+            Iterator<Path> pathIterator = doPrivilegedIOWithReturn(() -> {
+                return Files.newDirectoryStream(JFC_DIRECTORY.toPath(), "*").iterator();
+            });
+            while (pathIterator.hasNext()) {
+                Path path = pathIterator.next();
+                if (path.toString().endsWith(".jfc")) {
+                    list.add(new SafePath(path));
+                }
+            }
+        } catch (IOException ioe) {
+            Logger.log(LogTag.JFR, LogLevel.WARN, "Could not access .jfc-files in " + JFC_DIRECTORY + ", " + ioe.getMessage());
+        }
+        return list;
+    }
+
+    static void makeVisibleToJFR(Class<?> clazz) {
+        Module classModule = clazz.getModule();
+        Modules.addReads(JFR_MODULE, classModule);
+        if (clazz.getPackage() != null) {
+            String packageName = clazz.getPackage().getName();
+            Modules.addExports(classModule, packageName, JFR_MODULE);
+            Modules.addOpens(classModule, packageName, JFR_MODULE);
+        }
+    }
+
+    /**
+     * Adds a qualified export of the internal.jdk.jfr.internal.handlers package
+     * (for EventHandler)
+     */
+    static void addHandlerExport(Class<?> clazz) {
+        Modules.addExports(JFR_MODULE, Utils.HANDLERS_PACKAGE_NAME, clazz.getModule());
+    }
+
+    public static void registerEvent(Class<? extends Event> eventClass) {
+        doPrivileged(() -> FlightRecorder.register(eventClass), new FlightRecorderPermission(Utils.REGISTER_EVENT));
+    }
+
+    static boolean getBooleanProperty(String propertyName) {
+        return doPrivilegedWithReturn(() -> Boolean.getBoolean(propertyName), new PropertyPermission(propertyName, "read"));
+    }
+
+    private static SafePath getPathInProperty(String prop, String subPath) {
+        return doPrivilegedWithReturn(() -> {
+            String path = System.getProperty(prop);
+            if (path == null) {
+                return null;
+            }
+            File file = subPath == null ? new File(path) : new File(path, subPath);
+            return new SafePath(file.getAbsolutePath());
+        }, new PropertyPermission("*", "read"));
+    }
+
+    // Called by JVM during initialization of JFR
+    static Thread createRecorderThread(ThreadGroup systemThreadGroup, ClassLoader contextClassLoader) {
+        // The thread should have permission = new Permission[0], and not "modifyThreadGroup" and "modifyThread" on the stack,
+        // but it's hard circumvent if we are going to pass in system thread group in the constructor
+        Thread thread = doPrivilegedWithReturn(() -> new Thread(systemThreadGroup, "JFR Recorder Thread"), new RuntimePermission("modifyThreadGroup"), new RuntimePermission("modifyThread"));
+        doPrivileged(() -> thread.setContextClassLoader(contextClassLoader), new RuntimePermission("setContextClassLoader"), new RuntimePermission("modifyThread"));
+        return thread;
+    }
+
+    static void registerShutdownHook(Thread shutdownHook) {
+        doPrivileged(() -> Runtime.getRuntime().addShutdownHook(shutdownHook), new RuntimePermission("shutdownHooks"));
+    }
+
+    static void setUncaughtExceptionHandler(Thread thread, Thread.UncaughtExceptionHandler eh) {
+        doPrivileged(() -> thread.setUncaughtExceptionHandler(eh), new RuntimePermission("modifyThread"));
+    }
+
+    static void moveReplace(SafePath from, SafePath to) throws IOException {
+        doPrivilegedIOWithReturn(() -> Files.move(from.toPath(), to.toPath()));
+    }
+
+    static void clearDirectory(SafePath safePath) throws IOException {
+        doPriviligedIO(() -> Files.walkFileTree(safePath.toPath(), new DirectoryCleaner()));
+    }
+
+    static SafePath toRealPath(SafePath safePath) throws Exception {
+        return new SafePath(doPrivilegedIOWithReturn(() -> safePath.toPath().toRealPath()));
+    }
+
+    static boolean existDirectory(SafePath directory) throws IOException {
+        return doPrivilegedIOWithReturn(() -> Files.exists(directory.toPath()));
+    }
+
+    static RandomAccessFile createRandomAccessFile(SafePath path) throws Exception {
+        return doPrivilegedIOWithReturn(() -> new RandomAccessFile(path.toPath().toFile(), "rw"));
+    }
+
+    public static InputStream newFileInputStream(SafePath safePath) throws IOException {
+        return doPrivilegedIOWithReturn(() -> Files.newInputStream(safePath.toPath()));
+    }
+
+    public static long getFileSize(SafePath safePath) throws IOException {
+        return doPrivilegedIOWithReturn(() -> Files.size(safePath.toPath()));
+    }
+
+    static SafePath createDirectories(SafePath safePath) throws IOException {
+        Path p = doPrivilegedIOWithReturn(() -> Files.createDirectories(safePath.toPath()));
+        return new SafePath(p);
+    }
+
+    public static boolean exists(SafePath safePath) throws IOException {
+        return doPrivilegedIOWithReturn(() -> Files.exists(safePath.toPath()));
+    }
+
+    public static boolean isDirectory(SafePath safePath) throws IOException {
+        return doPrivilegedIOWithReturn(() -> Files.isDirectory(safePath.toPath()));
+    }
+
+    static void delete(SafePath localPath) throws IOException {
+        doPriviligedIO(() -> Files.delete(localPath.toPath()));
+    }
+
+    static boolean isWritable(SafePath safePath) throws IOException {
+        return doPrivilegedIOWithReturn(() -> Files.isWritable(safePath.toPath()));
+    }
+
+    static void deleteOnExit(SafePath safePath) {
+        doPrivileged(() -> safePath.toPath().toFile().deleteOnExit());
+    }
+
+    static ReadableByteChannel newFileChannelToRead(SafePath safePath) throws IOException {
+        return doPrivilegedIOWithReturn(() -> FileChannel.open(safePath.toPath(), StandardOpenOption.READ));
+    }
+
+    public static InputStream getResourceAsStream(String name) throws IOException {
+        return doPrivilegedIOWithReturn(() -> SecuritySupport.class.getResourceAsStream(name));
+    }
+
+    public static Reader newFileReader(SafePath safePath) throws FileNotFoundException, IOException {
+        return doPrivilegedIOWithReturn(() -> Files.newBufferedReader(safePath.toPath()));
+    }
+
+    static void touch(SafePath path) throws IOException {
+        doPriviligedIO(() -> new RandomAccessFile(path.toPath().toFile(), "rw").close());
+    }
+
+    static void setAccessible(Method method) {
+        doPrivileged(() -> method.setAccessible(true), new ReflectPermission("suppressAccessChecks"));
+    }
+
+    static void setAccessible(Field field) {
+        doPrivileged(() -> field.setAccessible(true), new ReflectPermission("suppressAccessChecks"));
+    }
+
+    static void setAccessible(Constructor<?> constructor) {
+        doPrivileged(() -> constructor.setAccessible(true), new ReflectPermission("suppressAccessChecks"));
+    }
+
+    static void ensureClassIsInitialized(Class<?> clazz) {
+        unsafe.ensureClassInitialized(clazz);
+    }
+
+    static Class<?> defineClass(String name, byte[] bytes, ClassLoader classLoader) {
+        return unsafe.defineClass(name, bytes, 0, bytes.length, classLoader, null);
+    }
+
+    static Thread createThreadWitNoPermissions(String threadName, Runnable runnable) {
+        return doPrivilegedWithReturn(() -> new Thread(runnable, threadName), new Permission[0]);
+    }
+
+    static void setDaemonThread(Thread t, boolean daeomn) {
+      doPrivileged(()-> t.setDaemon(daeomn), new RuntimePermission("modifyThread"));
+    }
+
+    public static SafePath getAbsolutePath(SafePath path) throws IOException {
+        return new SafePath(doPrivilegedIOWithReturn((()-> path.toPath().toAbsolutePath())));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/SettingsManager.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.StringJoiner;
+
+import jdk.jfr.Event;
+import jdk.jfr.internal.handlers.EventHandler;
+
+final class SettingsManager {
+
+    private static class InternalSetting {
+
+        private final String identifier;
+        private Map<String, Set<String>> enabledMap = new LinkedHashMap<>(5);
+        private Map<String, Set<String>> allMap = new LinkedHashMap<>(5);
+        private boolean enabled;
+
+        /**
+         * Settings identifier, for example "com.example.HelloWorld" or "56"
+         * (id of event)
+         *
+         * @param settingsId
+         */
+        public InternalSetting(String settingsId) {
+            this.identifier = settingsId;
+        }
+
+        public Set<String> getValues(String key) {
+            if (enabled) {
+                return enabledMap.get(key);
+            } else {
+                return allMap.get(key);
+            }
+        }
+
+        public void add(String attribute, String value) {
+            if ("enabled".equals(attribute) && "true".equals(value)) {
+                enabled = true;
+                allMap = null; // no need to keep these around
+            }
+            addToMap(enabledMap, attribute, value);
+            if (allMap != null) {
+                addToMap(allMap, attribute, value);
+            }
+        }
+
+        private void addToMap(Map<String, Set<String>> map, String attribute, String value) {
+            Set<String> values = map.get(attribute);
+            if (values == null) {
+                values = new HashSet<String>(5);
+                map.put(attribute, values);
+            }
+            values.add(value);
+
+        }
+
+        public String getSettingsId() {
+            return identifier;
+        }
+
+        public void add(InternalSetting enabled) {
+            for (Map.Entry<String, Set<String>> entry : enabled.enabledMap.entrySet()) {
+                for (String value : entry.getValue()) {
+                    add(entry.getKey(), value);
+                }
+            }
+        }
+
+        public boolean isEnabled() {
+            return enabled;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append(identifier);
+            sb.append(": ");
+            sb.append(enabledMap.toString());
+            return sb.toString();
+        }
+
+        public void finish() {
+            if (!enabled) {
+                // settings from disabled
+                // events should not impact results, but
+                // we can't clear enabledMap since enabled=false
+                // needs be there, so events that are enabled
+                // by default are turned off
+                Map<String, Set<String>> disabledMap = new HashMap<>(2);
+                Set<String> values = new HashSet<>(2);
+                values.add("false");
+                disabledMap.put("enabled", values);
+                enabledMap = disabledMap;
+            }
+        }
+    }
+
+   private Map<String, InternalSetting> availableSettings = new LinkedHashMap<>();
+
+    void setSettings(List<Map<String, String>> activeSettings) {
+        // store settings so they are available if a new event class is loaded
+        availableSettings = createSettingsMap(activeSettings);
+        List<EventControl> eventControls = MetadataRepository.getInstance().getEventControls();
+        if (!JVM.getJVM().isRecording()) {
+            for (EventControl ec : eventControls) {
+                ec.disable();
+            }
+        } else {
+            if (LogTag.JFR_SETTING.shouldLog(LogLevel.INFO.level)) {
+                Collections.sort(eventControls, (x,y) -> x.getEventType().getName().compareTo(y.getEventType().getName()));
+            }
+            for (EventControl ec : eventControls) {
+                setEventControl(ec);
+            }
+        }
+        if (JVM.getJVM().getAllowedToDoEventRetransforms()) {
+            updateRetransform(JVM.getJVM().getAllEventClasses());
+        }
+    }
+
+    public void updateRetransform(List<Class<? extends Event>> eventClasses) {
+        List<Class<?>> classes = new ArrayList<>();
+        for(Class<? extends Event> eventClass: eventClasses) {
+            EventHandler eh = Utils.getHandler(eventClass);
+            if (eh != null ) {
+                PlatformEventType eventType = eh.getPlatformEventType();
+                if (eventType.isMarkedForInstrumentation()) {
+                    classes.add(eventClass);
+                    eventType.markForInstrumentation(false);
+                    // A bit premature to set it here, but hard to check
+                    // after call to retransformClasses.
+                    eventType.setInstrumented();
+                }
+            }
+        }
+        if (!classes.isEmpty()) {
+            JVM.getJVM().retransformClasses(classes.toArray(new Class<?>[0]));
+        }
+    }
+
+    private Map<String, InternalSetting> createSettingsMap(List<Map<String,String>> activeSettings) {
+        Map<String, InternalSetting> map = new LinkedHashMap<>(activeSettings.size());
+        for (Map<String, String> rec : activeSettings) {
+            for (InternalSetting internal : makeInternalSettings(rec)) {
+                InternalSetting is = map.get(internal.getSettingsId());
+                if (is == null) {
+                    map.put(internal.getSettingsId(), internal);
+                } else {
+                    is.add(internal);
+                }
+            }
+        }
+        return map;
+    }
+
+    private Collection<InternalSetting> makeInternalSettings(Map<String, String> rec) {
+        Map<String, InternalSetting> internals = new LinkedHashMap<>();
+        for (Map.Entry<String, String> entry : rec.entrySet()) {
+            String key = entry.getKey();
+            String value = entry.getValue();
+            int index = key.indexOf("#");
+            if (index > 1 && index < key.length() - 2) {
+                String eventName = key.substring(0, index);
+                eventName = Utils.upgradeLegacyJDKEvent(eventName);
+                InternalSetting s = internals.get(eventName);
+                String settingName = key.substring(index + 1).trim();
+                if (s == null) {
+                    s = new InternalSetting(eventName);
+                    internals.put(eventName, s);
+                }
+                s.add(settingName, value);
+            }
+        }
+      for (InternalSetting s : internals.values()) {
+         s.finish();
+      }
+
+      return internals.values();
+    }
+
+    void setEventControl(EventControl ec) {
+        InternalSetting is = getInternalSetting(ec);
+        Logger.log(LogTag.JFR_SETTING, LogLevel.INFO, "Applied settings for " + ec.getEventType().getLogName() + " {");
+        for (Entry<String, Control> entry : ec.getEntries()) {
+            Set<String> values = null;
+            String settingName = entry.getKey();
+            if (is != null) {
+                values = is.getValues(settingName);
+            }
+            Control control = entry.getValue();
+            if (values != null) {
+                control.apply(values);
+                String after = control.getLastValue();
+                if (LogTag.JFR_SETTING.shouldLog(LogLevel.INFO.level)) {
+                    if (Utils.isSettingVisible(control, ec.getEventType().hasEventHook())) {
+                        if (values.size() > 1) {
+                            StringJoiner sj = new StringJoiner(", ", "{", "}");
+                            for (String s : values) {
+                                sj.add("\"" + s + "\"");
+                            }
+                            String message = "  " + settingName + "= " + sj.toString() + " => \"" + after + "\"";
+                            Logger.log(LogTag.JFR_SETTING, LogLevel.INFO, message);
+                        } else {
+                            String message = "  " + settingName + "=\"" + control.getLastValue() + "\"";
+                            Logger.log(LogTag.JFR_SETTING, LogLevel.INFO, message);
+                        }
+                    }
+                }
+            } else {
+                control.setDefault();
+                if (LogTag.JFR_SETTING.shouldLog(LogLevel.INFO.level)) {
+                    String message = "  " + settingName + "=\"" + control.getLastValue() + "\"";
+                    Logger.log(LogTag.JFR_SETTING, LogLevel.INFO, message);
+                }
+            }
+        }
+        ec.writeActiveSettingEvent();
+        Logger.log(LogTag.JFR_SETTING, LogLevel.INFO, "}");
+    }
+
+    private InternalSetting getInternalSetting(EventControl ec) {
+        String name = ec.getEventType().getName();
+        InternalSetting nameBased = availableSettings.get(name);
+        InternalSetting idBased = availableSettings.get(ec.getSettingsId());
+
+        if (nameBased == null && idBased == null) {
+            return null;
+        }
+        if (idBased == null) {
+            return nameBased;
+        }
+        if (nameBased == null) {
+            return idBased;
+        }
+        InternalSetting mixed = new InternalSetting(nameBased.getSettingsId());
+        mixed.add(nameBased);
+        mixed.add(idBased);
+        return mixed;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        for (InternalSetting enabled : availableSettings.values()) {
+            sb.append(enabled.toString());
+            sb.append("\n");
+        }
+        return sb.toString();
+    }
+
+    boolean isEnabled(String eventName) {
+        InternalSetting is = availableSettings.get(eventName);
+        if (is == null) {
+            return false;
+        }
+        return is.isEnabled();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/ShutdownHook.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import java.io.IOException;
+import java.nio.file.Paths;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.time.LocalDateTime;
+
+import jdk.jfr.RecordingState;
+
+/**
+ * Class responsible for dumping recordings on exit
+ *
+ */
+final class ShutdownHook implements Runnable {
+    private final PlatformRecorder recorder;
+    Object tlabDummyObject;
+
+    ShutdownHook(PlatformRecorder recorder) {
+        this.recorder = recorder;
+    }
+
+    @Override
+    public void run() {
+        // this allocation is done in order to fetch a new TLAB before
+        // starting any "real" operations. In low memory situations,
+        // we would like to take an OOM as early as possible.
+        tlabDummyObject = new Object();
+
+        for (PlatformRecording recording : recorder.getRecordings()) {
+            if (recording.getDumpOnExit() && recording.getState() == RecordingState.RUNNING) {
+                dump(recording);
+            }
+        }
+        recorder.destroy();
+    }
+
+    private void dump(PlatformRecording recording) {
+        try {
+            WriteableUserPath dest = recording.getDestination();
+            if (dest == null) {
+                dest = makeDumpOnExitPath(recording);
+            }
+            if (dest != null) {
+                recording.stop("Dump on exit", dest);
+            }
+        } catch (Exception e) {
+            Logger.log(LogTag.JFR, LogLevel.DEBUG, () -> "Could not dump recording " + recording.getName() + " on exit.");
+        }
+    }
+
+    private WriteableUserPath makeDumpOnExitPath(PlatformRecording recording) {
+        try {
+            String pid = JVM.getJVM().getPid();
+            String dfText = Repository.REPO_DATE_FORMAT.format(LocalDateTime.now());
+            String name = "hotspot-" + "pid-" + pid + "-id-" + recording.getId() + "-" + dfText + ".jfr";
+            AccessControlContext acc = recording.getNoDestinationDumpOnExitAccessControlContext();
+            return AccessController.doPrivileged(new PrivilegedExceptionAction<WriteableUserPath>() {
+                @Override
+                public WriteableUserPath run() throws Exception {
+                    return new WriteableUserPath(Paths.get(".", name));
+                }
+            }, acc);
+        } catch (PrivilegedActionException e) {
+            Throwable t = e.getCause();
+            if (t instanceof SecurityException) {
+                Logger.log(LogTag.JFR, LogLevel.WARN, "Not allowed to create dump path for recording " + recording.getId() + " on exit. " + e.getMessage());
+            }
+            if (t instanceof IOException) {
+                Logger.log(LogTag.JFR, LogLevel.WARN, "Could not dump " + recording.getId() + " on exit. " + e.getMessage());
+            }
+            return null;
+        }
+    }
+
+    static final class ExceptionHandler implements Thread.UncaughtExceptionHandler {
+        public void uncaughtException(Thread t, Throwable e) {
+            JVM.getJVM().uncaughtException(t, e);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/StringPool.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.internal;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+import jdk.internal.misc.Unsafe;
+
+public final class StringPool {
+
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+
+    static final int MIN_LIMIT = 16;
+    static final int MAX_LIMIT = 128; /* 0 MAX means disabled */
+    private static final long epochAddress;
+    private static final SimpleStringIdPool sp = new SimpleStringIdPool();
+    static {
+        epochAddress = JVM.getJVM().getEpochAddress();
+        sp.reset();
+    }
+    public static long addString(String s) {
+        return sp.addString(s);
+    }
+    private static boolean getCurrentEpoch() {
+        return unsafe.getByte(epochAddress) == 1;
+    }
+    private static class SimpleStringIdPool {
+        /* string id index */
+        private final AtomicLong sidIdx = new AtomicLong();
+        /* epoch of cached strings */
+        private boolean poolEpoch;
+        /* the cache */
+        private final ConcurrentHashMap<String, Long> cache;
+        /* max size */
+        private final int MAX_SIZE = 32*1024;
+        /* max size bytes*/
+        private final long MAX_SIZE_UTF16 = 16*1024*1024;
+        /* max size bytes*/
+        private long currentSizeUTF16;
+
+        /* looking at a biased data set 4 is a good value */
+        private final String[] preCache = new String[]{"", "" , "" ,""};
+        /* index of oldest */
+        private int preCacheOld = 0;
+        /* loop mask */
+        private static final int preCacheMask = 0x03;
+
+        SimpleStringIdPool() {
+            cache = new ConcurrentHashMap<>(MAX_SIZE, 0.75f);
+        }
+        void reset() {
+            reset(getCurrentEpoch());
+        }
+        private void reset(boolean epoch) {
+            this.cache.clear();
+            this.poolEpoch = epoch;
+            this.currentSizeUTF16 = 0;
+        }
+        private long addString(String s) {
+            boolean currentEpoch = getCurrentEpoch();
+            if (poolEpoch == currentEpoch) {
+                /* pool is for current chunk */
+                Long lsid = this.cache.get(s);
+                if (lsid != null) {
+                    return lsid.longValue();
+                }
+            } else {
+                /* pool is for an old chunk */
+                reset(currentEpoch);
+            }
+            if (!preCache(s)) {
+                /* we should not pool this string */
+                return -1;
+            }
+            if (cache.size() > MAX_SIZE || currentSizeUTF16 > MAX_SIZE_UTF16) {
+                /* pool was full */
+                reset(currentEpoch);
+            }
+            return storeString(s);
+        }
+
+        private long storeString(String s) {
+            long sid = this.sidIdx.getAndIncrement();
+            /* we can race but it is ok */
+            this.cache.put(s, sid);
+            boolean currentEpoch;
+            synchronized(SimpleStringIdPool.class) {
+                currentEpoch = JVM.addStringConstant(poolEpoch, sid, s);
+                currentSizeUTF16 += s.length();
+            }
+            /* did we write in chunk that this pool represent */
+            return currentEpoch == poolEpoch ? sid : -1;
+        }
+        private boolean preCache(String s) {
+            if (preCache[0].equals(s)) {
+                return true;
+            }
+            if (preCache[1].equals(s)) {
+                return true;
+            }
+            if (preCache[2].equals(s)) {
+                return true;
+            }
+            if (preCache[3].equals(s)) {
+                return true;
+            }
+            preCacheOld = (preCacheOld - 1) & preCacheMask;
+            preCache[preCacheOld] = s;
+            return false;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/Type.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.Event;
+import jdk.jfr.SettingControl;
+import jdk.jfr.ValueDescriptor;
+
+/**
+ * Internal data structure that describes a type,
+ *
+ * Used to create event types, value descriptor and annotations.
+ *
+ */
+public class Type implements Comparable<Type> {
+    public static final String SUPER_TYPE_ANNOTATION = java.lang.annotation.Annotation.class.getName();
+    public static final String SUPER_TYPE_SETTING = SettingControl.class.getName();
+    public static final String SUPER_TYPE_EVENT = Event.class.getName();
+    public static final String EVENT_NAME_PREFIX = "jdk.";
+    public static final String TYPES_PREFIX = "jdk.types.";
+    public static final String SETTINGS_PREFIX = "jdk.settings.";
+
+
+    // Initialization of known types
+    private final static Map<Type, Class<?>> knownTypes = new HashMap<>();
+    static final Type BOOLEAN = register(boolean.class, new Type("boolean", null, 4));
+    static final Type CHAR = register(char.class, new Type("char", null, 5));
+    static final Type FLOAT = register(float.class, new Type("float", null, 6));
+    static final Type DOUBLE = register(double.class, new Type("double", null, 7));
+    static final Type BYTE = register(byte.class, new Type("byte", null, 8));
+    static final Type SHORT = register(short.class, new Type("short", null, 9));
+    static final Type INT = register(int.class, new Type("int", null, 10));
+    static final Type LONG = register(long.class, new Type("long", null, 11));
+    static final Type CLASS = register(Class.class, new Type("java.lang.Class", null, 20));
+    static final Type STRING = register(String.class, new Type("java.lang.String", null, 21));
+    static final Type THREAD = register(Thread.class, new Type("java.lang.Thread", null, 22));
+    static final Type STACK_TRACE = register(null, new Type(TYPES_PREFIX + "StackTrace", null, 23));
+
+    private final AnnotationConstruct annos = new AnnotationConstruct();
+    private final String name;
+    private final String superType;
+    private final boolean constantPool;
+    private final long id;
+    private final ArrayList<ValueDescriptor> fields = new ArrayList<>();
+    private Boolean simpleType; // calculated lazy
+    private boolean remove = true;
+    /**
+     * Creates a type
+     *
+     * @param javaTypeName i.e "java.lang.String"
+     * @param superType i.e "java.lang.Annotation"
+     * @param id the class id that represents the class in the JVM
+     *
+     */
+    public Type(String javaTypeName, String superType, long typeId) {
+        this(javaTypeName, superType, typeId, false);
+    }
+
+    Type(String javaTypeName, String superType, long typeId, boolean contantPool) {
+        this(javaTypeName, superType, typeId, contantPool, null);
+    }
+
+    Type(String javaTypeName, String superType, long typeId, boolean contantPool, Boolean simpleType) {
+        Objects.requireNonNull(javaTypeName);
+
+        if (!isValidJavaIdentifier(javaTypeName)) {
+            throw new IllegalArgumentException(javaTypeName + " is not a valid Java identifier");
+        }
+        this.constantPool = contantPool;
+        this.superType = superType;
+        this.name = javaTypeName;
+        this.id = typeId;
+        this.simpleType = simpleType;
+    }
+
+    static boolean isDefinedByJVM(long id) {
+        return id < JVM.RESERVED_CLASS_ID_LIMIT;
+    }
+
+    public static long getTypeId(Class<?> clazz) {
+        Type type = Type.getKnownType(clazz);
+        return type == null ? JVM.getJVM().getTypeId(clazz) : type.getId();
+    }
+
+    static Collection<Type> getKnownTypes() {
+        return knownTypes.keySet();
+    }
+
+    public static boolean isValidJavaIdentifier(String identifier) {
+        if (identifier.isEmpty()) {
+            return false;
+        }
+        if (!Character.isJavaIdentifierStart(identifier.charAt(0))) {
+            return false;
+        }
+        for (int i = 1; i < identifier.length(); i++) {
+            char c = identifier.charAt(i);
+            if (c != '.') {
+                if (!Character.isJavaIdentifierPart(c)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    public static boolean isValidJavaFieldType(String name) {
+        for (Map.Entry<Type, Class<?>> entry : knownTypes.entrySet()) {
+            Class<?> clazz = entry.getValue();
+            if (clazz != null && name.equals(clazz.getName())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static Type getKnownType(String typeName) {
+        for (Type type : knownTypes.keySet()) {
+            if (type.getName().equals(typeName)) {
+                return type;
+            }
+        }
+        return null;
+    }
+
+    static boolean isKnownType(Class<?> type) {
+        if (type.isPrimitive()) {
+            return true;
+        }
+        if (type.equals(Class.class) || type.equals(Thread.class) || type.equals(String.class)) {
+            return true;
+        }
+        return false;
+    }
+
+    public static Type getKnownType(Class<?> clazz) {
+        for (Map.Entry<Type, Class<?>> entry : knownTypes.entrySet()) {
+            if (clazz != null && clazz.equals(entry.getValue())) {
+                return entry.getKey();
+            }
+        }
+        return null;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getLogName() {
+       return getName() + "(" + getId() + ")";
+    }
+
+    public List<ValueDescriptor> getFields() {
+        return fields;
+    }
+
+    public boolean isSimpleType() {
+        if (simpleType == null) {
+            simpleType = calculateSimpleType();
+        }
+        return simpleType.booleanValue();
+    }
+
+    private boolean calculateSimpleType() {
+        if (fields.size() != 1) {
+            return false;
+        }
+        // annotation, settings and event can never be simple types
+        return superType == null;
+    }
+
+    public boolean isDefinedByJVM() {
+        return id < JVM.RESERVED_CLASS_ID_LIMIT;
+    }
+
+    private static Type register(Class<?> clazz, Type type) {
+        knownTypes.put(type, clazz);
+        return type;
+    }
+
+    public void add(ValueDescriptor valueDescriptor) {
+        Objects.requireNonNull(valueDescriptor);
+        fields.add(valueDescriptor);
+    }
+
+    void trimFields() {
+        fields.trimToSize();
+    }
+
+    void setAnnotations(List<AnnotationElement> annotations) {
+        annos.setAnnotationElements(annotations);
+    }
+
+    public String getSuperType() {
+        return superType;
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public boolean isConstantPool() {
+        return constantPool;
+    }
+
+    public String getLabel() {
+        return annos.getLabel();
+    }
+
+    public List<AnnotationElement> getAnnotationElements() {
+        return annos.getUnmodifiableAnnotationElements();
+    }
+
+    public <T> T getAnnotation(Class<? extends java.lang.annotation.Annotation> clazz) {
+        return annos.getAnnotation(clazz);
+    }
+
+    public String getDescription() {
+        return annos.getDescription();
+    }
+
+    @Override
+    public int hashCode() {
+        return Long.hashCode(id);
+    }
+
+    @Override
+    public boolean equals(Object object) {
+        if (object instanceof Type) {
+            Type that = (Type) object;
+            return that.id == this.id;
+        }
+        return false;
+    }
+
+    @Override
+    public int compareTo(Type that) {
+        return Long.compare(this.id, that.id);
+    }
+
+    void log(String action, LogTag logTag, LogLevel level) {
+        if (logTag.shouldLog(level.level) && !isSimpleType()) {
+            Logger.log(logTag, LogLevel.TRACE, action + " " + typeText() + " " + getLogName() + " {");
+            for (ValueDescriptor v : getFields()) {
+                String array = v.isArray() ? "[]" : "";
+                Logger.log(logTag, LogLevel.TRACE, "  " + v.getTypeName() + array + " " + v.getName() + ";");
+            }
+            Logger.log(logTag, LogLevel.TRACE, "}");
+        } else {
+            if (logTag.shouldLog(LogLevel.INFO.level) && !isSimpleType()) {
+                Logger.log(logTag, LogLevel.INFO, action + " " + typeText() + " " + getLogName());
+            }
+        }
+    }
+
+    private String typeText() {
+        if (this instanceof PlatformEventType) {
+            return "event type";
+        }
+        if (Type.SUPER_TYPE_SETTING.equals(superType)) {
+            return "setting type";
+        }
+        if (Type.SUPER_TYPE_ANNOTATION.equals(superType)) {
+            return "annotation type";
+        }
+        return "type";
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(getLogName());
+        if (!getFields().isEmpty()) {
+            sb.append(" {\n");
+            for (ValueDescriptor td : getFields()) {
+                sb.append("  type=" + td.getTypeName() + "(" + td.getTypeId() + ") name=" + td.getName() + "\n");
+            }
+            sb.append("}\n");
+        }
+        return sb.toString();
+    }
+
+    public void setRemove(boolean remove) {
+       this.remove = remove;
+    }
+
+    public boolean getRemove() {
+        return remove;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/TypeLibrary.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,492 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.lang.annotation.Repeatable;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.Description;
+import jdk.jfr.Event;
+import jdk.jfr.Label;
+import jdk.jfr.MetadataDefinition;
+import jdk.jfr.Name;
+import jdk.jfr.SettingDescriptor;
+import jdk.jfr.Timespan;
+import jdk.jfr.Timestamp;
+import jdk.jfr.ValueDescriptor;
+
+public final class TypeLibrary {
+
+    private static TypeLibrary instance;
+    private static final Map<Long, Type> types = new LinkedHashMap<>(100);
+    static final ValueDescriptor DURATION_FIELD = createDurationField();
+    static final ValueDescriptor THREAD_FIELD = createThreadField();
+    static final ValueDescriptor STACK_TRACE_FIELD = createStackTraceField();
+    static final ValueDescriptor START_TIME_FIELD = createStartTimeField();
+
+    private TypeLibrary(List<Type> jvmTypes) {
+        visitReachable(jvmTypes, t -> !types.containsKey(t.getId()), t -> types.put(t.getId(), t));
+        if (LogTag.JFR_SYSTEM_METADATA.shouldLog(LogLevel.INFO.level)) {
+            Stream<Type> s = types.values().stream().sorted((x, y) -> Long.compare(x.getId(), y.getId()));
+            s.forEach(t -> t.log("Added", LogTag.JFR_SYSTEM_METADATA, LogLevel.INFO));
+        }
+    }
+
+    private static ValueDescriptor createStartTimeField() {
+        List<AnnotationElement> annos = createStandardAnnotations("Start Time", null);
+        annos.add(new jdk.jfr.AnnotationElement(Timestamp.class, Timestamp.TICKS));
+        return PrivateAccess.getInstance().newValueDescriptor(EventInstrumentation.FIELD_START_TIME, Type.LONG, annos, 0, false,
+                EventInstrumentation.FIELD_START_TIME);
+
+    }
+
+    private static ValueDescriptor createStackTraceField() {
+        List<AnnotationElement> annos = new ArrayList<>();
+        annos = createStandardAnnotations("Stack Trace", "Stack Trace starting from the method the event was committed in");
+        return PrivateAccess.getInstance().newValueDescriptor(EventInstrumentation.FIELD_STACK_TRACE, Type.STACK_TRACE, annos, 0, true,
+                EventInstrumentation.FIELD_STACK_TRACE);
+    }
+
+    private static ValueDescriptor createThreadField() {
+        List<AnnotationElement> annos = new ArrayList<>();
+        annos = createStandardAnnotations("Event Thread", "Thread in which event was committed in");
+        return PrivateAccess.getInstance().newValueDescriptor(EventInstrumentation.FIELD_EVENT_THREAD, Type.THREAD, annos, 0, true,
+                EventInstrumentation.FIELD_EVENT_THREAD);
+    }
+
+    private static ValueDescriptor createDurationField() {
+        List<AnnotationElement> annos = new ArrayList<>();
+        annos = createStandardAnnotations("Duration", null);
+        annos.add(new jdk.jfr.AnnotationElement(Timespan.class, Timespan.TICKS));
+        return PrivateAccess.getInstance().newValueDescriptor(EventInstrumentation.FIELD_DURATION, Type.LONG, annos, 0, false, EventInstrumentation.FIELD_DURATION);
+    }
+
+    public static TypeLibrary getInstance() {
+        synchronized (TypeLibrary.class) {
+            if (instance == null) {
+                List<Type> jvmTypes;
+                try {
+                    jvmTypes = MetadataHandler.createTypes();
+                    Collections.sort(jvmTypes, (a,b) -> Long.compare(a.getId(), b.getId()));
+                } catch (IOException e) {
+                    throw new Error("JFR: Could not read metadata");
+                }
+                instance = new TypeLibrary(jvmTypes);
+            }
+            return instance;
+        }
+    }
+
+    public List<Type> getTypes() {
+        return new ArrayList<>(types.values());
+    }
+
+    public static Type createAnnotationType(Class<? extends Annotation> a) {
+        if (shouldPersist(a)) {
+            Type type = defineType(a, Type.SUPER_TYPE_ANNOTATION, false);
+            if (type != null) {
+                SecuritySupport.makeVisibleToJFR(a);
+                for (Method method : a.getDeclaredMethods()) {
+                    type.add(PrivateAccess.getInstance().newValueDescriptor(method.getReturnType(), method.getName()));
+                }
+                ArrayList<AnnotationElement> aes = new ArrayList<>();
+                for (Annotation annotation : resolveRepeatedAnnotations(a.getAnnotations())) {
+                    AnnotationElement ae = createAnnotation(annotation);
+                    if (ae != null) {
+                        aes.add(ae);
+                    }
+                }
+                aes.trimToSize();
+                type.setAnnotations(aes);
+            }
+            return getType(a);
+        }
+        return null;
+    }
+
+    static AnnotationElement createAnnotation(Annotation annotation) {
+        Class<? extends Annotation> annotationType = annotation.annotationType();
+        Type type = createAnnotationType(annotationType);
+        if (type != null) {
+            List<Object> values = new ArrayList<>();
+            for (ValueDescriptor v : type.getFields()) {
+                values.add(invokeAnnotation(annotation, v.getName()));
+            }
+
+            return PrivateAccess.getInstance().newAnnotation(type, values, annotation.annotationType().getClassLoader() == null);
+        }
+        return null;
+    }
+
+    private static Object invokeAnnotation(Annotation annotation, String methodName) {
+        final Method m;
+        try {
+            m = annotation.getClass().getMethod(methodName, new Class<?>[0]);
+        } catch (NoSuchMethodException e1) {
+            throw (Error) new InternalError("Could not loacate method " + methodName + " in annotation " + annotation.getClass().getName());
+        }
+        SecuritySupport.setAccessible(m);
+        try {
+            return m.invoke(annotation, new Object[0]);
+        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+            throw (Error) new InternalError("Could not get value for method " + methodName + " in annotation " + annotation.getClass().getName());
+        }
+    }
+
+    private static boolean shouldPersist(Class<? extends Annotation> a) {
+        if (a == MetadataDefinition.class || a.getAnnotation(MetadataDefinition.class) == null) {
+            return false;
+        }
+        return true;
+    }
+
+    private static boolean isDefined(Class<?> clazz) {
+        return types.containsKey(Type.getTypeId(clazz));
+    }
+
+    private static Type getType(Class<?> clazz) {
+        return types.get(Type.getTypeId(clazz));
+    }
+
+    private static Type defineType(Class<?> clazz, String superType, boolean eventType) {
+        if (!isDefined(clazz)) {
+            Name name = clazz.getAnnotation(Name.class);
+            String typeName = name != null ? name.value() : clazz.getName();
+            long id = Type.getTypeId(clazz);
+            Type t;
+            if (eventType) {
+                t = new PlatformEventType(typeName, id, clazz.getClassLoader() == null, true);
+            } else {
+                t = new Type(typeName, superType, id);
+            }
+            types.put(t.getId(), t);
+            return t;
+        }
+        return null;
+    }
+    public static Type createType(Class<?> clazz) {
+        return createType(clazz, Collections.emptyList(), Collections.emptyList());
+    }
+
+    public static Type createType(Class<?> clazz, List<AnnotationElement> dynamicAnnotations, List<ValueDescriptor> dynamicFields) {
+
+        if (Thread.class == clazz) {
+            return Type.THREAD;
+        }
+
+        if (Class.class.isAssignableFrom(clazz)) {
+            return Type.CLASS;
+        }
+
+        if (String.class.equals(clazz)) {
+            return Type.STRING;
+        }
+
+        if (isDefined(clazz)) {
+            return getType(clazz);
+        }
+
+        if (clazz.isPrimitive()) {
+            return defineType(clazz, null,false);
+        }
+
+        if (clazz.isArray()) {
+            throw new InternalError("Arrays not supported");
+        }
+
+        // STRUCT
+        String superType = null;
+        boolean eventType = false;
+        if (Event.class.isAssignableFrom(clazz)) {
+            superType = Type.SUPER_TYPE_EVENT;
+            eventType= true;
+        }
+        if (Control.class.isAssignableFrom(clazz)) {
+            superType = Type.SUPER_TYPE_SETTING;
+        }
+
+        // forward declare to avoid infinite recursion
+        defineType(clazz, superType, eventType);
+        Type type = getType(clazz);
+
+        if (eventType) {
+            addImplicitFields(type, true, true, true, true ,false);
+            addUserFields(clazz, type, dynamicFields);
+            type.trimFields();
+        }
+        addAnnotations(clazz, type, dynamicAnnotations);
+
+        if (clazz.getClassLoader() == null) {
+            type.log("Added", LogTag.JFR_SYSTEM_METADATA, LogLevel.INFO);
+        } else {
+            type.log("Added", LogTag.JFR_METADATA, LogLevel.INFO);
+        }
+        return type;
+    }
+
+    private static void addAnnotations(Class<?> clazz, Type type, List<AnnotationElement> dynamicAnnotations) {
+        ArrayList<AnnotationElement> aes = new ArrayList<>();
+        if (dynamicAnnotations.isEmpty()) {
+            for (Annotation a : Utils.getAnnotations(clazz)) {
+                AnnotationElement ae = createAnnotation(a);
+                if (ae != null) {
+                    aes.add(ae);
+                }
+            }
+        } else {
+            List<Type> newTypes = new ArrayList<>();
+            aes.addAll(dynamicAnnotations);
+            for (AnnotationElement ae : dynamicAnnotations) {
+                newTypes.add(PrivateAccess.getInstance().getType(ae));
+            }
+            addTypes(newTypes);
+        }
+        type.setAnnotations(aes);
+        aes.trimToSize();
+    }
+
+    private static void addUserFields(Class<?> clazz, Type type, List<ValueDescriptor> dynamicFields) {
+        Map<String, ValueDescriptor> dynamicFieldSet = new HashMap<>();
+        for (ValueDescriptor dynamicField : dynamicFields) {
+            dynamicFieldSet.put(dynamicField.getName(), dynamicField);
+        }
+        List<Type> newTypes = new ArrayList<>();
+        for (Field field : Utils.getVisibleEventFields(clazz)) {
+            ValueDescriptor vd = dynamicFieldSet.get(field.getName());
+            if (vd != null) {
+                if (!vd.getTypeName().equals(field.getType().getName())) {
+                    throw new InternalError("Type expected to match for field " + vd.getName() + " expected "  + field.getName() + " but got " + vd.getName());
+                }
+                for (AnnotationElement ae : vd.getAnnotationElements()) {
+                    newTypes.add(PrivateAccess.getInstance().getType(ae));
+                }
+                newTypes.add(PrivateAccess.getInstance().getType(vd));
+            } else {
+                vd = createField(field);
+            }
+            if (vd != null) {
+                type.add(vd);
+            }
+        }
+        addTypes(newTypes);
+    }
+
+    // By convention all events have these fields.
+    static void addImplicitFields(Type type, boolean requestable, boolean hasDuration, boolean hasThread, boolean hasStackTrace, boolean hasCutoff) {
+        createAnnotationType(Timespan.class);
+        createAnnotationType(Timestamp.class);
+        createAnnotationType(Label.class);
+        defineType(long.class, null,false);
+        addFields(type, requestable, hasDuration, hasThread, hasStackTrace, hasCutoff);
+    }
+
+    private static void addFields(Type type, boolean requestable, boolean hasDuration, boolean hasThread, boolean hasStackTrace, boolean hasCutoff) {
+        type.add(START_TIME_FIELD);
+        if (hasDuration || hasCutoff) {
+            type.add(DURATION_FIELD);
+        }
+        if (hasThread) {
+            type.add(THREAD_FIELD);
+        }
+        if (hasStackTrace) {
+            type.add(STACK_TRACE_FIELD);
+        }
+    }
+
+    private static List<AnnotationElement> createStandardAnnotations(String name, String description) {
+        List<AnnotationElement> annotationElements = new ArrayList<>(2);
+        annotationElements.add(new jdk.jfr.AnnotationElement(Label.class, name));
+        if (description != null) {
+            annotationElements.add(new jdk.jfr.AnnotationElement(Description.class, description));
+        }
+        return annotationElements;
+    }
+
+    private static ValueDescriptor createField(Field field) {
+        int mod = field.getModifiers();
+        if (Modifier.isTransient(mod)) {
+            return null;
+        }
+        if (Modifier.isStatic(mod)) {
+            return null;
+        }
+        Class<?> fieldType = field.getType();
+        if (!Type.isKnownType(fieldType)) {
+            return null;
+        }
+        boolean constantPool = Thread.class == fieldType || fieldType == Class.class;
+        Type type = createType(fieldType);
+        String fieldName = field.getName();
+        Name name = field.getAnnotation(Name.class);
+        String useName = fieldName;
+        if (name != null) {
+            useName = name.value();
+        }
+        List<jdk.jfr.AnnotationElement> ans = new ArrayList<>();
+        for (Annotation a : resolveRepeatedAnnotations(field.getAnnotations())) {
+            AnnotationElement ae = createAnnotation(a);
+            if (ae != null) {
+                ans.add(ae);
+            }
+        }
+        return PrivateAccess.getInstance().newValueDescriptor(useName, type, ans, 0, constantPool, fieldName);
+    }
+
+    private static List<Annotation> resolveRepeatedAnnotations(Annotation[] annotations) {
+        List<Annotation> annos = new ArrayList<>(annotations.length);
+        for (Annotation a : annotations) {
+            boolean repeated = false;
+            Method m;
+            try {
+                m = a.annotationType().getMethod("value");
+                Class<?> returnType = m.getReturnType();
+                if (returnType.isArray()) {
+                    Class<?> ct = returnType.getComponentType();
+                    if (Annotation.class.isAssignableFrom(ct) && ct.getAnnotation(Repeatable.class) != null) {
+                        Object res = m.invoke(a, new Object[0]);
+                        if (res != null && Annotation[].class.isAssignableFrom(res.getClass())) {
+                            for (Annotation rep : (Annotation[]) m.invoke(a, new Object[0])) {
+                                annos.add(rep);
+                            }
+                            repeated = true;
+                        }
+                    }
+                }
+            } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+                // Ignore, can't access repeatable information
+            }
+            if (!repeated) {
+                annos.add(a);
+            }
+        }
+        return annos;
+    }
+
+    // Purpose of this method is to mark types that are reachable
+    // from registered event types. Those types that are not reachable can
+    // safely be removed
+    public boolean clearUnregistered() {
+        Logger.log(LogTag.JFR_METADATA, LogLevel.TRACE, "Cleaning out obsolete metadata");
+        List<Type> registered = new ArrayList<>();
+        for (Type type : types.values()) {
+            if (type instanceof PlatformEventType) {
+                if (((PlatformEventType) type).isRegistered()) {
+                    registered.add(type);
+                }
+            }
+        }
+        visitReachable(registered, t -> t.getRemove(), t -> t.setRemove(false));
+        List<Long> removeIds = new ArrayList<>();
+        for (Type type :  types.values()) {
+            if (type.getRemove() && !Type.isDefinedByJVM(type.getId())) {
+                removeIds.add(type.getId());
+                if (LogTag.JFR_METADATA.shouldLog(LogLevel.TRACE.level)) {
+                    Logger.log(LogTag.JFR_METADATA, LogLevel.TRACE, "Removed obsolete metadata " + type.getName());
+                }
+            }
+            // Optimization, set to true now to avoid iterating
+            // types first thing at next call to clearUnregistered
+            type.setRemove(true);
+        }
+        for (Long id : removeIds) {
+            types.remove(id);
+        }
+        return !removeIds.isEmpty();
+    }
+
+    public void addType(Type type) {
+        addTypes(Collections.singletonList(type));
+    }
+
+    public static void addTypes(List<Type> ts) {
+        if (!ts.isEmpty()) {
+            visitReachable(ts, t -> !types.containsKey(t.getId()), t -> types.put(t.getId(), t));
+        }
+    }
+
+    /**
+     * Iterates all reachable types from a start collection
+     *
+     * @param rootSet the types to start from
+     * @param p if a type should be accepted
+     * @param c action to take on an accepted type
+     */
+    private  static void visitReachable(Collection<Type> rootSet, Predicate<Type> p,  Consumer<Type> c) {
+        Queue<Type> typeQ = new ArrayDeque<>(rootSet);
+        while (!typeQ.isEmpty()) {
+            Type type = typeQ.poll();
+            if (p.test(type)) {
+                c.accept(type);
+                visitAnnotations(typeQ, type.getAnnotationElements());
+                for (ValueDescriptor v : type.getFields()) {
+                    typeQ.add(PrivateAccess.getInstance().getType(v));
+                    visitAnnotations(typeQ, v.getAnnotationElements());
+                }
+                if (type instanceof PlatformEventType) {
+                    PlatformEventType pe = (PlatformEventType) type;
+                    for (SettingDescriptor s : pe.getAllSettings()) {
+                        typeQ.add(PrivateAccess.getInstance().getType(s));
+                        visitAnnotations(typeQ, s.getAnnotationElements());
+                    }
+                }
+            }
+        }
+    }
+
+    private static void visitAnnotations(Queue<Type> typeQ, List<AnnotationElement> aes) {
+        Queue<AnnotationElement> aQ = new ArrayDeque<>(aes);
+        Set<AnnotationElement> visited = new HashSet<>();
+        while (!aQ.isEmpty()) {
+            AnnotationElement ae = aQ.poll();
+            if (!visited.contains(ae)) {
+                Type ty = PrivateAccess.getInstance().getType(ae);
+                typeQ.add(ty);
+                visited.add(ae);
+            }
+            aQ.addAll(ae.getAnnotationElements());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/Utils.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,506 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import static java.util.concurrent.TimeUnit.MICROSECONDS;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.RandomAccessFile;
+import java.lang.annotation.Annotation;
+import java.lang.annotation.Repeatable;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.nio.file.Path;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
+import jdk.jfr.Event;
+import jdk.jfr.FlightRecorderPermission;
+import jdk.jfr.RecordingState;
+import jdk.jfr.internal.handlers.EventHandler;
+import jdk.jfr.internal.settings.PeriodSetting;
+import jdk.jfr.internal.settings.StackTraceSetting;
+import jdk.jfr.internal.settings.ThresholdSetting;
+
+public final class Utils {
+
+    private static Boolean SAVE_GENERATED;
+
+    public static final String EVENTS_PACKAGE_NAME = "jdk.jfr.events";
+    public static final String INSTRUMENT_PACKAGE_NAME = "jdk.jfr.internal.instrument";
+    public static final String HANDLERS_PACKAGE_NAME = "jdk.jfr.internal.handlers";
+    public static final String REGISTER_EVENT = "registerEvent";
+    public static final String ACCESS_FLIGHT_RECORDER = "accessFlightRecorder";
+
+    private final static String LEGACY_EVENT_NAME_PREFIX = "com.oracle.jdk.";
+
+    public static void checkAccessFlightRecorder() throws SecurityException {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(new FlightRecorderPermission(ACCESS_FLIGHT_RECORDER));
+        }
+    }
+
+    public static void checkRegisterPermission() throws SecurityException {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(new FlightRecorderPermission(REGISTER_EVENT));
+        }
+    }
+
+    private static enum TimespanUnit {
+        NANOSECONDS("ns", 1000), MICROSECONDS("us", 1000), MILLISECONDS("ms", 1000), SECONDS("s", 60), MINUTES("m", 60), HOURS("h", 24), DAYS("d", 7);
+
+        final String text;
+        final long amount;
+
+        TimespanUnit(String unit, long amount) {
+            this.text = unit;
+            this.amount = amount;
+        }
+    }
+
+    public static String formatBytes(long bytes, String separation) {
+        if (bytes < 1024) {
+            return bytes + " bytes";
+        }
+        int exp = (int) (Math.log(bytes) / Math.log(1024));
+        char bytePrefix = "kMGTPE".charAt(exp - 1);
+        return String.format("%.1f%s%cB", bytes / Math.pow(1024, exp), separation, bytePrefix);
+    }
+
+    public static String formatTimespan(Duration dValue, String separation) {
+        if (dValue == null) {
+            return "0";
+        }
+
+        long value = dValue.toNanos();
+        TimespanUnit result = TimespanUnit.NANOSECONDS;
+        for (TimespanUnit unit : TimespanUnit.values()) {
+            result = unit;
+            long amount = unit.amount;
+            if (result == TimespanUnit.DAYS || value < amount || value % amount != 0) {
+                break;
+            }
+            value /= amount;
+        }
+        return String.format("%d%s%s", value, separation, result.text);
+    }
+
+    public static long parseTimespan(String s) {
+        if (s.endsWith("ns")) {
+            return Long.parseLong(s.substring(0, s.length() - 2).trim());
+        }
+        if (s.endsWith("us")) {
+            return NANOSECONDS.convert(Long.parseLong(s.substring(0, s.length() - 2).trim()), MICROSECONDS);
+        }
+        if (s.endsWith("ms")) {
+            return NANOSECONDS.convert(Long.parseLong(s.substring(0, s.length() - 2).trim()), MILLISECONDS);
+        }
+        if (s.endsWith("s")) {
+            return NANOSECONDS.convert(Long.parseLong(s.substring(0, s.length() - 1).trim()), SECONDS);
+        }
+        if (s.endsWith("m")) {
+            return 60 * NANOSECONDS.convert(Long.parseLong(s.substring(0, s.length() - 1).trim()), SECONDS);
+        }
+        if (s.endsWith("h")) {
+            return 60 * 60 * NANOSECONDS.convert(Long.parseLong(s.substring(0, s.length() - 1).trim()), SECONDS);
+        }
+        if (s.endsWith("d")) {
+            return 24 * 60 * 60 * NANOSECONDS.convert(Long.parseLong(s.substring(0, s.length() - 1).trim()), SECONDS);
+        }
+
+        try {
+            Long.parseLong(s);
+        } catch (NumberFormatException nfe) {
+            throw new NumberFormatException("'" + s + "' is not a valid timespan. Shoule be numeric value followed by a unit, i.e. 20 ms. Valid units are ns, us, s, m, h and d.");
+        }
+        // Only accept values with units
+        throw new NumberFormatException("Timespan + '" + s + "' is missing unit. Valid units are ns, us, s, m, h and d.");
+    }
+
+    /**
+     * Return all annotations as they are visible in the source code
+     *
+     * @param clazz class to return annotations from
+     *
+     * @return list of annotation
+     *
+     */
+    static List<Annotation> getAnnotations(Class<?> clazz) {
+        List<Annotation> annos = new ArrayList<>();
+        for (Annotation a : clazz.getAnnotations()) {
+            annos.addAll(getAnnotation(a));
+        }
+        return annos;
+    }
+
+    private static List<? extends Annotation> getAnnotation(Annotation a) {
+        Class<?> annotated = a.annotationType();
+        Method valueMethod = getValueMethod(annotated);
+        if (valueMethod != null) {
+            Class<?> returnType = valueMethod.getReturnType();
+            if (returnType.isArray()) {
+                Class<?> candidate = returnType.getComponentType();
+                Repeatable r = candidate.getAnnotation(Repeatable.class);
+                if (r != null) {
+                    Class<?> repeatClass = r.value();
+                    if (annotated == repeatClass) {
+                        return getAnnotationValues(a, valueMethod);
+                    }
+                }
+            }
+        }
+        List<Annotation> annos = new ArrayList<>();
+        annos.add(a);
+        return annos;
+    }
+
+    static boolean isAfter(RecordingState stateToTest, RecordingState b) {
+        return stateToTest.ordinal() > b.ordinal();
+    }
+
+    static boolean isBefore(RecordingState stateToTest, RecordingState b) {
+        return stateToTest.ordinal() < b.ordinal();
+    }
+
+    static boolean isState(RecordingState stateToTest, RecordingState... states) {
+        for (RecordingState s : states) {
+            if (s == stateToTest) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static List<Annotation> getAnnotationValues(Annotation a, Method valueMethod) {
+        try {
+            return Arrays.asList((Annotation[]) valueMethod.invoke(a, new Object[0]));
+        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+            return new ArrayList<>();
+        }
+    }
+
+    private static Method getValueMethod(Class<?> annotated) {
+        try {
+            return annotated.getMethod("value", new Class<?>[0]);
+        } catch (NoSuchMethodException e) {
+            return null;
+        }
+    }
+
+    public static void touch(Path dumpFile) throws IOException {
+        RandomAccessFile raf = new RandomAccessFile(dumpFile.toFile(), "rw");
+        raf.close();
+    }
+
+    public static Class<?> unboxType(Class<?> t) {
+        if (t == Integer.class) {
+            return int.class;
+        }
+        if (t == Long.class) {
+            return long.class;
+        }
+        if (t == Float.class) {
+            return float.class;
+        }
+        if (t == Double.class) {
+            return double.class;
+        }
+        if (t == Byte.class) {
+            return byte.class;
+        }
+        if (t == Short.class) {
+            return short.class;
+        }
+        if (t == Boolean.class) {
+            return boolean.class;
+        }
+        if (t == Character.class) {
+            return char.class;
+        }
+        return t;
+    }
+
+    static long nanosToTicks(long nanos) {
+        return (long) (nanos * JVM.getJVM().getTimeConversionFactor());
+    }
+
+    static synchronized EventHandler getHandler(Class<? extends Event> eventClass) {
+        Utils.ensureValidEventSubclass(eventClass);
+        try {
+            Field f = eventClass.getDeclaredField(EventInstrumentation.FIELD_EVENT_HANDLER);
+            SecuritySupport.setAccessible(f);
+            return (EventHandler) f.get(null);
+        } catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) {
+            throw new InternalError("Could not access event handler");
+        }
+    }
+
+    static synchronized void setHandler(Class<? extends Event> eventClass, EventHandler handler) {
+        Utils.ensureValidEventSubclass(eventClass);
+        try {
+            Field field = eventClass.getDeclaredField(EventInstrumentation.FIELD_EVENT_HANDLER);
+            SecuritySupport.setAccessible(field);
+            field.set(null, handler);
+        } catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) {
+            throw new InternalError("Could not access event handler");
+        }
+    }
+
+    public static Map<String, String> sanitizeNullFreeStringMap(Map<String, String> settings) {
+        HashMap<String, String> map = new HashMap<>(settings.size());
+        for (Map.Entry<String, String> e : settings.entrySet()) {
+            String key = e.getKey();
+            if (key == null) {
+                throw new NullPointerException("Null key is not allowed in map");
+            }
+            String value = e.getValue();
+            if (value == null) {
+                throw new NullPointerException("Null value is not allowed in map");
+            }
+            map.put(key, value);
+        }
+        return map;
+    }
+
+    public static <T> List<T> sanitizeNullFreeList(List<T> elements, Class<T> clazz) {
+        List<T> sanitized = new ArrayList<>(elements.size());
+        for (T element : elements) {
+            if (element == null) {
+                throw new NullPointerException("Null is not an allowed element in list");
+            }
+            if (element.getClass() != clazz) {
+                throw new ClassCastException();
+            }
+            sanitized.add(element);
+        }
+        return sanitized;
+    }
+
+    static List<Field> getVisibleEventFields(Class<?> clazz) {
+        Utils.ensureValidEventSubclass(clazz);
+        List<Field> fields = new ArrayList<>();
+        for (Class<?> c = clazz; c != Event.class; c = c.getSuperclass()) {
+            for (Field field : c.getDeclaredFields()) {
+                // skip private field in base classes
+                if (c == clazz || !Modifier.isPrivate(field.getModifiers())) {
+                    fields.add(field);
+                }
+            }
+        }
+        return fields;
+    }
+
+    public static void ensureValidEventSubclass(Class<?> eventClass) {
+        if (Event.class.isAssignableFrom(eventClass) && Modifier.isAbstract(eventClass.getModifiers())) {
+            throw new IllegalArgumentException("Abstract event classes are not allowed");
+        }
+        if (eventClass == Event.class || !Event.class.isAssignableFrom(eventClass)) {
+            throw new IllegalArgumentException("Must be a subclass to " + Event.class.getName());
+        }
+    }
+
+    public static void writeGeneratedASM(String className, byte[] bytes) {
+        if (SAVE_GENERATED == null) {
+            // We can't calculate value statically because it will force
+            // initialization of SecuritySupport, which cause
+            // UnsatisfiedLinkedError on JDK 8 or non-Oracle JDKs
+            SAVE_GENERATED = SecuritySupport.getBooleanProperty("jfr.save.generated.asm");
+        }
+        if (SAVE_GENERATED) {
+            try {
+                try (FileOutputStream fos = new FileOutputStream(className + ".class")) {
+                    fos.write(bytes);
+                }
+
+                try (FileWriter fw = new FileWriter(className + ".asm"); PrintWriter pw = new PrintWriter(fw)) {
+                    ClassReader cr = new ClassReader(bytes);
+                    CheckClassAdapter.verify(cr, true, pw);
+                }
+                Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.INFO, "Instrumented code saved to " + className + ".class and .asm");
+            } catch (IOException e) {
+                Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.INFO, "Could not save instrumented code, for " + className + ".class and .asm");
+            }
+        }
+    }
+
+    public static void ensureInitialized(Class<? extends Event> eventClass) {
+        SecuritySupport.ensureClassIsInitialized(eventClass);
+    }
+
+    public static Object makePrimitiveArray(String typeName, List<Object> values) {
+        int length = values.size();
+        switch (typeName) {
+        case "int":
+            int[] ints = new int[length];
+            for (int i = 0; i < length; i++) {
+                ints[i] = (int) values.get(i);
+            }
+            return ints;
+        case "long":
+            long[] longs = new long[length];
+            for (int i = 0; i < length; i++) {
+                longs[i] = (long) values.get(i);
+            }
+            return longs;
+
+        case "float":
+            float[] floats = new float[length];
+            for (int i = 0; i < length; i++) {
+                floats[i] = (float) values.get(i);
+            }
+            return floats;
+
+        case "double":
+            double[] doubles = new double[length];
+            for (int i = 0; i < length; i++) {
+                doubles[i] = (double) values.get(i);
+            }
+            return doubles;
+
+        case "short":
+            short[] shorts = new short[length];
+            for (int i = 0; i < length; i++) {
+                shorts[i] = (short) values.get(i);
+            }
+            return shorts;
+        case "char":
+            char[] chars = new char[length];
+            for (int i = 0; i < length; i++) {
+                chars[i] = (char) values.get(i);
+            }
+            return chars;
+        case "byte":
+            byte[] bytes = new byte[length];
+            for (int i = 0; i < length; i++) {
+                bytes[i] = (byte) values.get(i);
+            }
+            return bytes;
+        case "boolean":
+            boolean[] booleans = new boolean[length];
+            for (int i = 0; i < length; i++) {
+                booleans[i] = (boolean) values.get(i);
+            }
+            return booleans;
+        case "java.lang.String":
+            String[] strings = new String[length];
+            for (int i = 0; i < length; i++) {
+                strings[i] = (String) values.get(i);
+            }
+            return strings;
+        }
+        return null;
+    }
+
+    public static boolean isSettingVisible(Control c, boolean hasEventHook) {
+        if (c instanceof ThresholdSetting) {
+            return !hasEventHook;
+        }
+        if (c instanceof PeriodSetting) {
+            return hasEventHook;
+        }
+        if (c instanceof StackTraceSetting) {
+            return !hasEventHook;
+        }
+        return true;
+    }
+
+    public static boolean isSettingVisible(long typeId, boolean hasEventHook) {
+        if (ThresholdSetting.isType(typeId)) {
+            return !hasEventHook;
+        }
+        if (PeriodSetting.isType(typeId)) {
+            return hasEventHook;
+        }
+        if (StackTraceSetting.isType(typeId)) {
+            return !hasEventHook;
+        }
+        return true;
+    }
+
+    public static Type getValidType(Class<?> type, String name) {
+        Objects.requireNonNull(type, "Null is not a valid type for value descriptor " + name);
+        if (type.isArray()) {
+            type = type.getComponentType();
+            if (type != String.class && !type.isPrimitive()) {
+                throw new IllegalArgumentException("Only arrays of primitives and Strings are allowed");
+            }
+        }
+
+        Type knownType = Type.getKnownType(type);
+        if (knownType == null || knownType == Type.STACK_TRACE) {
+            throw new IllegalArgumentException("Only primitive types, java.lang.Thread, java.lang.String and java.lang.Class are allowed for value descriptors. " + type.getName());
+        }
+        return knownType;
+    }
+
+    public static <T> List<T> smallUnmodifiable(List<T> list) {
+        if (list.isEmpty()) {
+            return Collections.emptyList();
+        }
+        if (list.size() == 1) {
+            return Collections.singletonList(list.get(0));
+        }
+        return Collections.unmodifiableList(list);
+    }
+
+    public static void updateSettingPathToGcRoots(Map<String, String> settings, Boolean pathToGcRoots) {
+        if (pathToGcRoots != null) {
+            settings.put(Type.EVENT_NAME_PREFIX + "OldObjectSample#cutoff", pathToGcRoots ? "infinity" : "0 ns" );
+        }
+    }
+
+
+    public static String upgradeLegacyJDKEvent(String eventName) {
+        if (eventName.length() <= LEGACY_EVENT_NAME_PREFIX.length()) {
+            return eventName;
+        }
+        if (eventName.startsWith(LEGACY_EVENT_NAME_PREFIX)) {
+            int index = eventName.lastIndexOf(".");
+            if (index == LEGACY_EVENT_NAME_PREFIX.length() - 1) {
+                return Type.EVENT_NAME_PREFIX + eventName.substring(index + 1);
+            }
+        }
+        return eventName;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/WriteableUserPath.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import java.io.BufferedWriter;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+import java.util.concurrent.Callable;
+
+/**
+ * Purpose of this class is to simplify analysis of security risks.
+ * <p>
+ * Paths in the public API should be wrapped in this class so we
+ * at all time know what kind of paths we are dealing with.
+ * <p>
+ * A user supplied path must never be used in an unsafe context, such as a
+ * shutdown hook or any other thread created by JFR.
+ * <p>
+ * All operation using this path must happen in {@link #doPriviligedIO(Callable)}
+ */
+public final class WriteableUserPath {
+    private final AccessControlContext controlContext;
+    private final Path original;
+    private final Path real;
+    private final String text;
+
+    // Not to ensure security, but to help
+    // against programming errors
+    private volatile boolean inPrivileged;
+
+    public WriteableUserPath(Path path) throws IOException {
+        controlContext = AccessController.getContext();
+        // verify that the path is writeable
+        if (Files.exists(path) && !Files.isWritable(path)) {
+            // throw same type of exception as FileOutputStream
+            // constructor, if file can't be opened.
+            throw new FileNotFoundException("Could not write to file: " + path.toAbsolutePath());
+        }
+        // will throw if non-writeable
+        BufferedWriter fw = Files.newBufferedWriter(path);
+        fw.close();
+        this.original = path;
+        this.real = path.toRealPath();
+        this.text = real.toString();
+    }
+
+    /**
+     * Returns a potentially malicious path where the user may have implemented
+     * their own version of Path. This method should never be called in an
+     * unsafe context and the Path value should never be passed along to other
+     * methods.
+     *
+     * @return path from a potentially malicious user
+     */
+    public Path getPotentiallyMaliciousOriginal() {
+        return original;
+    }
+
+    /**
+     * Returns a string representation of the path.
+     *
+     * @return path as text
+     */
+    public String getText() {
+        return text;
+    }
+
+    /**
+     * Returns a potentially malicious path where the user may have implemented
+     * their own version of Path. This method should never be called in an
+     * unsafe context and the Path value should never be passed along to other
+     * methods.
+     *
+     * @return path from a potentially malicious user
+     */
+    public Path getReal() {
+        if (!inPrivileged) {
+            throw new InternalError("A user path was accessed outside the context it was supplied in");
+        }
+        return real;
+    }
+
+    public void doPriviligedIO(Callable<?> function) throws IOException {
+        try {
+            inPrivileged = true;
+            AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
+                @Override
+                public Void run() throws Exception {
+                    function.call();
+                    return null;
+                }
+            }, controlContext);
+        } catch (Throwable t) {
+            // prevent malicious user to propagate exception callback
+            // in the wrong context
+            throw new IOException("Unexpected error during I/O operation");
+        } finally {
+            inPrivileged = false;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/Command.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.cmd;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.List;
+
+abstract class Command {
+
+    private final static Command HELP = new HelpCommand();
+    private final static List<Command> COMMANDS = createCommands();
+
+    static void displayHelp() {
+        System.out.println("Usage: java " + Execute.class.getName() + " <command> [<options>]");
+        System.out.println();
+        displayAvailableCommands();
+    }
+
+    static void displayAvailableCommands() {
+        System.out.println("Available commands are:");
+        System.out.println();
+        boolean first = true;
+        for (Command c : Command.COMMANDS) {
+            if (!first) {
+                System.out.println();
+            }
+            System.out.println("  " + c.getName() + " " + c.getOptionSyntax());
+            System.out.println("    " + c.getDescription());
+            first = false;
+        }
+    }
+
+    public static List<Command> getCommands() {
+        return COMMANDS;
+    }
+
+    public static Command valueOf(String commandName) {
+        for (Command command : COMMANDS) {
+            if (command.getName().equals(commandName)) {
+                return command;
+            }
+        }
+        return null;
+    }
+
+    abstract public String getOptionSyntax();
+
+    abstract public String getName();
+
+    abstract public String getDescription();
+
+    abstract public void displayOptionUsage();
+
+    abstract public void execute(Deque<String> options);
+
+    final protected void userFailed(String message) {
+        println();
+        println(message);
+        displayUsage();
+        throw new IllegalArgumentException(message);
+    }
+
+    final protected void ensureMaxArgumentCount(Deque<String> options, int maxCount) {
+        if (options.size() > maxCount) {
+            userFailed("Too many arguments");
+        }
+    }
+
+    final protected void ensureMinArgumentCount(Deque<String> options, int minCount) {
+        if (options.size() < minCount) {
+            userFailed("Too few arguments");
+        }
+    }
+
+    final protected void ensureFileExist(Path file) {
+        if (!Files.exists(file)) {
+            userFailed("Could not find file " + file);
+        }
+    }
+
+    final protected Path ensureFileDoesNotExist(Path file) {
+        if (Files.exists(file)) {
+            userFailed("File " + file + " already exists");
+        }
+        return file;
+    }
+
+    final protected void ensureJFRFile(Path path) {
+        if (!path.toString().endsWith(".jfr")) {
+            userFailed("Filename must end with .jfr");
+        }
+    }
+
+    final protected void displayUsage() {
+        String javaText = "java " + Execute.class.getName();
+        println();
+        println("Usage: " + javaText + " " + getName() + " " + getOptionSyntax());
+        println();
+        displayOptionUsage();
+    }
+
+    final protected void println() {
+        System.out.println();
+    }
+
+    final protected void print(String text) {
+        System.out.print(text);
+    }
+
+    final protected void println(String text) {
+        System.out.println(text);
+    }
+
+    private static List<Command> createCommands() {
+        List<Command> commands = new ArrayList<>();
+        commands.add(new PrintCommand());
+        commands.add(new SummaryCommand());
+        commands.add(new ReconstructCommand());
+        commands.add(new SplitCommand());
+        commands.add(HELP);
+        return Collections.unmodifiableList(commands);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/Execute.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.cmd;
+
+import java.util.Arrays;
+import java.util.Deque;
+import java.util.LinkedList;
+
+/**
+ * Launcher class for JFR tools
+ *
+ */
+public final class Execute {
+
+    public static void main(String... args) {
+        Deque<String> argList = new LinkedList<>(Arrays.asList(args));
+        if (argList.isEmpty()) {
+            System.out.println();
+            Command.displayHelp();
+            return;
+        }
+        String command = argList.remove();
+        for (Command c : Command.getCommands()) {
+            if (c.getName().equals(command)) {
+                try {
+                    c.execute(argList);
+                } catch (IllegalArgumentException iae) {
+                    return; // already handled by command
+                } catch (Throwable e) {
+                    System.out.println();
+                    System.out.println(e.getMessage());
+                    System.out.println();
+                }
+                return;
+            }
+        }
+        System.out.println();
+        System.out.println("Unknown command " + command + ".");
+        System.out.println();
+        Command.displayHelp();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/HelpCommand.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.cmd;
+
+import java.util.Deque;
+
+final class HelpCommand extends Command {
+
+    @Override
+    public String getOptionSyntax() {
+        return "[<command>]";
+    }
+
+    @Override
+    public void displayOptionUsage() {
+        println("  <command>   The name of the command to get help for");
+        println();
+        Command.displayAvailableCommands();
+    }
+
+    @Override
+    public String getName() {
+        return "help";
+    }
+
+    @Override
+    public String getDescription() {
+        return "Display help about a command";
+    }
+
+    @Override
+    public void execute(Deque<String> options) {
+        if (options.isEmpty()) {
+            displayUsage();
+        } else {
+            ensureMaxArgumentCount(options, 1);
+            String commandName = options.remove();
+            Command c = Command.valueOf(commandName);
+            if (c == null) {
+                userFailed("Unknown command " + commandName);
+            }
+            c.displayUsage();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/JSONWriter.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.cmd;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Path;
+
+import jdk.jfr.EventType;
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedObject;
+import jdk.jfr.consumer.RecordingFile;
+
+final class JSONWriter extends StructuredWriter {
+
+    public JSONWriter(PrintWriter writer) {
+        super(writer);
+    }
+
+    public void print(Path source) throws IOException {
+        try (RecordingFile es = new RecordingFile(source)) {
+            printObjectBegin();
+            printRecording(es);
+            printObjectEnd();
+            flush();
+        }
+    }
+
+    private void printRecording(RecordingFile es) throws IOException {
+        printDataStructureName("recording");
+        printObjectBegin();
+        printEvents(es);
+        printObjectEnd();
+    }
+
+    private void printEvents(RecordingFile es) throws IOException {
+        printDataStructureName("events");
+        printArrayBegin();
+        boolean first = true;
+        while (es.hasMoreEvents()) {
+            RecordedEvent e = es.readEvent();
+            printNewDataStructure(first, true, null);
+            printEvent(e);
+            flush();
+            first = false;
+        }
+        printArrayEnd();
+    }
+
+    private void printEvent(RecordedEvent e) {
+        printObjectBegin();
+        EventType type = e.getEventType();
+        printValue(true, false, "name", type.getName());
+        printValue(false, false, "typeId", type.getId());
+        printValue(false, false, "startTime", e.getStartTime());
+        printValue(false, false, "duration", e.getDuration());
+        printNewDataStructure(false, false, "values");
+        printObject(e);
+        printObjectEnd();
+    }
+
+    void printValue(boolean first, boolean arrayElement, String name, Object value) {
+        printNewDataStructure(first, arrayElement, name);
+        if (!printIfNull(value)) {
+            if (value instanceof Boolean) {
+                printAsString(value);
+                return;
+            }
+            if (value instanceof Double) {
+                Double dValue = (Double) value;
+                if (Double.isNaN(dValue) || Double.isInfinite(dValue)) {
+                    printNull();
+                    return;
+                }
+                printAsString(value);
+                return;
+            }
+            if (value instanceof Float) {
+                Float fValue = (Float) value;
+                if (Float.isNaN(fValue) || Float.isInfinite(fValue)) {
+                    printNull();
+                    return;
+                }
+                printAsString(value);
+                return;
+            }
+            if (value instanceof Number) {
+                printAsString(value);
+                return;
+            }
+            print("\"");
+            printEscaped(String.valueOf(value));
+            print("\"");
+        }
+    }
+
+    public void printObject(RecordedObject object) {
+        printObjectBegin();
+        boolean first = true;
+        for (ValueDescriptor v : object.getFields()) {
+            printValueDescriptor(first, false, v, object.getValue(v.getName()));
+            first = false;
+        }
+        printObjectEnd();
+    }
+
+    private void printArray(ValueDescriptor v, Object[] array) {
+        printArrayBegin();
+        boolean first = true;
+        for (Object arrayElement : array) {
+            printValueDescriptor(first, true, v, arrayElement);
+            first = false;
+        }
+        printArrayEnd();
+    }
+
+    private void printValueDescriptor(boolean first, boolean arrayElement, ValueDescriptor vd, Object value) {
+        if (vd.isArray() && !arrayElement) {
+            printNewDataStructure(first, arrayElement, vd.getName());
+            if (!printIfNull(value)) {
+                printArray(vd, (Object[]) value);
+            }
+            return;
+        }
+        if (!vd.getFields().isEmpty()) {
+            printNewDataStructure(first, arrayElement, vd.getName());
+            if (!printIfNull(value)) {
+                printObject((RecordedObject) value);
+            }
+            return;
+        }
+        printValue(first, arrayElement, vd.getName(), value);
+    }
+
+    private void printNewDataStructure(boolean first, boolean arrayElement, String name) {
+        if (!first) {
+            print(", ");
+            if (!arrayElement) {
+                println();
+            }
+        }
+        if (!arrayElement) {
+            printDataStructureName(name);
+        }
+    }
+
+    private boolean printIfNull(Object value) {
+        if (value == null) {
+            printNull();
+            return true;
+        }
+        return false;
+    }
+
+    private void printNull() {
+        print("null");
+    }
+
+    private void printDataStructureName(String text) {
+        printIndent();
+        print("\"");
+        print(text);
+        print("\": ");
+    }
+
+    private void printObjectEnd() {
+        retract();
+        println();
+        printIndent();
+        print("}");
+    }
+
+    private void printObjectBegin() {
+        println("{");
+        indent();
+    }
+
+    private void printArrayEnd() {
+        print("]");
+    }
+
+    private void printArrayBegin() {
+        print("[");
+    }
+
+    private void printEscaped(String text) {
+        for (int i = 0; i < text.length(); i++) {
+            printEscaped(text.charAt(i));
+        }
+    }
+
+    private void printEscaped(char c) {
+        if (c == '\b') {
+            print("\\b");
+            return;
+        }
+        if (c == '\n') {
+            print("\\n");
+            return;
+        }
+        if (c == '\t') {
+            print("\\t");
+            return;
+        }
+        if (c == '\f') {
+            print("\\f");
+            return;
+        }
+        if (c == '\r') {
+            print("\\r");
+            return;
+        }
+        if (c == '\"') {
+            print("\\\"");
+            return;
+        }
+        if (c == '\\') {
+            print("\\\\");
+            return;
+        }
+        if (c == '/') {
+            print("\\/");
+            return;
+        }
+        if (c > 0x7F || c < 32) {
+            print("\\u");
+            // 0x10000 will pad with zeros.
+            print(Integer.toHexString(0x10000 + (int) c).substring(1));
+            return;
+        }
+        print(c);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/PrettyWriter.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.cmd;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.StringJoiner;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedObject;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.jfr.internal.PrivateAccess;
+import jdk.jfr.internal.Type;
+import jdk.jfr.internal.consumer.ChunkHeader;
+import jdk.jfr.internal.consumer.RecordingInput;
+
+public final class PrettyWriter extends StructuredWriter {
+
+    public PrettyWriter(PrintWriter destination) {
+        super(destination);
+    }
+
+    void print(Path source) throws FileNotFoundException, IOException {
+        try (RecordingInput input = new RecordingInput(source.toFile())) {
+            HashSet<Type> typeSet = new HashSet<>();
+            for (ChunkHeader ch = new ChunkHeader(input); !ch.isLastChunk(); ch = ch.nextHeader()) {
+                typeSet.addAll(ch.readMetadata().getTypes());
+            }
+            List<Type> types = new ArrayList<>(typeSet);
+            Collections.sort(types, (c1, c2) -> Long.compare(c1.getId(), c2.getId()));
+            for (Type t : types) {
+                printType(t);
+            }
+            flush();
+        }
+
+        try (RecordingFile es = new RecordingFile(source)) {
+            while (es.hasMoreEvents()) {
+                print(es.readEvent());
+                flush();
+            }
+        }
+        flush();
+    }
+
+    public void printType(Type t) throws IOException {
+        print("// id: ");
+        println(String.valueOf(t.getId()));
+        int commentIndex = t.getName().length() + 10;
+        String typeName = t.getName();
+        int index = typeName.lastIndexOf(".");
+        if (index != -1) {
+            println("package " + typeName.substring(0, index) + ";");
+        }
+        printAnnotations(commentIndex, t.getAnnotationElements());
+        print("class " + typeName.substring(index + 1));
+        String superType = t.getSuperType();
+        if (superType != null) {
+            print(" extends " + superType);
+        }
+        println(" {");
+        indent();
+        for (ValueDescriptor v : t.getFields()) {
+            printField(commentIndex, v);
+        }
+        retract();
+        println("}");
+        println();
+    }
+
+    private void printField(int commentIndex, ValueDescriptor v) throws IOException {
+        println();
+        printAnnotations(commentIndex, v.getAnnotationElements());
+        printIndent();
+        Type vType = PrivateAccess.getInstance().getType(v);
+        if (Type.SUPER_TYPE_SETTING.equals(vType.getSuperType())) {
+            print("static ");
+        }
+        print(makeSimpleType(v.getTypeName()));
+        if (v.isArray()) {
+            print("[]");
+        }
+        print(" ");
+        print(v.getName());
+        print(";");
+        printCommentRef(commentIndex, v.getTypeId());
+    }
+
+    private void printCommentRef(int commentIndex, long typeId) throws IOException {
+        int column = getColumn();
+        if (column > commentIndex) {
+            print("  ");
+        } else {
+            while (column < commentIndex) {
+                print(" ");
+                column++;
+            }
+        }
+        println(" // id=" + typeId);
+    }
+
+    private void printAnnotations(int commentIndex, List<AnnotationElement> annotations) throws IOException {
+        for (AnnotationElement a : annotations) {
+            printIndent();
+            print("@");
+            print(makeSimpleType(a.getTypeName()));
+            List<ValueDescriptor> vs = a.getValueDescriptors();
+            if (!vs.isEmpty()) {
+                printAnnotation(a);
+                printCommentRef(commentIndex, a.getTypeId());
+            } else {
+                println();
+            }
+        }
+    }
+
+    private void printAnnotation(AnnotationElement a) throws IOException {
+        StringJoiner sj = new StringJoiner(", ", "(", ")");
+        List<ValueDescriptor> vs = a.getValueDescriptors();
+        for (ValueDescriptor v : vs) {
+            Object o = a.getValue(v.getName());
+            if (vs.size() == 1 && v.getName().equals("value")) {
+                sj.add(textify(o));
+            } else {
+                sj.add(v.getName() + "=" + textify(o));
+            }
+        }
+        print(sj.toString());
+    }
+
+    private String textify(Object o) {
+        if (o.getClass().isArray()) {
+            Object[] array = (Object[]) o;
+            if (array.length == 1) {
+                return quoteIfNeeded(array[0]);
+            }
+            StringJoiner s = new StringJoiner(", ", "{", "}") ;
+            for (Object ob : array) {
+                s.add(quoteIfNeeded(ob));
+            }
+            return s.toString();
+        } else {
+            return quoteIfNeeded(o);
+        }
+    }
+
+    private String quoteIfNeeded(Object o) {
+        if (o instanceof String) {
+            return "\"" + o + "\"";
+        } else {
+            return String.valueOf(o);
+        }
+    }
+
+    private String makeSimpleType(String typeName) {
+        int index = typeName.lastIndexOf(".");
+        return typeName.substring(index + 1);
+    }
+
+    public void print(RecordedEvent event) throws IOException {
+        print(makeSimpleType(event.getEventType().getName()), " ");
+        print((RecordedObject) event, "");
+    }
+
+    public void print(RecordedObject struct, String postFix) throws IOException {
+        println("{");
+        indent();
+        for (ValueDescriptor v : struct.getFields()) {
+            printIndent();
+            print(v.getName(), " = ");
+            printValue(struct.getValue(v.getName()), "");
+        }
+        retract();
+        printIndent();
+        println("}" + postFix);
+    }
+
+    private void printArray(Object[] array) throws IOException {
+        println("[");
+        indent();
+        for (int i = 0; i < array.length; i++) {
+            printIndent();
+            printValue(array[i], i + 1 < array.length ? ", " : "");
+        }
+        retract();
+        printIndent();
+        println("]");
+    }
+
+    private void printValue(Object value, String postFix) throws IOException {
+        if (value == null) {
+            println("null" + postFix);
+        } else if (value instanceof RecordedObject) {
+            print((RecordedObject) value, postFix);
+        } else if (value.getClass().isArray()) {
+            printArray((Object[]) value);
+        } else {
+            String text = String.valueOf(value);
+            if (value instanceof String) {
+                text = "\"" + text + "\"";
+            }
+            println(text);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/PrintCommand.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.cmd;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Deque;
+
+final class PrintCommand extends Command {
+    @Override
+    public String getName() {
+        return "print";
+    }
+
+    @Override
+    public String getOptionSyntax() {
+        return "[--xml|--json] <file>";
+    }
+
+    @Override
+    public String getDescription() {
+        return "Print contents of a recording file (.jfr)";
+    }
+
+    @Override
+    public void displayOptionUsage() {
+        println("  --xml    Print a recording in XML format");
+        println();
+        println("  --json   Print a recording in JSON format");
+        println();
+        println("  <file>   Location of the recording file (.jfr) to print");
+    }
+
+    @Override
+    public void execute(Deque<String> options) {
+        if (options.isEmpty()) {
+            userFailed("Missing file");
+        }
+        ensureMaxArgumentCount(options, 2);
+
+        Path file = Paths.get(options.removeLast());
+
+        ensureFileExist(file);
+        ensureJFRFile(file);
+        ensureMaxArgumentCount(options, 1);
+
+        String format = "--pretty";
+        if (!options.isEmpty()) {
+            format = options.remove();
+        }
+        try (PrintWriter pw = new PrintWriter(System.out)) {
+            try {
+                switch (format) {
+                case "--pretty":
+                    PrettyWriter prettyWriter = new PrettyWriter(pw);
+                    prettyWriter.print(file);
+                    break;
+                case "--xml":
+                    XMLWriter xmlPrinter = new XMLWriter(pw);
+                    xmlPrinter.print(file);
+                    break;
+                case "--json":
+                    JSONWriter jsonWriter = new JSONWriter(pw);
+                    jsonWriter.print(file);
+                    break;
+                default:
+                    userFailed("Unknown option " + format);
+                    break;
+                }
+            } catch (IOException ioe) {
+                userFailed("Could not read recording at " + file.toAbsolutePath() + ". " + ioe.getMessage());
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/ReconstructCommand.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.cmd;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.List;
+
+final class ReconstructCommand extends Command {
+
+    @Override
+    public String getOptionSyntax() {
+        return "<repository> <file>";
+    }
+
+    @Override
+    public String getName() {
+        return "reconstruct";
+    }
+
+    @Override
+    public String getDescription() {
+        return "Assemble leftover chunks, from a disk repository, into a recording file (.jfr)";
+    }
+
+    @Override
+    public void displayOptionUsage() {
+        println("  <repository>   Directory where the repository is located");
+        println();
+        println("  <file>         Name of the recording file (.jfr) to create");
+    }
+
+    @Override
+    public void execute(Deque<String> options) {
+        ensureMinArgumentCount(options, 2);
+        ensureMaxArgumentCount(options, 2);
+
+        Path repository = Paths.get(options.pop()).toAbsolutePath();
+        if (!Files.exists(repository)) {
+            userFailed("Could not find disk repository at " + repository);
+        }
+        if (!Files.isDirectory(repository)) {
+            userFailed("Must specify a directory as disk repository");
+        }
+        Path output = Paths.get(options.pop());
+        ensureFileDoesNotExist(output);
+        ensureJFRFile(output);
+
+        try (FileOutputStream fos = new FileOutputStream(output.toFile())) {
+            List<Path> files = listJFRFiles(repository);
+            if (files.isEmpty()) {
+                throw new IllegalStateException("No *.jfr files found at " + repository);
+            }
+            println();
+            println("Combining files... ");
+            println();
+            transferTo(files, output, fos.getChannel());
+            println();
+            println("Reconstruction complete.");
+        } catch (IOException e) {
+            userFailed("Could not open destination file " + output + ". " + e.getMessage());
+        }
+    }
+
+    private List<Path> listJFRFiles(Path path) throws IOException {
+        try {
+            List<Path> files = new ArrayList<>();
+            if (Files.isDirectory(path)) {
+                try (DirectoryStream<Path> stream = Files.newDirectoryStream(path, "*.jfr")) {
+                    for (Path p : stream) {
+                        if (!Files.isDirectory(p) && Files.isReadable(p)) {
+                            files.add(p);
+                        }
+                    }
+                }
+            }
+            files.sort((u, v) -> u.getFileName().compareTo(v.getFileName()));
+            return files;
+        } catch (IOException ioe) {
+            throw new IllegalStateException("Could not list *.jfr for directory " + path + ". " + ioe.getMessage());
+        }
+    }
+
+    private void transferTo(List<Path> sourceFiles, Path output, FileChannel out) {
+        long pos = 0;
+        for (Path p : sourceFiles) {
+            println(" " + p.toString());
+            try (FileChannel sourceChannel = FileChannel.open(p)) {
+                long rem = Files.size(p);
+                while (rem > 0) {
+                    long n = Math.min(rem, 1024 * 1024);
+                    long w = out.transferFrom(sourceChannel, pos, n);
+                    pos += w;
+                    rem -= w;
+                }
+            } catch (IOException ioe) {
+                throw new IllegalStateException("Could not copy recording chunk " + p + " to new file. " + ioe.getMessage());
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/SplitCommand.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.cmd;
+
+import java.io.BufferedInputStream;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.List;
+
+import jdk.jfr.internal.consumer.ChunkHeader;
+import jdk.jfr.internal.consumer.RecordingInput;
+
+final class SplitCommand extends Command {
+
+    @Override
+    public String getOptionSyntax() {
+        return "[--maxchunks <chunks>] <file>";
+    }
+
+    @Override
+    public void displayOptionUsage() {
+        println("  --maxchunks <chunks>   Maximum number of chunks per splitted file (default 5).");
+        println("                         The chunk size varies, but is typically around 15 MB.");
+        println();
+        println("  <file>                 Location of recording file (.jfr) to split");
+    }
+
+    @Override
+    public String getName() {
+        return "split";
+    }
+
+    @Override
+    public String getDescription() {
+        return "Splits a recording file into smaller files";
+    }
+
+    @Override
+    public void execute(Deque<String> options) {
+        if (options.isEmpty()) {
+            userFailed("Missing file");
+        }
+        ensureMaxArgumentCount(options, 3);
+        Path file = Paths.get(options.removeLast());
+        ensureFileExist(file);
+        ensureJFRFile(file);
+        int maxchunks = 5;
+        if (!options.isEmpty()) {
+            String option = options.pop();
+            if (!"--maxchunks".equals(option)) {
+                userFailed("Unknown option " + option);
+            }
+            if (options.isEmpty()) {
+                userFailed("Missing value for --maxChunks");
+            }
+            String value = options.pop();
+            try {
+                maxchunks = Integer.parseInt(value);
+                if (maxchunks < 1) {
+                    userFailed("Must be at least one chunk per file.");
+                }
+            } catch (NumberFormatException nfe) {
+                userFailed("Not a valid value for --maxchunks.");
+            }
+        }
+        ensureMaxArgumentCount(options, 0);
+        println();
+        println("Examining recording " + file + " ...");
+        List<Long> sizes;
+
+        try {
+            sizes = findChunkSizes(file);
+        } catch (IOException e) {
+            throw new IllegalStateException("Unexpected error. " + e.getMessage());
+        }
+        if (sizes.size() <= maxchunks) {
+            throw new IllegalStateException("Number of chunks in recording (" + sizes.size() + ") doesn't exceed max chunks (" + maxchunks + ")");
+        }
+        println();
+
+        println();
+        if (sizes.size() > 0) {
+            print("File consists of " + sizes.size() + " chunks. The recording will be split into ");
+            sizes = combineChunkSizes(sizes, maxchunks);
+            println(sizes.size() + " files with at most " + maxchunks + " chunks per file.");
+            println();
+
+            try {
+                splitFile(file, sizes);
+            } catch (IOException e) {
+                throw new IllegalStateException("Unexpected error. " + e.getMessage());
+            }
+        } else {
+            println("No JFR chunks found in file. ");
+        }
+    }
+
+    private List<Long> findChunkSizes(Path p) throws IOException {
+        try (RecordingInput input = new RecordingInput(p.toFile())) {
+            List<Long> sizes = new ArrayList<>();
+            ChunkHeader ch = new ChunkHeader(input);
+            sizes.add(ch.getSize());
+            while (!ch.isLastChunk()) {
+                ch = ch.nextHeader();
+                sizes.add(ch.getSize());
+            }
+            return sizes;
+        }
+    }
+
+    private List<Long> combineChunkSizes(List<Long> sizes, int chunksPerFile) {
+        List<Long> reduced = new ArrayList<Long>();
+        long size = sizes.get(0);
+        for (int n = 1; n < sizes.size(); n++) {
+            if (n % chunksPerFile == 0) {
+                reduced.add(size);
+                size = 0;
+            }
+            size += sizes.get(n);
+        }
+        reduced.add(size);
+        return reduced;
+    }
+
+    private void splitFile(Path file, List<Long> splitPositions) throws IOException {
+
+        int padAmountZeros = String.valueOf(splitPositions.size() - 1).length();
+        String fileName = file.toString();
+        String fileFormatter = fileName.subSequence(0, fileName.length() - 4) + "_%0" + padAmountZeros + "d.jfr";
+        for (int i = 0; i < splitPositions.size(); i++) {
+            Path p = Paths.get(String.format(fileFormatter, i));
+            if (Files.exists(p)) {
+                throw new IllegalStateException("Can't create split file " + p + ", a file with that name already exist");
+            }
+        }
+        DataInputStream stream = new DataInputStream(new BufferedInputStream(new FileInputStream(file.toFile())));
+
+        for (int i = 0; i < splitPositions.size(); i++) {
+            Long l = splitPositions.get(i);
+            byte[] bytes = readBytes(stream, l.intValue());
+            Path p = Paths.get(String.format(fileFormatter, i));
+            File splittedFile = p.toFile();
+            println("Writing " + splittedFile + " ...");
+            FileOutputStream fos = new FileOutputStream(splittedFile);
+            fos.write(bytes);
+            fos.close();
+        }
+        stream.close();
+    }
+
+    private byte[] readBytes(InputStream stream, int count) throws IOException {
+        byte[] data = new byte[count];
+        int totalRead = 0;
+        while (totalRead < data.length) {
+            int read = stream.read(data, totalRead, data.length - totalRead);
+            if (read == -1) {
+                throw new IOException("Unexpected end of data.");
+            }
+            totalRead += read;
+        }
+        return data;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/StructuredWriter.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.cmd;
+
+import java.io.PrintWriter;
+
+abstract class StructuredWriter {
+    private final static String LINE_SEPARATOR = String.format("%n");
+
+    private final PrintWriter out;
+    private final StringBuilder builder = new StringBuilder(4000);
+
+    private char[] indentionArray = new char[0];
+    private int indent = 0;
+    private int column;
+
+    StructuredWriter(PrintWriter p) {
+        out = p;
+    }
+
+    final protected int getColumn() {
+        return column;
+    }
+
+    // Flush to print writer
+    public final void flush() {
+        out.print(builder.toString());
+        builder.setLength(0);
+    }
+
+    final public void printIndent() {
+        builder.append(indentionArray, 0, indent);
+        column += indent;
+    }
+
+    final public void println() {
+        builder.append(LINE_SEPARATOR);
+        column = 0;
+    }
+
+    final public void print(String... texts) {
+        for (String text : texts) {
+            print(text);
+        }
+    }
+
+    final public void printAsString(Object o) {
+        print(String.valueOf(o));
+    }
+
+    final public void print(String text) {
+        builder.append(text);
+        column += text.length();
+    }
+
+    final public void print(char c) {
+        builder.append(c);
+        column++;
+    }
+
+    final public void print(int value) {
+        print(String.valueOf(value));
+    }
+
+    final public void indent() {
+        indent += 2;
+        updateIndent();
+    }
+
+    final public void retract() {
+        indent -= 2;
+        updateIndent();
+    }
+
+    final public void println(String text) {
+        print(text);
+        println();
+    }
+
+    private void updateIndent() {
+        if (indent > indentionArray.length) {
+            indentionArray = new char[indent];
+            for (int i = 0; i < indentionArray.length; i++) {
+                indentionArray[i] = ' ';
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/SummaryCommand.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.cmd;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.List;
+
+import jdk.jfr.EventType;
+import jdk.jfr.internal.MetadataDescriptor;
+import jdk.jfr.internal.Type;
+import jdk.jfr.internal.consumer.ChunkHeader;
+import jdk.jfr.internal.consumer.RecordingInput;
+
+final class SummaryCommand extends Command {
+
+    private static class Statistics {
+        Statistics(String name) {
+            this.name = name;
+        }
+
+        String name;
+        long count;
+        long size;
+    }
+
+    @Override
+    public String getOptionSyntax() {
+        return "<file>";
+    }
+
+    @Override
+    public void displayOptionUsage() {
+        println("  <file>   Location of the recording file (.jfr) to display information about");
+    }
+
+    @Override
+    public String getName() {
+        return "summary";
+    }
+
+    @Override
+    public String getDescription() {
+        return "Display general information about a recording file (.jfr)";
+    }
+
+    @Override
+    public void execute(Deque<String> options) {
+        if (options.isEmpty()) {
+            userFailed("Missing file");
+        }
+        ensureMaxArgumentCount(options, 1);
+        Path p = Paths.get(options.remove());
+        ensureFileExist(p);
+        ensureJFRFile(p);
+        try {
+            printInformation(p);
+        } catch (IOException e) {
+            throw new IllegalStateException("Unexpected error. " + e.getMessage());
+        }
+    }
+
+    private void printInformation(Path p) throws IOException {
+        long totalSize = 0;
+        long totalDuration = 0;
+        long chunks = 0;
+
+        try (RecordingInput input = new RecordingInput(p.toFile())) {
+            ChunkHeader first = new ChunkHeader(input);
+            ChunkHeader ch = first;
+            String eventPrefix = Type.EVENT_NAME_PREFIX;
+            if (first.getMajor() == 1) {
+                eventPrefix = "com.oracle.jdk.";
+            }
+            HashMap<Long, Statistics> stats = new HashMap<>();
+            stats.put(0L, new Statistics(eventPrefix + "Metadata"));
+            stats.put(1L, new Statistics(eventPrefix + "CheckPoint"));
+            int minWidth = 0;
+            while (true) {
+                long chunkEnd = ch.getEnd();
+                MetadataDescriptor md = ch.readMetadata();
+
+                for (EventType eventType : md.getEventTypes()) {
+                    stats.computeIfAbsent(eventType.getId(), (e) -> new Statistics(eventType.getName()));
+                    minWidth = Math.max(minWidth, eventType.getName().length());
+                }
+
+                totalSize += ch.getSize();
+                totalDuration += ch.getDuration();
+                chunks++;
+                input.position(ch.getEventStart());
+                while (input.position() < chunkEnd) {
+
+                    long pos = input.position();
+                    int size = input.readInt();
+                    long eventTypeId = input.readLong();
+                    Statistics s = stats.get(eventTypeId);
+
+                    if (s != null) {
+                        s.count++;
+                        s.size += size;
+                    }
+                    input.position(pos + size);
+                }
+                if (ch.isLastChunk()) {
+                    break;
+                }
+                ch = ch.nextHeader();
+            }
+            println();
+            long epochSeconds = first.getStartNanos() / 1_000_000_000L;
+            long adjustNanos = first.getStartNanos() - epochSeconds * 1_000_000_000L;
+            println(" Version: " + first.getMajor() + "." + first.getMinor());
+            println(" Chunks: " + chunks);
+            println(" Size: " + totalSize + " bytes");
+            println(" Start: " + Instant.ofEpochSecond(epochSeconds, adjustNanos));
+            println(" Duration: " + Duration.ofNanos(totalDuration));
+            println();
+            println(" Start Ticks: " + first.getStartTicks());
+            println(" Ticks / Second: " + first.getTicksPerSecond());
+
+            List<Statistics> statsList = new ArrayList<>(stats.values());
+            Collections.sort(statsList, (u, v) -> Long.compare(v.count, u.count));
+            println();
+            String header = "      Count  Size (bytes) ";
+            String typeHeader = " Event Type";
+            minWidth = Math.max(minWidth, typeHeader.length());
+            println(typeHeader + pad(minWidth - typeHeader.length(), ' ') + header);
+            println(pad(minWidth + header.length(), '='));
+            for (Statistics s : statsList) {
+                System.out.printf(" %-" + minWidth + "s%10d  %12d\n", s.name, s.count, s.size);
+            }
+        }
+    }
+
+    private String pad(int count, char c) {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < count; i++) {
+            sb.append(c);
+        }
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/XMLWriter.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.cmd;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Path;
+
+import jdk.jfr.EventType;
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedObject;
+import jdk.jfr.consumer.RecordingFile;
+
+final class XMLWriter extends StructuredWriter {
+
+    public XMLWriter(PrintWriter destination) {
+        super(destination);
+    }
+
+    public void print(Path source) throws IOException {
+        try (RecordingFile es = new RecordingFile(source)) {
+            println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+            println("<recording>");
+            indent();
+            printIndent();
+            println("<events>");
+            indent();
+            while (es.hasMoreEvents()) {
+                printEvent(es.readEvent());
+                flush();
+            }
+            retract();
+            printIndent();
+            println("</events>");
+            retract();
+            println("</recording>");
+            flush();
+        }
+    }
+
+    private void printEvent(RecordedEvent e) throws IOException {
+        EventType type = e.getEventType();
+        printIndent();
+        print("<event");
+        printAttribute("typeId", String.valueOf(type.getId()));
+        printAttribute("name", type.getName());
+        printAttribute("startTime",e.getStartTime().toString());
+        printAttribute("duration", e.getDuration().toString());
+        print(">");
+        printObject(e);
+        printIndent();
+        println("</event>");
+        println();
+    }
+
+    private void printAttribute(String name, String value) {
+        print(" ", name, "=\"", value, "\"");
+    }
+
+    public void printObject(RecordedObject struct) {
+        println();
+        indent();
+        for (ValueDescriptor v : struct.getFields()) {
+            printValueDescriptor(v, struct.getValue(v.getName()), -1);
+        }
+        retract();
+    }
+
+    private void printArray(ValueDescriptor v, Object[] array) {
+        println();
+        indent();
+        for (int index = 0; index < array.length; index++) {
+            printValueDescriptor(v, array[index], index);
+        }
+        retract();
+    }
+
+    private void printValueDescriptor(ValueDescriptor vd, Object value, int index) {
+        boolean arrayElement = index != -1;
+        String name = arrayElement ? null : vd.getName();
+        if (vd.isArray() && !arrayElement) {
+            if (printBeginElement("array", name, value, index)) {
+                printArray(vd, (Object[]) value);
+                printIndent();
+                printEndElement("array");
+            }
+            return;
+        }
+        if (!vd.getFields().isEmpty()) {
+            if (printBeginElement("struct", name, value, index)) {
+                printObject((RecordedObject) value);
+                printIndent();
+                printEndElement("struct");
+            }
+            return;
+        }
+        if (printBeginElement("value", name, value, index)) {
+            printEscaped(String.valueOf(value));
+            printEndElement("value");
+        }
+    }
+
+    private boolean printBeginElement(String elementName, String name, Object value, int index) {
+        printIndent();
+        print("<", elementName);
+        if (name != null) {
+            printAttribute("name", name);
+        }
+        if (index != -1) {
+            printAttribute("index", Integer.toString(index));
+        }
+        if (value == null) {
+            print("><null/></");
+            print(elementName);
+            println(">");
+            return false;
+        }
+        if (value.getClass().isArray()) {
+            Object[] array = (Object[]) value;
+            printAttribute("size", Integer.toString(array.length));
+        }
+        print(">");
+        return true;
+    }
+
+    private void printEndElement(String elementName) {
+        print("</");
+        print(elementName);
+        println(">");
+    }
+
+    private void printEscaped(String text) {
+        for (int i = 0; i < text.length(); i++) {
+            printEscaped(text.charAt(i));
+        }
+    }
+
+    private void printEscaped(char c) {
+        if (c == 34) {
+            print("&quot;");
+            return;
+        }
+        if (c == 38) {
+            print("&amp;");
+            return;
+        }
+        if (c == 39) {
+            print("&apos;");
+            return;
+        }
+        if (c == 60) {
+            print("&lt;");
+            return;
+        }
+        if (c == 62) {
+            print("&gt;");
+            return;
+        }
+        if (c > 0x7F) {
+            print("&#");
+            print((int) c);
+            print(';');
+            return;
+        }
+        print(c);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.consumer;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+import jdk.jfr.internal.LogLevel;
+import jdk.jfr.internal.LogTag;
+import jdk.jfr.internal.Logger;
+import jdk.jfr.internal.MetadataDescriptor;
+
+public final class ChunkHeader {
+    private static final long METADATA_TYPE_ID = 0;
+    private static final byte[] FILE_MAGIC = { 'F', 'L', 'R', '\0' };
+
+    private final short major;
+    private final short minor;
+    private final long chunkSize;
+    private final long chunkStartTicks;
+    private final long ticksPerSecond;
+    private final long chunkStartNanos;
+    private final long metadataPosition;
+ //   private final long absoluteInitialConstantPoolPosition;
+    private final long absoluteChunkEnd;
+    private final long absoluteEventStart;
+    private final long absoluteChunkStart;
+    private final boolean lastChunk;
+    private final RecordingInput input;
+    private final long durationNanos;
+    private final long id;
+    private long constantPoolPosition;
+
+    public ChunkHeader(RecordingInput input) throws IOException {
+        this(input, 0, 0);
+    }
+
+    private ChunkHeader(RecordingInput input, long absoluteChunkStart, long id) throws IOException {
+        input.position(absoluteChunkStart);
+        if (input.position() >= input.size()) {
+            throw new IOException("Chunk contains no data");
+        }
+        verifyMagic(input);
+        this.input = input;
+        this.id = id;
+        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk " + id);
+        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: startPosition=" + absoluteChunkStart);
+        major = input.readRawShort();
+        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: major=" + major);
+        minor = input.readRawShort();
+        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: minor=" + minor);
+        if (major != 1 && major != 2) {
+            throw new IOException("File version " + major + "." + minor + ". Only Flight Recorder files of version 1.x and 2.x can be read by this JDK.");
+        }
+        chunkSize = input.readRawLong();
+        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: chunkSize=" + chunkSize);
+        this.constantPoolPosition = input.readRawLong();
+        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: constantPoolPosition=" + constantPoolPosition);
+        metadataPosition = input.readRawLong();
+        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: metadataPosition=" + metadataPosition);
+        chunkStartNanos = input.readRawLong(); // nanos since epoch
+        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: startNanos=" + chunkStartNanos);
+        durationNanos = input.readRawLong(); // duration nanos, not used
+        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: durationNanos=" + durationNanos);
+        chunkStartTicks = input.readRawLong();
+        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: startTicks=" + chunkStartTicks);
+        ticksPerSecond = input.readRawLong();
+        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: ticksPerSecond=" + ticksPerSecond);
+        input.readRawInt(); // features, not used
+
+        // set up boundaries
+        this.absoluteChunkStart = absoluteChunkStart;
+        absoluteChunkEnd = absoluteChunkStart + chunkSize;
+        lastChunk = input.size() == absoluteChunkEnd;
+        absoluteEventStart = input.position();
+
+        // read metadata
+        input.position(absoluteEventStart);
+    }
+
+    public ChunkHeader nextHeader() throws IOException {
+        return new ChunkHeader(input, absoluteChunkEnd, id + 1);
+    }
+
+    public MetadataDescriptor readMetadata() throws IOException {
+        input.position(absoluteChunkStart + metadataPosition);
+        input.readInt(); // size
+        long id = input.readLong(); // event type id
+        if (id != METADATA_TYPE_ID) {
+            throw new IOException("Expected metadata event. Type id=" + id + ", should have been " + METADATA_TYPE_ID);
+        }
+        input.readLong(); // start time
+        input.readLong(); // duration
+        long metadataId = input.readLong();
+        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.TRACE, "Metadata id=" + metadataId);
+        // No need to read if metadataId == lastMetadataId, but we
+        // do it for verification purposes.
+        return MetadataDescriptor.read(input);
+    }
+
+    public boolean isLastChunk() {
+        return lastChunk;
+    }
+
+    public short getMajor() {
+        return major;
+    }
+
+    public short getMinor() {
+        return minor;
+    }
+
+    public long getAbsoluteChunkStart() {
+        return absoluteChunkStart;
+    }
+
+    public long getConstantPoolPosition() {
+        return constantPoolPosition;
+    }
+
+    public long getStartTicks() {
+        return chunkStartTicks;
+    }
+
+    public double getTicksPerSecond() {
+        return ticksPerSecond;
+    }
+
+    public long getStartNanos() {
+        return chunkStartNanos;
+    }
+
+    public long getEnd() {
+        return absoluteChunkEnd;
+    }
+
+    public long getSize() {
+        return chunkSize;
+    }
+
+    public long getDuration() {
+        return durationNanos;
+    }
+
+    public RecordingInput getInput() {
+        return input;
+    }
+
+    private static void verifyMagic(DataInput input) throws IOException {
+        for (byte c : FILE_MAGIC) {
+            if (input.readByte() != c) {
+                throw new IOException("Not a Flight Recorder file");
+            }
+        }
+    }
+
+    public long getEventStart() {
+        return absoluteEventStart;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RecordingInput.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,339 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.consumer;
+
+import java.io.DataInput;
+import java.io.EOFException;
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.charset.Charset;
+
+public final class RecordingInput implements DataInput, AutoCloseable {
+
+    public static final byte STRING_ENCODING_NULL = 0;
+    public static final byte STRING_ENCODING_EMPTY_STRING = 1;
+    public static final byte STRING_ENCODING_CONSTANT_POOL = 2;
+    public static final byte STRING_ENCODING_UTF8_BYTE_ARRAY = 3;
+    public static final byte STRING_ENCODING_CHAR_ARRAY = 4;
+    public static final byte STRING_ENCODING_LATIN1_BYTE_ARRAY = 5;
+
+    private final static int DEFAULT_BLOCK_SIZE = 16 * 1024 * 1024;
+    private final static Charset UTF8 = Charset.forName("UTF-8");
+    private final static Charset LATIN1 = Charset.forName("ISO-8859-1");
+
+    private static final class Block {
+        private byte[] bytes = new byte[0];
+        private long blockPosition;
+
+        boolean contains(long position) {
+            return position >= blockPosition && position < blockPosition + bytes.length;
+        }
+
+        public void read(RandomAccessFile file, int amount) throws IOException {
+            blockPosition = file.getFilePointer();
+            // reuse byte array, if possible
+            if (amount != bytes.length) {
+                bytes = new byte[amount];
+            }
+            file.readFully(bytes);
+        }
+
+        public byte get(long position) {
+            return bytes[(int) (position - blockPosition)];
+        }
+    }
+
+    private final RandomAccessFile file;
+    private final long size;
+    private Block currentBlock = new Block();
+    private Block previousBlock = new Block();
+    private long position;
+    private final int blockSize;
+
+    private RecordingInput(File f, int blockSize) throws IOException {
+        this.size = f.length();
+        this.blockSize = blockSize;
+        this.file = new RandomAccessFile(f, "r");
+        if (size < 8) {
+            throw new IOException("Not a valid Flight Recorder file. File length is only " + size + " bytes.");
+        }
+    }
+
+    public RecordingInput(File f) throws IOException {
+        this(f, DEFAULT_BLOCK_SIZE);
+    }
+
+    @Override
+    public final byte readByte() throws IOException {
+        if (!currentBlock.contains(position)) {
+            position(position);
+        }
+        return currentBlock.get(position++);
+    }
+
+    @Override
+    public final void readFully(byte[] dest, int offset, int length) throws IOException {
+        // TODO: Optimize, use Arrays.copy if all bytes are in current block
+        // array
+        for (int i = 0; i < length; i++) {
+            dest[i + offset] = readByte();
+        }
+    }
+
+    @Override
+    public final void readFully(byte[] dst) throws IOException {
+        readFully(dst, 0, dst.length);
+    }
+
+    public final short readRawShort() throws IOException {
+        // copied from java.io.Bits
+        byte b0 = readByte();
+        byte b1 = readByte();
+        return (short) ((b1 & 0xFF) + (b0 << 8));
+    }
+
+    @Override
+    public final double readDouble() throws IOException {
+        // copied from java.io.Bits
+        return Double.longBitsToDouble(readRawLong());
+    }
+
+    @Override
+    public final float readFloat() throws IOException {
+        // copied from java.io.Bits
+        return Float.intBitsToFloat(readRawInt());
+    }
+
+    public final int readRawInt() throws IOException {
+        // copied from java.io.Bits
+        byte b0 = readByte();
+        byte b1 = readByte();
+        byte b2 = readByte();
+        byte b3 = readByte();
+        return ((b3 & 0xFF)) + ((b2 & 0xFF) << 8) + ((b1 & 0xFF) << 16) + ((b0) << 24);
+    }
+
+    public final long readRawLong() throws IOException {
+        // copied from java.io.Bits
+        byte b0 = readByte();
+        byte b1 = readByte();
+        byte b2 = readByte();
+        byte b3 = readByte();
+        byte b4 = readByte();
+        byte b5 = readByte();
+        byte b6 = readByte();
+        byte b7 = readByte();
+        return ((b7 & 0xFFL)) + ((b6 & 0xFFL) << 8) + ((b5 & 0xFFL) << 16) + ((b4 & 0xFFL) << 24) + ((b3 & 0xFFL) << 32) + ((b2 & 0xFFL) << 40) + ((b1 & 0xFFL) << 48) + (((long) b0) << 56);
+    }
+
+    public final long position() throws IOException {
+        return position;
+    }
+
+    public final void position(long newPosition) throws IOException {
+        if (!currentBlock.contains(newPosition)) {
+            if (!previousBlock.contains(newPosition)) {
+                if (newPosition > size()) {
+                    throw new EOFException("Trying to read at " + newPosition + ", but file is only " + size() + " bytes.");
+                }
+                long blockStart = trimToFileSize(calculateBlockStart(newPosition));
+                file.seek(blockStart);
+                // trim amount to file size
+                long amount = Math.min(size() - blockStart, blockSize);
+                previousBlock.read(file, (int) amount);
+            }
+            // swap previous and current
+            Block tmp = currentBlock;
+            currentBlock = previousBlock;
+            previousBlock = tmp;
+        }
+        position = newPosition;
+    }
+
+    private final long trimToFileSize(long position) throws IOException {
+        return Math.min(size(), Math.max(0, position));
+    }
+
+    private final long calculateBlockStart(long newPosition) {
+        // align to end of current block
+        if (currentBlock.contains(newPosition - blockSize)) {
+            return currentBlock.blockPosition + currentBlock.bytes.length;
+        }
+        // align before current block
+        if (currentBlock.contains(newPosition + blockSize)) {
+            return currentBlock.blockPosition - blockSize;
+        }
+        // not near current block, pick middle
+        return newPosition - blockSize / 2;
+    }
+
+    public final long size() throws IOException {
+        return size;
+    }
+
+    public final void close() throws IOException {
+        file.close();
+    }
+
+    @Override
+    public final int skipBytes(int n) throws IOException {
+        long position = position();
+        position(position + n);
+        return (int) (position() - position);
+    }
+
+    @Override
+    public final boolean readBoolean() throws IOException {
+        return readByte() != 0;
+    }
+
+    @Override
+    public int readUnsignedByte() throws IOException {
+        return readByte() & 0x00FF;
+    }
+
+    @Override
+    public int readUnsignedShort() throws IOException {
+        return readShort() & 0xFFFF;
+    }
+
+    @Override
+    public final String readLine() throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    // NOTE, this method should really be called readString
+    // but can't be renamed without making RecordingInput a
+    // public class.
+    //
+    // This method DOES Not read as expected (s2 + utf8 encoded character)
+    // instead it read:
+    // byte encoding
+    // int size
+    // data (byte or char)
+    //
+    // where encoding
+    //
+    // 0, means null
+    // 1, means UTF8 encoded byte array
+    // 2, means char array
+    // 3, means latin-1 (ISO-8859-1) encoded byte array
+    // 4, means ""
+    @Override
+    public String readUTF() throws IOException {
+        return readEncodedString(readByte());
+    }
+
+    public String readEncodedString(byte encoding) throws IOException {
+        if (encoding == STRING_ENCODING_NULL) {
+            return null;
+        }
+        if (encoding == STRING_ENCODING_EMPTY_STRING) {
+            return "";
+        }
+        int size = readInt();
+        if (encoding == STRING_ENCODING_CHAR_ARRAY) {
+            char[] c = new char[size];
+            for (int i = 0; i < size; i++) {
+                c[i] = readChar();
+            }
+            return new String(c);
+        }
+        byte[] bytes = new byte[size];
+        readFully(bytes); // TODO: optimize, check size, and copy only if needed
+        if (encoding == STRING_ENCODING_UTF8_BYTE_ARRAY) {
+            return new String(bytes, UTF8);
+        }
+
+        if (encoding == STRING_ENCODING_LATIN1_BYTE_ARRAY) {
+            return new String(bytes, LATIN1);
+        }
+        throw new IOException("Unknown string encoding " + encoding);
+    }
+
+    @Override
+    public char readChar() throws IOException {
+        return (char) readLong();
+    }
+
+    @Override
+    public short readShort() throws IOException {
+        return (short) readLong();
+    }
+
+    @Override
+    public int readInt() throws IOException {
+        return (int) readLong();
+    }
+
+    @Override
+    public long readLong() throws IOException {
+        // can be optimized by branching checks, but will do for now
+        byte b0 = readByte();
+        long ret = (b0 & 0x7FL);
+        if (b0 >= 0) {
+            return ret;
+        }
+        int b1 = readByte();
+        ret += (b1 & 0x7FL) << 7;
+        if (b1 >= 0) {
+            return ret;
+        }
+        int b2 = readByte();
+        ret += (b2 & 0x7FL) << 14;
+        if (b2 >= 0) {
+            return ret;
+        }
+        int b3 = readByte();
+        ret += (b3 & 0x7FL) << 21;
+        if (b3 >= 0) {
+            return ret;
+        }
+        int b4 = readByte();
+        ret += (b4 & 0x7FL) << 28;
+        if (b4 >= 0) {
+            return ret;
+        }
+        int b5 = readByte();
+        ret += (b5 & 0x7FL) << 35;
+        if (b5 >= 0) {
+            return ret;
+        }
+        int b6 = readByte();
+        ret += (b6 & 0x7FL) << 42;
+        if (b6 >= 0) {
+            return ret;
+        }
+        int b7 = readByte();
+        ret += (b7 & 0x7FL) << 49;
+        if (b7 >= 0) {
+            return ret;
+        }
+        int b8 = readByte(); // read last byte raw
+        return ret + (((long) (b8 & 0XFF)) << 56);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/AbstractDCmd.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.internal.dcmd;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.file.InvalidPathException;
+import java.nio.file.Path;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Recording;
+import jdk.jfr.internal.SecuritySupport;
+import jdk.jfr.internal.SecuritySupport.SafePath;
+import jdk.jfr.internal.Utils;
+
+/**
+ * Base class for JFR diagnostic commands
+ *
+ */
+abstract class AbstractDCmd {
+
+    private final StringWriter result;
+    private final PrintWriter log;
+
+    protected AbstractDCmd() {
+        result = new StringWriter();
+        log = new PrintWriter(result);
+    }
+
+    protected final FlightRecorder getFlightRecorder() {
+        return FlightRecorder.getFlightRecorder();
+    }
+
+    public final String getResult() {
+        return result.toString();
+    }
+
+    protected final SafePath resolvePath(String path, String errorMsg) throws DCmdException {
+        if (path == null) {
+            return null;
+        }
+        try {
+            return new SafePath(path);
+        } catch (InvalidPathException e) {
+            throw new DCmdException(e, errorMsg, ", invalid path \"" + path + "\".");
+        }
+    }
+
+    protected final Recording findRecording(String name) throws DCmdException {
+        try {
+            return findRecordingById(Integer.parseInt(name));
+        } catch (NumberFormatException nfe) {
+            // User specified a name, not an id.
+            return findRecordingByName(name);
+        }
+    }
+
+    protected final void reportOperationComplete(String actionPrefix, Recording r, SafePath file) {
+        print(actionPrefix);
+        print(" recording ");
+        print("\"" + r.getName() + "\"");
+        if (file != null) {
+            print(",");
+            try {
+                print(" ");
+                long bytes = SecuritySupport.getFileSize(file);
+                printBytes(bytes, " ");
+            } catch (IOException e) {
+                // Ignore, not essential
+            }
+            println(" written to:");
+            println();
+            printPath(file);
+        } else {
+            println(".");
+        }
+    }
+
+    protected final List<Recording> getRecordings() {
+        List<Recording> list = new ArrayList<>(getFlightRecorder().getRecordings());
+        Collections.sort(list, (a, b) -> a.getName().compareTo(b.getName()));
+        return list;
+    }
+
+    static String quoteIfNeeded(String text) {
+        if (text.contains(" ")) {
+            return "\\\"" + text + "\\\"";
+        } else {
+            return text;
+        }
+    }
+
+    protected final void println() {
+        log.println();
+    }
+
+    protected final void print(String s) {
+        log.print(s);
+    }
+
+    protected final void print(String s, Object... args) {
+        log.printf(s, args);
+    }
+
+    protected final void println(String s, Object... args) {
+        print(s, args);
+        println();
+    }
+
+    protected final void printBytes(long bytes, String separation) {
+       print(Utils.formatBytes(bytes, separation));
+    }
+
+    protected final void printTimespan(Duration timespan, String separator) {
+        print(Utils.formatTimespan(timespan, separator));
+    }
+
+    protected final void printPath(SafePath path) {
+        if (path == null) {
+            print("N/A");
+            return;
+        }
+        try {
+            printPath(SecuritySupport.getAbsolutePath(path).toPath());
+        } catch (IOException ioe) {
+            printPath(path.toPath());
+        }
+    }
+
+    protected final void printPath(Path path) {
+        try {
+            println(path.toAbsolutePath().toString());
+        } catch (SecurityException e) {
+            // fall back on filename
+            println(path.toString());
+        }
+    }
+
+    private Recording findRecordingById(int id) throws DCmdException {
+        for (Recording r : getFlightRecorder().getRecordings()) {
+            if (r.getId() == id) {
+                return r;
+            }
+        }
+        throw new DCmdException("Could not find %d.\n\nUse JFR.check without options to see list of all available recordings.", id);
+    }
+
+    private Recording findRecordingByName(String name) throws DCmdException {
+        for (Recording recording : getFlightRecorder().getRecordings()) {
+            if (name.equals(recording.getName())) {
+                return recording;
+            }
+        }
+        throw new DCmdException("Could not find %s.\n\nUse JFR.check without options to see list of all available recordings.", name);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdCheck.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.internal.dcmd;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.StringJoiner;
+
+import jdk.jfr.EventType;
+import jdk.jfr.Recording;
+import jdk.jfr.SettingDescriptor;
+
+/**
+ * JFR.check - invoked from native
+ *
+ */
+final class DCmdCheck extends AbstractDCmd {
+    /**
+     * Execute JFR.check
+     *
+     * @param recordingText name or id of the recording to check, or
+     *        <code>null</code> to show a list of all recordings.
+     *
+     * @param verbose if event settings should be included.
+     *
+     * @return result output
+     *
+     * @throws DCmdException if the check could not be completed.
+     */
+    public String execute(String recordingText, Boolean verbose) throws DCmdException {
+        executeInternal(recordingText, verbose);
+        return getResult();
+    }
+
+    private void executeInternal(String recordingText, Boolean verbose) throws DCmdException {
+        if (verbose == null) {
+            verbose = Boolean.FALSE;
+        }
+
+        if (recordingText != null) {
+            printRecording(findRecording(recordingText), verbose);
+            return;
+        }
+
+        List<Recording> recordings = getRecordings();
+        if (!verbose && recordings.isEmpty()) {
+            println("No available recordings.");
+            println();
+            println("Use JFR.start to start a recording.");
+            return;
+        }
+        boolean first = true;
+        for (Recording recording : recordings) {
+            // Print separation between recordings,
+            if (!first) {
+                println();
+                if (Boolean.TRUE.equals(verbose)) {
+                    println();
+                }
+            }
+            first = false;
+            printRecording(recording, verbose);
+        }
+    }
+
+    private void printRecording(Recording recording, boolean verbose) {
+        printGeneral(recording);
+        if (verbose) {
+            println();
+            printSetttings(recording);
+        }
+    }
+
+    private void printGeneral(Recording recording) {
+        String format = "Recording: recording=%d name=\"%s\"";
+        print(format, recording.getId(), recording.getName());
+
+        Duration duration = recording.getDuration();
+        if (duration != null) {
+            print(" duration=");
+            printTimespan(duration, "");
+        }
+
+        long maxSize = recording.getMaxSize();
+        if (maxSize != 0) {
+            print(" maxsize=");
+            printBytes(maxSize, "");
+        }
+        Duration maxAge = recording.getMaxAge();
+        if (maxAge != null) {
+            print(" maxage=");
+            printTimespan(maxAge, "");
+        }
+
+        print(" (" + recording.getState().toString().toLowerCase() + ")");
+        println();
+    }
+
+    private void printSetttings(Recording recording) {
+        Map<String, String> settings = recording.getSettings();
+        for (EventType eventType : sortByEventPath(getFlightRecorder().getEventTypes())) {
+            StringJoiner sj = new StringJoiner(",", "[", "]");
+            sj.setEmptyValue("");
+            for (SettingDescriptor s : eventType.getSettingDescriptors()) {
+                String settingsPath = eventType.getName() + "#" + s.getName();
+                if (settings.containsKey(settingsPath)) {
+                    sj.add(s.getName() + "=" + settings.get(settingsPath));
+                }
+            }
+            String settingsText = sj.toString();
+            if (!settingsText.isEmpty()) {
+                print(" %s (%s)", eventType.getLabel(), eventType.getName());
+                println();
+                println("   " + settingsText);
+            }
+        }
+    }
+
+    private static List<EventType> sortByEventPath(Collection<EventType> events) {
+        List<EventType> sorted = new ArrayList<>();
+        sorted.addAll(events);
+        Collections.sort(sorted, new Comparator<EventType>() {
+            @Override
+            public int compare(EventType e1, EventType e2) {
+                return e1.getName().compareTo(e2.getName());
+            }
+        });
+        return sorted;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdConfigure.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.dcmd;
+
+
+
+import jdk.jfr.internal.LogLevel;
+import jdk.jfr.internal.LogTag;
+import jdk.jfr.internal.Logger;
+import jdk.jfr.internal.Options;
+import jdk.jfr.internal.Repository;
+import jdk.jfr.internal.SecuritySupport.SafePath;
+
+/**
+ * JFR.configure - invoked from native
+ *
+ */
+//Instantiated by native
+final class DCmdConfigure extends AbstractDCmd {
+    /**
+     * Execute JFR.configure.
+     *
+     * @param repositoryPath the path
+     * @param dumpPath path to dump to on fatal error (oom)
+     * @param stackDepth depth of stack traces
+     * @param globalBufferCount number of global buffers
+     * @param globalBufferSize size of global buffers
+     * @param threadBufferSize size of thread buffer for events
+     * @param maxChunkSize threshold at which a new chunk is created in the disk repository
+     * @param sampleThreads if thread sampling should be enabled
+     *
+     * @return result
+
+     * @throws DCmdException
+     *             if the dump could not be completed
+     */
+    public String execute
+    (
+            String repositoryPath,
+            String dumpPath,
+            Integer stackDepth,
+            Long globalBufferCount,
+            Long globalBufferSize,
+            Long threadBufferSize,
+            Long memorySize,
+            Long maxChunkSize,
+            Boolean sampleThreads
+
+    ) throws DCmdException {
+        boolean updated = false;
+        if (repositoryPath != null) {
+            try {
+                SafePath s = new SafePath(repositoryPath);
+                Repository.getRepository().setBasePath(s);
+                Logger.log(LogTag.JFR, LogLevel.INFO, "Base repository path set to " + repositoryPath);
+            } catch (Exception e) {
+                throw new DCmdException("Could not use " + repositoryPath + " as repository. " + e.getMessage(), e);
+            }
+            printRepositoryPath();
+            updated = true;
+        }
+
+        if (dumpPath != null)  {
+            Options.setDumpPath(new SafePath(dumpPath));
+            Logger.log(LogTag.JFR, LogLevel.INFO, "Emergency dump path set to " + dumpPath);
+            printDumpPath();
+            updated = true;
+        }
+
+        if (stackDepth != null)  {
+            Options.setStackDepth(stackDepth);
+            Logger.log(LogTag.JFR, LogLevel.INFO, "Stack depth set to " + stackDepth);
+            printStackDepth();
+            updated = true;
+        }
+
+        if (globalBufferCount != null)  {
+            Options.setGlobalBufferCount(globalBufferCount);
+            Logger.log(LogTag.JFR, LogLevel.INFO, "Global buffer count set to " + globalBufferCount);
+            printGlobalBufferCount();
+            updated = true;
+        }
+
+        if (globalBufferSize != null)  {
+            Options.setGlobalBufferSize(globalBufferSize);
+            Logger.log(LogTag.JFR, LogLevel.INFO, "Global buffer size set to " + globalBufferSize);
+            printGlobalBufferSize();
+            updated = true;
+        }
+
+        if (threadBufferSize != null)  {
+            Options.setThreadBufferSize(threadBufferSize);
+            Logger.log(LogTag.JFR, LogLevel.INFO, "Thread buffer size set to " + threadBufferSize);
+            printThreadBufferSize();
+            updated = true;
+        }
+
+        if (memorySize != null) {
+            Options.setMemorySize(memorySize);
+            Logger.log(LogTag.JFR, LogLevel.INFO, "Memory size set to " + memorySize);
+            printMemorySize();
+            updated = true;
+        }
+
+        if (maxChunkSize != null)  {
+            Options.setMaxChunkSize(maxChunkSize);
+            Logger.log(LogTag.JFR, LogLevel.INFO, "Max chunk size set to " + maxChunkSize);
+            printMaxChunkSize();
+            updated = true;
+        }
+
+        if (sampleThreads != null)  {
+            Options.setSampleThreads(sampleThreads);
+            Logger.log(LogTag.JFR, LogLevel.INFO, "Sample threads set to " + sampleThreads);
+            printSampleThreads();
+            updated = true;
+        }
+
+        if (!updated) {
+            println("Current configuration:");
+            println();
+            printRepositoryPath();
+            printStackDepth();
+            printGlobalBufferCount();
+            printGlobalBufferSize();
+            printThreadBufferSize();
+            printMemorySize();
+            printMaxChunkSize();
+            printSampleThreads();
+        }
+        return getResult();
+    }
+
+    private void printRepositoryPath() {
+        print("Repository path: ");
+        printPath(Repository.getRepository().getRepositoryPath());
+        println();
+    }
+
+    private void printDumpPath() {
+        print("Dump path: ");
+        printPath(Options.getDumpPath());
+        println();
+    }
+
+    private void printSampleThreads() {
+        println("Sample threads: " + Options.getSampleThreads());
+    }
+
+    private void printStackDepth() {
+        println("Stack depth: " +  Options.getStackDepth());
+    }
+
+    private void printGlobalBufferCount() {
+        println("Global buffer count: " +  Options.getGlobalBufferCount());
+    }
+
+    private void printGlobalBufferSize() {
+        print("Global buffer size: ");
+        printBytes(Options.getGlobalBufferSize(), " ");
+        println();
+    }
+
+    private void printThreadBufferSize() {
+        print("Thread buffer size: ");
+        printBytes(Options.getThreadBufferSize(), " ");
+        println();
+    }
+
+    private void printMemorySize() {
+        print("Memory size: ");
+        printBytes(Options.getMemorySize(), " ");
+        println();
+    }
+
+    private void printMaxChunkSize() {
+        print("Max chunk size: ");
+        printBytes(Options.getMaxChunkSize(), " ");
+        println();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdDump.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.internal.dcmd;
+
+import java.io.IOException;
+import java.nio.file.InvalidPathException;
+import java.util.HashMap;
+import java.util.Map;
+
+import jdk.jfr.Recording;
+import jdk.jfr.internal.PlatformRecording;
+import jdk.jfr.internal.PrivateAccess;
+import jdk.jfr.internal.SecuritySupport.SafePath;
+import jdk.jfr.internal.Utils;
+import jdk.jfr.internal.WriteableUserPath;
+
+/**
+ * JFR.dump
+ *
+ */
+//Instantiated by native
+final class DCmdDump extends AbstractDCmd {
+    /**
+     * Execute JFR.dump.
+     *
+     * @param recordingText name or id of the recording to dump, or
+     *        <code>null</code>
+     *
+     * @param textPath file path where recording should be written.
+     *
+     * @return result output
+     *
+     * @throws DCmdException if the dump could not be completed
+     */
+    public String execute(String recordingText, String textPath,  Boolean pathToGcRoots) throws DCmdException {
+        if (textPath == null) {
+            throw new DCmdException("Failed to dump %s, missing filename.", recordingText);
+        }
+        Recording recording = findRecording(recordingText);
+        try {
+            SafePath dumpFile = resolvePath(textPath, "Failed to dump %s");
+            // create file for JVM
+            Utils.touch(dumpFile.toPath());
+            PlatformRecording r = PrivateAccess.getInstance().getPlatformRecording(recording);
+            WriteableUserPath wup = new WriteableUserPath(dumpFile.toPath());
+
+            Map<String, String> overlay = new HashMap<>();
+            Utils.updateSettingPathToGcRoots(overlay, pathToGcRoots);
+
+            r.copyTo(wup, "Dumped by user", overlay);
+            reportOperationComplete("Dumped", recording, dumpFile);
+        } catch (IOException | InvalidPathException e) {
+            throw new DCmdException("Failed to dump %s. Could not copy recording for dump. %s", recordingText, e.getMessage());
+        }
+        return getResult();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdException.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.internal.dcmd;
+
+import java.util.Formatter;
+
+/**
+ * Thrown to indicate that a diagnostic command could not be executed
+ * successfully.
+ */
+final class DCmdException extends Exception {
+    private static final long serialVersionUID = -3792411099340016465L;
+
+    /**
+     * Constructs a new exception with message derived from a format string.
+     *
+     * @param format format string as described in {@link Formatter} class.
+     *
+     * @param args arguments referenced by the format specifiers in the format
+     *        string.
+     *
+     */
+    public DCmdException(String format, Object... args) {
+        super(format(format, args));
+    }
+
+    /**
+     * Constructs a new exception with message derived from a format string.
+     *
+     * @param cause exception that stopped the diagnostic command to complete.
+     *
+     * @param format format string as described in {@link Formatter} class.
+     *
+     * @param args arguments referenced by the format specifiers in the format
+     *        string.
+     *
+     */
+    public DCmdException(Throwable cause, String format, Object... args) {
+        super(format(format, args), cause);
+    }
+
+    private static String format(String message, Object... args) {
+        try (Formatter formatter = new Formatter()) {
+            return formatter.format(message, args).toString();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.internal.dcmd;
+
+import java.io.IOException;
+import java.nio.file.InvalidPathException;
+import java.nio.file.Paths;
+import java.text.ParseException;
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.Map;
+
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Recording;
+import jdk.jfr.internal.JVM;
+import jdk.jfr.internal.SecuritySupport.SafePath;
+import jdk.jfr.internal.Type;
+import jdk.jfr.internal.Utils;
+import jdk.jfr.internal.jfc.JFC;
+
+/**
+ * JFR.start
+ *
+ */
+//Instantiated by native
+final class DCmdStart extends AbstractDCmd {
+
+    /**
+     * Execute JFR.start.
+     *
+     * @param name optional name that can be used to identify recording.
+     * @param configurations names of settings files to use, i.e. "default" or
+     *        "default.jfc".
+     * @param delay delay before recording is started, in nanoseconds. Must be
+     *        at least 1 second.
+     * @param duration duration of the recording, in nanoseconds. Must be at
+     *        least 1 second.
+     * @param disk if recording should be persisted to disk
+     * @param path file path where recording data should be written
+     * @param maxAge how long recording data should be kept in the disk
+     *        repository, or <code>0</code> if no limit should be set.
+     *
+     * @param maxSize the minimum amount data to keep in the disk repository
+     *        before it is discarded, or <code>0</code> if no limit should be
+     *        set.
+     *
+     * @param dumpOnExit if recording should dump on exit
+     *
+     * @return result output
+     *
+     * @throws DCmdException if recording could not be started
+     */
+    @SuppressWarnings("resource")
+    public String execute(String name, String[] configurations, Long delay, Long duration, Boolean disk, String path, Long maxAge, Long maxSize, Boolean dumpOnExit, Boolean pathToGcRoots) throws DCmdException {
+        if (name != null) {
+            try {
+                Integer.parseInt(name);
+                throw new DCmdException("Name of recording can't be numeric");
+            } catch (NumberFormatException nfe) {
+                // ok, can't be mixed up with name
+            }
+        }
+
+        if (duration == null && Boolean.FALSE.equals(dumpOnExit) && path != null) {
+            throw new DCmdException("Filename can only be set for a time bound recording or if dumponexit=true. Set duration/dumponexit or omit filename.");
+        }
+        if (dumpOnExit == null && path != null) {
+            dumpOnExit = Boolean.TRUE;
+        }
+
+        Map<String, String> s = new HashMap<>();
+
+        if (configurations == null || configurations.length == 0) {
+            configurations = new String[] { "default" };
+        }
+
+        for (String configName : configurations) {
+            try {
+                s.putAll(JFC.createKnown(configName).getSettings());
+            } catch (IOException | ParseException e) {
+                throw new DCmdException("Could not parse setting " + configurations[0], e);
+            }
+        }
+
+        Utils.updateSettingPathToGcRoots(s, pathToGcRoots);
+
+        if (duration != null) {
+            if (duration < 1000L * 1000L * 1000L) {
+                // to avoid typo, duration below 1s makes no sense
+                throw new DCmdException("Could not start recording, duration must be at least 1 second.");
+            }
+        }
+
+        if (delay != null) {
+            if (delay < 1000L * 1000L * 1000) {
+                // to avoid typo, delay shorter than 1s makes no sense.
+                throw new DCmdException("Could not start recording, delay must be at least 1 second.");
+            }
+        }
+
+        if (!FlightRecorder.isInitialized() && delay == null) {
+            initializeWithForcedInstrumentation(s);
+        }
+
+        Recording recording = new Recording();
+        if (name == null) {
+            recording.setName("Recording-" + recording.getId());
+        } else {
+            recording.setName(name);
+        }
+
+        if (disk != null) {
+            recording.setToDisk(disk.booleanValue());
+        }
+        recording.setSettings(s);
+
+        if (path != null) {
+            try {
+                recording.setDestination(Paths.get(path));
+            } catch (IOException | InvalidPathException e) {
+                recording.close();
+                throw new DCmdException("Could not start recording, not able to write to file %s. %s ", path, e.getMessage());
+            }
+        }
+
+        if (maxAge != null) {
+            recording.setMaxAge(Duration.ofNanos(maxAge));
+        }
+
+        if (maxSize != null) {
+            recording.setMaxSize(maxSize);
+        }
+
+        if (duration != null) {
+            recording.setDuration(Duration.ofNanos(duration));
+        }
+
+        if (dumpOnExit != null) {
+            recording.setDumpOnExit(dumpOnExit);
+        }
+
+        if (delay != null) {
+            Duration dDelay = Duration.ofNanos(delay);
+            recording.scheduleStart(dDelay);
+            print("Recording " + recording.getId() + " scheduled to start in ");
+            printTimespan(dDelay, " ");
+            print(".");
+        } else {
+            recording.start();
+            print("Started recording " + recording.getId() + ".");
+        }
+
+        if (recording.isToDisk() && duration == null && maxAge == null && maxSize == null) {
+            print(" No limit specified, using maxsize=250MB as default.");
+            recording.setMaxSize(250*1024L*1024L);
+        }
+
+        if (path != null && duration != null) {
+            println(" The result will be written to:");
+            println();
+            printPath(new SafePath(path));
+        } else {
+            println();
+            println();
+            String cmd = duration == null ? "dump" : "stop";
+            String fileOption = path == null ? "filename=FILEPATH " : "";
+            String recordingspecifier = "name=" + recording.getId();
+            // if user supplied a name, use it.
+            if (name != null) {
+                recordingspecifier = "name=" + quoteIfNeeded(name);
+            }
+            print("Use JFR." + cmd + " " + recordingspecifier + " " + fileOption + "to copy recording data to file.");
+            println();
+        }
+        return getResult();
+    }
+
+    // Instruments JDK-events on class load to reduce startup time
+    private void initializeWithForcedInstrumentation(Map<String, String> settings) {
+        if (!hasJDKEvents(settings)) {
+            return;
+        }
+        JVM jvm = JVM.getJVM();
+        try {
+            jvm.setForceInstrumentation(true);
+            FlightRecorder.getFlightRecorder();
+        } finally {
+            jvm.setForceInstrumentation(false);
+        }
+    }
+
+    private boolean hasJDKEvents(Map<String, String> settings) {
+        String[] eventNames = new String[7];
+        eventNames[0] = "FileRead";
+        eventNames[1] = "FileWrite";
+        eventNames[2] = "SocketRead";
+        eventNames[3] = "SocketWrite";
+        eventNames[4] = "JavaErrorThrow";
+        eventNames[5] = "JavaExceptionThrow";
+        eventNames[6] = "FileForce";
+        for (String eventName : eventNames) {
+            if ("true".equals(settings.get(Type.EVENT_NAME_PREFIX + eventName + "#enabled"))) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStop.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.internal.dcmd;
+
+import java.io.IOException;
+import java.nio.file.InvalidPathException;
+import java.nio.file.Paths;
+
+import jdk.jfr.Recording;
+import jdk.jfr.internal.SecuritySupport.SafePath;
+
+/**
+ * JFR.stop
+ *
+ */
+//Instantiated by native
+final class DCmdStop extends AbstractDCmd {
+
+    /**
+     * Execute JFR.stop
+     *
+     * Requires that either <code>name or <code>id</code> is set.
+     *
+     * @param recordingText name or id of the recording to stop.
+     *
+     * @param textPath file path where data should be written after recording
+     *        has been stopped, or <code>null</code> if recording shouldn't be
+     *        written to disk.
+     * @return result text
+     *
+     * @throws DCmdException if recording could not be stopped
+     */
+    public String execute(String recordingText, String textPath) throws DCmdException {
+        try {
+            SafePath path = resolvePath(textPath, "Failed to stop %s");
+            Recording recording = findRecording(recordingText);
+            if (textPath != null) {
+                try {
+                    recording.setDestination(Paths.get(textPath));
+                } catch (IOException e) {
+                    throw new DCmdException("Failed to stop %s. Could not set destination for \"%s\" to file %s", recording.getName(), textPath, e.getMessage());
+                }
+            }
+            recording.stop();
+            reportOperationComplete("Stopped", recording, path);
+            recording.close();
+            return getResult();
+        } catch (InvalidPathException | DCmdException e) {
+            if (textPath != null) {
+                throw new DCmdException("Could not write recording \"%s\" to file. %s", recordingText, e.getMessage());
+            }
+            throw new DCmdException(e, "Could not stop recording \"%s\".", recordingText, e.getMessage());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/handlers/EventHandler.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.handlers;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import jdk.jfr.EventType;
+import jdk.jfr.internal.EventControl;
+import jdk.jfr.internal.JVM;
+import jdk.jfr.internal.PlatformEventType;
+import jdk.jfr.internal.PrivateAccess;
+import jdk.jfr.internal.StringPool;
+
+// Users should not be subclass for security reasons.
+public abstract class EventHandler {
+    // Accessed by generated sub class
+    protected final PlatformEventType platformEventType;
+
+    private final EventType eventType;
+    private final EventControl eventControl;
+
+    // Accessed by generated sub class
+    EventHandler(boolean registered, EventType eventType, EventControl eventControl) {
+        this.eventType = eventType;
+        this.platformEventType = PrivateAccess.getInstance().getPlatformEventType(eventType);
+        this.eventControl = eventControl;
+        platformEventType.setRegistered(registered);
+    }
+
+    final protected StringPool createStringFieldWriter() {
+        return new StringPool();
+    }
+
+    // Accessed by generated code in event class
+    public final boolean shouldCommit(long duration) {
+        return isEnabled() && duration >= platformEventType.getThresholdTicks();
+    }
+
+    // Accessed by generated code in event class
+    // Accessed by generated sub class
+    public final boolean isEnabled() {
+        return platformEventType.isCommitable();
+    }
+
+    public final EventType getEventType() {
+        return eventType;
+    }
+
+    public final PlatformEventType getPlatformEventType() {
+        return platformEventType;
+    }
+
+    public final EventControl getEventControl() {
+        return eventControl;
+    }
+
+    public static long timestamp() {
+        return JVM.counterTime();
+    }
+
+    public static long duration(long startTime) {
+        if (startTime == 0) {
+            // User forgot to invoke begin, or instrumentation was
+            // added after the user invoked begin.
+            // Returning 0 will make it an instant event
+            return 0;
+        }
+        return timestamp() - startTime;
+    }
+
+    // Prevent a malicious user from instantiating a generated event handlers.
+    @Override
+    public final Object clone() throws java.lang.CloneNotSupportedException {
+        throw new CloneNotSupportedException();
+    }
+
+    private final void writeObject(ObjectOutputStream out) throws IOException {
+        throw new IOException("Object cannot be serialized");
+    }
+
+    private final void readObject(ObjectInputStream in) throws IOException {
+        throw new IOException("Class cannot be deserialized");
+    }
+
+    public boolean isRegistered() {
+        return platformEventType.isRegistered();
+    }
+
+    public boolean setRegistered(boolean registered) {
+       return platformEventType.setRegistered(registered);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/ConstructorTracerWriter.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.instrument;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassVisitor;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.internal.org.objectweb.asm.Type;
+
+final class ConstructorTracerWriter extends ClassVisitor {
+
+    private ConstructorWriter useInputParameter, noUseInputParameter;
+
+    static byte[] generateBytes(Class<?> clz, byte[] oldBytes) throws IOException {
+        InputStream in = new ByteArrayInputStream(oldBytes);
+        ClassReader cr = new ClassReader(in);
+        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
+        ConstructorTracerWriter ctw = new ConstructorTracerWriter(cw, clz);
+        cr.accept(ctw, 0);
+        return cw.toByteArray();
+    }
+
+    private ConstructorTracerWriter(ClassVisitor cv, Class<?> classToChange) {
+        super(Opcodes.ASM5, cv);
+        useInputParameter = new ConstructorWriter(classToChange, true);
+        noUseInputParameter = new ConstructorWriter(classToChange, false);
+    }
+
+    private boolean isConstructor(String name) {
+        return name.equals("<init>");
+    }
+
+    private boolean takesStringParameter(String desc) {
+        Type[] types = Type.getArgumentTypes(desc);
+        if (types.length > 0 && types[0].getClassName().equals(String.class.getName())) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+
+        MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
+
+        // Get a hold of the constructors that takes a String as a parameter
+        if (isConstructor(name)) {
+            if (takesStringParameter(desc)) {
+                useInputParameter.setMethodVisitor(mv);
+                return useInputParameter;
+            }
+            noUseInputParameter.setMethodVisitor(mv);
+            return noUseInputParameter;
+        }
+        return mv;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/ConstructorWriter.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.instrument;
+
+import static jdk.internal.org.objectweb.asm.Opcodes.ACONST_NULL;
+import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD;
+import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC;
+import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+
+final class ConstructorWriter extends MethodVisitor {
+
+    private boolean useInputParameter;
+    private String shortClassName;
+    private String fullClassName;
+
+    ConstructorWriter(Class<?> classToChange, boolean useInputParameter) {
+        super(Opcodes.ASM5);
+        this.useInputParameter = useInputParameter;
+        shortClassName = classToChange.getSimpleName();
+        fullClassName = classToChange.getName().replace('.', '/');
+    }
+
+    @Override
+    public void visitInsn(int opcode)
+    {
+        if (opcode == RETURN) {
+            if (useInputParameter) {
+                useInput();
+            } else {
+                noInput();
+            }
+        }
+        mv.visitInsn(opcode);
+    }
+    @SuppressWarnings("deprecation")
+    private void useInput()
+    {
+        //Load 'this' from local variable 0
+        //Load first input parameter
+        //Invoke ThrowableTracer.traceCLASS(this, parameter) for current class
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitVarInsn(ALOAD, 1);
+        mv.visitMethodInsn(INVOKESTATIC, "jdk/jfr/internal/instrument/ThrowableTracer",
+                "trace" + shortClassName, "(L" + fullClassName +
+                ";Ljava/lang/String;)V");
+    }
+
+    @SuppressWarnings("deprecation")
+    private void noInput()
+    {
+        //Load 'this' from local variable 0
+        //Load ""
+        //Invoke ThrowableTracer.traceCLASS(this, "") for current class
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitInsn(ACONST_NULL);
+        mv.visitMethodInsn(INVOKESTATIC, "jdk/jfr/internal/instrument/ThrowableTracer",
+                "trace" + shortClassName, "(L" + fullClassName +
+                ";Ljava/lang/String;)V");
+    }
+
+    public void setMethodVisitor(MethodVisitor mv) {
+        this.mv = mv;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/FileChannelImplInstrumentor.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.instrument;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import jdk.jfr.events.FileForceEvent;
+import jdk.jfr.events.FileReadEvent;
+import jdk.jfr.events.FileWriteEvent;
+
+/**
+ * See {@link JITracer} for an explanation of this code.
+ */
+@JIInstrumentationTarget("sun.nio.ch.FileChannelImpl")
+final class FileChannelImplInstrumentor {
+
+    private FileChannelImplInstrumentor() {
+    }
+
+    private String path;
+
+    @SuppressWarnings("deprecation")
+    @JIInstrumentationMethod
+    public void force(boolean metaData) throws IOException {
+        FileForceEvent event = FileForceEvent.EVENT.get();
+        if (!event.isEnabled()) {
+            force(metaData);
+            return;
+        }
+        try {
+            event.begin();
+            force(metaData);
+        } finally {
+            event.path = path;
+            event.metaData = metaData;
+            event.commit();
+            event.reset();
+        }
+    }
+
+    @SuppressWarnings("deprecation")
+    @JIInstrumentationMethod
+    public int read(ByteBuffer dst) throws IOException {
+        FileReadEvent event = FileReadEvent.EVENT.get();
+        if (!event.isEnabled()) {
+            return read(dst);
+        }
+        int bytesRead = 0;
+        try {
+            event.begin();
+            bytesRead = read(dst);
+        } finally {
+            if (bytesRead < 0) {
+                event.endOfFile = true;
+            } else {
+                event.bytesRead = bytesRead;
+            }
+            event.path = path;
+            event.commit();
+            event.reset();
+        }
+        return bytesRead;
+    }
+
+    @SuppressWarnings("deprecation")
+    @JIInstrumentationMethod
+    public int read(ByteBuffer dst, long position) throws IOException {
+        FileReadEvent event = FileReadEvent.EVENT.get();
+        if (!event.isEnabled()) {
+            return read(dst, position);
+        }
+        int bytesRead = 0;
+        try {
+            event.begin();
+            bytesRead = read(dst, position);
+        } finally {
+            if (bytesRead < 0) {
+                event.endOfFile = true;
+            } else {
+                event.bytesRead = bytesRead;
+            }
+            event.path = path;
+            event.commit();
+            event.reset();
+        }
+        return bytesRead;
+    }
+
+    @SuppressWarnings("deprecation")
+    @JIInstrumentationMethod
+    public long read(ByteBuffer[] dsts, int offset, int length) throws IOException {
+        FileReadEvent event = FileReadEvent.EVENT.get();
+        if (!event.isEnabled()) {
+            return read(dsts, offset, length);
+        }
+        long bytesRead = 0;
+        try {
+            event.begin();
+            bytesRead = read(dsts, offset, length);
+        } finally {
+            if (bytesRead < 0) {
+                event.endOfFile = true;
+            } else {
+                event.bytesRead = bytesRead;
+            }
+            event.path = path;
+            event.commit();
+            event.reset();
+        }
+        return bytesRead;
+    }
+
+    @SuppressWarnings("deprecation")
+    @JIInstrumentationMethod
+    public int write(ByteBuffer src) throws IOException {
+        FileWriteEvent event = FileWriteEvent.EVENT.get();
+        if (!event.isEnabled()) {
+            return write(src);
+        }
+        int bytesWritten = 0;
+        try {
+            event.begin();
+            bytesWritten = write(src);
+        } finally {
+            event.bytesWritten = bytesWritten > 0 ? bytesWritten : 0;
+            event.path = path;
+            event.commit();
+            event.reset();
+        }
+        return bytesWritten;
+    }
+
+    @SuppressWarnings("deprecation")
+    @JIInstrumentationMethod
+    public int write(ByteBuffer src, long position) throws IOException {
+        FileWriteEvent event = FileWriteEvent.EVENT.get();
+        if (!event.isEnabled()) {
+            return write(src, position);
+        }
+
+        int bytesWritten = 0;
+        try {
+            event.begin();
+            bytesWritten = write(src, position);
+        } finally {
+            event.bytesWritten = bytesWritten > 0 ? bytesWritten : 0;
+            event.path = path;
+            event.commit();
+            event.reset();
+        }
+        return bytesWritten;
+    }
+
+    @SuppressWarnings("deprecation")
+    @JIInstrumentationMethod
+    public long write(ByteBuffer[] srcs, int offset, int length) throws IOException {
+        FileWriteEvent event = FileWriteEvent.EVENT.get();
+        if (!event.isEnabled()) {
+            return write(srcs, offset, length);
+        }
+        long bytesWritten = 0;
+        try {
+            event.begin();
+            bytesWritten = write(srcs, offset, length);
+        } finally {
+            event.bytesWritten = bytesWritten > 0 ? bytesWritten : 0;
+            event.path = path;
+            event.commit();
+            event.reset();
+        }
+        return bytesWritten;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/FileInputStreamInstrumentor.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.instrument;
+
+import java.io.IOException;
+
+import jdk.jfr.events.FileReadEvent;
+
+/**
+ * See {@link JITracer} for an explanation of this code.
+ */
+@JIInstrumentationTarget("java.io.FileInputStream")
+final class FileInputStreamInstrumentor {
+
+    private FileInputStreamInstrumentor() {
+    }
+
+    private String path;
+
+    @SuppressWarnings("deprecation")
+    @JIInstrumentationMethod
+    public int read() throws IOException {
+        FileReadEvent event = FileReadEvent.EVENT.get();
+        if (!event.isEnabled()) {
+            return read();
+        }
+        int result = 0;
+        try {
+            event.begin();
+            result = read();
+            if (result < 0) {
+                event.endOfFile = true;
+            } else {
+                event.bytesRead = 1;
+            }
+        } finally {
+            event.path = path;
+            event.commit();
+            event.reset();
+        }
+        return result;
+    }
+
+    @SuppressWarnings("deprecation")
+    @JIInstrumentationMethod
+    public int read(byte b[]) throws IOException {
+        FileReadEvent event = FileReadEvent.EVENT.get();
+        if (!event.isEnabled()) {
+            return read(b);
+        }
+        int bytesRead = 0;
+        try {
+            event.begin();
+            bytesRead = read(b);
+        } finally {
+            if (bytesRead < 0) {
+                event.endOfFile = true;
+            } else {
+                event.bytesRead = bytesRead;
+            }
+            event.path = path;
+            event.commit();
+            event.reset();
+        }
+        return bytesRead;
+    }
+
+    @SuppressWarnings("deprecation")
+    @JIInstrumentationMethod
+    public int read(byte b[], int off, int len) throws IOException {
+        FileReadEvent event = FileReadEvent.EVENT.get();
+        if (!event.isEnabled()) {
+            return read(b, off, len);
+        }
+        int bytesRead = 0;
+        try {
+            event.begin();
+            bytesRead = read(b, off, len);
+        } finally {
+            if (bytesRead < 0) {
+                event.endOfFile = true;
+            } else {
+                event.bytesRead = bytesRead;
+            }
+            event.path = path;
+            event.commit();
+            event.reset();
+        }
+        return bytesRead;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/FileOutputStreamInstrumentor.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.instrument;
+
+import java.io.IOException;
+
+import jdk.jfr.events.FileWriteEvent;
+
+/**
+ * See {@link JITracer} for an explanation of this code.
+ */
+@JIInstrumentationTarget("java.io.FileOutputStream")
+final class FileOutputStreamInstrumentor {
+
+    private FileOutputStreamInstrumentor() {
+    }
+
+    private String path;
+
+    @SuppressWarnings("deprecation")
+    @JIInstrumentationMethod
+    public void write(int b) throws IOException {
+        FileWriteEvent event = FileWriteEvent.EVENT.get();
+        if (!event.isEnabled()) {
+            write(b);
+            return;
+        }
+        try {
+            event.begin();
+            write(b);
+            event.bytesWritten = 1;
+        } finally {
+            event.path = path;
+            event.commit();
+            event.reset();
+        }
+    }
+
+    @SuppressWarnings("deprecation")
+    @JIInstrumentationMethod
+    public void write(byte b[]) throws IOException {
+        FileWriteEvent event = FileWriteEvent.EVENT.get();
+        if (!event.isEnabled()) {
+            write(b);
+            return;
+        }
+        try {
+            event.begin();
+            write(b);
+            event.bytesWritten = b.length;
+        } finally {
+            event.path = path;
+            event.commit();
+            event.reset();
+        }
+    }
+
+    @SuppressWarnings("deprecation")
+    @JIInstrumentationMethod
+    public void write(byte b[], int off, int len) throws IOException {
+        FileWriteEvent event = FileWriteEvent.EVENT.get();
+        if (!event.isEnabled()) {
+            write(b, off, len);
+            return;
+        }
+        try {
+            event.begin();
+            write(b, off, len);
+            event.bytesWritten = len;
+        } finally {
+            event.path = path;
+            event.commit();
+            event.reset();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/JDKEvents.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.instrument;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.internal.module.Modules;
+import jdk.jfr.Event;
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.events.ActiveRecordingEvent;
+import jdk.jfr.events.ActiveSettingEvent;
+import jdk.jfr.events.ErrorThrownEvent;
+import jdk.jfr.events.ExceptionStatisticsEvent;
+import jdk.jfr.events.ExceptionThrownEvent;
+import jdk.jfr.events.FileForceEvent;
+import jdk.jfr.events.FileReadEvent;
+import jdk.jfr.events.FileWriteEvent;
+import jdk.jfr.events.SocketReadEvent;
+import jdk.jfr.events.SocketWriteEvent;
+import jdk.jfr.internal.JVM;
+import jdk.jfr.internal.LogLevel;
+import jdk.jfr.internal.LogTag;
+import jdk.jfr.internal.Logger;
+import jdk.jfr.internal.RequestEngine;
+import jdk.jfr.internal.SecuritySupport;
+import jdk.jfr.internal.Utils;
+
+public final class JDKEvents {
+
+    private static final Class<?>[] eventClasses = {
+        FileForceEvent.class,
+        FileReadEvent.class,
+        FileWriteEvent.class,
+        SocketReadEvent.class,
+        SocketWriteEvent.class,
+        ExceptionThrownEvent.class,
+        ExceptionStatisticsEvent.class,
+        ErrorThrownEvent.class,
+        ActiveSettingEvent.class,
+        ActiveRecordingEvent.class
+    };
+
+    // This is a list of the classes with instrumentation code that should be applied.
+    private static final Class<?>[] instrumentationClasses = new Class<?>[] {
+        FileInputStreamInstrumentor.class,
+        FileOutputStreamInstrumentor.class,
+        RandomAccessFileInstrumentor.class,
+        FileChannelImplInstrumentor.class,
+        SocketInputStreamInstrumentor.class,
+        SocketOutputStreamInstrumentor.class,
+        SocketChannelImplInstrumentor.class
+    };
+
+    private static final Class<?>[] targetClasses = new Class<?>[instrumentationClasses.length];
+    private static final JVM jvm = JVM.getJVM();
+    private static final Runnable emitExceptionStatistics = JDKEvents::emitExceptionStatistics;
+    private static boolean initializationTriggered;
+
+    @SuppressWarnings("unchecked")
+    public synchronized static void initialize() {
+        try {
+            if (initializationTriggered == false) {
+                Module jdkJfrModule = Event.class.getModule();
+                Module javaBaseModule = Object.class.getModule();
+                Modules.addReads(javaBaseModule, jdkJfrModule);
+                Modules.addExports(jdkJfrModule, Utils.EVENTS_PACKAGE_NAME, javaBaseModule);
+                Modules.addExports(jdkJfrModule, Utils.INSTRUMENT_PACKAGE_NAME, javaBaseModule);
+                Modules.addExports(jdkJfrModule, Utils.HANDLERS_PACKAGE_NAME, javaBaseModule);
+                for (Class<?> eventClass : eventClasses) {
+                    SecuritySupport.registerEvent((Class<? extends Event>) eventClass);
+                }
+                initializationTriggered = true;
+                FlightRecorder.addPeriodicEvent(ExceptionStatisticsEvent.class, emitExceptionStatistics);
+            }
+        } catch (Exception e) {
+            Logger.log(LogTag.JFR_SYSTEM, LogLevel.WARN, "Could not initialize JDK events. " + e.getMessage());
+        }
+    }
+
+    public static void addInstrumentation() {
+        try {
+            List<Class<?>> list = new ArrayList<>();
+            for (int i = 0; i < instrumentationClasses.length; i++) {
+                JIInstrumentationTarget tgt = instrumentationClasses[i].getAnnotation(JIInstrumentationTarget.class);
+                Class<?> clazz = Class.forName(tgt.value());
+                targetClasses[i] = clazz;
+                list.add(clazz);
+            }
+            list.add(java.lang.Throwable.class);
+            list.add(java.lang.Error.class);
+            Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "Retransformed JDK classes");
+            jvm.retransformClasses(list.toArray(new Class<?>[list.size()]));
+        } catch (Exception e) {
+            Logger.log(LogTag.JFR_SYSTEM, LogLevel.WARN, "Could not add instrumentation for JDK events. " + e.getMessage());
+        }
+    }
+
+    private static void emitExceptionStatistics() {
+        ExceptionStatisticsEvent t = new ExceptionStatisticsEvent();
+        t.throwables = ThrowableTracer.numThrowables();
+        t.commit();
+    }
+
+    @SuppressWarnings("deprecation")
+    public static byte[] retransformCallback(Class<?> klass, byte[] oldBytes) throws Throwable {
+        if (java.lang.Throwable.class == klass) {
+            Logger.log(LogTag.JFR_SYSTEM, LogLevel.TRACE, "Instrumenting java.lang.Throwable");
+            return ConstructorTracerWriter.generateBytes(java.lang.Throwable.class, oldBytes);
+        }
+
+        if (java.lang.Error.class == klass) {
+            Logger.log(LogTag.JFR_SYSTEM, LogLevel.TRACE, "Instrumenting java.lang.Error");
+            return ConstructorTracerWriter.generateBytes(java.lang.Error.class, oldBytes);
+        }
+
+        for (int i = 0; i < targetClasses.length; i++) {
+            if (targetClasses[i].equals(klass)) {
+                Class<?> c = instrumentationClasses[i];
+                Logger.log(LogTag.JFR_SYSTEM, LogLevel.TRACE, () -> "Processing instrumentation class: " + c);
+                return new JIClassInstrumentation(instrumentationClasses[i], klass, oldBytes).getNewBytes();
+            }
+        }
+        return oldBytes;
+    }
+
+    public static void remove() {
+        RequestEngine.removeHook(JDKEvents::emitExceptionStatistics);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/JIClassInstrumentation.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.instrument;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassVisitor;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.internal.org.objectweb.asm.tree.ClassNode;
+import jdk.jfr.internal.SecuritySupport;
+import jdk.jfr.internal.Utils;
+
+/**
+ * This class will perform byte code instrumentation given an "instrumentor" class.
+ *
+ * @see JITracer
+ *
+ * @author Staffan Larsen
+ */
+@Deprecated
+final class JIClassInstrumentation {
+    private final Class<?> instrumentor;
+    private final String targetName;
+    private final String instrumentorName;
+    private final byte[] newBytes;
+    private final ClassReader targetClassReader;
+    private final ClassReader instrClassReader;
+
+    /**
+     * Creates an instance and performs the instrumentation.
+     *
+     * @param instrumentor instrumentor class
+     * @param target target class
+     * @param old_target_bytes bytes in target
+     *
+     * @throws ClassNotFoundException
+     * @throws IOException
+     */
+    JIClassInstrumentation(Class<?> instrumentor, Class<?> target, byte[] old_target_bytes) throws ClassNotFoundException, IOException {
+        instrumentorName = instrumentor.getName();
+        this.targetName = target.getName();
+        this.instrumentor = instrumentor;
+        this.targetClassReader = new ClassReader(old_target_bytes);
+        this.instrClassReader = new ClassReader(getOriginalClassBytes(instrumentor));
+        this.newBytes = makeBytecode();
+        Utils.writeGeneratedASM(target.getName(), newBytes);
+    }
+
+    private static byte[] getOriginalClassBytes(Class<?> clazz) throws IOException {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        String name = "/" + clazz.getName().replace(".", "/") + ".class";
+        InputStream is = SecuritySupport.getResourceAsStream(name);
+        int bytesRead;
+        byte[] buffer = new byte[16384];
+        while ((bytesRead = is.read(buffer, 0, buffer.length)) != -1) {
+            baos.write(buffer, 0, bytesRead);
+        }
+        baos.flush();
+        is.close();
+        return baos.toByteArray();
+    }
+
+    private byte[] makeBytecode() throws IOException, ClassNotFoundException {
+
+        // Find the methods to instrument and inline
+
+        final List<Method> instrumentationMethods = new ArrayList<>();
+        for (final Method m : instrumentor.getDeclaredMethods()) {
+            JIInstrumentationMethod im = m.getAnnotation(JIInstrumentationMethod.class);
+            if (im != null) {
+                instrumentationMethods.add(m);
+            }
+        }
+
+        // We begin by inlining the target's methods into the instrumentor
+
+        ClassNode temporary = new ClassNode();
+        ClassVisitor inliner = new JIInliner(
+                Opcodes.ASM5,
+                temporary,
+                targetName,
+                instrumentorName,
+                targetClassReader,
+                instrumentationMethods);
+        instrClassReader.accept(inliner, ClassReader.EXPAND_FRAMES);
+
+        // Now we have the target's methods inlined into the instrumentation code (in 'temporary').
+        // We now need to replace the target's method with the code in the
+        // instrumentation method.
+
+        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
+        JIMethodMergeAdapter ma = new JIMethodMergeAdapter(
+                cw,
+                temporary,
+                instrumentationMethods,
+                instrumentor.getAnnotationsByType(JITypeMapping.class));
+        targetClassReader.accept(ma, ClassReader.EXPAND_FRAMES);
+
+       return cw.toByteArray();
+    }
+
+    /**
+     * Get the instrumented byte codes that can be used to retransform the class.
+     *
+     * @return bytes
+     */
+    public byte[] getNewBytes() {
+        return newBytes.clone();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/JIInliner.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.instrument;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.List;
+
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassVisitor;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.internal.org.objectweb.asm.Type;
+import jdk.internal.org.objectweb.asm.tree.ClassNode;
+import jdk.internal.org.objectweb.asm.tree.MethodNode;
+import jdk.jfr.internal.LogLevel;
+import jdk.jfr.internal.LogTag;
+import jdk.jfr.internal.Logger;
+
+@Deprecated
+final class JIInliner extends ClassVisitor {
+    private final String targetClassName;
+    private final String instrumentationClassName;
+    private final ClassNode targetClassNode;
+    private final List<Method> instrumentationMethods;
+
+    /**
+     * A ClassVisitor which will check all methods of the class it visits against the instrumentationMethods
+     * list. If a method is on that list, the method will be further processed for inlining into that
+     * method.
+     */
+    JIInliner(int api, ClassVisitor cv, String targetClassName, String instrumentationClassName,
+            ClassReader targetClassReader,
+            List<Method> instrumentationMethods) {
+        super(api, cv);
+        this.targetClassName = targetClassName;
+        this.instrumentationClassName = instrumentationClassName;
+        this.instrumentationMethods = instrumentationMethods;
+
+        ClassNode cn = new ClassNode(Opcodes.ASM5);
+        targetClassReader.accept(cn, ClassReader.EXPAND_FRAMES);
+        this.targetClassNode = cn;
+    }
+
+    @Override
+    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+        MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
+
+        if (isInstrumentationMethod(name, desc)) {
+            MethodNode methodToInline = findTargetMethodNode(name, desc);
+            if (methodToInline == null) {
+                throw new IllegalArgumentException("Could not find the method to instrument in the target class");
+            }
+            if (Modifier.isNative(methodToInline.access)) {
+                throw new IllegalArgumentException("Cannot instrument native methods: " + targetClassNode.name + "." + methodToInline.name + methodToInline.desc);
+            }
+
+            Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.DEBUG, "Inliner processing method " + name + desc);
+
+            JIMethodCallInliner mci = new JIMethodCallInliner(access,
+                    desc,
+                    mv,
+                    methodToInline,
+                    targetClassName,
+                    instrumentationClassName);
+            return mci;
+        }
+
+        return mv;
+    }
+
+    private boolean isInstrumentationMethod(String name, String desc) {
+        for(Method m : instrumentationMethods) {
+            if (m.getName().equals(name) && Type.getMethodDescriptor(m).equals(desc)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private MethodNode findTargetMethodNode(String name, String desc) {
+        for (MethodNode mn : targetClassNode.methods) {
+            if (mn.desc.equals(desc) && mn.name.equals(name)) {
+                return mn;
+            }
+        }
+        throw new IllegalArgumentException("could not find MethodNode for "
+                + name + desc);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/JIInstrumentationMethod.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.instrument;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@interface JIInstrumentationMethod {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/JIInstrumentationTarget.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.instrument;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@interface JIInstrumentationTarget {
+    String value();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/JIMethodCallInliner.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.instrument;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.internal.org.objectweb.asm.Label;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.internal.org.objectweb.asm.commons.LocalVariablesSorter;
+import jdk.internal.org.objectweb.asm.commons.Remapper;
+import jdk.internal.org.objectweb.asm.commons.SimpleRemapper;
+import jdk.internal.org.objectweb.asm.tree.MethodNode;
+import jdk.jfr.internal.LogLevel;
+import jdk.jfr.internal.LogTag;
+import jdk.jfr.internal.Logger;
+
+/**
+ * Class responsible for finding the call to inline and inlining it.
+ *
+ * This code is heavily influenced by section 3.2.6 "Inline Method" in
+ * "Using ASM framework to implement common bytecode transformation patterns",
+ * E. Kuleshov, AOSD.07, March 2007, Vancouver, Canada.
+ * http://asm.ow2.org/index.html
+ */
+@Deprecated
+final class JIMethodCallInliner extends LocalVariablesSorter {
+
+    private final String oldClass;
+    private final String newClass;
+    private final MethodNode inlineTarget;
+    private final List<CatchBlock> blocks = new ArrayList<>();
+    private boolean inlining;
+
+    /**
+     * inlineTarget defines the method to inline and also contains the actual
+     * code to inline.
+     *
+     * @param access
+     * @param desc
+     * @param mv
+     * @param inlineTarget
+     * @param oldClass
+     * @param newClass
+     * @param logger
+     */
+    public JIMethodCallInliner(int access, String desc, MethodVisitor mv,
+            MethodNode inlineTarget, String oldClass, String newClass) {
+        super(Opcodes.ASM5, access, desc, mv);
+        this.oldClass = oldClass;
+        this.newClass = newClass;
+        this.inlineTarget = inlineTarget;
+
+        Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.DEBUG, "MethodCallInliner: targetMethod=" + newClass + "."
+                + inlineTarget.name + inlineTarget.desc);
+    }
+
+    @Override
+    public void visitMethodInsn(int opcode, String owner, String name,
+            String desc, boolean itf) {
+        // Now we are looking at method call in the source method
+        if (!shouldBeInlined(owner, name, desc)) {
+            // If this method call should not be inlined, just keep it
+            mv.visitMethodInsn(opcode, owner, name, desc, itf);
+            return;
+        }
+        // If the call should be inlined, we create a MethodInliningAdapter
+        // The MIA will walk the instructions in the inlineTarget and add them
+        // to the current method, doing the necessary name remappings.
+        Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.DEBUG, "Inlining call to " + name + desc);
+        Remapper remapper = new SimpleRemapper(oldClass, newClass);
+        Label end = new Label();
+        inlining = true;
+        inlineTarget.instructions.resetLabels();
+        JIMethodInliningAdapter mia = new JIMethodInliningAdapter(this, end,
+                opcode == Opcodes.INVOKESTATIC ? Opcodes.ACC_STATIC : 0, desc,
+                remapper);
+        inlineTarget.accept(mia);
+        inlining = false;
+        super.visitLabel(end);
+    }
+
+    /**
+     * Determine if the method should be inlined or not.
+     */
+    private boolean shouldBeInlined(String owner, String name, String desc) {
+        return inlineTarget.desc.equals(desc) && inlineTarget.name.equals(name)
+                && owner.equals(newClass.replace('.', '/'));
+    }
+
+    @Override
+    public void visitTryCatchBlock(Label start, Label end, Label handler,
+            String type) {
+        if (!inlining) {
+            // try-catch blocks are saved here and replayed at the end
+            // of the method (in visitMaxs)
+            blocks.add(new CatchBlock(start, end, handler, type));
+        } else {
+            super.visitTryCatchBlock(start, end, handler, type);
+        }
+    }
+
+    @Override
+    public void visitMaxs(int stack, int locals) {
+        for (CatchBlock b : blocks) {
+            super.visitTryCatchBlock(b.start, b.end, b.handler, b.type);
+        }
+        super.visitMaxs(stack, locals);
+    }
+
+    static final class CatchBlock {
+
+        final Label start;
+        final Label end;
+        final Label handler;
+        final String type;
+
+        CatchBlock(Label start, Label end, Label handler, String type) {
+            this.start = start;
+            this.end = end;
+            this.handler = handler;
+            this.type = type;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/JIMethodInliningAdapter.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.instrument;
+
+import jdk.internal.org.objectweb.asm.Label;
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.internal.org.objectweb.asm.Type;
+import jdk.internal.org.objectweb.asm.commons.LocalVariablesSorter;
+import jdk.internal.org.objectweb.asm.commons.Remapper;
+import jdk.internal.org.objectweb.asm.commons.RemappingMethodAdapter;
+
+@Deprecated
+final class JIMethodInliningAdapter extends RemappingMethodAdapter {
+    private final LocalVariablesSorter lvs;
+    private final Label end;
+
+    public JIMethodInliningAdapter(LocalVariablesSorter mv, Label end, int acc, String desc, Remapper remapper) {
+        super(acc, desc, mv, remapper);
+        this.lvs = mv;
+        this.end = end;
+        int offset = isStatic(acc) ? 0 : 1;
+        Type[] args = Type.getArgumentTypes(desc);
+        for (int i = args.length - 1; i >= 0; i--) {
+            super.visitVarInsn(args[i].getOpcode(Opcodes.ISTORE), i + offset);
+        }
+        if (offset > 0) {
+            super.visitVarInsn(Opcodes.ASTORE, 0);
+        }
+    }
+
+    private boolean isStatic(int acc) {
+        return (acc & Opcodes.ACC_STATIC) != 0;
+    }
+
+    @Override
+    public void visitInsn(int opcode) {
+        if (opcode == Opcodes.RETURN || opcode == Opcodes.IRETURN
+                || opcode == Opcodes.ARETURN || opcode == Opcodes.LRETURN) {
+            super.visitJumpInsn(Opcodes.GOTO, end);
+        } else {
+            super.visitInsn(opcode);
+        }
+    }
+
+    @Override
+    public void visitMaxs(int stack, int locals) {
+    }
+
+    @Override
+    protected int newLocalMapping(Type type) {
+        return lvs.newLocal(type);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/JIMethodMergeAdapter.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.instrument;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jdk.internal.org.objectweb.asm.ClassVisitor;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.internal.org.objectweb.asm.Type;
+import jdk.internal.org.objectweb.asm.commons.RemappingMethodAdapter;
+import jdk.internal.org.objectweb.asm.commons.SimpleRemapper;
+import jdk.internal.org.objectweb.asm.tree.ClassNode;
+import jdk.internal.org.objectweb.asm.tree.MethodNode;
+import jdk.jfr.internal.LogLevel;
+import jdk.jfr.internal.LogTag;
+import jdk.jfr.internal.Logger;
+
+/**
+ * This class will merge (some) methods from one class into another one.
+ *
+ * @author Staffan Larsen
+ */
+@Deprecated
+final class JIMethodMergeAdapter extends ClassVisitor {
+
+    private final ClassNode cn;
+    private final List<Method> methodFilter;
+    private final Map<String, String> typeMap;
+
+    /**
+     * Methods in methodFilter that exist in cn will be merged into cv. If the method already exists,
+     * the original method will be deleted.
+     *
+     * @param cv
+     * @param cn - a ClassNode with Methods that will be merged into this class
+     * @param methodFilter - only methods in this list will be merged
+     * @param typeMappings - while merging, type references in the methods will be changed according to this map
+     */
+    public JIMethodMergeAdapter(ClassVisitor cv, ClassNode cn, List<Method> methodFilter, JITypeMapping[] typeMappings) {
+        super(Opcodes.ASM5, cv);
+        this.cn = cn;
+        this.methodFilter = methodFilter;
+
+        this.typeMap = new HashMap<>();
+        for (JITypeMapping tm : typeMappings) {
+            typeMap.put(tm.from().replace('.', '/'), tm.to().replace('.', '/'));
+        }
+    }
+
+    @Override
+    public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+        super.visit(version, access, name, signature, superName, interfaces);
+        typeMap.put(cn.name, name);
+    }
+
+    @Override
+    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+        if(methodInFilter(name, desc)) {
+            // If the method is one that we will be replacing, delete the method
+            Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.DEBUG, "Deleting " + name + desc);
+            return null;
+        }
+        return super.visitMethod(access, name, desc, signature, exceptions);
+    }
+
+    @Override
+    public void visitEnd() {
+        SimpleRemapper remapper = new SimpleRemapper(typeMap);
+        for (MethodNode mn : cn.methods) {
+            // Check if the method is in the list of methods to copy
+            if (methodInFilter(mn.name, mn.desc)) {
+                Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.DEBUG, "Copying method: " + mn.name + mn.desc);
+                Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.DEBUG,  "   with mapper: " + typeMap);
+
+                String[] exceptions = new String[mn.exceptions.size()];
+                mn.exceptions.toArray(exceptions);
+                MethodVisitor mv = cv.visitMethod(mn.access, mn.name, mn.desc, mn.signature, exceptions);
+                mn.instructions.resetLabels();
+                mn.accept(new RemappingMethodAdapter(mn.access, mn.desc, mv, remapper));
+            }
+        }
+        super.visitEnd();
+    }
+
+    private boolean methodInFilter(String name, String desc) {
+        for(Method m : methodFilter) {
+            if (m.getName().equals(name) && Type.getMethodDescriptor(m).equals(desc)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/JITypeMapping.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.instrument;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+@interface JITypeMapping {
+    String from();
+    String to();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/RandomAccessFileInstrumentor.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.instrument;
+
+import java.io.IOException;
+
+import jdk.jfr.events.FileReadEvent;
+import jdk.jfr.events.FileWriteEvent;
+
+/**
+ * See {@link JITracer} for an explanation of this code.
+ */
+@JIInstrumentationTarget("java.io.RandomAccessFile")
+final class RandomAccessFileInstrumentor {
+
+    private RandomAccessFileInstrumentor() {
+    }
+
+    private String path;
+
+    @SuppressWarnings("deprecation")
+    @JIInstrumentationMethod
+    public int read() throws IOException {
+        FileReadEvent event = FileReadEvent.EVENT.get();
+        if (!event.isEnabled()) {
+            return read();
+        }
+        int result = 0;
+        try {
+            event.begin();
+            result = read();
+            if (result < 0) {
+                event.endOfFile = true;
+            } else {
+                event.bytesRead = 1;
+            }
+        } finally {
+            event.path = path;
+            event.commit();
+            event.reset();
+        }
+        return result;
+    }
+
+    @SuppressWarnings("deprecation")
+    @JIInstrumentationMethod
+    public int read(byte b[]) throws IOException {
+        FileReadEvent event = FileReadEvent.EVENT.get();
+        if (!event.isEnabled()) {
+            return read(b);
+        }
+        int bytesRead = 0;
+        try {
+            event.begin();
+            bytesRead = read(b);
+        } finally {
+            if (bytesRead < 0) {
+                event.endOfFile = true;
+            } else {
+                event.bytesRead = bytesRead;
+            }
+            event.path = path;
+            event.commit();
+            event.reset();
+        }
+        return bytesRead;
+    }
+
+    @SuppressWarnings("deprecation")
+    @JIInstrumentationMethod
+    public int read(byte b[], int off, int len) throws IOException {
+        FileReadEvent event = FileReadEvent.EVENT.get();
+        if (!event.isEnabled()) {
+            return read(b, off, len);
+        }
+        int bytesRead = 0;
+        try {
+            event.begin();
+            bytesRead = read(b, off, len);
+        } finally {
+            if (bytesRead < 0) {
+                event.endOfFile = true;
+            } else {
+                event.bytesRead = bytesRead;
+            }
+            event.path = path;
+            event.commit();
+            event.reset();
+        }
+        return bytesRead;
+    }
+
+    @SuppressWarnings("deprecation")
+    @JIInstrumentationMethod
+    public void write(int b) throws IOException {
+        FileWriteEvent event = FileWriteEvent.EVENT.get();
+        if (!event.isEnabled()) {
+            write(b);
+            return;
+        }
+        try {
+            event.begin();
+            write(b);
+            event.bytesWritten = 1;
+        } finally {
+            event.path = path;
+            event.commit();
+            event.reset();
+        }
+    }
+
+    @SuppressWarnings("deprecation")
+    @JIInstrumentationMethod
+    public void write(byte b[]) throws IOException {
+        FileWriteEvent event = FileWriteEvent.EVENT.get();
+        if (!event.isEnabled()) {
+            write(b);
+            return;
+        }
+        try {
+            event.begin();
+            write(b);
+            event.bytesWritten = b.length;
+        } finally {
+            event.path = path;
+            event.commit();
+            event.reset();
+        }
+    }
+
+    @SuppressWarnings("deprecation")
+    @JIInstrumentationMethod
+    public void write(byte b[], int off, int len) throws IOException {
+        FileWriteEvent event = FileWriteEvent.EVENT.get();
+        if (!event.isEnabled()) {
+            write(b, off, len);
+            return;
+        }
+        try {
+            event.begin();
+            write(b, off, len);
+            event.bytesWritten = len;
+        } finally {
+            event.path = path;
+            event.commit();
+            event.reset();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/SocketChannelImplInstrumentor.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.instrument;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+
+import jdk.jfr.events.SocketReadEvent;
+import jdk.jfr.events.SocketWriteEvent;
+
+/**
+ * See {@link JITracer} for an explanation of this code.
+ */
+@JIInstrumentationTarget("sun.nio.ch.SocketChannelImpl")
+final class SocketChannelImplInstrumentor {
+
+    private SocketChannelImplInstrumentor() {
+    }
+
+    private InetSocketAddress remoteAddress;
+
+    @SuppressWarnings("deprecation")
+    @JIInstrumentationMethod
+    public int read(ByteBuffer dst) throws IOException {
+        SocketReadEvent event = SocketReadEvent.EVENT.get();
+        if (!event.isEnabled()) {
+            return read(dst);
+        }
+        int bytesRead = 0;
+        try {
+            event.begin();
+            bytesRead = read(dst);
+        } finally {
+            event.end();
+            if (event.shouldCommit())  {
+                String hostString  = remoteAddress.getAddress().toString();
+                int delimiterIndex = hostString.lastIndexOf('/');
+
+                event.host      = hostString.substring(0, delimiterIndex);
+                event.address   = hostString.substring(delimiterIndex + 1);
+                event.port      = remoteAddress.getPort();
+                if (bytesRead < 0) {
+                    event.endOfStream = true;
+                } else {
+                    event.bytesRead = bytesRead;
+                }
+                event.timeout   = 0;
+
+                event.commit();
+                event.reset();
+            }
+        }
+        return bytesRead;
+    }
+
+    @SuppressWarnings("deprecation")
+    @JIInstrumentationMethod
+    public long read(ByteBuffer[] dsts, int offset, int length) throws IOException {
+        SocketReadEvent event = SocketReadEvent.EVENT.get();
+        if(!event.isEnabled()) {
+            return read(dsts, offset, length);
+        }
+
+        long bytesRead = 0;
+        try {
+            event.begin();
+            bytesRead = read(dsts, offset, length);
+        } finally {
+            event.end();
+            if (event.shouldCommit()) {
+                String hostString  = remoteAddress.getAddress().toString();
+                int delimiterIndex = hostString.lastIndexOf('/');
+
+                event.host      = hostString.substring(0, delimiterIndex);
+                event.address   = hostString.substring(delimiterIndex + 1);
+                event.port      = remoteAddress.getPort();
+                if (bytesRead < 0) {
+                    event.endOfStream = true;
+                } else {
+                    event.bytesRead = bytesRead;
+                }
+                event.timeout   = 0;
+
+                event.commit();
+                event.reset();
+            }
+        }
+        return bytesRead;
+    }
+
+    @SuppressWarnings("deprecation")
+    @JIInstrumentationMethod
+    public int write(ByteBuffer buf) throws IOException {
+        SocketWriteEvent event = SocketWriteEvent.EVENT.get();
+        if (!event.isEnabled()) {
+            return write(buf);
+        }
+
+        int bytesWritten = 0;
+        try {
+            event.begin();
+            bytesWritten = write(buf);
+        } finally {
+            event.end();
+            if (event.shouldCommit()) {
+                String hostString  = remoteAddress.getAddress().toString();
+                int delimiterIndex = hostString.lastIndexOf('/');
+
+                event.host         = hostString.substring(0, delimiterIndex);
+                event.address      = hostString.substring(delimiterIndex + 1);
+                event.port         = remoteAddress.getPort();
+                event.bytesWritten = bytesWritten < 0 ? 0 : bytesWritten;
+
+                event.commit();
+                event.reset();
+            }
+        }
+        return bytesWritten;
+    }
+
+    @SuppressWarnings("deprecation")
+    @JIInstrumentationMethod
+    public long write(ByteBuffer[] srcs, int offset, int length) throws IOException {
+        SocketWriteEvent event = SocketWriteEvent.EVENT.get();
+        if (!event.isEnabled()) {
+            return write(srcs, offset, length);
+        }
+        long bytesWritten = 0;
+        try {
+            event.begin();
+            bytesWritten = write(srcs, offset, length);
+        } finally {
+            event.end();
+            if (event.shouldCommit()) {
+                String hostString  = remoteAddress.getAddress().toString();
+                int delimiterIndex = hostString.lastIndexOf('/');
+
+                event.host         = hostString.substring(0, delimiterIndex);
+                event.address      = hostString.substring(delimiterIndex + 1);
+                event.port         = remoteAddress.getPort();
+                event.bytesWritten = bytesWritten < 0 ? 0 : bytesWritten;
+
+                event.commit();
+                event.reset();
+            }
+        }
+        return bytesWritten;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/SocketInputStreamInstrumentor.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.instrument;
+
+import java.io.IOException;
+import java.net.InetAddress;
+
+import jdk.jfr.events.SocketReadEvent;
+
+/**
+ * See {@link JITracer} for an explanation of this code.
+ */
+@JIInstrumentationTarget("java.net.SocketInputStream")
+@JITypeMapping(from = "jdk.jfr.internal.instrument.SocketInputStreamInstrumentor$AbstractPlainSocketImpl",
+            to = "java.net.AbstractPlainSocketImpl")
+final class SocketInputStreamInstrumentor {
+
+    private SocketInputStreamInstrumentor() {
+    }
+
+    @SuppressWarnings("deprecation")
+    @JIInstrumentationMethod
+    int read(byte b[], int off, int length, int timeout) throws IOException {
+        SocketReadEvent event = SocketReadEvent.EVENT.get();
+        if (!event.isEnabled()) {
+            return read(b, off, length, timeout);
+        }
+        int bytesRead = 0;
+        try {
+            event.begin();
+            bytesRead = read(b, off, length, timeout);
+        } finally {
+            event.end();
+            if (event.shouldCommit()) {
+                String hostString  = impl.address.toString();
+                int delimiterIndex = hostString.lastIndexOf('/');
+
+                event.host      = hostString.substring(0, delimiterIndex);
+                event.address   = hostString.substring(delimiterIndex + 1);
+                event.port      = impl.port;
+                if (bytesRead < 0) {
+                    event.endOfStream = true;
+                } else {
+                    event.bytesRead = bytesRead;
+                }
+                event.timeout   = timeout;
+
+                event.commit();
+                event.reset();
+            }
+        }
+        return bytesRead;
+    }
+
+    private AbstractPlainSocketImpl impl = null;
+
+    void silenceFindBugsUnwrittenField(InetAddress dummy) {
+        impl.address = dummy;
+    }
+
+    static class AbstractPlainSocketImpl {
+        InetAddress address;
+        int port;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/SocketOutputStreamInstrumentor.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.instrument;
+
+import java.io.IOException;
+import java.net.InetAddress;
+
+import jdk.jfr.events.SocketWriteEvent;
+
+/**
+ * See {@link JITracer} for an explanation of this code.
+ */
+@JIInstrumentationTarget("java.net.SocketOutputStream")
+@JITypeMapping(from = "jdk.jfr.internal.instrument.SocketOutputStreamInstrumentor$AbstractPlainSocketImpl",
+            to = "java.net.AbstractPlainSocketImpl")
+final class SocketOutputStreamInstrumentor {
+
+    private SocketOutputStreamInstrumentor() {
+    }
+
+    @SuppressWarnings("deprecation")
+    @JIInstrumentationMethod
+    private void socketWrite(byte b[], int off, int len) throws IOException {
+        SocketWriteEvent event = SocketWriteEvent.EVENT.get();
+        if (!event.isEnabled()) {
+            socketWrite(b, off, len);
+            return;
+        }
+        int bytesWritten = 0;
+        try {
+            event.begin();
+            socketWrite(b, off, len);
+            bytesWritten = len;
+        } finally {
+            event.end() ;
+            if (event.shouldCommit()) {
+                String hostString  = impl.address.toString();
+                int delimiterIndex = hostString.lastIndexOf('/');
+
+                event.host         = hostString.substring(0, delimiterIndex);
+                event.address      = hostString.substring(delimiterIndex + 1);
+                event.port         = impl.port;
+                event.bytesWritten = bytesWritten < 0 ? 0 : bytesWritten;
+
+                event.commit();
+                event.reset();
+            }
+        }
+    }
+
+    private AbstractPlainSocketImpl impl = null;
+
+    void silenceFindBugsUnwrittenField(InetAddress dummy) {
+        impl.address = dummy;
+    }
+
+    static class AbstractPlainSocketImpl {
+        InetAddress address;
+        int port;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/ThrowableTracer.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.instrument;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+import jdk.jfr.events.ErrorThrownEvent;
+import jdk.jfr.events.ExceptionThrownEvent;
+
+public final class ThrowableTracer {
+
+    private static AtomicLong numThrowables = new AtomicLong(0);
+
+    public static void traceError(Error e, String message) {
+        if (e instanceof OutOfMemoryError) {
+            return;
+        }
+        ErrorThrownEvent errorEvent = new ErrorThrownEvent();
+        errorEvent.message = message;
+        errorEvent.thrownClass = e.getClass();
+        errorEvent.commit();
+
+        ExceptionThrownEvent exceptionEvent = new ExceptionThrownEvent();
+        exceptionEvent.message = message;
+        exceptionEvent.thrownClass = e.getClass();
+        exceptionEvent.commit();
+        numThrowables.incrementAndGet();
+    }
+
+    public static void traceThrowable(Throwable t, String message) {
+        ExceptionThrownEvent event = new ExceptionThrownEvent();
+        event.message = message;
+        event.thrownClass = t.getClass();
+        event.commit();
+        numThrowables.incrementAndGet();
+    }
+
+    public static long numThrowables() {
+        return numThrowables.get();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/JFC.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.jfc;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import jdk.jfr.Configuration;
+import jdk.jfr.internal.LogLevel;
+import jdk.jfr.internal.LogTag;
+import jdk.jfr.internal.Logger;
+import jdk.jfr.internal.SecuritySupport;
+import jdk.jfr.internal.SecuritySupport.SafePath;
+
+/**
+ * {@link Configuration} factory for JFC files. *
+ */
+public final class JFC {
+    private static final int BUFFER_SIZE = 8192;
+    private static final int MAXIMUM_FILE_SIZE = 1024 * 1024;
+    private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
+    private static volatile List<KnownConfiguration> knownConfigurations;
+
+    /**
+     * Reads a known configuration file (located into a string, but doesn't
+     * parse it until it's being used.
+     */
+    private static final class KnownConfiguration {
+        private final String content;
+        private final String filename;
+        private final String name;
+        private Configuration configuration;
+
+        public KnownConfiguration(SafePath knownPath) throws IOException {
+            this.content = readContent(knownPath);
+            this.name = nameFromPath(knownPath.toPath());
+            this.filename = nullSafeFileName(knownPath.toPath());
+        }
+
+        public boolean isNamed(String name) {
+            return filename.equals(name) || this.name.equals(name);
+        }
+
+        public Configuration getConfigurationFile() throws IOException, ParseException {
+            if (configuration == null) {
+                configuration = JFCParser.createConfiguration(name, content);
+            }
+            return configuration;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        private static String readContent(SafePath knownPath) throws IOException {
+            if (SecuritySupport.getFileSize(knownPath) > MAXIMUM_FILE_SIZE) {
+                throw new IOException("Configuration with more than "
+                        + MAXIMUM_FILE_SIZE + " characters can't be read.");
+            }
+            try (InputStream r = SecuritySupport.newFileInputStream(knownPath)) {
+                return JFC.readContent(r);
+            }
+        }
+    }
+
+    private JFC() {
+        // private utility class
+    }
+
+    /**
+     * Reads a configuration from a file.
+     *
+     * @param path the file containing the configuration, not {@code null}
+     * @return {@link Configuration}, not {@code null}
+     * @throws ParseException if the file can't be parsed
+     * @throws IOException if the file can't be read
+     *
+     * @throws SecurityException if a security manager exists and its
+     *         <code>checkRead</code> method denies read access to the file.
+     * @see java.io.File#getPath()
+     * @see java.lang.SecurityManager#checkRead(java.lang.String)
+     */
+    public static Configuration create(String name, Reader reader) throws IOException, ParseException {
+        return JFCParser.createConfiguration(name, reader);
+    }
+
+    private static String nullSafeFileName(Path file) throws IOException {
+        Path filename = file.getFileName();
+        if (filename == null) {
+            throw new IOException("Path has no file name");
+        }
+        return filename.toString();
+    }
+
+    public static String nameFromPath(Path file) throws IOException {
+        String f = nullSafeFileName(file);
+        return f.substring(0, f.length() - JFCParser.FILE_EXTENSION.length());
+    }
+
+    // Invoked by DCmdStart
+    public static Configuration createKnown(String name) throws IOException, ParseException {
+        // Known name, no need for permission
+        for (KnownConfiguration known : getKnownConfigurations()) {
+            if (known.isNamed(name)) {
+                return known.getConfigurationFile();
+            }
+        }
+        // Check JFC directory
+        SafePath path = SecuritySupport.JFC_DIRECTORY;
+        if (path != null && SecuritySupport.exists(path)) {
+            for (String extension : Arrays.asList("", JFCParser.FILE_EXTENSION)) {
+                SafePath file = new SafePath(path.toPath().resolveSibling(name + extension));
+                if (SecuritySupport.exists(file) && !SecuritySupport.isDirectory(file)) {
+                    try (Reader r = SecuritySupport.newFileReader(file)) {
+                        String jfcName = nameFromPath(file.toPath());
+                        return JFCParser.createConfiguration(jfcName, r);
+                    }
+                }
+            }
+        }
+
+        // Assume path included in name
+
+        Path localPath = Paths.get(name);
+        String jfcName = nameFromPath(localPath);
+        try (Reader r = Files.newBufferedReader(localPath)) {
+            return JFCParser.createConfiguration(jfcName, r);
+        }
+    }
+
+    private static String readContent(InputStream source) throws IOException {
+        byte[] bytes = read(source, BUFFER_SIZE);
+        return new String(bytes, StandardCharsets.UTF_8);
+    }
+
+    // copied from java.io.file.Files to avoid dependency on JDK 9 code
+    private static byte[] read(InputStream source, int initialSize) throws IOException {
+        int capacity = initialSize;
+        byte[] buf = new byte[capacity];
+        int nread = 0;
+        int n;
+        for (;;) {
+            // read to EOF which may read more or less than initialSize (eg: file
+            // is truncated while we are reading)
+            while ((n = source.read(buf, nread, capacity - nread)) > 0)
+                nread += n;
+
+            // if last call to source.read() returned -1, we are done
+            // otherwise, try to read one more byte; if that failed we're done too
+            if (n < 0 || (n = source.read()) < 0)
+                break;
+
+            // one more byte was read; need to allocate a larger buffer
+            if (capacity <= MAX_BUFFER_SIZE - capacity) {
+                capacity = Math.max(capacity << 1, BUFFER_SIZE);
+            } else {
+                if (capacity == MAX_BUFFER_SIZE)
+                    throw new OutOfMemoryError("Required array size too large");
+                capacity = MAX_BUFFER_SIZE;
+            }
+            buf = Arrays.copyOf(buf, capacity);
+            buf[nread++] = (byte)n;
+        }
+        return (capacity == nread) ? buf : Arrays.copyOf(buf, nread);
+    }
+
+
+    /**
+     * Returns list of predefined configurations available.
+     *
+     * @return list of configurations, not null
+     */
+    public static List<Configuration> getConfigurations() {
+        List<Configuration> configs = new ArrayList<>();
+        for (KnownConfiguration knownConfig : getKnownConfigurations()) {
+            try {
+                configs.add(knownConfig.getConfigurationFile());
+            } catch (IOException e) {
+                Logger.log(LogTag.JFR, LogLevel.WARN, "Could not load configuration " + knownConfig.getName() + ". " + e.getMessage());
+            } catch (ParseException e) {
+                Logger.log(LogTag.JFR, LogLevel.WARN, "Could not parse configuration " + knownConfig.getName() + ". " + e.getMessage());
+            }
+        }
+        return configs;
+    }
+
+    private static List<KnownConfiguration> getKnownConfigurations() {
+        if (knownConfigurations == null) {
+            List<KnownConfiguration> configProxies = new ArrayList<>();
+            for (SafePath p : SecuritySupport.getPredefinedJFCFiles()) {
+                try {
+                    configProxies.add(new KnownConfiguration(p));
+                } catch (IOException ioe) {
+                    // ignore
+                }
+            }
+            knownConfigurations = configProxies;
+        }
+        return knownConfigurations;
+    }
+
+    public static Configuration getPredefined(String name) throws IOException, ParseException {
+        for (KnownConfiguration knownConfig : getKnownConfigurations()) {
+            if (knownConfig.getName().equals(name)) {
+                return knownConfig.getConfigurationFile();
+            }
+        }
+        throw new NoSuchFileException("Could not locate configuration with name " + name);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/JFCParser.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.jfc;
+
+import java.io.CharArrayReader;
+import java.io.CharArrayWriter;
+import java.io.IOException;
+import java.io.Reader;
+import java.text.ParseException;
+import jdk.internal.org.xml.sax.InputSource;
+import jdk.internal.org.xml.sax.SAXException;
+import jdk.internal.util.xml.SAXParser;
+import jdk.internal.util.xml.impl.SAXParserImpl;
+import jdk.jfr.Configuration;
+
+import jdk.jfr.internal.PrivateAccess;
+
+/**
+ * Parses a JDK Flight Recorder Configuration file (.jfc)
+ */
+final class JFCParser {
+    static final String FILE_EXTENSION = ".jfc";
+    private static final int MAXIMUM_FILE_SIZE = 1024 * 1024;
+
+    public static Configuration createConfiguration(String name, Reader reader) throws IOException, ParseException {
+        return createConfiguration(name, readContent(reader));
+    }
+
+    public static Configuration createConfiguration(String name, String content) throws IOException, ParseException {
+        try {
+            JFCParserHandler ch = new JFCParserHandler();
+            parseXML(content, ch);
+            return PrivateAccess.getInstance().newConfiguration(name, ch.label, ch.description, ch.provider, ch.settings, content);
+        } catch (IllegalArgumentException iae) {
+            throw new ParseException(iae.getMessage(), -1);
+        } catch (SAXException e) {
+            ParseException pe =  new ParseException("Error reading JFC file. " + e.getMessage(), -1);
+            pe.initCause(e);
+            throw pe;
+        }
+    }
+
+    private static void parseXML(String content, JFCParserHandler ch) throws SAXException, IOException {
+        CharArrayReader r = new CharArrayReader(content.toCharArray());
+        SAXParser parser = new SAXParserImpl();
+        parser.parse(new InputSource(r), ch);
+    }
+
+    private static String readContent(Reader r) throws IOException {
+        CharArrayWriter writer = new CharArrayWriter(1024);
+        int count = 0;
+        int ch;
+        while ((ch = r.read()) != -1) {
+            writer.write(ch);
+            count++;
+            if (count >= MAXIMUM_FILE_SIZE) {
+                throw new IOException("Presets with more than " + MAXIMUM_FILE_SIZE + " characters can't be read.");
+            }
+        }
+        return new String(writer.toCharArray());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/JFCParserHandler.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.jfc;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import jdk.internal.org.xml.sax.Attributes;
+import jdk.internal.org.xml.sax.SAXException;
+import jdk.internal.org.xml.sax.helpers.DefaultHandler;
+
+final class JFCParserHandler extends DefaultHandler {
+    private static final String ELEMENT_CONFIGURATION = "configuration";
+    private static final String ELEMENT_EVENT_TYPE = "event";
+    private static final String ELEMENT_SETTING = "setting";
+    private static final String ATTRIBUTE_NAME = "name";
+    private static final String ATTRIBUTE_LABEL = "label";
+    private static final String ATTRIBUTE_DESCRIPTION = "description";
+    private static final String ATTRIBUTE_PROVIDER = "provider";
+    private static final String ATTRIBUTE_VERSION = "version";
+
+    final Map<String, String> settings = new LinkedHashMap<String, String>();
+    private String currentEventPath;
+    private String currentSettingsName;
+    private StringBuilder currentCharacters;
+    String label;
+    String provider;
+    String description;
+
+    @Override
+    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+        switch (qName.toLowerCase()) {
+        case ELEMENT_CONFIGURATION:
+            String version = attributes.getValue(ATTRIBUTE_VERSION);
+            if (version == null || !version.startsWith("2.")) {
+               throw new SAXException("This version of Flight Recorder can only read JFC file format version 2.x");
+            }
+            label = attributes.getValue(ATTRIBUTE_LABEL);
+            description = getOptional(attributes, ATTRIBUTE_DESCRIPTION, "");
+            provider = getOptional(attributes, ATTRIBUTE_PROVIDER, "");
+            break;
+        case ELEMENT_EVENT_TYPE:
+            currentEventPath = attributes.getValue(ATTRIBUTE_NAME);
+            break;
+        case ELEMENT_SETTING:
+            currentSettingsName = attributes.getValue(ATTRIBUTE_NAME);
+            break;
+        }
+        currentCharacters = null;
+    }
+
+    private String getOptional(Attributes attributes, String name, String defaultValue) {
+        String value = attributes.getValue(name);
+        return value == null ? defaultValue : value;
+    }
+
+    @Override
+    public void characters(char[] ch, int start, int length) throws SAXException {
+        if (currentCharacters == null) {
+            currentCharacters = new StringBuilder(length);
+        }
+        currentCharacters.append(ch, start, length);
+    }
+
+    @Override
+    public void endElement(String uri, String localName, String qName) {
+        switch (qName.toLowerCase()) {
+        case ELEMENT_CONFIGURATION:
+            break;
+        case ELEMENT_EVENT_TYPE:
+            currentEventPath = null;
+            break;
+        case ELEMENT_SETTING:
+            String settingsValue = currentCharacters == null ? "" : currentCharacters.toString();
+            settings.put(currentEventPath + "#" + currentSettingsName, "" + settingsValue);
+            currentSettingsName = null;
+            break;
+        }
+    }
+
+    public Map<String, String> getSettings() {
+        return settings;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/jfc.xsd	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,177 @@
+<?xml version="1.0" encoding="utf-8"?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="unqualified" attributeFormDefault="unqualified"
+	version="1.0">
+
+	<xsd:element name="configuration" type="configurationType" />
+
+	<xsd:complexType name="configurationType">
+		<xsd:sequence>
+			<xsd:element minOccurs="0" maxOccurs="unbounded" name="producer" type="producerType" />
+		</xsd:sequence>
+		<xsd:attribute use="required" name="version" type="xsd:decimal" />
+		<xsd:attribute use="required" name="name" type="xsd:string" />
+		<xsd:attribute use="optional" name="description" type="xsd:string" default="" />
+		<xsd:attribute use="optional" name="provider" type="xsd:string" default="" />
+	</xsd:complexType>
+
+	<xsd:complexType name="producerType">
+		<xsd:sequence>
+			<xsd:element minOccurs="0" maxOccurs="1" name="control" type="controlType" />
+			<xsd:element minOccurs="0" maxOccurs="unbounded" name="event" type="eventType" />
+		</xsd:sequence>
+		<xsd:attribute use="required" name="uri" type="xsd:anyURI" />
+		<xsd:attribute use="optional" name="label" type="xsd:string" default="" />
+		<xsd:attribute use="optional" name="description" type="xsd:string" default="" />
+	</xsd:complexType>
+
+	<xsd:complexType name="eventType">
+		<xsd:sequence>
+			<xsd:element minOccurs="0" maxOccurs="unbounded" name="setting" type="settingType" />
+		</xsd:sequence>
+		<xsd:attribute use="required" name="path" type="xsd:string" />
+		<xsd:attribute use="optional" name="label" type="xsd:string" />
+		<xsd:attribute use="optional" name="description" type="xsd:string" />
+	</xsd:complexType>
+
+	<xsd:simpleType name="controlIdentifier">
+		<xsd:restriction base="xsd:NMTOKEN" />
+	</xsd:simpleType>
+
+	<xsd:complexType name="settingType" mixed="true">
+		<xsd:attribute use="required" name="name" type="xsd:string" />
+		<xsd:attribute use="optional" name="control" type="xsd:anyURI" />
+	</xsd:complexType>
+
+	<!-- The elements below are ignored by the JVM -->
+
+	<xsd:complexType name="controlType">
+		<xsd:sequence minOccurs="0" maxOccurs="unbounded">
+			<xsd:choice>
+				<xsd:element name="text" type="textType" />
+				<xsd:element name="selection" type="selectionType" />
+				<xsd:element name="flag" type="flagType" />
+				<xsd:element name="condition" type="conditionType" />
+			</xsd:choice>
+		</xsd:sequence>
+	</xsd:complexType>
+
+	<!-- Content type is an optional tag (identifier) that hints how a value should be interpreted. -->
+	<xsd:simpleType name="contentType">
+		<xsd:restriction base="xsd:NMTOKEN" />
+	</xsd:simpleType>
+
+	<!-- Flag represents a boolean input that can be true or false. -->
+	<xsd:complexType name="flagType">
+		<xsd:simpleContent>
+			<xsd:extension base="xsd:string">
+				<xsd:attribute use="required" name="label" type="xsd:string" />
+				<xsd:attribute use="required" name="name" type="controlIdentifier" />
+				<xsd:attribute use="optional" name="description" type="xsd:string" default="" />
+			</xsd:extension>
+		</xsd:simpleContent>
+	</xsd:complexType>
+
+	<!-- Text represents a string based input which may have a contentType that hints how the text should be interpreted. 
+	For content that can be ordered (i.e numbers) it's possible to set a minimum and maximum value. How values are 
+	ordered are determined by the contentType. For instance, if the contenType would be "timeSpan" "1 s" would 
+	larger then "1 ns". -->
+	<xsd:complexType name="textType">
+		<xsd:simpleContent>
+			<xsd:extension base="xsd:string">
+				<xsd:attribute use="required" name="label" type="xsd:string" />
+				<xsd:attribute use="required" name="name" type="controlIdentifier" />
+				<xsd:attribute use="optional" name="description" type="xsd:string" default="" />
+				<xsd:attribute use="optional" name="contentType" type="contentType" default="text" />
+				<xsd:attribute use="optional" name="minimum" type="xsd:string" />
+				<xsd:attribute use="optional" name="maximum" type="xsd:string" />
+			</xsd:extension>
+		</xsd:simpleContent>
+	</xsd:complexType>
+
+	<!-- Selection represents an input from a set of values. Values are stored in the option elements and 
+	they each have unique identifier (selectionIdentfier). The default attribute should point to one of 
+	these values -->
+	<xsd:simpleType name="selectionIdentifier">
+		<xsd:restriction base="xsd:NMTOKEN" />
+	</xsd:simpleType>
+
+	<xsd:complexType name="selectionType">
+		<xsd:sequence minOccurs="1" maxOccurs="unbounded">
+			<xsd:element name="option" type="optionType" />
+		</xsd:sequence>
+		<xsd:attribute use="required" name="label" type="xsd:string" />
+		<xsd:attribute use="required" name="name" type="controlIdentifier" />
+		<xsd:attribute use="required" name="default" type="selectionIdentifier" />
+		<xsd:attribute use="optional" name="description" type="xsd:string" default="" />
+	</xsd:complexType>
+
+	<xsd:complexType name="optionType">
+		<xsd:simpleContent>
+			<xsd:extension base="xsd:string">
+				<xsd:attribute use="required" name="name" type="selectionIdentifier" />
+				<xsd:attribute use="required" name="label" type="xsd:string" />
+				<xsd:attribute use="optional" name="description" type="xsd:string" default="" />
+			</xsd:extension>
+		</xsd:simpleContent>
+	</xsd:complexType>
+
+	<!--Condition represents an input that depends on other inputs. The child elements defines a 
+	boolean expression with test as leaf nodes. If the expression evaluates to true the input returns 
+	"true" and if it's false "false". It's possible to override this behavior by setting the attributes 
+	true and false to the values that should be returned. -->
+	<xsd:complexType name="conditionType">
+		<xsd:choice>
+			<xsd:element name="test" type="testType" />
+			<xsd:element name="and" type="andType" />
+			<xsd:element name="not" type="notType" />
+			<xsd:element name="or" type="orType" />
+		</xsd:choice>
+		<xsd:attribute use="required" name="name" type="xsd:string" />
+		<xsd:attribute default="true" name="true" type="xsd:string" />
+		<xsd:attribute default="false" name="false" type="xsd:string" />
+	</xsd:complexType>
+
+	<xsd:complexType name="orType">
+		<xsd:sequence minOccurs="2" maxOccurs="unbounded">
+			<xsd:choice>
+				<xsd:element name="test" type="testType" />
+				<xsd:element name="and" type="andType" />
+				<xsd:element name="not" type="notType" />
+				<xsd:element name="or" type="orType" />
+			</xsd:choice>
+		</xsd:sequence>
+	</xsd:complexType>
+
+	<xsd:complexType name="andType">
+		<xsd:sequence minOccurs="2" maxOccurs="unbounded">
+			<xsd:choice>
+				<xsd:element name="test" type="testType" />
+				<xsd:element name="and" type="andType" />
+				<xsd:element name="not" type="notType" />
+				<xsd:element name="or" type="orType" />
+			</xsd:choice>
+		</xsd:sequence>
+	</xsd:complexType>
+
+	<xsd:complexType name="notType">
+		<xsd:choice>
+			<xsd:element name="test" type="testType" />
+			<xsd:element name="and" type="andType" />
+			<xsd:element name="or" type="orType" />
+			<xsd:element name="not" type="notType" />
+		</xsd:choice>
+	</xsd:complexType>
+
+	<xsd:simpleType name="operatorType">
+		<xsd:restriction base="xsd:NMTOKEN">
+			<xsd:enumeration value="equal" />
+		</xsd:restriction>
+	</xsd:simpleType>
+
+	<xsd:complexType name="testType">
+		<xsd:attribute use="required" name="name" type="controlIdentifier" />
+		<xsd:attribute use="required" name="operator" type="operatorType" />
+		<xsd:attribute use="required" name="value" type="xsd:string" />
+		<xsd:attribute use="optional" name="contentType" type="contentType" default="text" />
+	</xsd:complexType>
+</xsd:schema>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/package-info.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * This package contains classes for configuring Flight Recorder using JFC-files.
+ *
+ * @since 9
+ */
+package jdk.jfr.internal.jfc;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/management/ManagementSupport.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.management;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import jdk.jfr.EventType;
+import jdk.jfr.internal.JVMSupport;
+import jdk.jfr.internal.LogLevel;
+import jdk.jfr.internal.LogTag;
+import jdk.jfr.internal.Logger;
+import jdk.jfr.internal.MetadataRepository;
+import jdk.jfr.internal.Utils;
+import jdk.jfr.internal.instrument.JDKEvents;
+
+/**
+ * The management API in module jdk.management.jfr should be built on top of the
+ * public API in jdk.jfr. Before putting more functionality here, consider if it
+ * should not be part of the public API, and if not, please provide motivation
+ *
+ */
+public final class ManagementSupport {
+
+    // Purpose of this method is to expose the event types to the
+    // FlightRecorderMXBean without instantiating Flight Recorder.
+    //
+    // This allows:
+    //
+    // 1) discoverability, so event settings can be exposed without the need to
+    // create a new Recording in FlightrecorderMXBean.
+    //
+    // 2) a graphical JMX client to list all attributes to the user, without
+    // loading JFR memory buffers. This is especially important when there is
+    // no intent to use Flight Recorder.
+    //
+    // An alternative design would be to make FlightRecorder#getEventTypes
+    // static, but it would the make the API look strange
+    //
+    public static List<EventType> getEventTypes() {
+        // would normally be checked when a Flight Recorder instance is created
+        Utils.checkAccessFlightRecorder();
+        if (JVMSupport.isNotAvailable()) {
+            return new ArrayList<>();
+        }
+        JDKEvents.initialize(); // make sure JDK events are available
+        return Collections.unmodifiableList(MetadataRepository.getInstance().getRegisteredEventTypes());
+    }
+
+    // Reuse internal code for parsing a timespan
+    public static long parseTimespan(String s) {
+        return Utils.parseTimespan(s);
+    }
+
+    // Reuse internal code for formatting settings
+    public static final String formatTimespan(Duration dValue, String separation) {
+        return Utils.formatTimespan(dValue, separation);
+    }
+
+    // Reuse internal logging mechanism
+    public static void logError(String message) {
+        Logger.log(LogTag.JFR, LogLevel.ERROR, message);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/BooleanValue.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.settings;
+
+import java.util.Set;
+
+/**
+ * Helper class for settings that use boolean numbers
+ *
+ */
+final class BooleanValue  {
+    private String value = "false";
+    private boolean booleanValue;
+
+    private BooleanValue(boolean b) {
+        booleanValue = b;
+        value = b ? "true" : "false";
+    }
+
+    public String union(Set<String> values) {
+        for (String v : values) {
+            if ("true".equals(v)) {
+                return "true";
+            }
+        }
+        return "false";
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+        this.booleanValue = Boolean.valueOf(value);
+    }
+
+    public final String getValue() {
+        return this.value;
+    }
+
+    public boolean getBoolean() {
+        return booleanValue;
+    }
+
+    public static BooleanValue valueOf(String defaultValue) {
+        if ("true".equals(defaultValue)) {
+            return new BooleanValue(true);
+        }
+        if ("false".equals(defaultValue)) {
+            return new BooleanValue(false);
+        }
+        throw new InternalError("Unknown default value for settings '" + defaultValue + "'");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/CutoffSetting.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.settings;
+
+import java.util.Objects;
+import java.util.Set;
+
+import jdk.jfr.BooleanFlag;
+import jdk.jfr.Description;
+import jdk.jfr.Label;
+import jdk.jfr.MetadataDefinition;
+import jdk.jfr.Name;
+import jdk.jfr.internal.Control;
+import jdk.jfr.internal.PlatformEventType;
+import jdk.jfr.internal.Type;
+import jdk.jfr.internal.Utils;
+
+@MetadataDefinition
+@Label("Cutoff")
+@Description("Limit running time of event")
+@Name(Type.SETTINGS_PREFIX + "Cutoff")
+@BooleanFlag
+public final class CutoffSetting extends Control {
+    private final static long typeId = Type.getTypeId(CutoffSetting.class);
+
+    private String value = "0 ns";
+    private final PlatformEventType eventType;
+
+    public CutoffSetting(PlatformEventType eventType, String defaultValue) {
+       super(defaultValue);
+       this.eventType = Objects.requireNonNull(eventType);
+    }
+
+    @Override
+    public String combine(Set<String> values) {
+        long max = 0;
+        String text = "0 ns";
+        for (String value : values) {
+            long l = parseValue(value);
+            if (l > max) {
+                text = value;
+                max = l;
+            }
+        }
+        return text;
+    }
+
+    @Override
+    public void setValue(String value) {
+        long l = parseValue(value);
+        this.value = value;
+        eventType.setCutoff(l);
+    }
+
+    private long parseValue(String value) {
+        return isInfinity(value) ? Long.MAX_VALUE : Utils.parseTimespan(value);
+    }
+
+    @Override
+    public String getValue() {
+        return value;
+    }
+
+    public static boolean isType(long typeId) {
+        return CutoffSetting.typeId == typeId;
+    }
+
+    private static boolean isInfinity(String s) {
+        return s.equals("infinity");
+    }
+
+    public static long parseValueSafe(String value) {
+        if (value == null) {
+            return 0L;
+        }
+        try {
+            return isInfinity(value) ? Long.MAX_VALUE : Utils.parseTimespan(value);
+        } catch (NumberFormatException nfe) {
+            return 0L;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/EnabledSetting.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.settings;
+
+import java.util.Objects;
+import java.util.Set;
+
+import jdk.jfr.Description;
+import jdk.jfr.BooleanFlag;
+import jdk.jfr.Label;
+import jdk.jfr.MetadataDefinition;
+import jdk.jfr.Name;
+import jdk.jfr.internal.PlatformEventType;
+import jdk.jfr.internal.Type;
+import jdk.jfr.internal.Control;
+
+@MetadataDefinition
+@Label("Enabled")
+@Description("Record event")
+@Name(Type.SETTINGS_PREFIX + "Enabled")
+@BooleanFlag
+public final class EnabledSetting extends Control {
+    private final BooleanValue booleanValue;
+    private final PlatformEventType eventType;
+
+    public EnabledSetting(PlatformEventType eventType, String defaultValue) {
+        super(defaultValue);
+        this.booleanValue = BooleanValue.valueOf(defaultValue);
+        this.eventType = Objects.requireNonNull(eventType);
+    }
+
+    @Override
+    public String combine(Set<String> values) {
+        return booleanValue.union(values);
+    }
+
+    @Override
+    public void setValue(String value) {
+        booleanValue.setValue(value);
+        eventType.setEnabled(booleanValue.getBoolean());
+        if (eventType.isEnabled() && !eventType.isJVM()) {
+            if (!eventType.isInstrumented()) {
+                eventType.markForInstrumentation(true);
+            }
+        }
+    }
+
+    @Override
+    public String getValue() {
+        return booleanValue.getValue();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/PeriodSetting.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.settings;
+
+import java.util.Objects;
+import java.util.Set;
+
+import jdk.jfr.Description;
+import jdk.jfr.Label;
+import jdk.jfr.MetadataDefinition;
+import jdk.jfr.Name;
+import jdk.jfr.internal.PlatformEventType;
+import jdk.jfr.internal.Control;
+import jdk.jfr.internal.Type;
+import jdk.jfr.internal.Utils;
+
+@MetadataDefinition
+@Label("Period")
+@Description("Record event at interval")
+@Name(Type.SETTINGS_PREFIX + "Period")
+public final class PeriodSetting extends Control {
+    private static final long typeId = Type.getTypeId(PeriodSetting.class);
+
+    public static final String EVERY_CHUNK = "everyChunk";
+    public static final String BEGIN_CHUNK = "beginChunk";
+    public static final String END_CHUNK = "endChunk";
+    public static final String NAME = "period";
+    private final PlatformEventType eventType;
+    private String value = EVERY_CHUNK;
+
+    public PeriodSetting(PlatformEventType eventType, String defaultValue) {
+        super(defaultValue);
+        this.eventType = Objects.requireNonNull(eventType);
+    }
+
+    @Override
+    public String combine(Set<String> values) {
+        long min = Long.MAX_VALUE;
+        boolean beginChunk = false;
+        boolean endChunk = false;
+        String text = EVERY_CHUNK;
+        for (String value : values) {
+            switch (value) {
+            case EVERY_CHUNK:
+                beginChunk = true;
+                endChunk = true;
+                break;
+            case BEGIN_CHUNK:
+                beginChunk = true;
+                break;
+            case END_CHUNK:
+                endChunk = true;
+                break;
+            default:
+                long l = Utils.parseTimespan(value);
+                if (l < min) {
+                    text = value;
+                    min = l;
+                }
+            }
+        }
+        if (min != Long.MAX_VALUE) {
+            return text;
+        }
+        if (beginChunk && !endChunk) {
+            return BEGIN_CHUNK;
+        }
+        if (!beginChunk && endChunk) {
+            return END_CHUNK;
+        }
+        return text;
+    }
+
+    @Override
+    public void setValue(String value) {
+        switch (value) {
+        case EVERY_CHUNK:
+            eventType.setPeriod(0, true, true);
+            break;
+        case BEGIN_CHUNK:
+            eventType.setPeriod(0, true, false);
+            break;
+        case END_CHUNK:
+            eventType.setPeriod(0, false, true);
+            break;
+        default:
+            eventType.setPeriod(Utils.parseTimespan(value) / 1_000_000, false, false);
+        }
+        this.value = value;
+    }
+
+    @Override
+    public String getValue() {
+        return value;
+    }
+
+    public static boolean isType(long typeId) {
+        return PeriodSetting.typeId == typeId;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/StackTraceSetting.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.settings;
+
+import java.util.Objects;
+import java.util.Set;
+
+import jdk.jfr.Description;
+import jdk.jfr.BooleanFlag;
+import jdk.jfr.Label;
+import jdk.jfr.MetadataDefinition;
+import jdk.jfr.Name;
+import jdk.jfr.internal.PlatformEventType;
+import jdk.jfr.internal.Control;
+import jdk.jfr.internal.Type;
+
+@MetadataDefinition
+@Label("Stack Trace")
+@Name(Type.SETTINGS_PREFIX + "StackTrace")
+@Description("Record stack traces")
+@BooleanFlag
+public final class StackTraceSetting extends Control {
+    private final static long typeId =  Type.getTypeId(StackTraceSetting.class);
+    private final BooleanValue booleanValue;
+    private final PlatformEventType eventType;
+
+    public StackTraceSetting(PlatformEventType eventType, String defaultValue) {
+        super(defaultValue);
+        this.booleanValue = BooleanValue.valueOf(defaultValue);
+        this.eventType = Objects.requireNonNull(eventType);
+    }
+
+    @Override
+    public String combine(Set<String> values) {
+        return booleanValue.union(values);
+    }
+
+    @Override
+    public void setValue(String value) {
+        booleanValue.setValue(value);
+        eventType.setStackTraceEnabled(booleanValue.getBoolean());
+    }
+
+    @Override
+    public String getValue() {
+        return booleanValue.getValue();
+    }
+
+    public static boolean isType(long typeId) {
+        return StackTraceSetting.typeId == typeId;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThresholdSetting.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.settings;
+
+import java.util.Objects;
+import java.util.Set;
+
+import jdk.jfr.Description;
+import jdk.jfr.Label;
+import jdk.jfr.MetadataDefinition;
+import jdk.jfr.Name;
+import jdk.jfr.Timespan;
+import jdk.jfr.internal.PlatformEventType;
+import jdk.jfr.internal.Control;
+import jdk.jfr.internal.Type;
+import jdk.jfr.internal.Utils;
+@MetadataDefinition
+@Label("Threshold")
+@Name(Type.SETTINGS_PREFIX + "Threshold")
+@Description("Record event with duration above or equal to threshold")
+@Timespan
+public final class ThresholdSetting extends Control {
+    private final static long typeId = Type.getTypeId(ThresholdSetting.class);
+    private String value = "0 ns";
+    private final PlatformEventType eventType;
+
+    public ThresholdSetting(PlatformEventType eventType, String defaultValue) {
+       super(defaultValue);
+       this.eventType = Objects.requireNonNull(eventType);
+    }
+
+    @Override
+    public String combine(Set<String> values) {
+        long min = Long.MAX_VALUE;
+        String text = "0 ns";
+        for (String value : values) {
+            long l = Utils.parseTimespan(value);
+            if (l < min) {
+                text = value;
+                min = l;
+            }
+        }
+        return text;
+    }
+
+    @Override
+    public void setValue(String value) {
+        long l = Utils.parseTimespan(value);
+        this.value = value;
+        eventType.setThreshold(l);
+    }
+
+    @Override
+    public String getValue() {
+        return value;
+    }
+
+    public static boolean isType(long typeId) {
+        return ThresholdSetting.typeId == typeId;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/test/WhiteBox.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.test;
+
+public final class WhiteBox {
+
+    private static boolean writeAllObjectSamples;
+
+    /**
+     * If OldObjectSample event is enabled, calling this method
+     * ensures that all object samples are written, including short-lived objects.
+     * Purpose of this method is to increase determinism in tests.
+     *
+     * @param writeAllObjectSamples if all samples should be written or not
+     *
+     */
+    public static void setWriteAllObjectSamples(boolean writeAllSamples) {
+        writeAllObjectSamples = writeAllSamples;
+    }
+
+    public static boolean getWriteAllObjectSamples() {
+        return writeAllObjectSamples;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/package-info.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * This package provides classes to create events and control Flight Recorder.
+ * <p>
+ * <b>Defining events</b>
+ * <p>
+ * Flight Recorder collects data as events. An event has a time stamp, duration
+ * and usually an application-specific payload, useful for diagnosing the
+ * running application up to the failure or crash.
+ * <p>
+ * To define a Flight Recorder event, extend {@link jdk.jfr.Event} and add
+ * fields that matches the data types of the payload. Metadata about fields,
+ * such as labels, descriptions and units, can be added by using the annotations
+ * available in the <code>jdk.jfr</code> package, or by using a user-defined
+ * annotation that has the {@link jdk.jfr.MetadataDefinition} annotation.
+ * <p>
+ * After an event class is defined, instances can be created (event objects).
+ * Data is stored in the event by assigning data to fields. Event timing can be
+ * explicitly controlled by using the <code>begin</code> and {@code end} methods
+ * available in the <code>Event</code> class.
+ * <p>
+ * Gathering data to store in an event can be expensive. The
+ * {@link Event#shouldCommit()} method can be used to verify whether an event
+ * instance would actually be written to the system when the
+ * {@code Event#commit()} method is invoked. If
+ * {@link Event#shouldCommit()} returns {@code false}, then those operations can be
+ * avoided.
+ * <p>
+ * Sometimes the field layout of an event is not known at compile time. In that
+ * case, an event can be dynamically defined. However, dynamic events might not
+ * have the same level of performance as statically defined ones and tools might
+ * not be able to identify and visualize the data without knowing the layout.
+ * <p>
+ * To dynamically define an event, use the {@link jdk.jfr.EventFactory} class
+ * and define fields by using the {@link jdk.jfr.ValueDescriptor} class, and
+ * define annotations by using the {@link jdk.jfr.AnnotationElement} class. Use
+ * the factory to allocate an event and the
+ * {@link jdk.jfr.Event#set(int, Object)} method to populate it.
+ * <p>
+ * <b>Controlling Flight Recorder</b>
+ * <p>
+ * Flight Recorder can be controlled locally by using the <code>jcmd</code>
+ * command line tool or remotely by using the <code>FlightRecorderMXBean</code>
+ * interface, registered in the platform MBeanServer. When direct programmatic
+ * access is needed, a Flight Recorder instance can be obtained by invoking
+ * {@link jdk.jfr.FlightRecorder#getFlightRecorder()} and a recording created by
+ * using {@link jdk.jfr.Recording} class, from which the amount of data to
+ * record is configured.
+ * <p>
+ * <b>Settings and configuration</b>
+ * <p>
+ * A setting consists of a name/value pair, where <em>name</em> specifies the
+ * event and setting to configure, and the <em>value</em> specifies what to set
+ * it to.
+ * <p>
+ * The name can be formed in the following ways:
+ * <p>
+ * {@code
+ *   <event-name> + "#" + <setting-name>
+ * }
+ * <p>
+ * or
+ * <p>
+ * {@code
+ *   <event-id> + "#" + <setting-name>
+ * }
+ * <p>
+ * For example, to set the sample interval of the CPU Load event to once every
+ * second, use the name {@code "jdk.CPULoad#period"} and the value
+ * {@code "1 s"}. If multiple events use the same name, for example if an event
+ * class is loaded in multiple class loaders, and differentiation is needed
+ * between them, then the name is {@code "56#period"}. The ID for an event is
+ * obtained by invoking {@link jdk.jfr.EventType#getId()} method and is valid
+ * for the Java Virtual Machine instance that the event is registered in.
+ * <p>
+ * A list of available event names is retrieved by invoking
+ * {@link jdk.jfr.FlightRecorder#getEventTypes()} and
+ * {@link jdk.jfr.EventType#getName()}. A list of available settings for an
+ * event type is obtained by invoking
+ * {@link jdk.jfr.EventType#getSettingDescriptors()} and
+ * {@link jdk.jfr.ValueDescriptor#getName()}.
+ * <p>
+ * <b>Predefined settings</b>
+ * <p>
+ * <table class="striped">
+ * <caption>Event setting names and their purpose.</caption> <thead>
+ * <tr>
+ * <th scope="col">Name</th>
+ * <th scope="col">Description</th>
+ * <th scope="col">Default value</th>
+ * <th scope="col">Format</th>
+ * <th scope="col">Example values</th>
+ * </tr>
+ * </thead> <tbody>
+ * <tr>
+ * <th scope="row">{@code enabled}</th>
+ * <td>Specifies whether the event is recorded</td>
+ * <td>{@code "true"}</td>
+ * <td>String representation of a {@code Boolean} ({@code "true"} or
+ * {@code "false"})</td>
+ * <td>{@code "true"}<br>
+ * {@code "false"}</td>
+ * </tr>
+ * <tr>
+ * <th scope="row">{@code threshold}</th>
+ * <td>Specifies the duration below which an event is not recorded</td>
+ * <td>{@code "0"} (no limit)</td>
+ * <td>{@code "0"} if no threshold is used, otherwise a string representation of
+ * a positive {@code Long} followed by a space and one of the following units:
+ * <ul style="list-style-type:none">
+ * <li>{@code "ns"} (nanoseconds)
+ * <li>{@code "us"} (microseconds)
+ * <li>{@code "ms"} (milliseconds)
+ * <li>{@code "s"} (seconds)
+ * <li>{@code "m"} (minutes)
+ * <li>{@code "h"} (hours)
+ * <li>{@code "d"} (days)
+ * </ul>
+ * <td>{@code "0"}<br>
+ * {@code "10 ms"}<br>
+ * "1 s"</td>
+ * </tr>
+ * <tr>
+ * <th scope="row">{@code period}</th>
+ * <td>Specifies the interval at which the event is emitted, if it is
+ * periodic</td>
+ * <td>{@code "everyChunk"}</td>
+ * <td>{@code "everyChunk"}, if a periodic event should be emitted with every
+ * file rotation, otherwise a string representation of a positive {@code Long}
+ * value followed by an empty space and one of the following units:
+ * <ul style="list-style-type:none">
+ * <li>{@code "ns"} (nanoseconds)
+ * <li>{@code "us"} (microseconds)
+ * <li>{@code "ms"} (milliseconds)
+ * <li>{@code "s"} (seconds)
+ * <li>{@code "m"} (minutes)
+ * <li>{@code "h"} (hours)
+ * <li>{@code "d"} (days)
+ * </ul>
+ * </td>
+ * <td>{@code "20 ms"}<br>
+ * {@code "1 s"}<br>
+ * {@code "everyChunk"}</td>
+ *
+ * </tr>
+ * <tr>
+ * <th scope="row">{@code stackTrace}</th>
+ * <td>Specifies whether the stack trace from the {@code Event#commit()} method
+ * is recorded</td>
+ * <td>{@code "true"}</td>
+ * <td>String representation of a {@code Boolean} ({@code "true"} or
+ * {@code "false"})</td>
+ * <td>{@code "true"},<br>
+ * {@code "false"}</td>
+ * </tr>
+ * </tbody>
+ * </table>
+ * <p>
+ * <b>Null-handling</b>
+ * <p>
+ * All methods define whether they accept or return {@code null} in the Javadoc.
+ * Typically this is expressed as {@code "not null"}. If a {@code null}
+ * parameter is used where it is not allowed, a
+ * {@code java.lang.NullPointerException} is thrown. If a {@code null}
+ * parameters is passed to a method that throws other exceptions, such as
+ * {@code java.io.IOException}, the {@code java.lang.NullPointerException} takes
+ * precedence, unless the Javadoc for the method explicitly states how
+ * {@code null} is handled, i.e. by throwing
+ * {@code java.lang.IllegalArgumentException}.
+ *
+ * @since 9
+ */
+package jdk.jfr;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/module-info.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Defines the API for JDK Flight Recorder.
+ *
+ * @moduleGraph
+ * @since 9
+ */
+module jdk.jfr {
+    exports jdk.jfr;
+    exports jdk.jfr.consumer;
+
+    exports jdk.jfr.internal.management to jdk.management.jfr;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/conf/jfr/default.jfc	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,802 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+     Recommended way to edit .jfc files is to use Java Mission Control,
+     see Window -> Flight Recorder Template Manager.
+-->
+
+<configuration version="2.0" label="Continuous" description="Low overhead configuration safe for continuous use in production environments, typically less than 1 % overhead." provider="Oracle">
+
+    <event name="jdk.ThreadAllocationStatistics">
+      <setting name="enabled">true</setting>
+      <setting name="period">everyChunk</setting>
+    </event>
+
+    <event name="jdk.ClassLoadingStatistics">
+      <setting name="enabled">true</setting>
+      <setting name="period">1000 ms</setting>
+    </event>
+
+    <event name="jdk.ClassLoaderStatistics">
+      <setting name="enabled">true</setting>
+      <setting name="period">everyChunk</setting>
+    </event>
+
+    <event name="jdk.JavaThreadStatistics">
+      <setting name="enabled">true</setting>
+      <setting name="period">1000 ms</setting>
+    </event>
+
+    <event name="jdk.ThreadStart">
+      <setting name="enabled">true</setting>
+    </event>
+
+    <event name="jdk.ThreadEnd">
+      <setting name="enabled">true</setting>
+    </event>
+
+    <event name="jdk.ThreadSleep">
+      <setting name="enabled">true</setting>
+      <setting name="stackTrace">true</setting>
+      <setting name="threshold" control="synchronization-threshold">20 ms</setting>
+    </event>
+
+    <event name="jdk.ThreadPark">
+      <setting name="enabled">true</setting>
+      <setting name="stackTrace">true</setting>
+      <setting name="threshold" control="synchronization-threshold">20 ms</setting>
+    </event>
+
+    <event name="jdk.JavaMonitorEnter">
+      <setting name="enabled">true</setting>
+      <setting name="stackTrace">true</setting>
+      <setting name="threshold" control="synchronization-threshold">20 ms</setting>
+    </event>
+
+    <event name="jdk.JavaMonitorWait">
+      <setting name="enabled">true</setting>
+      <setting name="stackTrace">true</setting>
+      <setting name="threshold" control="synchronization-threshold">20 ms</setting>
+    </event>
+
+    <event name="jdk.JavaMonitorInflate">
+      <setting name="enabled">false</setting>
+      <setting name="stackTrace">true</setting>
+      <setting name="threshold" control="synchronization-threshold">20 ms</setting>
+    </event>
+
+    <event name="jdk.BiasedLockRevocation">
+      <setting name="enabled">true</setting>
+      <setting name="stackTrace">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.BiasedLockSelfRevocation">
+      <setting name="enabled">true</setting>
+      <setting name="stackTrace">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.BiasedLockClassRevocation">
+      <setting name="enabled">true</setting>
+      <setting name="stackTrace">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.ReservedStackActivation">
+      <setting name="enabled">true</setting>
+      <setting name="stackTrace">true</setting>
+    </event>
+
+    <event name="jdk.ClassLoad">
+      <setting name="enabled" control="class-loading-enabled">false</setting>
+      <setting name="stackTrace">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.ClassDefine">
+      <setting name="enabled" control="class-loading-enabled">false</setting>
+      <setting name="stackTrace">true</setting>
+    </event>
+
+    <event name="jdk.ClassUnload">
+      <setting name="enabled" control="class-loading-enabled">false</setting>
+    </event>
+
+    <event name="jdk.JVMInformation">
+      <setting name="enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.InitialSystemProperty">
+      <setting name="enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.ExecutionSample">
+      <setting name="enabled" control="method-sampling-enabled">true</setting>
+      <setting name="period" control="method-sampling-interval">20 ms</setting>
+    </event>
+
+    <event name="jdk.NativeMethodSample">
+      <setting name="enabled" control="method-sampling-enabled">true</setting>
+      <setting name="period" control="method-sampling-interval">20 ms</setting>
+    </event>
+
+    <event name="jdk.SafepointBegin">
+      <setting name="enabled">true</setting>
+      <setting name="threshold">10 ms</setting>
+    </event>
+
+    <event name="jdk.SafepointStateSynchronization">
+      <setting name="enabled">false</setting>
+      <setting name="threshold">10 ms</setting>
+    </event>
+
+    <event name="jdk.SafepointWaitBlocked">
+      <setting name="enabled">false</setting>
+      <setting name="threshold">10 ms</setting>
+    </event>
+
+    <event name="jdk.SafepointCleanup">
+      <setting name="enabled">false</setting>
+      <setting name="threshold">10 ms</setting>
+    </event>
+
+    <event name="jdk.SafepointCleanupTask">
+      <setting name="enabled">false</setting>
+      <setting name="threshold">10 ms</setting>
+    </event>
+
+    <event name="jdk.SafepointEnd">
+      <setting name="enabled">false</setting>
+      <setting name="threshold">10 ms</setting>
+    </event>
+
+    <event name="jdk.ExecuteVMOperation">
+      <setting name="enabled">true</setting>
+      <setting name="threshold">10 ms</setting>
+    </event>
+
+    <event name="jdk.Shutdown">
+      <setting name="enabled">true</setting>
+      <setting name="stackTrace">true</setting>
+    </event>
+
+    <event name="jdk.ThreadDump">
+      <setting name="enabled" control="thread-dump-enabled">true</setting>
+      <setting name="period" control="thread-dump-interval">everyChunk</setting>
+    </event>
+
+    <event name="jdk.IntFlag">
+      <setting name="enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.UnsignedIntFlag">
+      <setting name="enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.LongFlag">
+      <setting name="enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.UnsignedLongFlag">
+      <setting name="enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.DoubleFlag">
+      <setting name="enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.BooleanFlag">
+      <setting name="enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.StringFlag">
+      <setting name="enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.IntFlagChanged">
+      <setting name="enabled">true</setting>
+    </event>
+
+    <event name="jdk.UnsignedIntFlagChanged">
+      <setting name="enabled">true</setting>
+    </event>
+
+    <event name="jdk.LongFlagChanged">
+      <setting name="enabled">true</setting>
+    </event>
+
+    <event name="jdk.UnsignedLongFlagChanged">
+      <setting name="enabled">true</setting>
+    </event>
+
+    <event name="jdk.DoubleFlagChanged">
+      <setting name="enabled">true</setting>
+    </event>
+
+    <event name="jdk.BooleanFlagChanged">
+      <setting name="enabled">true</setting>
+    </event>
+
+    <event name="jdk.StringFlagChanged">
+      <setting name="enabled">true</setting>
+    </event>
+
+    <event name="jdk.ObjectCount">
+      <setting name="enabled" control="memory-profiling-enabled-all">false</setting>
+      <setting name="period">everyChunk</setting>
+    </event>
+
+    <event name="jdk.GCConfiguration">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+      <setting name="period">everyChunk</setting>
+    </event>
+
+    <event name="jdk.GCHeapConfiguration">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.YoungGenerationConfiguration">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.GCTLABConfiguration">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.GCSurvivorConfiguration">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.ObjectCountAfterGC">
+      <setting name="enabled">false</setting>
+    </event>
+
+    <event name="jdk.GCHeapSummary">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.PSHeapSummary">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.G1HeapSummary">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.MetaspaceSummary">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.MetaspaceGCThreshold">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.MetaspaceAllocationFailure">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+      <setting name="stackTrace">true</setting>
+    </event>
+
+    <event name="jdk.MetaspaceOOM">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+      <setting name="stackTrace">true</setting>
+    </event>
+
+    <event name="jdk.MetaspaceChunkFreeListSummary">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.GarbageCollection">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.ParallelOldGarbageCollection">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.YoungGarbageCollection">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.OldGarbageCollection">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.G1GarbageCollection">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.GCPhasePause">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.GCPhasePauseLevel1">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.GCPhasePauseLevel2">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.GCPhasePauseLevel3">
+      <setting name="enabled" control="gc-enabled-all">false</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.GCPhasePauseLevel4">
+      <setting name="enabled" control="gc-enabled-all">false</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.GCPhaseConcurrent">
+      <setting name="enabled" control="gc-enabled-all">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.GCReferenceStatistics">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.PromotionFailed">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.EvacuationFailed">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.EvacuationInformation">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.G1MMU">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.G1EvacuationYoungStatistics">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.G1EvacuationOldStatistics">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.G1BasicIHOP">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.G1AdaptiveIHOP">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.PromoteObjectInNewPLAB">
+      <setting name="enabled" control="memory-profiling-enabled-medium">false</setting>
+    </event>
+
+    <event name="jdk.PromoteObjectOutsidePLAB">
+      <setting name="enabled" control="memory-profiling-enabled-medium">false</setting>
+    </event>
+
+    <event name="jdk.ConcurrentModeFailure">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.AllocationRequiringGC">
+      <setting name="enabled" control="gc-enabled-all">false</setting>
+      <setting name="stackTrace">true</setting>
+    </event>
+
+    <event name="jdk.TenuringDistribution">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.G1HeapRegionInformation">
+      <setting name="enabled" control="gc-enabled-all">false</setting>
+      <setting name="period">everyChunk</setting>
+    </event>
+
+    <event name="jdk.G1HeapRegionTypeChange">
+      <setting name="enabled" control="gc-enabled-all">false</setting>
+    </event>
+
+    <event name="jdk.OldObjectSample">
+      <setting name="enabled" control="memory-leak-detection-enabled">true</setting>
+      <setting name="stackTrace" control="memory-leak-detection-stack-trace">false</setting>
+      <setting name="cutoff" control="memory-leak-detection-cutoff">0 ns</setting>
+    </event>
+
+    <event name="jdk.CompilerConfiguration">
+      <setting name="enabled" control="compiler-enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.CompilerStatistics">
+      <setting name="enabled" control="compiler-enabled">true</setting>
+      <setting name="period">1000 ms</setting>
+    </event>
+
+    <event name="jdk.Compilation">
+      <setting name="enabled" control="compiler-enabled">true</setting>
+      <setting name="threshold" control="compiler-compilation-threshold">1000 ms</setting>
+    </event>
+
+    <event name="jdk.CompilerPhase">
+      <setting name="enabled" control="compiler-enabled">true</setting>
+      <setting name="threshold" control="compiler-phase-threshold">60 s</setting>
+    </event>
+
+    <event name="jdk.CompilationFailure">
+      <setting name="enabled" control="compiler-enabled-failure">false</setting>
+    </event>
+
+    <event name="jdk.CompilerInlining">
+      <setting name="enabled" control="compiler-enabled-failure">false</setting>
+    </event>
+
+    <event name="jdk.CodeSweeperConfiguration">
+      <setting name="enabled" control="compiler-enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.CodeSweeperStatistics">
+      <setting name="enabled" control="compiler-enabled">true</setting>
+      <setting name="period">everyChunk</setting>
+    </event>
+
+    <event name="jdk.SweepCodeCache">
+      <setting name="enabled" control="compiler-enabled">true</setting>
+      <setting name="threshold" control="compiler-sweeper-threshold">100 ms</setting>
+    </event>
+
+    <event name="jdk.CodeCacheConfiguration">
+      <setting name="enabled" control="compiler-enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.CodeCacheStatistics">
+      <setting name="enabled" control="compiler-enabled">true</setting>
+      <setting name="period">everyChunk</setting>
+    </event>
+
+    <event name="jdk.CodeCacheFull">
+      <setting name="enabled" control="compiler-enabled">true</setting>
+    </event>
+
+    <event name="jdk.OSInformation">
+      <setting name="enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.CPUInformation">
+      <setting name="enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.ThreadContextSwitchRate">
+      <setting name="enabled" control="compiler-enabled">true</setting>
+      <setting name="period">10 s</setting>
+    </event>
+
+    <event name="jdk.CPULoad">
+      <setting name="enabled">true</setting>
+      <setting name="period">1000 ms</setting>
+    </event>
+
+    <event name="jdk.ThreadCPULoad">
+      <setting name="enabled">true</setting>
+      <setting name="period">10 s</setting>
+    </event>
+
+    <event name="jdk.CPUTimeStampCounter">
+      <setting name="enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.SystemProcess">
+      <setting name="enabled">true</setting>
+      <setting name="period">endChunk</setting>
+    </event>
+
+    <event name="jdk.InitialEnvironmentVariable">
+      <setting name="enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.PhysicalMemory">
+      <setting name="enabled">true</setting>
+      <setting name="period">everyChunk</setting>
+    </event>
+
+    <event name="jdk.ObjectAllocationInNewTLAB">
+      <setting name="enabled" control="memory-profiling-enabled-medium">false</setting>
+      <setting name="stackTrace">true</setting>
+    </event>
+
+    <event name="jdk.ObjectAllocationOutsideTLAB">
+      <setting name="enabled" control="memory-profiling-enabled-medium">false</setting>
+      <setting name="stackTrace">true</setting>
+    </event>
+
+    <event name="jdk.NativeLibrary">
+      <setting name="enabled">true</setting>
+      <setting name="period">everyChunk</setting>
+    </event>
+
+    <event name="jdk.ModuleRequire">
+      <setting name="enabled">true</setting>
+      <setting name="period">endChunk</setting>
+    </event>
+
+    <event name="jdk.ModuleExport">
+      <setting name="enabled">true</setting>
+      <setting name="period">endChunk</setting>
+    </event>
+
+    <event name="jdk.FileForce">
+      <setting name="enabled">true</setting>
+      <setting name="stackTrace">true</setting>
+      <setting name="threshold" control="file-io-threshold">20 ms</setting>
+    </event>
+
+    <event name="jdk.FileRead">
+      <setting name="enabled">true</setting>
+      <setting name="stackTrace">true</setting>
+      <setting name="threshold" control="file-io-threshold">20 ms</setting>
+    </event>
+
+    <event name="jdk.FileWrite">
+      <setting name="enabled">true</setting>
+      <setting name="stackTrace">true</setting>
+      <setting name="threshold" control="file-io-threshold">20 ms</setting>
+    </event>
+
+    <event name="jdk.SocketRead">
+      <setting name="enabled">true</setting>
+      <setting name="stackTrace">true</setting>
+      <setting name="threshold" control="socket-io-threshold">20 ms</setting>
+    </event>
+
+    <event name="jdk.SocketWrite">
+      <setting name="enabled">true</setting>
+      <setting name="stackTrace">true</setting>
+      <setting name="threshold" control="socket-io-threshold">20 ms</setting>
+    </event>
+
+    <event name="jdk.JavaExceptionThrow">
+      <setting name="enabled" control="enable-exceptions">false</setting>
+      <setting name="stackTrace">true</setting>
+    </event>
+
+    <event name="jdk.JavaErrorThrow">
+      <setting name="enabled" control="enable-errors">true</setting>
+      <setting name="stackTrace">true</setting>
+    </event>
+
+    <event name="jdk.ExceptionStatistics">
+      <setting name="enabled">true</setting>
+      <setting name="period">1000 ms</setting>
+    </event>
+
+    <event name="jdk.ActiveRecording">
+      <setting name="enabled">true</setting>
+    </event>
+
+    <event name="jdk.ActiveSetting">
+      <setting name="enabled">true</setting>
+    </event>
+
+    <event name="jdk.DataLoss">
+      <setting name="enabled">true</setting>
+    </event>
+
+    <event name="jdk.DumpReason">
+      <setting name="enabled">true</setting>
+    </event>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    <!--
+        Contents of the control element is not read by the JVM, it's used
+        by Java Mission Control to change settings that carry the control attribute.
+    -->
+    <control>
+      <selection name="gc-level" default="detailed" label="Garbage Collector">
+        <option label="Off" name="off">off</option>
+        <option label="Normal" name="detailed">normal</option>
+        <option label="All" name="all">all</option>
+      </selection>
+
+      <condition name="gc-enabled-normal" true="true" false="false">
+        <or>
+          <test name="gc-level" operator="equal" value="normal"/>
+          <test name="gc-level" operator="equal" value="all"/>
+        </or>
+      </condition>
+
+      <condition name="gc-enabled-all" true="true" false="false">
+        <test name="gc-level" operator="equal" value="all"/>
+      </condition>
+
+      <selection name="memory-profiling" default="off" label="Memory Profiling">
+        <option label="Off" name="off">off</option>
+        <option label="Object Allocation and Promotion" name="medium">medium</option>
+        <option label="All, including Heap Statistics (May cause long full GCs)" name="all">all</option>
+      </selection>
+
+      <condition name="memory-profiling-enabled-medium" true="true" false="false">
+        <or>
+          <test name="memory-profiling" operator="equal" value="medium"/>
+          <test name="memory-profiling" operator="equal" value="all"/>
+        </or>
+      </condition>
+
+      <condition name="memory-profiling-enabled-all" true="true" false="false">
+        <test name="memory-profiling" operator="equal" value="all"/>
+      </condition>
+
+      <selection name="compiler-level" default="normal" label="Compiler">
+        <option label="Off" name="off">off</option>
+        <option label="Normal" name="normal">normal</option>
+        <option label="Detailed" name="detailed">detailed</option>
+        <option label="All" name="all">all</option>
+      </selection>
+
+      <condition name="compiler-enabled" true="false" false="true">
+        <test name="compiler-level" operator="equal" value="off"/>
+      </condition>
+
+      <condition name="compiler-enabled-failure" true="true" false="false">
+        <or>
+          <test name="compiler-level" operator="equal" value="detailed"/>
+          <test name="compiler-level" operator="equal" value="all"/>
+        </or>
+      </condition>
+
+      <condition name="compiler-sweeper-threshold" true="0 ms" false="100 ms">
+        <test name="compiler-level" operator="equal" value="all"/>
+      </condition>
+
+      <condition name="compiler-compilation-threshold" true="1000 ms">
+        <test name="compiler-level" operator="equal" value="normal"/>
+      </condition>
+
+      <condition name="compiler-compilation-threshold" true="100 ms">
+        <test name="compiler-level" operator="equal" value="detailed"/>
+      </condition>
+
+      <condition name="compiler-compilation-threshold" true="0 ms">
+        <test name="compiler-level" operator="equal" value="all"/>
+      </condition>
+
+      <condition name="compiler-phase-threshold" true="60 s">
+        <test name="compiler-level" operator="equal" value="normal"/>
+      </condition>
+
+      <condition name="compiler-phase-threshold" true="10 s">
+        <test name="compiler-level" operator="equal" value="detailed"/>
+      </condition>
+
+      <condition name="compiler-phase-threshold" true="0 s">
+        <test name="compiler-level" operator="equal" value="all"/>
+      </condition>
+
+      <selection name="method-sampling-interval" default="normal" label="Method Sampling">
+        <option label="Off" name="off">999 d</option>
+        <option label="Normal" name="normal">20 ms</option>
+        <option label="Maximum" name="maximum">10 ms</option>
+      </selection>
+
+      <condition name="method-sampling-enabled" true="false" false="true">
+        <test name="method-sampling-interval" operator="equal" value="999 d"/>
+      </condition>
+
+      <selection name="thread-dump-interval" default="normal" label="Thread Dump">
+        <option label="Off" name="off">999 d</option>
+        <option label="At least Once" name="normal">everyChunk</option>
+        <option label="Every 60 s" name="everyMinute">60 s</option>
+        <option label="Every 10 s" name="everyTenSecond">10 s</option>
+        <option label="Every 1 s" name="everySecond">1 s</option>
+      </selection>
+
+      <condition name="thread-dump-enabled" true="false" false="true">
+        <test name="thread-dump-interval" operator="equal" value="999 d"/>
+      </condition>
+
+      <selection name="exception-level" default="errors" label="Exceptions">
+        <option label="Off" name="off">off</option>
+        <option label="Errors Only" name="errors">errors</option>
+        <option label="All Exceptions, including Errors" name="all">all</option>
+      </selection>
+
+      <condition name="enable-errors" true="true" false="false">
+        <or>
+          <test name="exception-level" operator="equal" value="errors"/>
+          <test name="exception-level" operator="equal" value="all"/>
+        </or>
+      </condition>
+
+      <condition name="enable-exceptions" true="true" false="false">
+        <test name="exception-level" operator="equal" value="all"/>
+      </condition>
+
+      <selection name="memory-leak-detection" default="minimal" label="Memory Leak Detection">
+        <option label="Off" name="off">off</option>
+        <option label="Object Types" name="minimal">minimal</option>
+        <option label="Object Types + Allocation Stack Traces" name="medium">medium</option>
+        <option label="Object Types + Allocation Stack Traces + Path to GC Root" name="full">full</option>
+      </selection>
+
+      <condition name="memory-leak-detection-enabled" true="false" false="true">
+        <test name="memory-leak-detection" operator="equal" value="off"/>
+      </condition>
+
+      <condition name="memory-leak-detection-stack-trace" true="true" false="false">
+        <or>
+          <test name="memory-leak-detection" operator="equal" value="medium"/>
+          <test name="memory-leak-detection" operator="equal" value="full"/>
+        </or>
+      </condition>
+
+      <condition name="memory-leak-detection-cutoff" true="1 h" false="0 ns">
+        <test name="memory-leak-detection" operator="equal" value="full"/>
+      </condition>
+
+      <text name="synchronization-threshold" label="Synchronization Threshold" contentType="timespan" minimum="0 s">20 ms</text>
+
+      <text name="file-io-threshold" label="File I/O Threshold" contentType="timespan" minimum="0 s">20 ms</text>
+
+      <text name="socket-io-threshold" label="Socket I/O Threshold" contentType="timespan" minimum="0 s">20 ms</text>
+
+      <flag name="class-loading-enabled" label="Class Loading">false</flag>
+
+    </control>
+
+</configuration>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/conf/jfr/profile.jfc	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,803 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+     Recommended way to edit .jfc files is to use Java Mission Control,
+     see Window -> Flight Recorder Template Manager.
+-->
+
+<configuration version="2.0" label="Profiling" description="Low overhead configuration for profiling, typically around 2 % overhead." provider="Oracle">
+
+    <event name="jdk.ThreadAllocationStatistics">
+      <setting name="enabled">true</setting>
+      <setting name="period">everyChunk</setting>
+    </event>
+
+    <event name="jdk.ClassLoadingStatistics">
+      <setting name="enabled">true</setting>
+      <setting name="period">1000 ms</setting>
+    </event>
+
+    <event name="jdk.ClassLoaderStatistics">
+      <setting name="enabled">true</setting>
+      <setting name="period">everyChunk</setting>
+    </event>
+
+    <event name="jdk.JavaThreadStatistics">
+      <setting name="enabled">true</setting>
+      <setting name="period">1000 ms</setting>
+    </event>
+
+    <event name="jdk.ThreadStart">
+      <setting name="enabled">true</setting>
+    </event>
+
+    <event name="jdk.ThreadEnd">
+      <setting name="enabled">true</setting>
+    </event>
+
+    <event name="jdk.ThreadSleep">
+      <setting name="enabled">true</setting>
+      <setting name="stackTrace">true</setting>
+      <setting name="threshold" control="synchronization-threshold">10 ms</setting>
+    </event>
+
+    <event name="jdk.ThreadPark">
+      <setting name="enabled">true</setting>
+      <setting name="stackTrace">true</setting>
+      <setting name="threshold" control="synchronization-threshold">10 ms</setting>
+    </event>
+
+    <event name="jdk.JavaMonitorEnter">
+      <setting name="enabled">true</setting>
+      <setting name="stackTrace">true</setting>
+      <setting name="threshold" control="synchronization-threshold">10 ms</setting>
+    </event>
+
+    <event name="jdk.JavaMonitorWait">
+      <setting name="enabled">true</setting>
+      <setting name="stackTrace">true</setting>
+      <setting name="threshold" control="synchronization-threshold">10 ms</setting>
+    </event>
+
+    <event name="jdk.JavaMonitorInflate">
+      <setting name="enabled">true</setting>
+      <setting name="stackTrace">true</setting>
+      <setting name="threshold" control="synchronization-threshold">10 ms</setting>
+    </event>
+
+    <event name="jdk.BiasedLockRevocation">
+      <setting name="enabled">true</setting>
+      <setting name="stackTrace">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.BiasedLockSelfRevocation">
+      <setting name="enabled">true</setting>
+      <setting name="stackTrace">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.BiasedLockClassRevocation">
+      <setting name="enabled">true</setting>
+      <setting name="stackTrace">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.ReservedStackActivation">
+      <setting name="enabled">true</setting>
+      <setting name="stackTrace">true</setting>
+    </event>
+
+    <event name="jdk.ClassLoad">
+      <setting name="enabled" control="class-loading-enabled">false</setting>
+      <setting name="stackTrace">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.ClassDefine">
+      <setting name="enabled" control="class-loading-enabled">false</setting>
+      <setting name="stackTrace">true</setting>
+    </event>
+
+    <event name="jdk.ClassUnload">
+      <setting name="enabled" control="class-loading-enabled">false</setting>
+    </event>
+
+    <event name="jdk.JVMInformation">
+      <setting name="enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.InitialSystemProperty">
+      <setting name="enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.ExecutionSample">
+      <setting name="enabled" control="method-sampling-enabled">true</setting>
+      <setting name="period" control="method-sampling-interval">10 ms</setting>
+    </event>
+
+    <event name="jdk.NativeMethodSample">
+      <setting name="enabled" control="method-sampling-enabled">true</setting>
+      <setting name="period" control="method-sampling-interval">10 ms</setting>
+    </event>
+
+    <event name="jdk.SafepointBegin">
+      <setting name="enabled">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.SafepointStateSynchronization">
+      <setting name="enabled">false</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.SafepointWaitBlocked">
+      <setting name="enabled">false</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.SafepointCleanup">
+      <setting name="enabled">false</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.SafepointCleanupTask">
+      <setting name="enabled">false</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.SafepointEnd">
+      <setting name="enabled">false</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.ExecuteVMOperation">
+      <setting name="enabled">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.Shutdown">
+      <setting name="enabled">true</setting>
+      <setting name="stackTrace">true</setting>
+    </event>
+
+    <event name="jdk.ThreadDump">
+      <setting name="enabled" control="thread-dump-enabled">true</setting>
+      <setting name="period" control="thread-dump-interval">60 s</setting>
+    </event>
+
+    <event name="jdk.IntFlag">
+      <setting name="enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.UnsignedIntFlag">
+      <setting name="enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.LongFlag">
+      <setting name="enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.UnsignedLongFlag">
+      <setting name="enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.DoubleFlag">
+      <setting name="enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.BooleanFlag">
+      <setting name="enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.StringFlag">
+      <setting name="enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.IntFlagChanged">
+      <setting name="enabled">true</setting>
+    </event>
+
+    <event name="jdk.UnsignedIntFlagChanged">
+      <setting name="enabled">true</setting>
+    </event>
+
+    <event name="jdk.LongFlagChanged">
+      <setting name="enabled">true</setting>
+    </event>
+
+    <event name="jdk.UnsignedLongFlagChanged">
+      <setting name="enabled">true</setting>
+    </event>
+
+    <event name="jdk.DoubleFlagChanged">
+      <setting name="enabled">true</setting>
+    </event>
+
+    <event name="jdk.BooleanFlagChanged">
+      <setting name="enabled">true</setting>
+    </event>
+
+    <event name="jdk.StringFlagChanged">
+      <setting name="enabled">true</setting>
+    </event>
+
+    <event name="jdk.ObjectCount">
+      <setting name="enabled" control="memory-profiling-enabled-all">false</setting>
+      <setting name="period">everyChunk</setting>
+    </event>
+
+    <event name="jdk.GCConfiguration">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+      <setting name="period">everyChunk</setting>
+    </event>
+
+    <event name="jdk.GCHeapConfiguration">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.YoungGenerationConfiguration">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.GCTLABConfiguration">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.GCSurvivorConfiguration">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.ObjectCountAfterGC">
+      <setting name="enabled">false</setting>
+    </event>
+
+    <event name="jdk.GCHeapSummary">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.PSHeapSummary">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.G1HeapSummary">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.MetaspaceSummary">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.MetaspaceGCThreshold">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.MetaspaceAllocationFailure">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+      <setting name="stackTrace">true</setting>
+    </event>
+
+    <event name="jdk.MetaspaceOOM">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+      <setting name="stackTrace">true</setting>
+    </event>
+
+    <event name="jdk.MetaspaceChunkFreeListSummary">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.GarbageCollection">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.ParallelOldGarbageCollection">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.YoungGarbageCollection">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.OldGarbageCollection">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.G1GarbageCollection">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.GCPhasePause">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.GCPhasePauseLevel1">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.GCPhasePauseLevel2">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.GCPhasePauseLevel3">
+      <setting name="enabled" control="gc-enabled-all">false</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.GCPhasePauseLevel4">
+      <setting name="enabled" control="gc-enabled-all">false</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.GCPhaseConcurrent">
+      <setting name="enabled" control="gc-enabled-all">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+
+    <event name="jdk.GCReferenceStatistics">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.PromotionFailed">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.EvacuationFailed">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.EvacuationInformation">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.G1MMU">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.G1EvacuationYoungStatistics">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.G1EvacuationOldStatistics">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.G1BasicIHOP">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.G1AdaptiveIHOP">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.PromoteObjectInNewPLAB">
+      <setting name="enabled" control="memory-profiling-enabled-medium">true</setting>
+    </event>
+
+    <event name="jdk.PromoteObjectOutsidePLAB">
+      <setting name="enabled" control="memory-profiling-enabled-medium">true</setting>
+    </event>
+
+    <event name="jdk.ConcurrentModeFailure">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.AllocationRequiringGC">
+      <setting name="enabled" control="gc-enabled-all">false</setting>
+      <setting name="stackTrace">true</setting>
+    </event>
+
+    <event name="jdk.TenuringDistribution">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+    </event>
+
+    <event name="jdk.G1HeapRegionInformation">
+      <setting name="enabled" control="gc-enabled-all">false</setting>
+      <setting name="period">everyChunk</setting>
+    </event>
+
+    <event name="jdk.G1HeapRegionTypeChange">
+      <setting name="enabled" control="gc-enabled-all">false</setting>
+    </event>
+
+    <event name="jdk.OldObjectSample">
+      <setting name="enabled" control="memory-leak-detection-enabled">true</setting>
+      <setting name="stackTrace" control="memory-leak-detection-stack-trace">true</setting>
+      <setting name="cutoff" control="memory-leak-detection-cutoff">0 ns</setting>
+    </event>
+
+    <event name="jdk.CompilerConfiguration">
+      <setting name="enabled" control="compiler-enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.CompilerStatistics">
+      <setting name="enabled" control="compiler-enabled">true</setting>
+      <setting name="period">1000 ms</setting>
+    </event>
+
+    <event name="jdk.Compilation">
+      <setting name="enabled" control="compiler-enabled">true</setting>
+      <setting name="threshold" control="compiler-compilation-threshold">100 ms</setting>
+    </event>
+
+    <event name="jdk.CompilerPhase">
+      <setting name="enabled" control="compiler-enabled">true</setting>
+      <setting name="threshold" control="compiler-phase-threshold">10 s</setting>
+    </event>
+
+    <event name="jdk.CompilationFailure">
+      <setting name="enabled" control="compiler-enabled-failure">true</setting>
+    </event>
+
+    <event name="jdk.CompilerInlining">
+      <setting name="enabled" control="compiler-enabled-failure">false</setting>
+    </event>
+
+    <event name="jdk.CodeSweeperConfiguration">
+      <setting name="enabled" control="compiler-enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.CodeSweeperStatistics">
+      <setting name="enabled" control="compiler-enabled">true</setting>
+      <setting name="period">everyChunk</setting>
+    </event>
+
+    <event name="jdk.SweepCodeCache">
+      <setting name="enabled" control="compiler-enabled">true</setting>
+      <setting name="threshold" control="compiler-sweeper-threshold">100 ms</setting>
+    </event>
+
+    <event name="jdk.CodeCacheConfiguration">
+      <setting name="enabled" control="compiler-enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.CodeCacheStatistics">
+      <setting name="enabled" control="compiler-enabled">true</setting>
+      <setting name="period">everyChunk</setting>
+    </event>
+
+    <event name="jdk.CodeCacheFull">
+      <setting name="enabled" control="compiler-enabled">true</setting>
+    </event>
+
+    <event name="jdk.OSInformation">
+      <setting name="enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.CPUInformation">
+      <setting name="enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.ThreadContextSwitchRate">
+      <setting name="enabled" control="compiler-enabled">true</setting>
+      <setting name="period">10 s</setting>
+    </event>
+
+    <event name="jdk.CPULoad">
+      <setting name="enabled">true</setting>
+      <setting name="period">1000 ms</setting>
+    </event>
+
+    <event name="jdk.ThreadCPULoad">
+      <setting name="enabled">true</setting>
+      <setting name="period">10 s</setting>
+    </event>
+
+    <event name="jdk.CPUTimeStampCounter">
+      <setting name="enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.SystemProcess">
+      <setting name="enabled">true</setting>
+      <setting name="period">endChunk</setting>
+    </event>
+
+    <event name="jdk.InitialEnvironmentVariable">
+      <setting name="enabled">true</setting>
+      <setting name="period">beginChunk</setting>
+    </event>
+
+    <event name="jdk.PhysicalMemory">
+      <setting name="enabled">true</setting>
+      <setting name="period">everyChunk</setting>
+    </event>
+
+    <event name="jdk.ObjectAllocationInNewTLAB">
+      <setting name="enabled" control="memory-profiling-enabled-medium">true</setting>
+      <setting name="stackTrace">true</setting>
+    </event>
+
+    <event name="jdk.ObjectAllocationOutsideTLAB">
+      <setting name="enabled" control="memory-profiling-enabled-medium">true</setting>
+      <setting name="stackTrace">true</setting>
+    </event>
+
+    <event name="jdk.NativeLibrary">
+      <setting name="enabled">true</setting>
+      <setting name="period">everyChunk</setting>
+    </event>
+
+    <event name="jdk.ModuleRequire">
+      <setting name="enabled">true</setting>
+      <setting name="period">endChunk</setting>
+    </event>
+
+    <event name="jdk.ModuleExport">
+      <setting name="enabled">true</setting>
+      <setting name="period">endChunk</setting>
+    </event>
+
+    <event name="jdk.FileForce">
+      <setting name="enabled">true</setting>
+      <setting name="stackTrace">true</setting>
+      <setting name="threshold" control="file-io-threshold">10 ms</setting>
+    </event>
+
+    <event name="jdk.FileRead">
+      <setting name="enabled">true</setting>
+      <setting name="stackTrace">true</setting>
+      <setting name="threshold" control="file-io-threshold">10 ms</setting>
+    </event>
+
+    <event name="jdk.FileWrite">
+      <setting name="enabled">true</setting>
+      <setting name="stackTrace">true</setting>
+      <setting name="threshold" control="file-io-threshold">10 ms</setting>
+    </event>
+
+    <event name="jdk.SocketRead">
+      <setting name="enabled">true</setting>
+      <setting name="stackTrace">true</setting>
+      <setting name="threshold" control="socket-io-threshold">10 ms</setting>
+    </event>
+
+    <event name="jdk.SocketWrite">
+      <setting name="enabled">true</setting>
+      <setting name="stackTrace">true</setting>
+      <setting name="threshold" control="socket-io-threshold">10 ms</setting>
+    </event>
+
+    <event name="jdk.JavaExceptionThrow">
+      <setting name="enabled" control="enable-exceptions">false</setting>
+      <setting name="stackTrace">true</setting>
+    </event>
+
+    <event name="jdk.JavaErrorThrow">
+      <setting name="enabled" control="enable-errors">true</setting>
+      <setting name="stackTrace">true</setting>
+    </event>
+
+    <event name="jdk.ExceptionStatistics">
+      <setting name="enabled">true</setting>
+      <setting name="period">1000 ms</setting>
+    </event>
+
+    <event name="jdk.ActiveRecording">
+      <setting name="enabled">true</setting>
+    </event>
+
+    <event name="jdk.ActiveSetting">
+      <setting name="enabled">true</setting>
+    </event>
+
+    <event name="jdk.DataLoss">
+      <setting name="enabled">true</setting>
+    </event>
+
+    <event name="jdk.DumpReason">
+      <setting name="enabled">true</setting>
+    </event>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    <!--
+         Contents of the control element is not read by the JVM, it's used
+         by Java Mission Control to change settings that carry the control attribute.
+    -->
+    <control>
+
+      <selection name="gc-level" default="detailed" label="Garbage Collector">
+        <option label="Off" name="off">off</option>
+        <option label="Normal" name="detailed">normal</option>
+        <option label="All" name="all">all</option>
+      </selection>
+
+      <condition name="gc-enabled-normal" true="true" false="false">
+        <or>
+          <test name="gc-level" operator="equal" value="normal"/>
+          <test name="gc-level" operator="equal" value="all"/>
+        </or>
+      </condition>
+
+      <condition name="gc-enabled-all" true="true" false="false">
+        <test name="gc-level" operator="equal" value="all"/>
+      </condition>
+
+      <selection name="memory-profiling" default="medium" label="Memory Profiling">
+        <option label="Off" name="off">off</option>
+        <option label="Object Allocation and Promotion" name="medium">medium</option>
+        <option label="All, including Heap Statistics (May cause long full GCs)" name="all">all</option>
+      </selection>
+
+      <condition name="memory-profiling-enabled-medium" true="true" false="false">
+        <or>
+          <test name="memory-profiling" operator="equal" value="medium"/>
+          <test name="memory-profiling" operator="equal" value="all"/>
+        </or>
+      </condition>
+
+      <condition name="memory-profiling-enabled-all" true="true" false="false">
+        <test name="memory-profiling" operator="equal" value="all"/>
+      </condition>
+
+      <selection name="compiler-level" default="detailed" label="Compiler">
+        <option label="Off" name="off">off</option>
+        <option label="Normal" name="normal">normal</option>
+        <option label="Detailed" name="detailed">detailed</option>
+        <option label="All" name="all">all</option>
+      </selection>
+
+      <condition name="compiler-enabled" true="false" false="true">
+        <test name="compiler-level" operator="equal" value="off"/>
+      </condition>
+
+      <condition name="compiler-enabled-failure" true="true" false="false">
+        <or>
+          <test name="compiler-level" operator="equal" value="detailed"/>
+          <test name="compiler-level" operator="equal" value="all"/>
+        </or>
+      </condition>
+
+      <condition name="compiler-sweeper-threshold" true="0 ms" false="100 ms">
+        <test name="compiler-level" operator="equal" value="all"/>
+      </condition>
+
+      <condition name="compiler-compilation-threshold" true="1000 ms">
+        <test name="compiler-level" operator="equal" value="normal"/>
+      </condition>
+
+      <condition name="compiler-compilation-threshold" true="100 ms">
+        <test name="compiler-level" operator="equal" value="detailed"/>
+      </condition>
+
+      <condition name="compiler-compilation-threshold" true="0 ms">
+        <test name="compiler-level" operator="equal" value="all"/>
+      </condition>
+
+      <condition name="compiler-phase-threshold" true="60 s">
+        <test name="compiler-level" operator="equal" value="normal"/>
+      </condition>
+
+      <condition name="compiler-phase-threshold" true="10 s">
+        <test name="compiler-level" operator="equal" value="detailed"/>
+      </condition>
+
+      <condition name="compiler-phase-threshold" true="0 s">
+        <test name="compiler-level" operator="equal" value="all"/>
+      </condition>
+
+      <selection name="method-sampling-interval" default="maximum" label="Method Sampling">
+        <option label="Off" name="off">999 d</option>
+        <option label="Normal" name="normal">20 ms</option>
+        <option label="Maximum" name="maximum">10 ms</option>
+      </selection>
+
+      <condition name="method-sampling-enabled" true="false" false="true">
+        <test name="method-sampling-interval" operator="equal" value="999 d"/>
+      </condition>
+
+      <selection name="thread-dump-interval" default="everyMinute" label="Thread Dump">
+        <option label="Off" name="off">999 d</option>
+        <option label="At least Once" name="normal">everyChunk</option>
+        <option label="Every 60 s" name="everyMinute">60 s</option>
+        <option label="Every 10 s" name="everyTenSecond">10 s</option>
+        <option label="Every 1 s" name="everySecond">1 s</option>
+      </selection>
+
+      <condition name="thread-dump-enabled" true="false" false="true">
+        <test name="thread-dump-interval" operator="equal" value="999 d"/>
+      </condition>
+
+      <selection name="exception-level" default="errors" label="Exceptions">
+        <option label="Off" name="off">off</option>
+        <option label="Errors Only" name="errors">errors</option>
+        <option label="All Exceptions, including Errors" name="all">all</option>
+      </selection>
+
+      <condition name="enable-errors" true="true" false="false">
+        <or>
+          <test name="exception-level" operator="equal" value="errors"/>
+          <test name="exception-level" operator="equal" value="all"/>
+        </or>
+      </condition>
+
+      <condition name="enable-exceptions" true="true" false="false">
+        <test name="exception-level" operator="equal" value="all"/>
+      </condition>
+
+      <selection name="memory-leak-detection" default="medium" label="Memory Leak Detection">
+        <option label="Off" name="off">off</option>
+        <option label="Object Types" name="minimal">minimal</option>
+        <option label="Object Types + Allocation Stack Traces" name="medium">medium</option>
+        <option label="Object Types + Allocation Stack Traces + Path to GC Root" name="full">full</option>
+      </selection>
+
+      <condition name="memory-leak-detection-enabled" true="false" false="true">
+        <test name="memory-leak-detection" operator="equal" value="off"/>
+      </condition>
+
+      <condition name="memory-leak-detection-stack-trace" true="true" false="false">
+        <or>
+          <test name="memory-leak-detection" operator="equal" value="medium"/>
+          <test name="memory-leak-detection" operator="equal" value="full"/>
+        </or>
+      </condition>
+
+      <condition name="memory-leak-detection-cutoff" true="1 h" false="0 ns">
+        <test name="memory-leak-detection" operator="equal" value="full"/>
+      </condition>
+
+      <text name="synchronization-threshold" label="Synchronization Threshold" contentType="timespan" minimum="0 s">10 ms</text>
+
+      <text name="file-io-threshold" label="File I/O Threshold" contentType="timespan" minimum="0 s">10 ms</text>
+
+      <text name="socket-io-threshold" label="Socket I/O Threshold" contentType="timespan" minimum="0 s">10 ms</text>
+
+      <flag name="class-loading-enabled" label="Class Loading">false</flag>
+
+    </control>
+
+</configuration>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/ConfigurationInfo.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.management.jfr;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularData;
+
+import jdk.jfr.Configuration;
+
+
+/**
+ * Management representation of a {@code Configuration}.
+ *
+ * @see Configuration
+ *
+ * @since 9
+ */
+public final class ConfigurationInfo {
+    private final Map<String, String> settings;
+    private final String name;
+    private final String label;
+    private final String description;
+    private final String provider;
+    private final String contents;
+
+    ConfigurationInfo(Configuration config) {
+        this.settings = config.getSettings();
+        this.name = config.getName();
+        this.label = config.getLabel();
+        this.description = config.getDescription();
+        this.provider = config.getProvider();
+        this.contents = config.getContents();
+    }
+
+    private ConfigurationInfo(CompositeData cd) {
+        this.settings = createMap(cd.get("settings"));
+        this.name = (String) cd.get("name");
+        this.label = (String) cd.get("label");
+        this.description = (String) cd.get("description");
+        this.provider = (String) cd.get("provider");
+        this.contents = (String) cd.get("contents");
+    }
+
+    private static Map<String, String> createMap(Object o) {
+        if (o instanceof TabularData) {
+            TabularData td = (TabularData) o;
+            Collection<?> values = td.values();
+            Map<String, String> map = new HashMap<>(values.size());
+            for (Object value : td.values()) {
+                if (value instanceof CompositeData) {
+                    CompositeData cdRow = (CompositeData) value;
+                    Object k = cdRow.get("key");
+                    Object v = cdRow.get("value");
+                    if (k instanceof String && v instanceof String) {
+                        map.put((String) k, (String) v);
+                    }
+                }
+            }
+            return Collections.unmodifiableMap(map);
+        }
+        return Collections.emptyMap();
+    }
+
+    /**
+     * Returns the provider of the configuration associated with this
+     * {@code ConfigurationInfo} (for example, {@code "OpenJDK"}).
+     *
+     * @return the provider, or {@code null} if doesn't exist
+     *
+     * @see Configuration#getProvider()
+     */
+    public String getProvider() {
+        return provider;
+    }
+
+    /**
+     * Returns the textual representation of the configuration associated with
+     * this {@code ConfigurationInfo}, typically the contents of the
+     * configuration file that was used to create the configuration.
+     *
+     * @return contents, or {@code null} if doesn't exist
+     *
+     * @see Configuration#getContents()
+     */
+    public String getContents() {
+        return contents;
+    }
+
+    /**
+     * Returns the settings for the configuration associated with this
+     * {@code ConfigurationInfo}.
+     *
+     * @return a {@code Map} with settings, not {@code null}
+     *
+     * @see Configuration#getSettings()
+     */
+    public Map<String, String> getSettings() {
+        return settings;
+    }
+
+    /**
+     * Returns the human-readable name (for example, {@code "Continuous"} or {@code "Profiling"}) for
+     * the configuration associated with this {@code ConfigurationInfo}
+     *
+     * @return the label, or {@code null} if doesn't exist
+     *
+     * @see Configuration#getLabel()
+     */
+    public String getLabel() {
+        return label;
+    }
+
+    /**
+     * Returns the name of the configuration associated with this
+     * {@code ConfigurationInfo} (for example, {@code "default"}).
+     *
+     * @return the name, or {@code null} if doesn't exist
+     *
+     * @see Configuration#getLabel()
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Returns a short sentence that describes the configuration associated with
+     * this {@code ConfigurationInfo} (for example, {@code "Low
+     * overhead configuration safe for continuous use in production
+     * environments"}.
+     *
+     * @return the description, or {@code null} if doesn't exist
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * Returns a {@code ConfigurationInfo} object represented by the specified
+     * {@code CompositeData}.
+     * <p>
+     * The following table shows the required attributes that the specified {@code CompositeData} must contain.
+     * <blockquote>
+     * <table class="striped">
+     * <caption>Required names and types for CompositeData</caption>
+     * <thead>
+     * <tr>
+     * <th scope="col" style="text-align:left">Name</th>
+     * <th scope="col" style="text-align:left">Type</th>
+     * </tr>
+     * </thead>
+     * <tbody>
+     * <tr>
+     * <th scope="row">name</th>
+     * <td>{@code String}</td>
+     * </tr>
+     * <tr>
+     * <th scope="row">label</th>
+     * <td>{@code String}</td>
+     * </tr>
+     * <tr>
+     * <th scope="row">description</th>
+     * <td>{@code String}</td>
+     * </tr>
+     * <tr>
+     * <th scope="row">provider</th>
+     * <td>{@code String}</td>
+     * </tr>
+     * <tr>
+     * <th scope="row">contents</th>
+     * <td>{@code String}</td>
+     * </tr>
+     *
+     * <tr>
+     * <th scope="row">settings</th>
+     * <td>{@code javax.management.openmbean.TabularData} with a
+     * {@code TabularType} with the keys {@code "key"} and {@code "value"}, both
+     * of the {@code String} type</td>
+     * </tr>
+     * </tbody>
+     * </table>
+     * </blockquote>
+     *
+     * @param cd {@code CompositeData} representing a {@code ConfigurationInfo}
+     *
+     * @throws IllegalArgumentException if {@code cd} does not represent a
+     *         {@code ConfigurationInfo} with the required attributes
+     *
+     * @return a {@code ConfigurationInfo} object represented by {@code cd} if
+     *         {@code cd} is not {@code null}, {@code null} otherwise
+     */
+    public static ConfigurationInfo from(CompositeData cd) {
+        if (cd == null) {
+            return null;
+        }
+        return new ConfigurationInfo(cd);
+    }
+
+    /**
+     * Returns a description of the configuration that is associated with this
+     * {@code ConfigurationInfo}.
+     *
+     * @return the description of the configuration, not {@code null}
+     */
+    @Override
+    public String toString() {
+        Stringifier s = new Stringifier();
+        s.add("name", name);
+        s.add("label", label);
+        s.add("description", description);
+        s.add("provider", provider);
+        return s.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/EventTypeInfo.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.management.jfr;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.StringJoiner;
+
+import javax.management.openmbean.CompositeData;
+
+import jdk.jfr.Category;
+import jdk.jfr.EventType;
+import jdk.jfr.SettingDescriptor;
+
+/**
+ * Management representation of an {@code EventType}.
+ *
+ * @see EventType
+ *
+ * @since 9
+ */
+public final class EventTypeInfo {
+    private final List<SettingDescriptorInfo> settings;
+    private final long id;
+    private final String name;
+    private final String description;
+    private final String label;
+    private final List<String> categoryNames;
+
+    // package private
+    EventTypeInfo(EventType eventType) {
+        this.settings = creatingSettingDescriptorInfos(eventType);
+        this.id = eventType.getId();
+        this.name = eventType.getName();
+        this.label = eventType.getLabel();
+        this.description = eventType.getDescription();
+        this.categoryNames = eventType.getCategoryNames();
+    }
+
+    private EventTypeInfo(CompositeData cd) {
+        this.settings = createSettings(cd.get("settings"));
+        this.id = (long) cd.get("id");
+        this.name = (String) cd.get("name");
+        this.label = (String) cd.get("label");
+        this.description = (String) cd.get("description");
+        this.categoryNames = createCategoryNames((Object[]) cd.get("category"));
+    }
+
+    private static List<String> createCategoryNames(Object[] array) {
+        List<String> list = new ArrayList<>(array.length);
+        for (int i = 0; i < array.length; i++) {
+            list.add((String) array[i]);
+        }
+        return Collections.unmodifiableList(list);
+    }
+
+    private static List<SettingDescriptorInfo> creatingSettingDescriptorInfos(EventType eventType) {
+        List<SettingDescriptor> settings = eventType.getSettingDescriptors();
+        List<SettingDescriptorInfo> settingDescriptorInfos = new ArrayList<>(settings.size());
+        for (SettingDescriptor s : settings) {
+            settingDescriptorInfos.add(new SettingDescriptorInfo(s));
+        }
+        return Collections.unmodifiableList(settingDescriptorInfos);
+    }
+
+    private static List<SettingDescriptorInfo> createSettings(Object settings) {
+        if (settings != null && settings.getClass().isArray()) {
+            Object[] settingsArray = (Object[]) settings;
+            List<SettingDescriptorInfo> list = new ArrayList<>(settingsArray.length);
+            for (Object cd : settingsArray) {
+                if (cd instanceof CompositeData) {
+                    list.add(SettingDescriptorInfo.from((CompositeData) cd));
+                }
+            }
+            return Collections.unmodifiableList(list);
+        }
+        return Collections.emptyList();
+    }
+
+    /**
+     * Returns the label, a human-readable name, associated with the event type
+     * for this {@code EventTypeInfo} (for example, {@code "Garbage Collection"}).
+     *
+     * @return the label, or {@code null} if a label is not set
+     *
+     * @see EventType#getLabel()
+     */
+    public String getLabel() {
+        return label;
+    }
+
+    /**
+     *
+     * Returns the list of human-readable names that makes up the category for this
+     * {@code EventTypeInfo} (for example, {@code "Java Virtual Machine"} or {@code "Garbage Collector"}).
+     *
+     * @return an immutable list of category names, or a list with the name
+     *         {@code "Uncategorized"} if no category has been set
+     *
+     * @see EventType#getCategoryNames()
+     * @see Category
+     */
+    public List<String> getCategoryNames() {
+        return categoryNames;
+    }
+
+    /**
+     * Returns the unique ID for the event type associated with this
+     * {@code EventTypeInfo}, not guaranteed to be the same for different Java
+     * Virtual Machines (JVMs) instances.
+     *
+     * @return the ID
+     *
+     * @see EventType#getId()
+     */
+    public long getId() {
+        return id;
+    }
+
+    /**
+     * Returns the name for the event type associated with this
+     * {@code EventTypeInfo} (for example, {@code "jdk.GarbageCollection"}).
+     *
+     * @return the name, not {@code null}
+     *
+     * @see EventType#getName()
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Returns a short sentence or two describing the event type associated with
+     * this {@code EventTypeInfo}, for example
+     * {@code "Garbage collection performed by the JVM""}.
+     *
+     * @return the description, or {@code null} if no description exists
+     *
+     * @see EventType#getDescription()
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * Returns settings for the event type associated with this
+     * {@code EventTypeInfo}.
+     *
+     * @return the settings, not {@code null}
+     *
+     * @see EventType#getSettingDescriptors()
+     */
+    public List<SettingDescriptorInfo> getSettingDescriptors() {
+        return settings;
+    }
+
+    /**
+     * Returns a description of this {@code EventTypeInfo}.
+     *
+     * @return description, not {@code null}
+     */
+    @Override
+    public String toString() {
+        Stringifier s = new Stringifier();
+        s.add("id", id);
+        s.add("name", name);
+        s.add("label", label);
+        s.add("description", description);
+        StringJoiner sj = new StringJoiner(", ", "{", "}");
+        for (String categoryName : categoryNames) {
+            sj.add(categoryName);
+        }
+        s.add("category", sj.toString());
+        return s.toString();
+    }
+
+    /**
+     * Returns an {@code EventType} represented by the specified
+     * {@code CompositeData}
+     * <p>
+     * The supplied {@code CompositeData} must have the following item names and
+     * item types to be valid. <blockquote>
+     * <table class="striped">
+     * <caption>The name and type the specified CompositeData must contain</caption>
+     * <thead>
+     * <tr>
+     * <th scope="col" style="text-align:left">Name</th>
+     * <th scope="col" style="text-align:left">Type</th>
+     * </tr>
+     * </thead>
+     * <tbody>
+     * <tr>
+     * <th scope="row">id</th>
+     * <td>{@code Long}</td>
+     * </tr>
+     * <tr>
+     * <th scope="row">name</th>
+     * <td>{@code String}</td>
+     * </tr>
+     * <tr>
+     * <th scope="row">label</th>
+     * <td>{@code String}</td>
+     * </tr>
+     * <tr>
+     * <th scope="row">description</th>
+     * <td>{@code String}</td>
+     * </tr>
+     * <tr>
+     * <th scope="row">category</th>
+     * <td><code>ArrayType(1, SimpleType.STRING)</code></td>
+     * </tr>
+     * <tr>
+     * <th scope="row">settings</th>
+     * <td>{@code javax.management.openmbean.CompositeData[]} whose element type
+     * is the mapped type for {@link SettingDescriptorInfo} as specified in the
+     * {@link SettingDescriptorInfo#from} method.</td>
+     *
+     * </tr>
+     * </tbody>
+     * </table>
+     * </blockquote>
+     *
+     * @param cd {@code CompositeData} representing the {@code EventTypeInfo} to
+     *        return
+     *
+     * @throws IllegalArgumentException if {@code cd} does not represent a valid
+     *         {@code EventTypeInfo}
+     *
+     * @return an {@code EventTypeInfo}, or {@code null} if {@code cd} is
+     *         {@code null}
+     */
+    public static EventTypeInfo from(CompositeData cd) {
+        if (cd == null) {
+            return null;
+        }
+        return new EventTypeInfo(cd);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/FlightRecorderMXBean.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,640 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.management.jfr;
+
+import java.io.IOException;
+import java.lang.management.PlatformManagedObject;
+import java.time.Instant;
+import java.util.List;
+import java.util.Map;
+
+import jdk.jfr.Configuration;
+import jdk.jfr.EventType;
+import jdk.jfr.Recording;
+
+/**
+ * Management interface for controlling Flight Recorder.
+ * <p>
+ * The object name for identifying the MXBean in the platform MBean
+ * server is: <blockquote> {@code jdk.management.jfr:type=FlightRecorder} </blockquote>
+ * <p>
+ * Flight Recorder can be configured in the following ways:
+ * <ul>
+ * <li><b>Recording options</b><br>
+ * Specify how long a recording should last, and where and when data
+ * should be dumped.</li>
+ * <li><b>Settings</b><br>
+ * Specify which events should be enabled and what kind information each
+ * event should capture.</li>
+ * <li><b>Configurations</b><br>
+ * Predefined sets of settings, typically derived from a settings file,
+ * that specify the configuration of multiple events simultaneously.</li>
+ * </ul>
+ * <p>
+ * See the package {@code jdk.jfr} documentation for descriptions of the settings
+ * syntax and the {@link ConfigurationInfo} class documentation for configuration information.
+ *
+ * <h3>Recording options</h3>
+ * <p>
+ * The following table shows the options names to use with {@link #setRecordingOptions(long, Map)}
+ * and {@link #getRecordingOptions(long)}.
+ *
+ * <table class="striped">
+ * <caption>Recording options</caption>
+ * <thead>
+ * <tr>
+ * <th scope="col">Name</th>
+ * <th scope="col">Descripion</th>
+ * <th scope="col">Default value</th>
+ * <th scope="col">Format</th>
+ * <th scope="col">Example values</th>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr>
+ * <th scope="row">{@code name}</th>
+ * <td>Sets a human-readable recording name</td>
+ * <td>String representation of the recording id</td>
+ * <td>{@code String}</td>
+ * <td>{@code "My Recording"}, <br>
+ * {@code "profiling"}</td>
+ * </tr>
+ * <tr>
+ * <th scope="row">{@code maxAge}</th>
+ * <td>Specify the length of time that the data is kept in the disk repository until the
+ * oldest data may be deleted. Only works if {@code disk=true}, otherwise
+ * this parameter is ignored.</td>
+ * <td>{@code "0"} (no limit)</td>
+ * <td>{@code "0"} if no limit is imposed, otherwise a string
+ * representation of a positive {@code Long} value followed by an empty space
+ * and one of the following units,<br>
+ * <br>
+ * {@code "ns"} (nanoseconds)<br>
+ * {@code "us"} (microseconds)<br>
+ * {@code "ms"} (milliseconds)<br>
+ * {@code "s"} (seconds)<br>
+ * {@code "m"} (minutes)<br>
+ * {@code "h"} (hours)<br>
+ * {@code "d"} (days)<br>
+ * </td>
+ * <td>{@code "2 h"},<br>
+ * {@code "24 h"},<br>
+ * {@code "2 d"},<br>
+ * {@code "0"}</td>
+ * </tr>
+ * <tr>
+ * <th scope="row">{@code maxSize}</th>
+ * <td>Specifies the size, measured in bytes, at which data is kept in disk
+ * repository. Only works if
+ * {@code disk=true}, otherwise this parameter is ignored.</td>
+ * <td>{@code "0"} (no limit)</td>
+ * <td>String representation of a {@code Long} value, must be positive</td>
+ * <td>{@code "0"}, <br>
+ * {@code "1000000000"}</td>
+ * </tr>
+ * <tr>
+ * <th scope="row">{@code dumpOnExit}</th>
+ * <td>Dumps recording data to disk on Java Virtual Machine (JVM) exit</td>
+ * <td>{@code "false"}</td>
+ * <td>String representation of a {@code Boolean} value, {@code "true"} or
+ * {@code "false"}</td>
+ * <td>{@code "true"},<br>
+ * {@code "false"}</td>
+ * </tr>
+ * <tr>
+ * <th scope="row">{@code destination}</th>
+ * <td>Specifies the path where recording data is written when the recording stops.</td>
+ * <td>{@code "false"}</td>
+ * <td>See {@code Paths#getPath} for format. <br>
+ * If this method is invoked from another process, the data is written on the
+ * machine where the target JVM is running. If destination is a relative path, it
+ * is relative to the working directory where the target JVM was started.}</td>
+ * <td>{@code "c:\recording\recotding.jfr"},<br>
+ * {@code "/recordings/recording.jfr"}, {@code "recording.jfr"}</td>
+ * </tr>
+ * <tr>
+ * <th scope="row">{@code disk}</th>
+ * <td>Stores recorded data as it is recorded</td>
+ * <td><code>"false"</code></td>
+ * <td>String representation of a {@code Boolean} value, {@code "true"} or
+ * {@code "false"}</td>
+ * <td>{@code "true"},<br>
+ * {@code "false"}</td>
+ * <tr>
+ * <th scope="row">{@code duration}</th>
+ * <td>Sets how long the recording should be running</td>
+ * <td>{@code "0"} (no limit, continuous)</td>
+ * <td>{@code "0"} if no limit should be imposed, otherwise a string
+ * representation of a positive {@code Long} followed by an empty space and one
+ * of the following units:<br>
+ * <br>
+ * {@code "ns"} (nanoseconds)<br>
+ * {@code "us"} (microseconds)<br>
+ * {@code "ms"} (milliseconds)<br>
+ * {@code "s"} (seconds)<br>
+ * {@code "m"} (minutes)<br>
+ * {@code "h"} (hours)<br>
+ * {@code "d"} (days)<br>
+ * </td>
+ * <td>{@code "60 s"},<br>
+ * {@code "10 m"},<br>
+ * {@code "4 h"},<br>
+ * {@code "0"}</td>
+ * </tr>
+ * </tbody>
+ * </table>
+ *
+ * @since 9
+ */
+public interface FlightRecorderMXBean extends PlatformManagedObject {
+    /**
+     * String representation of the {@code ObjectName} for the
+     * {@code FlightRecorderMXBean}.
+     */
+    public static final String MXBEAN_NAME = "jdk.management.jfr:type=FlightRecorder";
+
+    /**
+     * Creates a recording, but doesn't start it.
+     *
+     * @return a unique ID that can be used to start, stop, close and
+     *         configure the recording
+     *
+     * @throws IllegalStateException if Flight Recorder can't be created (for
+     *         example, if the Java Virtual Machine (JVM) lacks Flight Recorder
+     *         support, or if the file repository can't be created or accessed)
+     *
+     * @throws java.lang.SecurityException if a security manager exists and the
+     *         caller does not have {@code ManagementPermission("control")}
+     *
+     * @see Recording
+     */
+    long newRecording() throws IllegalStateException, SecurityException;
+
+    /**
+     * Creates a snapshot recording of all available recorded data.
+     * <p>
+     * A snapshot is a synthesized recording in a stopped state. If no data is
+     * available, a recording with size {@code 0} is returned.
+     * <p>
+     * A snapshot provides stable access to data for later operations (for example,
+     * operations to change the time interval or to reduce the data size).
+     * <p>
+     * The caller must close the recording when access to the data is no longer
+     * needed.
+     *
+     * @return a snapshot of all available recording data, not {@code null}
+     *
+     * @throws java.lang.SecurityException if a security manager exists and the
+     *         caller does not have {@code ManagementPermission("control")}
+     *
+     * @return a unique ID that can be used for reading recording data.
+     *
+     * @see Recording
+     */
+    public long takeSnapshot();
+
+    /**
+     * Creates a copy of an existing recording, useful for extracting parts of a
+     * recording.
+     * <p>
+     * The cloned recording contains the same recording data as the
+     * original, but it has a new ID and a name prefixed with
+     * {@code "Clone of recording"}. If the original recording is running, then
+     * the clone is also running.
+     *
+     * @param recordingId the recording ID of the recording to create a clone
+     *        from
+     *
+     * @param stop if the newly created clone is stopped before
+     *        returning.
+     *
+     * @return a unique ID that can be used to start, stop,
+     *         close and configure the recording
+     *
+     * @throws IllegalArgumentException if a recording with the specified ID
+     *         doesn't exist
+     *
+     * @throws java.lang.SecurityException if a security manager exists and the
+     *         caller does not have {@code ManagementPermission("control")}
+     *
+     * @see Recording
+     */
+    long cloneRecording(long recordingId, boolean stop) throws IllegalArgumentException, SecurityException;
+
+    /**
+     * Starts the recording with the specified ID.
+     * <p>
+     * A recording that is stopped can't be restarted.
+     *
+     * @param recordingId ID of the recording to start
+     *
+     * @throws IllegalArgumentException if a recording with the specified ID
+     *         doesn't exist
+     *
+     * @throws java.lang.SecurityException if a security manager exists and the
+     *         caller does not have {@code ManagementPermission("control")}
+     *
+     * @see Recording
+     */
+    void startRecording(long recordingId) throws IllegalStateException, SecurityException;
+
+    /**
+     * Stops the running recording with the specified ID.
+     *
+     * @param recordingId the ID of the recording to stop
+     *
+     * @return {@code true} if the recording is stopped, {@code false}
+     *         otherwise
+     *
+     * @throws IllegalArgumentException if a recording with the specified ID
+     *         doesn't exist
+     * @throws IllegalStateException if the recording is not running
+     * @throws java.lang.SecurityException if a security manager exists and the
+     *         caller does not have {@code ManagementPermission("control")}
+     *
+     * @see #newRecording()
+     */
+    boolean stopRecording(long recordingId) throws IllegalArgumentException, IllegalStateException, SecurityException;
+
+    /**
+     * Closes the recording with the specified ID and releases any system
+     * resources that are associated with the recording.
+     * <p>
+     * If the recording is already closed, invoking this method has no effect.
+     *
+     * @param recordingId the ID of the recording to close
+     *
+     * @throws IllegalArgumentException if a recording with the specified ID
+     *         doesn't exist
+     * @throws IOException if an I/O error occurs
+     * @throws java.lang.SecurityException if a security manager exists and the
+     *         caller does not have {@code ManagementPermission("control")}
+     *
+     * @see #newRecording()
+     */
+    void closeRecording(long recordingId) throws IOException;
+
+    /**
+     * Opens a data stream for the recording with the specified ID, or {@code 0}
+     * to get data irrespective of recording.
+     * <table class="striped">
+     * <caption>Recording stream options</caption>
+     * <thead>
+     * <tr>
+     * <th scope="col">Name</th>
+     * <th scope="col">Descripion</th>
+     * <th scope="col">Default value</th>
+     * <th scope="col">Format</th>
+     * <th scope="col">Example values</th>
+     * </tr>
+     * </thead>
+     * <tbody>
+     * <tr>
+     * <th scope="row">{@code startTime}</th>
+     * <td>Specifies the point in time to start a recording stream. Due to
+     * how data is stored, some events that start or end prior to the
+     * start time may be included.</td>
+     * <td>{@code Instant.MIN_VALUE.toString()}</td>
+     * <td>ISO-8601. See {@link Instant#toString}<br>
+     * or milliseconds since epoch</td>
+     * <td>{@code "2015-11-03T00:00"},<br>
+     * {@code "1446508800000"}</td>
+     * </tr>
+     * <tr>
+     * <th scope="row">{@code endTime}</th>
+     * <td>Specifies the point in time to end a recording stream. Due to how
+     * data is stored, some events that start or end after the end time may
+     * be included.</td>
+     * <td>{@code Instant.MAX_VALUE.toString()}</td>
+     * <td>ISO-8601. See {@link Instant#toString} <br>
+     * or milliseconds since epoch</td>
+     * <td>{@code "2015-11-03T01:00"}, <br>
+     * {@code "1446512400000"}</td>
+     * </tr>
+     *
+     * <tr>
+     * <th scope="row">{@code blockSize}</th>
+     * <td>Specifies the maximum number of bytes to read with a call to {@code readStream}
+     * </td>
+     * <td>{@code "50000"}</td>
+     * <td>A positive {@code long} value. <br>
+     * <br>
+     * Setting {@code blockSize} to a very high value may result in
+     * {@link OutOfMemoryError} or an {@link IllegalArgumentException}, if the
+     * Java Virtual Machine (JVM) deems the value too large to handle.</td>
+     * <td>{@code "50000"},<br>
+     * {@code "1000000"},<br>
+     * </tr>
+     * </tbody>
+     * </table>
+     * If an option is omitted from the map the default value is used.
+     * <p>
+     * The recording with the specified ID must be stopped before a stream can
+     * be opened. This restriction might be lifted in future releases.
+     *
+     * @param recordingId ID of the recording to open the stream for
+     *
+     * @param streamOptions a map that contains the options that controls the amount of data
+     *        and how it is read, or {@code null} to get all data for the
+     *        recording with the default block size
+     *
+     * @return a unique ID for the stream.
+     *
+     * @throws IllegalArgumentException if a recording with the iD doesn't
+     *         exist, or if {@code options} contains invalid values
+     *
+     * @throws IOException if the recording is closed, an I/O error occurs, or
+     *         no data is available for the specified recording or
+     *         interval
+     *
+     * @throws java.lang.SecurityException if a security manager exists and the
+     *         caller does not have {@code ManagementPermission("control")}
+     */
+    long openStream(long recordingId, Map<String, String> streamOptions) throws IOException;
+
+    /**
+     * Closes the recording stream with the specified ID and releases any system
+     * resources that are associated with the stream.
+     * <p>
+     * If the stream is already closed, invoking this method has no effect.
+     *
+     * @param streamId the ID of the stream
+     *
+     * @throws IllegalArgumentException if a stream with the specified ID doesn't
+     *         exist
+     * @throws IOException if an I/O error occurs while trying to close the stream
+     * @throws java.lang.SecurityException if a security manager exists and the
+     *         caller does not have {@code ManagementPermission("control")}
+     *
+     * @see #openStream(long, Map)
+     */
+    void closeStream(long streamId) throws IOException;
+
+    /**
+     * Reads a portion of data from the stream with the specified ID, or returns
+     * {@code null} if no more data is available.
+     * <p>
+     * To read all data for a recording, invoke this method repeatedly until
+     * {@code null} is returned.
+     *
+     * @param streamId the ID of the stream
+     *
+     * @return byte array that contains recording data, or {@code null} when no more
+     *         data is available
+     * @throws IOException if the stream is closed, or an I/O error occurred while
+     *         trying to read the stream
+     * @throws IllegalArgumentException if no recording with the stream ID exists
+     * @throws java.lang.SecurityException if a security manager exists and the
+     *         caller does not have {@code ManagementPermission("monitor")}
+     */
+    byte[] readStream(long streamId) throws IOException;
+
+    /**
+     * Returns a map that contains the options for the recording with the
+     * specified ID (for example, the destination file or time span to keep
+     * recorded data).
+     * <p>
+     * See {@link FlightRecorderMXBean} for available option names.
+     *
+     * @param recordingId the ID of the recording to get options for
+     *
+     * @return a map describing the recording options, not {@code null}
+     *
+     * @throws IllegalArgumentException if no recording with the
+     *         specified ID exists
+     * @throws java.lang.SecurityException if a security manager exists and the
+     *         caller does not have {@code ManagementPermission("monitor")}
+     *
+     */
+    Map<String, String> getRecordingOptions(long recordingId) throws IllegalArgumentException;
+
+    /**
+     * Returns a {@code Map} that contains the settings for the recording with the specified ID,
+     * (for example, the event thresholds)
+     * <p>
+     * If multiple recordings are running at the same time, more data could be
+     * recorded than what is specified in the {@code Map} object.
+     * <p>
+     * The name in the {@code Map} is the event name and the setting name separated by
+     * {@code "#"} (for example, {@code "jdk.VMInfo#period"}). The value
+     * is a textual representation of the settings value (for example,
+     * {@code "60 s"}).
+     *
+     * @param recordingId the ID of the recordings to get settings for
+     *
+     * @return a map that describes the recording settings, not {@code null}
+     *
+     * @throws IllegalArgumentException if no recording with the specified ID exists
+     * @throws java.lang.SecurityException if a security manager exists and the
+     *         caller does not have {@code ManagementPermission("monitor")}
+     */
+    Map<String, String> getRecordingSettings(long recordingId) throws IllegalArgumentException;
+
+    /**
+     * Sets a configuration as a string representation for the recording with the
+     * specified ID.
+     *
+     * @param recordingId ID of the recording
+     * @param contents a string representation of the configuration file to use,
+     *        not {@code null}
+     * @throws IllegalArgumentException if no recording with the
+     *         specified ID exists or if the configuration could not be parsed.
+     * @throws java.lang.SecurityException if a security manager exists and the
+     *         caller does not have {@code ManagementPermission("control")}
+     *
+     * @see Configuration#getContents()
+     */
+    void setConfiguration(long recordingId, String contents) throws IllegalArgumentException;
+
+    /**
+     * Sets a predefined configuration for the recording with the specified ID.
+     *
+     * @param recordingId ID of the recording to set the configuration for
+     * @param configurationName the name of the configuration (for example,
+     *        {@code "profile"} or {@code "default"}), not {@code null}
+     * @throws IllegalArgumentException if no recording with the
+     *         specified ID exists
+     * @throws java.lang.SecurityException if a security manager exists and the
+     *         caller does not have {@code ManagementPermission("control")}
+     *
+     * @see #getConfigurations()
+     */
+    void setPredefinedConfiguration(long recordingId, String configurationName) throws IllegalArgumentException;
+
+    /**
+     * Sets and replaces all previous settings for the specified recording.
+     * <p>
+     * A setting consists of a name/value pair, where <em>name</em> specifies the
+     * event and setting to configure, and the <em>value</em> specifies what to set
+     * it to.
+     * <p>
+     * The name can be formed in the following ways:
+     * <p>
+     * {@code
+     *   <event-name> + "#" + <setting-name>
+     * }
+     * <p>
+     * or
+     * <p>
+     * {@code
+     *   <event-id> + "#" + <setting-name>
+     * }
+     * <p>
+     * For example, to set the sample interval of the CPU Load event to once every
+     * second, use the name {@code "jdk.CPULoad#period"} and the value
+     * {@code "1 s"}. If multiple events use the same name, for example if an event
+     * class is loaded in multiple class loaders, and differentiation is needed
+     * between them, then the name is {@code "56#period"}. The ID for an event is
+     * obtained by invoking {@link jdk.jfr.EventType#getId()} method and is valid
+     * for the Java Virtual Machine (JVM) instance that the event is registered in.
+     * <p>
+     * A list of available event names is retrieved by invoking
+     * {@link jdk.jfr.FlightRecorder#getEventTypes()} and
+     * {@link jdk.jfr.EventType#getName()}. A list of available settings for an
+     * event type is obtained by invoking
+     * {@link jdk.jfr.EventType#getSettingDescriptors()} and
+     * {@link jdk.jfr.ValueDescriptor#getName()}.
+     * <p>
+     *
+     * @param recordingId ID of the recording
+     *
+     * @param settings name value map of the settings to set, not {@code null}
+     *
+     * @throws IllegalArgumentException if no recording with the specified ID exists
+     * @throws java.lang.SecurityException if a security manager exists and the
+     *         caller does not have {@code ManagementPermission("control")}
+     *
+     * @see Recording#getId()
+     */
+    void setRecordingSettings(long recordingId, Map<String, String> settings) throws IllegalArgumentException;
+
+    /**
+     * Configures the recording options (for example, destination file and time span
+     * to keep data).
+     * <p>
+     * See {@link FlightRecorderMXBean} for a description of the options and values
+     * that can be used. Setting a value to {@code null} restores the value to the
+     * default value.
+     *
+     * @param recordingId the ID of the recording to set options for
+     *
+     * @param options name/value map of the settings to set, not {@code null}
+     *
+     * @throws IllegalArgumentException if no recording with the specified ID exists
+     * @throws java.lang.SecurityException if a security manager exists, and the
+     *         caller does not have {@code ManagementPermission("control")} or an
+     *         option contains a file that the caller does not have permission to
+     *         operate on.
+     * @see Recording#getId()
+     */
+    void setRecordingOptions(long recordingId, Map<String, String> options) throws IllegalArgumentException;
+
+    /**
+     * Returns the list of the available recordings, not necessarily running.
+     * <p>
+     * <b>MBeanServer access</b>:<br>
+     * The mapped type of {@code RecordingInfo} is {@code CompositeData} with
+     * attributes as specified in the {@link RecordingInfo#from
+     * RecordingInfo.from} method.
+     *
+     * @return list of recordings, not {@code null}
+     *
+     * @throws java.lang.SecurityException if a security manager exists and the
+     *         caller does not have {@code  ManagementPermission("monitor")}
+     *
+     * @see RecordingInfo
+     * @see Recording
+     */
+    List<RecordingInfo> getRecordings();
+
+    /**
+     * Returns the list of predefined configurations for this Java Virtual Machine (JVM).
+     * <p>
+     * <b>MBeanServer access</b>:<br>
+     * The mapped type of {@code ConfigurationInfo} is {@code CompositeData}
+     * with attributes as specified in the {@link ConfigurationInfo#from
+     * ConfigurationInfo.from} method.
+     *
+     * @return the list of predefined configurations, not {@code null}
+     *
+     * @throws java.lang.SecurityException if a security manager exists and the
+     *         caller does not have {@code ManagementPermission("monitor")}
+     *
+     * @see ConfigurationInfo
+     * @see Configuration
+     */
+    List<ConfigurationInfo> getConfigurations();
+
+    /**
+     * Returns the list of currently registered event types.
+     * <p>
+     * <b>MBeanServer access</b>:<br>
+     * The mapped type of {@code EventTypeInfo} is {@code CompositeData} with
+     * attributes as specified in the {@link EventTypeInfo#from
+     * EventTypeInfo.from} method.
+     *
+     * @return the list of registered event types, not {@code null}
+     *
+     * @throws java.lang.SecurityException if a security manager exists and the
+     *         caller does not have {@code ManagementPermission("monitor")}
+     *
+     * @see EventTypeInfo
+     * @see EventType
+     */
+    List<EventTypeInfo> getEventTypes();
+
+    /**
+     * Writes recording data to the specified file.
+     * <p>
+     * If this method is invoked remotely from another process, the data is written
+     * to a file named {@code outputFile} on the machine where the target Java
+     * Virtual Machine (JVM) is running. If the file location is a relative path, it
+     * is relative to the working directory where the target JVM was started.
+     *
+     * @param recordingId the ID of the recording to dump data for
+     *
+     * @param outputFile the system-dependent file name where data is written, not
+     *        {@code null}
+     *
+     * @throws IOException if the recording can't be dumped due to an I/O error (for
+     *         example, an invalid path)
+     *
+     * @throws IllegalArgumentException if a recording with the specified ID doesn't
+     *         exist
+     *
+     * @throws IllegalStateException if the recording is not yet started or if it is
+     *         already closed
+     *
+     * @throws SecurityException if a security manager exists and its
+     *         {@code SecurityManager.checkWrite(java.lang.String)} method denies
+     *         write access to the named file or the caller does not have
+     *         {@code ManagmentPermission("control")}
+     *
+     * @see java.nio.file.Path#toString()
+     * @see Recording#dump(java.nio.file.Path)
+     */
+    void copyTo(long recordingId, String outputFile) throws IOException, SecurityException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/FlightRecorderMXBeanImpl.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,440 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.management.jfr;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.nio.file.Paths;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.text.ParseException;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+import javax.management.AttributeChangeNotification;
+import javax.management.AttributeNotFoundException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanNotificationInfo;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationEmitter;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+import javax.management.StandardEmitterMBean;
+
+import jdk.jfr.Configuration;
+import jdk.jfr.EventType;
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.FlightRecorderListener;
+import jdk.jfr.FlightRecorderPermission;
+import jdk.jfr.Recording;
+import jdk.jfr.RecordingState;
+import jdk.jfr.internal.management.ManagementSupport;
+
+// Instantiated by service provider
+final class FlightRecorderMXBeanImpl extends StandardEmitterMBean implements FlightRecorderMXBean, NotificationEmitter {
+
+    final class MXBeanListener implements FlightRecorderListener {
+        private final NotificationListener listener;
+        private final NotificationFilter filter;
+        private final Object handback;
+        private final AccessControlContext context;
+
+        public MXBeanListener(NotificationListener listener, NotificationFilter filter, Object handback) {
+            this.context = AccessController.getContext();
+            this.listener = listener;
+            this.filter = filter;
+            this.handback = handback;
+        }
+
+        public void recordingStateChanged(Recording recording) {
+            AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                @Override
+                public Void run() {
+                    sendNotification(createNotication(recording));
+                    return null;
+                }
+            }, context);
+        }
+    }
+
+    private static final String ATTRIBUTE_RECORDINGS = "Recordings";
+    private static final String OPTION_MAX_SIZE = "maxSize";
+    private static final String OPTION_MAX_AGE = "maxAge";
+    private static final String OPTION_NAME = "name";
+    private static final String OPTION_DISK = "disk";
+    private static final String OPTION_DUMP_ON_EXIT = "dumpOnExit";
+    private static final String OPTION_DURATION = "duration";
+    private static final List<String> OPTIONS = Arrays.asList(new String[] { OPTION_DUMP_ON_EXIT, OPTION_DURATION, OPTION_NAME, OPTION_MAX_AGE, OPTION_MAX_SIZE, OPTION_DISK, });
+    private final StreamManager streamHandler = new StreamManager();
+    private final Map<Long, Object> changes = new ConcurrentHashMap<>();
+    private final AtomicLong sequenceNumber = new AtomicLong();
+    private final List<MXBeanListener> listeners = new CopyOnWriteArrayList<>();
+    private FlightRecorder recorder;
+
+    FlightRecorderMXBeanImpl() {
+        super(FlightRecorderMXBean.class, true, new NotificationBroadcasterSupport(createNotificationInfo()));
+    }
+
+    @Override
+    public void startRecording(long id) {
+        MBeanUtils.checkControl();
+        getExistingRecording(id).start();
+    }
+
+    @Override
+    public boolean stopRecording(long id) {
+        MBeanUtils.checkControl();
+        return getExistingRecording(id).stop();
+    }
+
+    @Override
+    public void closeRecording(long id) {
+        MBeanUtils.checkControl();
+        getExistingRecording(id).close();
+    }
+
+    @Override
+    public long openStream(long id, Map<String, String> options) throws IOException {
+        MBeanUtils.checkControl();
+        if (!FlightRecorder.isInitialized()) {
+            throw new IllegalArgumentException("No recording available with id " + id);
+        }
+        // Make local copy to prevent concurrent modification
+        Map<String, String> s = options == null ? new HashMap<>() : new HashMap<>(options);
+        Instant starttime = MBeanUtils.parseTimestamp(s.get("startTime"), Instant.MIN);
+        Instant endtime = MBeanUtils.parseTimestamp(s.get("endTime"), Instant.MAX);
+        int blockSize = MBeanUtils.parseBlockSize(s.get("blockSize"), StreamManager.DEFAULT_BLOCK_SIZE);
+        InputStream is = getExistingRecording(id).getStream(starttime, endtime);
+        if (is == null) {
+            throw new IOException("No recording data available");
+        }
+        return streamHandler.create(is, blockSize).getId();
+    }
+
+    @Override
+    public void closeStream(long streamIdentifier) throws IOException {
+        MBeanUtils.checkControl();
+        streamHandler.getStream(streamIdentifier).close();
+    }
+
+    @Override
+    public byte[] readStream(long streamIdentifier) throws IOException {
+        MBeanUtils.checkMonitor();
+        return streamHandler.getStream(streamIdentifier).read();
+    }
+
+    @Override
+    public List<RecordingInfo> getRecordings() {
+        MBeanUtils.checkMonitor();
+        if (!FlightRecorder.isInitialized()) {
+            return Collections.emptyList();
+        }
+        return MBeanUtils.transformList(getRecorder().getRecordings(), RecordingInfo::new);
+    }
+
+    @Override
+    public List<ConfigurationInfo> getConfigurations() {
+        MBeanUtils.checkMonitor();
+        return MBeanUtils.transformList(Configuration.getConfigurations(), ConfigurationInfo::new);
+    }
+
+    @Override
+    public List<EventTypeInfo> getEventTypes() {
+        MBeanUtils.checkMonitor();
+        List<EventType> eventTypes = AccessController.doPrivileged(new PrivilegedAction<List<EventType>>() {
+            @Override
+            public List<EventType> run() {
+                return ManagementSupport.getEventTypes();
+            }
+        }, null, new FlightRecorderPermission("accessFlightRecorder"));
+
+        return MBeanUtils.transformList(eventTypes, EventTypeInfo::new);
+    }
+
+    @Override
+    public Map<String, String> getRecordingSettings(long recording) throws IllegalArgumentException {
+        MBeanUtils.checkMonitor();
+        return getExistingRecording(recording).getSettings();
+    }
+
+    @Override
+    public void setRecordingSettings(long recording, Map<String, String> values) throws IllegalArgumentException {
+        Objects.requireNonNull(values);
+        MBeanUtils.checkControl();
+        getExistingRecording(recording).setSettings(values);
+    }
+
+    @Override
+    public long newRecording() {
+        MBeanUtils.checkControl();
+        getRecorder(); // ensure notification listener is setup
+        return AccessController.doPrivileged(new PrivilegedAction<Recording>() {
+            @Override
+            public Recording run() {
+                return new Recording();
+            }
+        }, null, new FlightRecorderPermission("accessFlightRecorder")).getId();
+    }
+
+    @Override
+    public long takeSnapshot() {
+        MBeanUtils.checkControl();
+        return getRecorder().takeSnapshot().getId();
+    }
+
+    @Override
+    public void setConfiguration(long recording, String configuration) throws IllegalArgumentException {
+        Objects.requireNonNull(configuration);
+        MBeanUtils.checkControl();
+        try {
+            Configuration c = Configuration.create(new StringReader(configuration));
+            getExistingRecording(recording).setSettings(c.getSettings());
+        } catch (IOException | ParseException e) {
+            throw new IllegalArgumentException("Could not parse configuration", e);
+        }
+    }
+
+    @Override
+    public void setPredefinedConfiguration(long recording, String configurationName) throws IllegalArgumentException {
+        Objects.requireNonNull(configurationName);
+        MBeanUtils.checkControl();
+        Recording r = getExistingRecording(recording);
+        for (Configuration c : Configuration.getConfigurations()) {
+            if (c.getName().equals(configurationName)) {
+                r.setSettings(c.getSettings());
+                return;
+            }
+        }
+        throw new IllegalArgumentException("Could not find configuration with name " + configurationName);
+    }
+
+    @Override
+    public void copyTo(long recording, String path) throws IOException {
+        Objects.requireNonNull(path);
+        MBeanUtils.checkControl();
+        getExistingRecording(recording).dump(Paths.get(path));
+    }
+
+    @Override
+    public void setRecordingOptions(long recording, Map<String, String> options) throws IllegalArgumentException {
+        Objects.requireNonNull(options);
+        MBeanUtils.checkControl();
+        // Make local copy to prevent concurrent modification
+        Map<String, String> ops = new HashMap<String, String>(options);
+        for (Map.Entry<String, String> entry : ops.entrySet()) {
+            Object key = entry.getKey();
+            Object value = entry.getValue();
+            if (!(key instanceof String)) {
+                throw new IllegalArgumentException("Option key must not be null, or other type than " + String.class);
+            }
+            if (!OPTIONS.contains(key)) {
+                throw new IllegalArgumentException("Unknown recording option: " + key + ". Valid options are " + OPTIONS + ".");
+            }
+            if (value != null && !(value instanceof String)) {
+                throw new IllegalArgumentException("Incorrect value for option " + key + ". Values must be of type " + String.class + " .");
+            }
+        }
+
+        Recording r = getExistingRecording(recording);
+        validateOption(ops, OPTION_DUMP_ON_EXIT, MBeanUtils::booleanValue);
+        validateOption(ops, OPTION_DISK, MBeanUtils::booleanValue);
+        validateOption(ops, OPTION_NAME, Function.identity());
+        validateOption(ops, OPTION_MAX_AGE, MBeanUtils::duration);
+        validateOption(ops, OPTION_MAX_SIZE, MBeanUtils::size);
+        validateOption(ops, OPTION_DURATION, MBeanUtils::duration);
+
+        // All OK, now set them.atomically
+        setOption(ops, OPTION_DUMP_ON_EXIT, "false", MBeanUtils::booleanValue, x -> r.setDumpOnExit(x));
+        setOption(ops, OPTION_DISK, "true", MBeanUtils::booleanValue, x -> r.setToDisk(x));
+        setOption(ops, OPTION_NAME, String.valueOf(r.getId()), Function.identity(), x -> r.setName(x));
+        setOption(ops, OPTION_MAX_AGE, null, MBeanUtils::duration, x -> r.setMaxAge(x));
+        setOption(ops, OPTION_MAX_SIZE, "0", MBeanUtils::size, x -> r.setMaxSize(x));
+        setOption(ops, OPTION_DURATION, null, MBeanUtils::duration, x -> r.setDuration(x));
+    }
+
+    @Override
+    public Map<String, String> getRecordingOptions(long recording) throws IllegalArgumentException {
+        MBeanUtils.checkMonitor();
+        Recording r = getExistingRecording(recording);
+        Map<String, String> options = new HashMap<>(10);
+        options.put(OPTION_DUMP_ON_EXIT, String.valueOf(r.getDumpOnExit()));
+        options.put(OPTION_DISK, String.valueOf(r.isToDisk()));
+        options.put(OPTION_NAME, String.valueOf(r.getName()));
+        options.put(OPTION_MAX_AGE, ManagementSupport.formatTimespan(r.getMaxAge(), " "));
+        Long maxSize = r.getMaxSize();
+        options.put(OPTION_MAX_SIZE, String.valueOf(maxSize == null ? "0" : maxSize.toString()));
+        options.put(OPTION_DURATION, ManagementSupport.formatTimespan(r.getDuration(), " "));
+        return options;
+    }
+
+    @Override
+    public long cloneRecording(long id, boolean stop) throws IllegalStateException, SecurityException {
+        MBeanUtils.checkControl();
+        return getRecording(id).copy(stop).getId();
+    }
+
+    @Override
+    public ObjectName getObjectName() {
+        return MBeanUtils.createObjectName();
+    }
+
+    private Recording getExistingRecording(long id) {
+        if (FlightRecorder.isInitialized()) {
+            Recording recording = getRecording(id);
+            if (recording != null) {
+                return recording;
+            }
+        }
+        throw new IllegalArgumentException("No recording available with id " + id);
+    }
+
+    private Recording getRecording(long id) {
+        List<Recording> recs = getRecorder().getRecordings();
+        return recs.stream().filter(r -> r.getId() == id).findFirst().orElse(null);
+    }
+
+    private static <T, U> void setOption(Map<String, String> options, String name, String defaultValue, Function<String, U> converter, Consumer<U> setter) {
+        if (!options.containsKey(name)) {
+            return;
+        }
+        String v = options.get(name);
+        if (v == null) {
+            v = defaultValue;
+        }
+        try {
+            setter.accept(converter.apply(v));
+        } catch (IllegalArgumentException iae) {
+            throw new IllegalArgumentException("Not a valid value for option '" + name + "'. " + iae.getMessage());
+        }
+    }
+
+    private static <T, U> void validateOption(Map<String, String> options, String name, Function<String, U> validator) {
+        try {
+            String v = options.get(name);
+            if (v == null) {
+                return; // OK, will set default
+            }
+            validator.apply(v);
+        } catch (IllegalArgumentException iae) {
+            throw new IllegalArgumentException("Not a valid value for option '" + name + "'. " + iae.getMessage());
+        }
+    }
+
+    private FlightRecorder getRecorder() throws SecurityException {
+        // Synchronize on some private object that is always available
+        synchronized (streamHandler) {
+            if (recorder == null) {
+                recorder = AccessController.doPrivileged(new PrivilegedAction<FlightRecorder>() {
+                    @Override
+                    public FlightRecorder run() {
+                        return FlightRecorder.getFlightRecorder();
+                    }
+                }, null, new FlightRecorderPermission("accessFlightRecorder"));
+            }
+            return recorder;
+        }
+    }
+
+    private static MBeanNotificationInfo[] createNotificationInfo() {
+        String[] types = new String[] { AttributeChangeNotification.ATTRIBUTE_CHANGE };
+        String name = AttributeChangeNotification.class.getName();
+        String description = "Notifies if the RecordingState has changed for one of the recordings, for example if a recording starts or stops";
+        MBeanNotificationInfo info = new MBeanNotificationInfo(types, name, description);
+        return new MBeanNotificationInfo[] { info };
+    }
+
+    @Override
+    public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) {
+        MXBeanListener mxbeanListener = new MXBeanListener(listener, filter, handback);
+        listeners.add(mxbeanListener);
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            @Override
+            public Void run(){
+                FlightRecorder.addListener(mxbeanListener);
+                return null;
+            }
+        }, null, new FlightRecorderPermission("accessFlightRecorder"));
+        super.addNotificationListener(listener, filter, handback);
+    }
+
+    @Override
+    public void removeNotificationListener(NotificationListener listener) throws ListenerNotFoundException {
+        removeListeners( x -> listener == x.listener);
+        super.removeNotificationListener(listener);
+    }
+
+    @Override
+    public void removeNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws ListenerNotFoundException {
+        removeListeners( x -> listener == x.listener && filter == x.filter && handback == x.handback);
+        super.removeNotificationListener(listener, filter, handback);
+    }
+
+    private void removeListeners(Predicate<MXBeanListener> p) {
+        List<MXBeanListener> toBeRemoved = new ArrayList<>(listeners.size());
+        for (MXBeanListener l : listeners) {
+            if (p.test(l)) {
+                toBeRemoved.add(l);
+                FlightRecorder.removeListener(l);
+            }
+        }
+        listeners.removeAll(toBeRemoved);
+    }
+
+    private Notification createNotication(Recording recording) {
+        try {
+            Long id = recording.getId();
+            Object oldValue = changes.get(recording.getId());
+            Object newValue = getAttribute(ATTRIBUTE_RECORDINGS);
+            if (recording.getState() != RecordingState.CLOSED) {
+                changes.put(id, newValue);
+            } else {
+                changes.remove(id);
+            }
+            return new AttributeChangeNotification(getObjectName(), sequenceNumber.incrementAndGet(), System.currentTimeMillis(), "Recording " + recording.getName() + " is "
+                    + recording.getState(), ATTRIBUTE_RECORDINGS, newValue.getClass().getName(), oldValue, newValue);
+        } catch (AttributeNotFoundException | MBeanException | ReflectionException e) {
+            throw new RuntimeException("Could not create notifcation for FlightRecorderMXBean. " + e.getMessage(), e);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/MBeanUtils.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.management.jfr;
+
+import java.lang.management.ManagementPermission;
+import java.security.Permission;
+import java.time.DateTimeException;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.format.DateTimeParseException;
+import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import jdk.jfr.internal.management.ManagementSupport;
+
+final class MBeanUtils {
+
+    private static final Permission monitor = new ManagementPermission("monitor");
+    private static final Permission control = new ManagementPermission("control");
+
+    static ObjectName createObjectName() {
+        try {
+            return new ObjectName(FlightRecorderMXBean.MXBEAN_NAME);
+        } catch (MalformedObjectNameException mne) {
+            throw new Error("Can't happen", mne);
+        }
+    }
+
+    static void checkControl() {
+        SecurityManager secManager = System.getSecurityManager();
+        if (secManager != null) {
+            secManager.checkPermission(control);
+        }
+    }
+
+    static void checkMonitor() {
+        SecurityManager secManager = System.getSecurityManager();
+        if (secManager != null) {
+            secManager.checkPermission(monitor);
+        }
+    }
+
+    static <T, R> List<R> transformList(List<T> source, Function<T, R> function) {
+        return source.stream().map(function).collect(Collectors.toList());
+    }
+
+    static boolean booleanValue(String s) {
+        if ("true".equals(s)) {
+            return true;
+        }
+        if ("false".equals(s)) {
+            return false;
+        }
+        throw new IllegalArgumentException("Value must be true or false.");
+    }
+
+    static Duration duration(String s) throws NumberFormatException {
+        if (s == null) {
+            return null;
+        }
+        long l = ManagementSupport.parseTimespan(s);
+        if (l == 0) {
+            return null;
+        }
+        return Duration.ofNanos(l);
+    }
+
+    public static Instant parseTimestamp(String s, Instant defaultValue) {
+        if (s == null) {
+            return defaultValue;
+        }
+        try {
+            return Instant.parse(s);
+        } catch(DateTimeParseException e ) {
+            // OK, try with milliseconds since epoch
+            // before giving up.
+        }
+        try {
+            return Instant.ofEpochMilli(Long.parseLong(s));
+        } catch (NumberFormatException | DateTimeException nfr) {
+            throw new IllegalArgumentException("Not a valid timestamp " + s);
+        }
+    }
+
+    static Long size(String s) throws NumberFormatException {
+        long size = Long.parseLong(s);
+        if (size < 0) {
+            throw new IllegalArgumentException("Negative size not allowed");
+        }
+        return size;
+    }
+
+    public static int parseBlockSize(String string, int defaultSize) {
+        if (string == null) {
+            return defaultSize;
+        }
+        int size = Integer.parseInt(string);
+        if (size <1)  {
+            throw new IllegalArgumentException("Block size msut be at least 1 byte");
+        }
+        return size;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/RecordingInfo.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,398 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.management.jfr;
+
+import java.nio.file.Path;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularData;
+
+import jdk.jfr.Recording;
+import jdk.jfr.RecordingState;
+
+/**
+ * Management representation of a {@code Recording}.
+ *
+ * @see Recording
+ *
+ * @since 9
+ */
+public final class RecordingInfo {
+    private final long id;
+    private final String name;
+    private final String state;
+    private final boolean dumpOnExit;
+    private final long size;
+    private final boolean disk;
+    private final long maxAge;
+    private final long maxSize;
+    private final long startTime;
+    private final long stopTime;
+    private final String destination;
+    private final long durationInSeconds;
+    private final Map<String, String> settings;
+
+    // package private
+    RecordingInfo(Recording recording) {
+        id = recording.getId();
+        name = recording.getName();
+        state = recording.getState().toString();
+        dumpOnExit = recording.getDumpOnExit();
+        size = recording.getSize();
+        disk = recording.isToDisk();
+
+        Duration d = recording.getMaxAge();
+        if (d == null) {
+            maxAge = 0;
+        } else {
+            maxAge = d.getSeconds();
+        }
+        maxSize = recording.getMaxSize();
+        Instant s = recording.getStartTime();
+        startTime = s == null ? 0L : s.toEpochMilli();
+        Instant st = recording.getStopTime();
+        stopTime = st == null ? 0L : st.toEpochMilli();
+        Path p = recording.getDestination();
+        destination = p == null ? null : p.toString();
+        Duration duration = recording.getDuration();
+        durationInSeconds = duration == null ? 0 : duration.getSeconds();
+        settings = recording.getSettings();
+    }
+
+    private RecordingInfo(CompositeData cd) {
+        id = (int) cd.get("id");
+        name = (String) cd.get("name");
+        state = (String) cd.get("state");
+        dumpOnExit = (boolean) cd.get("dumpOnExit");
+        size = (long) cd.get("size");
+        disk = (boolean) cd.get("disk");
+        maxAge = (Long) cd.get("maxAge");
+        maxSize = (Long) cd.get("maxSize");
+        startTime = (Long) cd.get("startTime");
+        stopTime = (Long) cd.get("stopTime");
+        destination = (String) cd.get("destination");
+        durationInSeconds = (long) cd.get("duration");
+        settings = new LinkedHashMap<>();
+        Object map = cd.get("settings");
+        if (map instanceof TabularData) {
+            TabularData td = (TabularData) map;
+            List<String> keyNames = td.getTabularType().getIndexNames();
+            int size = keyNames.size();
+            for (Object keys : td.keySet()) {
+                Object[] keyValues = ((List<?>) keys).toArray();
+                for (int i = 0; i < size; i++) {
+                    String key = keyNames.get(i);
+                    Object value = keyValues[i];
+                    if (value instanceof String) {
+                        settings.put(key, (String) value);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns the name of the recording associated with this
+     * {@code RecordingInfo}.
+     *
+     * @return the recording name, not {@code null}
+     *
+     * @see Recording#getName()
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Returns the unique ID for the recording associated with this
+     * {@code RecordingInfo}.
+     *
+     * @return the recording ID
+     *
+     * @see Recording#getId()
+     */
+    public long getId() {
+        return id;
+    }
+
+    /**
+     * Returns if the recording associated with this {@code RecordingInfo}
+     * should be dumped to file when the JVM exits.
+     *
+     * @return {@code true} if recording should be dumped on exit, {@code false}
+     *         otherwise
+     *
+     * @see Recording#getDumpOnExit()
+     */
+    public boolean getDumpOnExit() {
+        return dumpOnExit;
+    }
+
+    /**
+     * Returns how many seconds data should be kept on disk, or {@code 0} if
+     * data is to be kept forever.
+     * <p>
+     * In-memory recordings are not affected by maximum age.
+     *
+     * @see Recording#getMaxAge()
+     * @see Recording#setToDisk(boolean)
+     * @return how long data should be kept on disk, measured in seconds
+     *
+     */
+    public long getMaxAge() {
+        return maxAge;
+    }
+
+    /**
+     * Returns the amount of data, measured in bytes, the recording associated
+     * with this {@code RecordingInfo}, should be kept on disk, before it's
+     * rotated away, or {@code 0} if data is to be kept indefinitely.
+     * <p>
+     * In-memory recordings are not affected by maximum size.
+     *
+     * @return the amount of data should be kept on disk, in bytes
+     *
+     * @see Recording#setToDisk(boolean)
+     * @see Recording#getMaxSize()
+     */
+    public long getMaxSize() {
+        return maxSize;
+    }
+
+    /**
+     * Returns a {@code String} representation of state of the recording
+     * associated with this {@code RecordingInfo}.
+     * <p>
+     * Valid return values are {@code "NEW"}, {@code "DELAYED"}, {@code "STARTING"},
+     * {@code "RUNNING"}, {@code "STOPPING"}, {@code "STOPPED"} and {@code "CLOSED"}.
+     *
+     * @return the recording state, not {@code null}
+     *
+     * @see RecordingState#toString()
+     * @see Recording#getState()
+     */
+    public String getState() {
+        return state;
+    }
+
+    /**
+     * Returns start time of the recording associated with this
+     * {@code RecordingInfo}, measured as ms since epoch, or {@code null} if the
+     * recording hasn't started.
+     *
+     * @return the start time of the recording, or {@code null} if the recording
+     *         hasn't started
+     *
+     * @see Recording#getStartTime()
+     */
+    public long getStartTime() {
+        return startTime;
+    }
+
+    /**
+     * Returns the actual or expected stop time of the recording associated with
+     * this {@code RecordingInfo}, measured as ms since epoch, or {@code null}
+     * if the expected or actual stop time is not known, which can only happen
+     * if the recording has not yet been stopped.
+     *
+     * @return the stop time of recording, or {@code null} if recording hasn't
+     *         been stopped.
+     *
+     * @see Recording#getStopTime()
+     */
+    public long getStopTime() {
+        return stopTime;
+    }
+
+    /**
+     * Returns the settings for the recording associated with this
+     * {@code RecordingInfo}.
+     *
+     * @return the recording settings, not {@code null}
+     *
+     * @see Recording#getSettings()
+     */
+    public Map<String, String> getSettings() {
+        return settings;
+    }
+
+    /**
+     * Returns destination path where data, for the recording associated with
+     * this {@link RecordingInfo}, should be written when the recording stops,
+     * or {@code null} if the recording should not be written.
+     *
+     * @return the destination, or {@code null} if not set
+     *
+     * @see Recording#getDestination()
+     */
+    public String getDestination() {
+        return destination;
+    }
+
+    /**
+     * Returns a string description of the recording associated with this
+     * {@code RecordingInfo}
+     *
+     * @return description, not {@code null}
+     */
+    @Override
+    public String toString() {
+        Stringifier s = new Stringifier();
+        s.add("name", name);
+        s.add("id", id);
+        s.add("maxAge", maxAge);
+        s.add("maxSize", maxSize);
+        return s.toString();
+    }
+
+    /**
+     * Returns the amount data recorded by recording. associated with this
+     * {@link RecordingInfo}.
+     *
+     * @return the amount of recorded data, measured in bytes
+     */
+    public long getSize() {
+        return size;
+    }
+
+    /**
+     * Returns {@code true} if the recording associated with this
+     * {@code RecordingInfo} should be flushed to disk, when memory buffers are
+     * full, {@code false} otherwise.
+     *
+     * @return {@code true} if recording is to disk, {@code false} otherwise
+     */
+    public boolean isToDisk() {
+        return disk;
+    }
+
+    /**
+     * Returns the desired duration, measured in seconds, of the recording
+     * associated with this {@link RecordingInfo}, or {code 0} if no duration
+     * has been set.
+     *
+     * @return the desired duration, or {code 0} if no duration has been set
+     *
+     * @see Recording#getDuration()
+     */
+    public long getDuration() {
+        return durationInSeconds;
+    }
+
+    /**
+     * Returns a {@code RecordingInfo} represented by the specified
+     * {@code CompositeData} object.
+     * <p>
+     * The specified {@code CompositeData} must have the following item names and
+     * item types to be valid. <blockquote>
+     * <table class="striped">
+     * <caption>Supported names and types in a specified {@code CompositeData} object</caption>
+     * <thead>
+     * <tr>
+     * <th scope="col" style="text-align:left">Name</th>
+     * <th scope="col" style="text-align:left">Type</th>
+     * </tr>
+     * </thead>
+     * <tbody>
+     * <tr>
+     * <th scope="row">id</th>
+     * <td>{@code Long}</td>
+     * </tr>
+     * <tr>
+     * <th scope="row">name</th>
+     * <td>{@code String}</td>
+     * </tr>
+     * <tr>
+     * <th scope="row">state</th>
+     * <td>{@code String}</td>
+     * </tr>
+     * <tr>
+     * <th scope="row">dumpOnExit</th>
+     * <td>{@code Boolean}</td>
+     * </tr>
+     * <tr>
+     * <th scope="row">size</th>
+     * <td>{@code Long}</td>
+     * </tr>
+     * <tr>
+     * <th scope="row">disk</th>
+     * <td>{@code Boolean}</td>
+     * </tr>
+     * <tr>
+     * <th scope="row">maxAge</th>
+     * <td>{@code Long}</td>
+     * </tr>
+     * <tr>
+     * <th scope="row">maxSize</th>
+     * <td>{@code Long}</td>
+     * </tr>
+     * <tr>
+     * <th scope="row">startTime</th>
+     * <td>{@code Long}</td>
+     * </tr>
+     * <tr>
+     * <th scope="row">stopTime</th>
+     * <td>{@code Long}</td>
+     * </tr>
+     * <tr>
+     * <th scope="row">destination</th>
+     * <td>{@code String}</td>
+     * </tr>
+     * <tr>
+     * <th scope="row">duration</th>
+     * <td>{@code Long}</td>
+     * </tr>
+     * <tr>
+     * <th scope="row">settings</th>
+     * <td>{@code javax.management.openmbean.CompositeData[]} whose element type
+     * is the mapped type for {@link SettingDescriptorInfo} as specified in the
+     * {@link SettingDescriptorInfo#from} method.</td>
+     * </tr>
+     * </tbody>
+     * </table>
+     * </blockquote>
+     *
+     * @param cd {@code CompositeData} representing the {@code RecordingInfo} to
+     *        return
+     *
+     * @throws IllegalArgumentException if {@code cd} does not represent a valid
+     *         {@code RecordingInfo}
+     *
+     * @return the {@code RecordingInfo} represented by {@code cd}, or
+     *         {@code null} if {@code cd} is {@code null}
+     */
+    public static RecordingInfo from(CompositeData cd) {
+        if (cd == null) {
+            return null;
+        }
+        return new RecordingInfo(cd);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/SettingDescriptorInfo.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.management.jfr;
+
+import java.util.concurrent.Callable;
+
+import javax.management.openmbean.CompositeData;
+
+import jdk.jfr.EventType;
+import jdk.jfr.SettingDescriptor;
+import jdk.management.jfr.internal.FlightRecorderMXBeanProvider;
+
+/**
+ * Management class that describes a setting, for example name, description and
+ * default value.
+ *
+ * @see EventType#getSettingDescriptors()
+ *
+ * @since 9
+ */
+public final class SettingDescriptorInfo {
+
+    // Purpose of this static initializer is to allow
+    // FlightRecorderMXBeanProvider
+    // to be in an internal package and not visible, but at the same time allow
+    // it to instantiate FlightRecorderMXBeanImpl.
+    //
+    // The reason the mechanism is in this class is because it is light weight
+    // and can easily be triggered from FlightRecorderMXBeanProvider.
+    static {
+        FlightRecorderMXBeanProvider.setFlightRecorderMXBeanFactory(new Callable<FlightRecorderMXBean>() {
+            @Override
+            public FlightRecorderMXBean call() throws Exception {
+                return new FlightRecorderMXBeanImpl();
+            }
+        });
+    }
+
+    private final String name;
+    private final String label;
+    private final String description;
+    private final String typeName;
+    private final String contentType;
+    private final String defaultValue;
+
+    // package private
+    SettingDescriptorInfo(SettingDescriptor settingDescriptor) {
+        this.name = settingDescriptor.getName();
+        this.label = settingDescriptor.getLabel();
+        this.description = settingDescriptor.getDescription();
+        this.typeName = settingDescriptor.getTypeName();
+        this.contentType = settingDescriptor.getContentType();
+        this.defaultValue = settingDescriptor.getDefaultValue();
+    }
+
+    private SettingDescriptorInfo(CompositeData cd) {
+        this.name = (String) cd.get("name");
+        this.label = (String) cd.get("label");
+        this.description = (String) cd.get("description");
+        this.typeName = (String) cd.get("typeName");
+        this.defaultValue = (String) cd.get("defaultValue");
+        this.contentType = (String) cd.get("contentType");
+    }
+
+    /**
+    * Returns the human-readable name of the setting associated with this
+     * {@code SettingDescriptorInfo} (for example, {@code "Threshold"}).
+     *
+     * @return the label for this setting, not {@code null}
+     */
+    public String getLabel() {
+        return label;
+    }
+
+    /**
+     * Returns the name of the setting associated with this
+     * {@code SettingDescriptorInfo} (for example, {@code "threshold"}).
+     *
+     * @return the name of this setting, not {@code null}
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Returns the description of the setting associated this
+     * {@code SettingDescriptorInfo} (for example,
+     * {@code "The duration an event must exceed to be be recorded"}).
+     *
+     * @return the description of this setting, not null
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * Returns the type name of the setting associated this
+     * {@code SettingDescriptorInfo} (for example,
+     * {@code "jdk.settings.Threshold"}).
+     * <p>
+     * The type can be used to identify what type of setting this is.
+     *
+     * @return the name of this settings type, not {@code null}
+     */
+    public String getTypeName() {
+        return typeName;
+    }
+
+    /**
+     * Returns the content type of the setting associated this
+     * {@code SettingDescriptorInfo} (for example, {@code "jdk.jfr.Timespan"}).
+     * <p>
+     * The content type can be used to determine how the setting should be
+     * rendered in a graphical user interface.
+     *
+     * @return the name of this settings type, not {@code null}
+     */
+    public String getContentType() {
+        return contentType;
+    }
+
+    /**
+     * Returns the default value of the setting associated this
+     * {@code SettingDescriptorInfo} (for example, {@code "20 ms"}).
+     *
+     * @return default value for this setting, not {@code null}
+     *
+     * @see SettingDescriptor#getDefaultValue()
+     */
+    public String getDefaultValue() {
+        return defaultValue;
+    }
+
+    /**
+     * Returns an {@code SettingDescriptorInfo} represented by the specified
+     * {@code CompositeData}
+     * <p>
+     * The supplied {@code CompositeData} must have the following item names and
+     * item types to be valid. <blockquote>
+     * <table class="striped">
+     * <caption>The name and type the specified CompositeData must contain</caption>
+     * <thead>
+     * <tr>
+     * <th scope="col" style="text-align:left">Name</th>
+     * <th scope="col" style="text-align:left">Type</th>
+     * </tr>
+     * </thead>
+     * <tbody>
+     * <tr>
+     * <th scope="row">name</th>
+     * <td>{@code String}</td>
+     * </tr>
+     * <tr>
+     * <th scope="row">label</th>
+     * <td>{@code String}</td>
+     * </tr>
+     * <tr>
+     * <th scope="row">description</th>
+     * <td>{@code String}</td>
+     * </tr>
+     * <tr>
+     * <th scope="row">typeName</th>
+     * <td>{@code String}</td>
+     * </tr>
+     * <tr>
+     * <th scope="row">contentType</th>
+     * <td>{@code String}</td>
+     * </tr>
+     * <tr>
+     * <th scope="row">defaultValue</th>
+     * <td>{@code String}</td>
+     * </tr>
+     * </tbody>
+     * </table>
+     * </blockquote>
+     *
+     * @param cd {@code CompositeData} representing the {@code SettingDescriptorInfo} to
+     *        return
+     *
+     * @throws IllegalArgumentException if {@code cd} does not represent a valid
+     *         {@code EventTypeInfo}
+     *
+     * @return a {@code SettingDescriptorInfo}, or {@code null} if {@code cd} is
+     *         {@code null}
+     */
+    public static SettingDescriptorInfo from(CompositeData cd) {
+        if (cd == null) {
+            return null;
+        }
+        return new SettingDescriptorInfo(cd);
+    }
+
+    /**
+     * Returns a {@code String} description of this {@code SettingDescriptorInfo}.
+     *
+     * @return a string describing this setting, not {@code null}
+     */
+    @Override
+    public String toString() {
+        Stringifier s = new Stringifier();
+        s.add("name", name);
+        s.add("label", label);
+        s.add("description", description);
+        s.add("typeName", typeName);
+        s.add("contentType", contentType);
+        s.add("defaultValue", defaultValue);
+        return s.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/Stream.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.management.jfr;
+
+import java.io.BufferedInputStream;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+
+final class Stream implements Closeable {
+
+    private final long identifier;
+    private final BufferedInputStream inputStream;
+    private final byte[] buffer;
+
+    private volatile long time;
+
+    Stream(InputStream is, long identifier, int blockSize) {
+        this.inputStream = new BufferedInputStream(is, 50000);
+        this.identifier = identifier;
+        this.buffer = new byte[blockSize];
+    }
+
+    private void touch() {
+        time = System.currentTimeMillis();
+    }
+
+    public long getLastTouched() {
+        return time;
+    }
+
+    public byte[] read() throws IOException {
+        // OK to reuse buffer since this
+        // is only used for serialization
+        touch();
+        int read = inputStream.read(buffer);
+        if (read == -1) {
+            // null indicate no more data
+            return null;
+        }
+        if (read != buffer.length) {
+            byte[] smallerBuffer = new byte[read];
+            System.arraycopy(buffer, 0, smallerBuffer, 0, read);
+            return smallerBuffer;
+        }
+
+        return buffer;
+    }
+
+    @Override
+    public void close() throws IOException {
+        inputStream.close();
+    }
+
+    public long getId() {
+        return identifier;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/StreamCleanupTask.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.management.jfr;
+
+import java.util.TimerTask;
+
+final class StreamCleanupTask extends TimerTask {
+
+    private final Stream stream;
+    private final StreamManager manager;
+
+    StreamCleanupTask(StreamManager streamManager, Stream stream) {
+        this.stream = stream;
+        this.manager = streamManager;
+    }
+
+    @Override
+    public void run() {
+        long lastTouched = stream.getLastTouched();
+        long now = System.currentTimeMillis();
+        if (now - lastTouched >= StreamManager.TIME_OUT) {
+            manager.destroy(stream);
+        } else {
+            manager.scheduleAbort(stream, lastTouched + StreamManager.TIME_OUT);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/StreamManager.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.management.jfr;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Timer;
+import java.util.concurrent.TimeUnit;
+
+final class StreamManager {
+
+    public static final long TIME_OUT = TimeUnit.MINUTES.toMillis(2);
+    public static final int DEFAULT_BLOCK_SIZE = 50000;
+
+    private static long idCounter = 0;
+
+    private final Map<Long, Stream> streams = new HashMap<>();
+    private Timer timer;
+
+    public synchronized Stream getStream(long streamIdentifer) {
+        Stream stream = streams.get(streamIdentifer);
+        if (stream == null) {
+            throw new IllegalArgumentException("Unknown stream identifier " + streamIdentifer);
+        }
+        return stream;
+    }
+
+    public synchronized Stream create(InputStream is, int blockSize) {
+        idCounter++;
+        Stream stream = new Stream(is, idCounter, blockSize);
+        streams.put(stream.getId(), stream);
+
+        scheduleAbort(stream, System.currentTimeMillis() + TIME_OUT);
+        return stream;
+    }
+
+    public synchronized void destroy(Stream stream) {
+        try {
+            stream.close();
+        } catch (IOException e) {
+            // OK
+        }
+        streams.remove(stream.getId());
+        if (streams.isEmpty()) {
+            timer.cancel();
+            timer = null;
+        }
+    }
+
+    public synchronized void scheduleAbort(Stream s, long when) {
+        if (timer == null) {
+            timer = new Timer(true);
+        }
+        timer.schedule(new StreamCleanupTask(this, s), new Date(when + TIME_OUT));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/Stringifier.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.management.jfr;
+/**
+ * Helper class for generating toString()
+ *
+ */
+final class Stringifier {
+    private final StringBuilder sb = new StringBuilder();
+    private boolean first = true;
+
+    public void add(String name, Object value) {
+        if (first) {
+            first = false;
+        } else {
+            sb.append(" ");
+        }
+        boolean isString = value instanceof String;
+        sb.append(name).append("=");
+        if (value == null) {
+            sb.append("null");
+        } else {
+            if (isString) {
+                sb.append("\"");
+            }
+            sb.append(value);
+            if (isString) {
+                sb.append("\"");
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/internal/FlightRecorderMXBeanProvider.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.management.jfr.internal;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+
+import jdk.jfr.internal.management.ManagementSupport;
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.management.jfr.SettingDescriptorInfo;
+import sun.management.spi.PlatformMBeanProvider;
+
+public final class FlightRecorderMXBeanProvider extends PlatformMBeanProvider {
+
+    private final static class SingleMBeanComponent
+            implements PlatformComponent<FlightRecorderMXBean> {
+        private final String objectName;
+        private final Class<FlightRecorderMXBean> mbeanInterface;
+
+        public SingleMBeanComponent(String objectName,
+                                    Class<FlightRecorderMXBean> mbeanInterface) {
+            this.objectName = objectName;
+            this.mbeanInterface = mbeanInterface;
+        }
+
+        @Override
+        public Set<String> mbeanInterfaceNames() {
+            return Collections.singleton(mbeanInterface.getName());
+        }
+
+        @Override
+        public Map<String, FlightRecorderMXBean> nameToMBeanMap() {
+            FlightRecorderMXBean bean = getFlightRecorderMXBean();
+            if (bean != null) {
+                return Collections.singletonMap(objectName, bean);
+            } else {
+                return Collections.emptyMap();
+            }
+        }
+
+        @Override
+        public String getObjectNamePattern() {
+            return objectName;
+        }
+
+        @Override
+        public Set<Class<? extends FlightRecorderMXBean>> mbeanInterfaces() {
+            return Collections.singleton(mbeanInterface);
+        }
+    }
+
+    private static Callable<FlightRecorderMXBean> flightRecorderMXBeanFactory;
+
+    private static volatile FlightRecorderMXBean flightRecorderMXBean;
+
+    private static FlightRecorderMXBean getFlightRecorderMXBean() {
+        FlightRecorderMXBean bean = flightRecorderMXBean;
+        if (bean == null) {
+            SettingDescriptorInfo.from(null); // Sets flightRecorderMXBeanFactory under <clinit> lock
+            synchronized (flightRecorderMXBeanFactory) {
+                bean = flightRecorderMXBean;
+                if (bean != null) {
+                    return bean;
+                }
+                try {
+                    bean = flightRecorderMXBean = flightRecorderMXBeanFactory.call();
+                } catch (Exception e) {
+                    ManagementSupport.logError("Could not create Flight Recorder "
+                            + "instance for MBeanServer. " + e.getMessage());
+                }
+            }
+        }
+        return bean;
+    }
+
+    public static void setFlightRecorderMXBeanFactory(Callable<FlightRecorderMXBean> factory) {
+        flightRecorderMXBeanFactory = factory;
+    }
+
+    @Override
+    public List<PlatformComponent<?>> getPlatformComponentList() {
+        String objectName = FlightRecorderMXBean.MXBEAN_NAME;
+        Class<FlightRecorderMXBean> mbeanInterface = FlightRecorderMXBean.class;
+        return Collections.singletonList(new SingleMBeanComponent(objectName, mbeanInterface));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/package-info.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * This package contains classes to control and monitor Flight Recorder over Java Management Extensions (JMX).
+ *
+ * @since 9
+ */
+package jdk.management.jfr;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.management.jfr/share/classes/module-info.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Defines the Management Interface for JDK Flight Recorder.
+ *
+ * @moduleGraph
+ * @since 9
+ */
+module jdk.management.jfr {
+    requires jdk.jfr;
+    requires jdk.management;
+
+    requires transitive java.management;
+
+    exports jdk.management.jfr;
+
+    provides sun.management.spi.PlatformMBeanProvider with
+        jdk.management.jfr.internal.FlightRecorderMXBeanProvider;
+}
--- a/test/hotspot/gtest/gc/shared/test_oopStorage_parperf.cpp	Tue May 15 11:28:29 2018 -0700
+++ b/test/hotspot/gtest/gc/shared/test_oopStorage_parperf.cpp	Tue May 15 20:24:34 2018 +0200
@@ -36,7 +36,7 @@
 #include "runtime/vmThread.hpp"
 #include "utilities/debug.hpp"
 #include "utilities/ostream.hpp"
-#include "utilities/ticks.inline.hpp"
+#include "utilities/ticks.hpp"
 
 #include "unittest.hpp"
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/gtest/jfr/precompiled.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// This file is included once when using gcc, the other time the real
+// precompiled.hpp is used.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/gtest/jfr/test_threadCpuLoad.cpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+
+// This test performs mocking of certain JVM functionality. This works by
+// including the source file under test inside an anonymous namespace (which
+// prevents linking conflicts) with the mocked symbols redefined.
+
+// The include list should mirror the one found in the included source file -
+// with the ones that should pick up the mocks removed. Those should be included
+// later after the mocks have been defined.
+
+#include "jvm.h"
+#include "classfile/classLoaderStats.hpp"
+#include "classfile/javaClasses.hpp"
+#include "code/codeCache.hpp"
+#include "compiler/compileBroker.hpp"
+#include "gc/g1/g1HeapRegionEventSender.hpp"
+#include "gc/shared/gcConfiguration.hpp"
+#include "gc/shared/gcTrace.hpp"
+#include "gc/shared/objectCountEventSender.hpp"
+#include "gc/shared/vmGCOperations.hpp"
+#include "jfr/jfrEvents.hpp"
+#include "jfr/periodic/jfrModuleEvent.hpp"
+#include "jfr/periodic/jfrOSInterface.hpp"
+#include "jfr/periodic/jfrThreadCPULoadEvent.hpp"
+#include "jfr/periodic/jfrThreadDumpEvent.hpp"
+#include "jfr/recorder/jfrRecorder.hpp"
+#include "jfr/support/jfrThreadId.hpp"
+#include "jfr/utilities/jfrTime.hpp"
+#include "logging/log.hpp"
+#include "memory/heapInspection.hpp"
+#include "memory/resourceArea.hpp"
+#include "oops/oop.inline.hpp"
+#include "runtime/arguments.hpp"
+#include "runtime/flags/jvmFlag.hpp"
+#include "runtime/globals.hpp"
+#include "runtime/os.hpp"
+#include "runtime/os_perf.hpp"
+#include "runtime/thread.inline.hpp"
+#include "runtime/threadSMR.hpp"
+#include "runtime/sweeper.hpp"
+#include "runtime/vmThread.hpp"
+#include "services/classLoadingService.hpp"
+#include "services/management.hpp"
+#include "services/threadService.hpp"
+#include "utilities/exceptions.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+#include "unittest.hpp"
+
+namespace {
+
+  class MockEventThreadCPULoad : public ::EventThreadCPULoad
+  {
+  public:
+    float user;
+    float system;
+
+  public:
+    MockEventThreadCPULoad(EventStartTime timing=TIMED) : ::EventThreadCPULoad(timing) {}
+
+    void set_user(float new_value) {
+      user = new_value;
+    }
+    void set_system(float new_value) {
+      system = new_value;
+    }
+  };
+
+  class MockOs : public ::os {
+  public:
+    static jlong user_cpu_time;
+    static jlong system_cpu_time;
+
+    static jlong thread_cpu_time(Thread *thread, bool user_sys_cpu_time) {
+      return user_sys_cpu_time ? user_cpu_time + system_cpu_time : user_cpu_time;
+    }
+  };
+
+  jlong MockOs::user_cpu_time;
+  jlong MockOs::system_cpu_time;
+
+// Reincluding source files in the anonymous namespace unfortunately seems to
+// behave strangely with precompiled headers (only when using gcc though)
+#ifndef DONT_USE_PRECOMPILED_HEADER
+#define DONT_USE_PRECOMPILED_HEADER
+#endif
+
+#define os MockOs
+#define EventThreadCPULoad MockEventThreadCPULoad
+
+#include "jfrfiles/jfrPeriodic.hpp"
+#include "jfr/periodic/jfrPeriodic.cpp"
+
+#undef os
+#undef EventThreadCPULoad
+
+} // anonymous namespace
+
+class JfrTestThreadCPULoadSingle : public ::testing::Test {
+protected:
+  JavaThread* thread;
+  JfrThreadLocal* thread_data;
+  MockEventThreadCPULoad event;
+
+  void SetUp() {
+    thread = new JavaThread();
+    thread_data = thread->jfr_thread_local();
+    thread_data->set_wallclock_time(0);
+    thread_data->set_user_time(0);
+    thread_data->set_cpu_time(0);
+  }
+
+  void TearDown() {
+    delete thread;
+  }
+};
+
+TEST_VM_F(JfrTestThreadCPULoadSingle, DISABLED_SingleCpu) {
+  MockOs::user_cpu_time = 100 * NANOSECS_PER_MILLISEC;
+  MockOs::system_cpu_time = 100 * NANOSECS_PER_MILLISEC;
+  EXPECT_TRUE(JfrThreadCPULoadEvent::update_event(event, thread, 400 * NANOSECS_PER_MILLISEC, 1));
+  EXPECT_FLOAT_EQ(0.25, event.user);
+  EXPECT_FLOAT_EQ(0.25, event.system);
+}
+
+TEST_VM_F(JfrTestThreadCPULoadSingle, DISABLED_MultipleCpus) {
+  MockOs::user_cpu_time = 100 * NANOSECS_PER_MILLISEC;
+  MockOs::system_cpu_time = 100 * NANOSECS_PER_MILLISEC;
+  EXPECT_TRUE(JfrThreadCPULoadEvent::update_event(event, thread, 400 * NANOSECS_PER_MILLISEC, 2));
+  EXPECT_FLOAT_EQ(0.125, event.user);
+  EXPECT_FLOAT_EQ(0.125, event.system);
+}
+
+TEST_VM_F(JfrTestThreadCPULoadSingle, DISABLED_BelowThreshold) {
+  MockOs::user_cpu_time = 100;
+  MockOs::system_cpu_time = 100;
+  EXPECT_FALSE(JfrThreadCPULoadEvent::update_event(event, thread, 400 * NANOSECS_PER_MILLISEC, 2));
+}
+
+TEST_VM_F(JfrTestThreadCPULoadSingle, DISABLED_UserAboveMaximum) {
+
+  // First call will not report above 100%
+  MockOs::user_cpu_time = 200 * NANOSECS_PER_MILLISEC;
+  MockOs::system_cpu_time = 100 * NANOSECS_PER_MILLISEC;
+  EXPECT_TRUE(JfrThreadCPULoadEvent::update_event(event, thread, 200 * NANOSECS_PER_MILLISEC, 1));
+  EXPECT_FLOAT_EQ(0.5, event.user);
+  EXPECT_FLOAT_EQ(0.5, event.system);
+
+  // Second call will see an extra 100 millisecs user time from the remainder
+  EXPECT_TRUE(JfrThreadCPULoadEvent::update_event(event, thread, (200 + 400) * NANOSECS_PER_MILLISEC, 1));
+  EXPECT_FLOAT_EQ(0.25, event.user);
+  EXPECT_FLOAT_EQ(0, event.system);
+}
+
+TEST_VM_F(JfrTestThreadCPULoadSingle, DISABLED_SystemAboveMaximum) {
+
+  // First call will not report above 100%
+  MockOs::user_cpu_time = 100 * NANOSECS_PER_MILLISEC;
+  MockOs::system_cpu_time = 300 * NANOSECS_PER_MILLISEC;
+  EXPECT_TRUE(JfrThreadCPULoadEvent::update_event(event, thread, 200 * NANOSECS_PER_MILLISEC, 1));
+  EXPECT_FLOAT_EQ(0, event.user);
+  EXPECT_FLOAT_EQ(1, event.system);
+
+  // Second call will see an extra 100 millisecs user and system time from the remainder
+  EXPECT_TRUE(JfrThreadCPULoadEvent::update_event(event, thread, (200 + 400) * NANOSECS_PER_MILLISEC, 1));
+  EXPECT_FLOAT_EQ(0.25, event.user);
+  EXPECT_FLOAT_EQ(0.25, event.system);
+}
+
+TEST_VM_F(JfrTestThreadCPULoadSingle, DISABLED_SystemTimeDecreasing) {
+
+  // As seen in an actual run - caused by different resolution for total and user time
+  // Total time    User time    (Calculated system time)
+  //       200          100         100
+  //       210          200          10
+  //       400          300         100
+
+  MockOs::user_cpu_time = 100 * NANOSECS_PER_MILLISEC;
+  MockOs::system_cpu_time = 100 * NANOSECS_PER_MILLISEC;
+  EXPECT_TRUE(JfrThreadCPULoadEvent::update_event(event, thread, 400 * NANOSECS_PER_MILLISEC, 1));
+  EXPECT_FLOAT_EQ(0.25, event.user);
+  EXPECT_FLOAT_EQ(0.25, event.system);
+
+  MockOs::user_cpu_time += 100 * NANOSECS_PER_MILLISEC;
+  MockOs::system_cpu_time -= 90 * NANOSECS_PER_MILLISEC;
+  EXPECT_TRUE(JfrThreadCPULoadEvent::update_event(event, thread, (400 + 400) * NANOSECS_PER_MILLISEC, 1));
+  EXPECT_FLOAT_EQ(0.25, event.user);
+  EXPECT_FLOAT_EQ(0, event.system);
+
+  MockOs::user_cpu_time += 100 * NANOSECS_PER_MILLISEC;
+  MockOs::system_cpu_time += 90 * NANOSECS_PER_MILLISEC;
+  EXPECT_TRUE(JfrThreadCPULoadEvent::update_event(event, thread, (400 + 400 + 400) * NANOSECS_PER_MILLISEC, 1));
+  EXPECT_FLOAT_EQ(0.25, event.user);
+  EXPECT_FLOAT_EQ(0, event.system);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/CDSandJFR.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @summary Make sure CDS and JFR work together.
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/test-classes test-classes
+ * @modules jdk.jfr
+ * @build Hello GetFlightRecorder
+ * @run driver ClassFileInstaller -jar CDSandJFR.jar Hello GetFlightRecorder GetFlightRecorder$TestEvent GetFlightRecorder$SimpleEvent
+ * @run main CDSandJFR
+ */
+
+import jdk.test.lib.BuildHelper;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class CDSandJFR {
+    static String[] classes = {
+        "jdk/jfr/Event",
+        "jdk/jfr/events/FileReadEvent",
+        "jdk/jfr/events/FileWriteEvent",
+        "jdk/jfr/events/SocketReadEvent",
+        "jdk/jfr/events/SocketWriteEvent",
+        "jdk/jfr/events/ExceptionThrownEvent",
+        "jdk/jfr/events/ExceptionStatisticsEvent",
+        "jdk/jfr/events/ErrorThrownEvent",
+        "jdk/jfr/events/ActiveSettingEvent",
+        "jdk/jfr/events/ActiveRecordingEvent",
+        "Hello",
+        "GetFlightRecorder",
+        "GetFlightRecorder$TestEvent",
+    };
+
+    public static void main(String[] args) throws Exception {
+        test(classes);
+    }
+
+    static void test(String[] classes) throws Exception {
+        String appJar = ClassFileInstaller.getJarPath("CDSandJFR.jar");
+        OutputAnalyzer output;
+        output = TestCommon.testDump(appJar, TestCommon.list(classes));
+        TestCommon.checkDump(output, "Skipping JFR event class jdk/jfr/");
+
+        output = TestCommon.exec(appJar,
+                                 "-XX:StartFlightRecording=dumponexit=true",
+                                 "Hello");
+        TestCommon.checkExec(output, "Hello World");
+
+        TestCommon.checkExec(TestCommon.exec(appJar,
+                                             "-XX:FlightRecorderOptions=retransform=true",
+                                             "GetFlightRecorder"));
+        TestCommon.checkExec(TestCommon.exec(appJar,
+                                             "-XX:FlightRecorderOptions=retransform=false",
+                                             "GetFlightRecorder"));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/TestWithProfiler.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @bug 8145221
+ * @summary After creating an AppCDS archive, run the test with the JFR profiler
+ *          enabled, and keep calling a method in the archive in a tight loop.
+ *          This is to test the safe handling of trampoline functions by the
+ *          profiler.
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds
+ * @modules java.base/jdk.internal.misc
+ *          java.management
+ *          jdk.jartool/sun.tools.jar
+ * @compile test-classes/MyThread.java
+ * @compile test-classes/TestWithProfilerHelper.java
+ * @run main TestWithProfiler
+ */
+
+import jdk.test.lib.BuildHelper;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class TestWithProfiler {
+    public static void main(String[] args) throws Exception {
+        JarBuilder.build("myThread", "MyThread", "TestWithProfilerHelper");
+        String appJar = TestCommon.getTestJar("myThread.jar");
+        OutputAnalyzer output = TestCommon.dump(appJar,
+            TestCommon.list("MyThread", "TestWithProfilerHelper"));
+        TestCommon.checkDump(output);
+        output = TestCommon.exec(appJar,
+            "-XX:+UnlockDiagnosticVMOptions",
+            "-Xint",
+            "-XX:+FlightRecorder",
+            "-XX:StartFlightRecording=duration=15s,filename=myrecording.jfr,settings=profile,dumponexit=true",
+            "TestWithProfilerHelper");
+        TestCommon.checkExec(output);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/test-classes/GetFlightRecorder.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.List;
+
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.jfr.consumer.RecordedEvent;
+
+public class GetFlightRecorder {
+    private static class TestEvent extends Event {
+    }
+    private static class SimpleEvent extends Event {
+        public int id;
+    }
+    public static void main(String args[]) throws Exception {
+        EventType type = EventType.getEventType(TestEvent.class); // This class is loaded before recording has started.
+        if (type.isEnabled()) {
+            throw new RuntimeException("Expected event to be disabled before recording start");
+        }
+
+        // (1) make sure you can obtain the flight recorder without error.
+        System.out.println("jdk.jfr.FlightRecorder.getFlightRecorder() = " + FlightRecorder.getFlightRecorder());
+
+        // (2) test that the event class loaded before recording can still work.
+        Recording r = new Recording();
+        r.start();
+        if (!type.isEnabled()) {
+            throw new RuntimeException("Expected event to be enabled during recording");
+        }
+        TestEvent testEvent = new TestEvent();
+        testEvent.commit();
+        loadEventClassDuringRecording();
+        r.stop();
+        if (type.isEnabled()) {
+            throw new RuntimeException("Expected event to be disabled after recording stopped");
+        }
+        System.out.println("Checking SimpleEvent");
+        hasEvent(r, SimpleEvent.class.getName());
+        System.out.println("OK");
+
+        System.out.println("Checking TestEvent");
+        hasEvent(r, TestEvent.class.getName());
+        System.out.println("OK");
+    }
+
+    // Classes that are loaded during a recording
+    // should get instrumentation on class load
+    private static void loadEventClassDuringRecording() {
+        SimpleEvent event = new SimpleEvent();
+        event.commit();
+    }
+
+    public static List<RecordedEvent> fromRecording(Recording recording) throws IOException {
+        return RecordingFile.readAllEvents(makeCopy(recording));
+    }
+
+    private static Path makeCopy(Recording recording) throws IOException {
+        Path p = recording.getDestination();
+        if (p == null) {
+            File directory = new File(".");
+            // FIXME: Must come up with a way to give human-readable name
+            // this will at least not clash when running parallel.
+            ProcessHandle h = ProcessHandle.current();
+            p = new File(directory.getAbsolutePath(), "recording-" + recording.getId() + "-pid" + h.pid() + ".jfr").toPath();
+            recording.dump(p);
+        }
+        return p;
+    }
+
+    public static void hasEvent(Recording r, String name) throws IOException {
+        List<RecordedEvent> events = fromRecording(r);
+        hasEvents(events);
+        hasEvent(events, name);
+    }
+
+    public static void hasEvents(List<RecordedEvent> events) {
+        if (events.isEmpty()) {
+            throw new RuntimeException("No events");
+        }
+    }
+
+    public static void hasEvent(List<RecordedEvent> events, String name) throws IOException {
+        if (!containsEvent(events, name)) {
+            throw new RuntimeException("Missing event " + name  + " in recording " + events.toString());
+        }
+    }
+
+    private static boolean containsEvent(List<RecordedEvent> events, String name) {
+        for (RecordedEvent event : events) {
+            if (event.getEventType().getName().equals(name)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/test-classes/MyThread.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+class MyThread extends Thread {
+    void foo() {}
+
+    public void run() {
+        while (true) {
+             foo();
+       }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/test-classes/TestWithProfilerHelper.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+public class TestWithProfilerHelper {
+    public static void main(String[] args) throws Exception {
+        Thread t = new MyThread();
+        t.start();
+        String prop = "TestWithProfiler.timeout";
+        int secs = Integer.parseInt(System.getProperty(prop, "15"));
+        System.out.println("Run for -D" + prop + "=" + secs  + " (seconds)");
+        Thread.sleep(secs * 1000);
+        System.exit(0);
+    }
+}
--- a/test/jdk/ProblemList.txt	Tue May 15 11:28:29 2018 -0700
+++ b/test/jdk/ProblemList.txt	Tue May 15 20:24:34 2018 +0200
@@ -787,4 +787,13 @@
 #
 # Java EE Module Removal
 #
-com/sun/jdi/RedefineCrossEvent.java                          8194308    generic-all  Java EE Module Removal
+com/sun/jdi/RedefineCrossEvent.java                             8194308    generic-all  Java EE Module Removal
+
+############################################################################
+
+# jdk_jfr
+
+jdk/jfr/event/io/TestInstrumentation.java                       8202142    generic-all
+jdk/jfr/event/sampling/TestNative.java                          8202142    generic-all
+jdk/jfr/event/os/TestSystemProcess.java                         8202835    linux-all
+jdk/jfr/event/runtime/TestBiasedLockRevocationEvents.java       8203237    generic-all
\ No newline at end of file
--- a/test/jdk/TEST.ROOT	Tue May 15 11:28:29 2018 -0700
+++ b/test/jdk/TEST.ROOT	Tue May 15 20:24:34 2018 +0200
@@ -14,7 +14,7 @@
 # A test flagged with key "printer" requires a printer to succeed, else
 # throws a PrinterException or the like.
 
-keys=2d dnd headful i18n intermittent printer randomness
+keys=2d dnd headful i18n intermittent printer randomness jfr
 
 # Tests that must run in othervm mode
 othervm.dirs=java/awt java/beans javax/accessibility javax/imageio javax/sound javax/swing javax/print javax/management com/sun/awt sun/awt sun/java2d javax/xml/jaxp/testng/validation java/lang/ProcessHandle
--- a/test/jdk/TEST.groups	Tue May 15 11:28:29 2018 -0700
+++ b/test/jdk/TEST.groups	Tue May 15 20:24:34 2018 +0200
@@ -288,6 +288,9 @@
     :core_tools \
     :svc_tools
 
+jdk_jfr = \
+    jdk/jfr
+
 #
 # Catch-all for other areas with a small number of tests
 #
@@ -337,6 +340,7 @@
     :jdk_instrument \
     :jdk_jmx \
     :jdk_jdi \
+    :jdk_jfr \
     :svc_tools
 
 #############################
@@ -410,6 +414,7 @@
     :jdk_instrument_sanity \
     :jdk_jmx_sanity \
     :jdk_jdi_sanity \
+    :jdk_jfr_sanity \
     :svc_tools_sanity
 
 jdk_management_sanity =
@@ -452,6 +457,20 @@
     com/sun/jdi/sde/MangleTest.java \
     com/sun/jdi/sde/TemperatureTableTest.java
 
+jdk_jfr_sanity = \
+    jdk/jfr/api/recording/event/TestLoadEventAfterStart.java \
+    jdk/jfr/api/recording/state/TestState.java \
+    jdk/jfr/event/os/TestCPULoad.java \
+    jdk/jfr/event/compiler/TestAllocInNewTLAB.java \
+    jdk/jfr/jcmd/TestJcmdStartStopDefault.java \
+    jdk/jfr/event/io/TestFileStreamEvents.java \
+    jdk/jfr/event/compiler/TestCompilerCompile.java \
+    jdk/jfr/event/gc/collection/TestGCGarbageCollectionEvent.java \
+    jdk/jfr/event/runtime/TestClassLoadEvent.java \
+    jdk/jfr/event/runtime/TestJavaBlockedEvent.java \
+    jdk/jfr/event/gc/collection/TestGCWithFasttime.java \
+    jdk/jfr/event/gc/configuration/TestGCConfigurationEvent.java
+
 svc_tools_sanity =
 
 #############################
@@ -470,3 +489,18 @@
     com/sun/java/swing \
     com/sun/awt
 
+needs_g1gc = \
+  jdk/jfr/event/gc/refstat/TestRefStatEventWithG1ConcurrentMark.java \
+  jdk/jfr/event/gc/refstat/TestRefStatEventWithG1FullCollection.java \
+  jdk/jfr/event/gc/refstat/TestRefStatEventWithG1New.java \
+  jdk/jfr/event/gc/detailed/TestEvacuationFailedEvent.java \
+  jdk/jfr/event/gc/detailed/TestEvacuationInfoEvent.java \
+  jdk/jfr/event/gc/detailed/TestG1ConcurrentModeFailureEvent.java \
+  jdk/jfr/event/gc/collection/TestGCCauseWithG1ConcurrentMark.java \
+  jdk/jfr/event/gc/collection/TestGCCauseWithG1FullCollection.java \
+  jdk/jfr/event/gc/collection/TestYoungGarbageCollectionEventWithG1New.java \
+  jdk/jfr/event/gc/collection/TestGCEventMixedWithG1FullCollection.java \
+  jdk/jfr/event/gc/collection/TestGCEventMixedWithG1ConcurrentMark.java \
+  jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithG1FullCollection.java \
+  jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithG1ConcurrentMark.java \
+  jdk/jfr/event/gc/heapsummary/TestHeapSummaryEventG1.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/TEST.properties	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,2 @@
+modules = jdk.jfr
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/consumer/TEST.properties	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,2 @@
+modules = java.management
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/consumer/TestFieldAccess.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.consumer;
+
+import java.util.List;
+
+import jdk.jfr.Event;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedClass;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedThread;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.consumer.TestFieldAccess
+ */
+public class TestFieldAccess {
+
+    private static class MyEvent extends Event {
+        String stringField = "Hello";
+        int intField = 4711;
+        long longField = 4712L;
+        short shortField = (short)67;
+        double doubleField = Double.NaN;
+        float floatField = Float.MIN_VALUE;
+        boolean booleanField = false;
+        Thread threadField = Thread.currentThread();
+        Class<?> classField = MyEvent.class;
+    }
+
+    public static void main(String[] args) throws Throwable {
+        try (Recording r = new Recording()) {
+            r.enable(MyEvent.class);
+            r.start();
+            MyEvent myEvent = new MyEvent();
+            myEvent.commit();
+            r.stop();
+            List<RecordedEvent> events = Events.fromRecording(r);
+            Events.hasEvents(events);
+            RecordedEvent event = events.get(0);
+            testHasField(event);
+            testGetField(event, myEvent);
+        }
+    }
+
+    private static void testGetField(RecordedEvent event, MyEvent myEvent) {
+        String stringField = event.getValue("stringField");
+        Asserts.assertEquals(stringField, myEvent.stringField);
+
+        int intField = event.getValue("intField");
+        Asserts.assertEquals(intField, myEvent.intField);
+
+        long longField = event.getValue("longField");
+        Asserts.assertEquals(longField, myEvent.longField);
+
+        short shortField = event.getValue("shortField");
+        Asserts.assertEquals(shortField, myEvent.shortField);
+
+        double doubleField = event.getValue("doubleField");
+        Asserts.assertEquals(doubleField, myEvent.doubleField);
+
+        float floatField = event.getValue("floatField");
+        Asserts.assertEquals(floatField, myEvent.floatField);
+
+        boolean booleanField = event.getValue("booleanField");
+        Asserts.assertEquals(booleanField, myEvent.booleanField);
+
+        RecordedThread threadField = event.getValue("eventThread");
+        Asserts.assertEquals(threadField.getJavaName(), myEvent.threadField.getName());
+        String threadGroupName = event.getValue("eventThread.group.name");
+        Asserts.assertEquals(threadField.getThreadGroup().getName(), threadGroupName);
+
+        RecordedClass  classField = event.getValue("classField");
+        Asserts.assertEquals(classField.getName(), myEvent.classField.getName());
+        String className = event.getValue("classField.name");
+        Asserts.assertEquals(classField.getName(), className.replace("/", "."));
+
+
+        try {
+            event.getValue("doesnotexist");
+        } catch (IllegalArgumentException iae) {
+            // as expected
+        }
+
+        try {
+            event.getValue("classField.doesnotexist");
+        } catch (IllegalArgumentException iae) {
+            // as expected
+        }
+
+        try {
+            event.getValue(null);
+        } catch (NullPointerException npe) {
+            // as expected
+        }
+    }
+
+    private static void testHasField(RecordedEvent event) {
+        System.out.println(event);
+        Asserts.assertTrue(event.hasField("stringField"));
+        Asserts.assertTrue(event.hasField("intField"));
+        Asserts.assertTrue(event.hasField("longField"));
+        Asserts.assertTrue(event.hasField("shortField"));
+        Asserts.assertTrue(event.hasField("doubleField"));
+        Asserts.assertTrue(event.hasField("floatField"));
+        Asserts.assertTrue(event.hasField("threadField"));
+        Asserts.assertTrue(event.hasField("classField"));
+        Asserts.assertTrue(event.hasField("classField.name"));
+        Asserts.assertTrue(event.hasField("eventThread"));
+        Asserts.assertTrue(event.hasField("eventThread.group.name"));
+        Asserts.assertTrue(event.hasField("startTime"));
+        Asserts.assertTrue(event.hasField("stackTrace"));
+        Asserts.assertTrue(event.hasField("duration"));
+        Asserts.assertFalse(event.hasField("doesNotExist"));
+        Asserts.assertFalse(event.hasField("classField.doesNotExist"));
+        Asserts.assertFalse(event.hasField(""));
+        try {
+            event.hasField(null);
+        } catch (NullPointerException npe) {
+            // as expected
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/consumer/TestGetStackTrace.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.consumer;
+
+import static jdk.test.lib.Asserts.assertEquals;
+import static jdk.test.lib.Asserts.assertNotNull;
+import static jdk.test.lib.Asserts.assertNull;
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.util.List;
+import java.util.function.Consumer;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedFrame;
+import jdk.jfr.consumer.RecordedMethod;
+import jdk.jfr.consumer.RecordedStackTrace;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.SimpleEvent;
+
+/*
+ * @test
+ * @summary Verifies that a recorded JFR event has the correct stack trace info
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.consumer.TestGetStackTrace
+ */
+public class TestGetStackTrace {
+
+    public static void main(String[] args) throws Throwable {
+        testStackTrace(r -> r.enable(SimpleEvent.class), TestGetStackTrace::assertNoStackTrace);
+        testStackTrace(r -> r.enable(SimpleEvent.class).withoutStackTrace(), TestGetStackTrace::assertStackTrace);
+    }
+
+    private static void testStackTrace(Consumer<Recording> recordingConfigurer, Consumer<RecordedEvent> asserter) throws Throwable {
+        Recording r = new Recording();
+        recordingConfigurer.accept(r);
+        r.start();
+        SimpleEvent event = new SimpleEvent();
+        event.commit();
+        r.stop();
+        List<RecordedEvent> events = Events.fromRecording(r);
+        r.close();
+        Events.hasEvents(events);
+    }
+
+    private static void assertNoStackTrace(RecordedEvent re) {
+        assertNull(re.getStackTrace());
+    }
+
+    private static void assertStackTrace(RecordedEvent re) {
+        assertNotNull(re.getStackTrace());
+        RecordedStackTrace strace = re.getStackTrace();
+        assertEquals(strace.isTruncated(), false);
+        List<RecordedFrame> frames = strace.getFrames();
+        assertTrue(frames.size() > 0);
+        for (RecordedFrame frame : frames) {
+            assertFrame(frame);
+        }
+    }
+
+    private static void assertFrame(RecordedFrame frame) {
+        int bci = frame.getBytecodeIndex();
+        int line = frame.getLineNumber();
+        boolean javaFrame = frame.isJavaFrame();
+        RecordedMethod method = frame.getMethod();
+        String type = frame.getType();
+        System.out.println("*** Frame Info ***");
+        System.out.println("bci=" + bci);
+        System.out.println("line=" + line);
+        System.out.println("type=" + type);
+        System.out.println("method=" + method);
+        System.out.println("***");
+        Asserts.assertTrue(javaFrame, "Only Java frame are currently supported");
+        Asserts.assertGreaterThanOrEqual(bci, -1);
+        Asserts.assertNotNull(method, "Method should not be null");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/consumer/TestHiddenMethod.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.api.consumer;
+
+import static jdk.test.lib.Asserts.assertEquals;
+import static jdk.test.lib.Asserts.assertFalse;
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.time.Duration;
+import java.util.List;
+
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+
+import jdk.jfr.Event;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedFrame;
+import jdk.jfr.consumer.RecordedStackTrace;
+import jdk.test.lib.jfr.Events;
+
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @library /test/lib
+ * @modules java.scripting
+ *          jdk.jfr
+ *
+ * @run main/othervm jdk.jfr.api.consumer.TestHiddenMethod
+ */
+public final class TestHiddenMethod {
+
+    public static void main(String[] args) throws Throwable {
+        Recording recording = new Recording();
+        recording.enable(MyEvent.class).withThreshold(Duration.ofMillis(0));
+        recording.start();
+
+        // Commit event with hidden methods
+        ScriptEngineManager manager = new ScriptEngineManager();
+        ScriptEngine engine = manager.getEngineByName("nashorn");
+        engine.eval(
+                "function emit() {"
+                + "  print('About to emit event from Javascript');"
+                + "  var TestEvent = Java.type(\"jdk.jfr.api.consumer.TestHiddenMethod$MyEvent\");"
+                + "  var event = new TestEvent;"
+                + "  event.begin();"
+                + "  event.end();"
+                + "  event.commit();"
+                + "  print('Event emitted from Javascript!');"
+                + "}"
+                + "emit();");
+
+        // Commit event with visible method
+        MyEvent visible = new MyEvent();
+        visible.begin();
+        visible.end();
+        visible.commit();
+        recording.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        assertEquals(2, events.size(), "Expected two events");
+        RecordedEvent hiddenEvent = events.get(0);
+        RecordedEvent visibleEvent = events.get(1);
+
+        System.out.println("hiddenEvent:" + hiddenEvent);
+        System.out.println("visibleEvent:" + visibleEvent);
+
+        assertTrue(hasHiddenStackFrame(hiddenEvent), "No hidden frame in hidden event: " + hiddenEvent);
+        assertFalse(hasHiddenStackFrame(visibleEvent), "Hidden frame in visible event: " + visibleEvent);
+    }
+
+    private static boolean hasHiddenStackFrame(RecordedEvent event) throws Throwable {
+        RecordedStackTrace stacktrace = event.getStackTrace();
+        List<RecordedFrame> frames = stacktrace.getFrames();
+        assertFalse(frames.isEmpty(), "Stacktrace frames was empty");
+        for (RecordedFrame frame : frames) {
+            if (frame.getMethod().isHidden()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static class MyEvent extends Event {
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/consumer/TestMethodGetModifiers.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.api.consumer;
+
+import static jdk.test.lib.Asserts.assertNotNull;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedClass;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedFrame;
+import jdk.jfr.consumer.RecordedMethod;
+import jdk.jfr.consumer.RecordedStackTrace;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.SimpleEvent;
+
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm -Xint jdk.jfr.api.consumer.TestMethodGetModifiers
+ */
+public final class TestMethodGetModifiers {
+
+    public static void main(String[] args) throws Throwable {
+        Recording recording = new Recording();
+        recording.start();
+
+        SimpleEvent ev = new SimpleEvent();
+        ev.commit();
+        recording.stop();
+
+        List<RecordedEvent> recordedEvents = Events.fromRecording(recording);
+        Events.hasEvents(recordedEvents);
+        RecordedEvent recordedEvent = recordedEvents.get(0);
+
+        System.out.println("recorded event:" + recordedEvent);
+
+        RecordedStackTrace stacktrace = recordedEvent.getStackTrace();
+        List<RecordedFrame> frames = stacktrace.getFrames();
+        for (RecordedFrame frame : frames) {
+            RecordedMethod method = frame.getMethod();
+            if (method.getName().equals("main")) {
+                System.out.println("'main' method: " + method);
+                int modifiers = TestMethodGetModifiers.class.getDeclaredMethod("main", (Class<?>)String[].class).getModifiers();
+                System.out.println("modifiers: " + modifiers);
+                Asserts.assertEquals(method.getModifiers(), modifiers, "Incorrect method modifier reported");
+                RecordedClass type = method.getType();
+                assertNotNull(type, "Recorded class can not be null");
+            }
+
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/consumer/TestReadTwice.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.consumer;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.LinkedList;
+import java.util.List;
+
+import jdk.jfr.Event;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+
+
+/*
+ * @test
+ * @summary Reads the recorded file two times and verifies that both reads are the same
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.consumer.TestReadTwice
+ */
+public class TestReadTwice {
+
+    private static class MyEvent extends Event {
+    }
+
+    public static void main(String[] args) throws Throwable {
+        Recording r = new Recording();
+        r.enable(MyEvent.class).withoutStackTrace();
+        r.start();
+
+        // Commit a single event to the recording
+        MyEvent event = new MyEvent();
+        event.commit();
+
+        r.stop();
+
+        // Dump the recording to a file
+        Path path = Files.createTempFile("recording", ".jfr");
+        System.out.println("Dumping to " + path);
+        r.dump(path);
+        r.close();
+
+        // Read all events from the file in one go
+        List<RecordedEvent> events = RecordingFile.readAllEvents(path);
+
+        // Read again the same events one by one
+        RecordingFile rfile = new RecordingFile(path);
+        List<RecordedEvent> events2 = new LinkedList<>();
+        while (rfile.hasMoreEvents()) {
+            events2.add(rfile.readEvent());
+        }
+
+        // Compare sizes
+        Asserts.assertEquals(events.size(), events2.size());
+        rfile.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/consumer/TestRecordedClassLoader.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.consumer;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedClass;
+import jdk.jfr.consumer.RecordedClassLoader;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.TestClassLoader;
+
+/*
+ * @test
+ * @summary Verifies the methods of the RecordedClassLoader
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.consumer.TestRecordedClassLoader
+ */
+public class TestRecordedClassLoader {
+    private final static String TEST_CLASS_NAME = "jdk.jfr.api.consumer.TestRecordedClassLoader$MyTestClass";
+    private final static String EVENT_NAME = EventNames.ClassDefine;
+
+    static class MyTestClass {
+    }
+
+    public static void main(String[] args) throws Exception {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME).withoutStackTrace();
+        TestClassLoader cl = new TestClassLoader();
+        recording.start();
+        cl.loadClass(TEST_CLASS_NAME);
+        recording.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        boolean isDefined = false;
+        for (RecordedEvent event : events) {
+            RecordedClass definedClass = event.getValue("definedClass");
+            if (TEST_CLASS_NAME.equals(definedClass.getName())) {
+                System.out.println(event);
+
+                // get the RecordedClassLoader from the RecordedClass, the "definedClass"
+                RecordedClassLoader definingClassLoader = definedClass.getClassLoader();
+                Asserts.assertNotNull(definingClassLoader, "Defining Class Loader should not be null");
+
+                // invoke RecordedClassLoader.getType() in order to validate the type of the RecordedClassLoader
+                RecordedClass definingClassLoaderType = definingClassLoader.getType();
+                Asserts.assertNotNull(definingClassLoaderType, "The defining Class Loader type should not be null");
+
+                // verify matching types
+                Asserts.assertEquals(cl.getClass().getName(), definingClassLoaderType.getName(),
+                    "Expected type " + cl.getClass().getName() + ", got type " + definingClassLoaderType.getName());
+
+                // get a RecordedClassLoader directly from the "definingClassLoader" field as well
+                RecordedClassLoader definingClassLoaderFromField = event.getValue("definingClassLoader");
+                Asserts.assertNotNull(definingClassLoaderFromField,
+                    "Defining Class Loader instantatiated from field should not be null");
+
+                // ensure that the class loader instance used in the test actually has a name
+                Asserts.assertNotNull(cl.getName(),
+                    "Expected a valid name for the TestClassLoader");
+
+                // invoke RecordedClassLoader.getName() to get the name of the class loader instance
+                Asserts.assertEquals(cl.getName(), definingClassLoader.getName(),
+                    "Defining Class Loader should have the same name as the original class loader");
+                Asserts.assertEquals(definingClassLoaderFromField.getName(), definingClassLoader.getName(),
+                    "Defining Class Loader representations should have the same class loader name");
+
+                // invoke uniqueID()
+                Asserts.assertGreaterThan(definingClassLoader.getId(), 0L, "Invalid id assignment");
+
+                // second order class loader information ("check class loader of the class loader")
+                RecordedClassLoader classLoaderOfDefClassLoader = definingClassLoaderType.getClassLoader();
+                Asserts.assertNotNull(classLoaderOfDefClassLoader,
+                    "The class loader for the definining class loader should not be null");
+                Asserts.assertEquals(cl.getClass().getClassLoader().getName(), classLoaderOfDefClassLoader.getName(),
+                    "Expected class loader name " + cl.getClass().getClassLoader().getName() + ", got name " + classLoaderOfDefClassLoader.getName());
+
+                RecordedClass classLoaderOfDefClassLoaderType = classLoaderOfDefClassLoader.getType();
+                Asserts.assertNotNull(classLoaderOfDefClassLoaderType,
+                    "The class loader type for the defining class loader should not be null");
+                Asserts.assertEquals(cl.getClass().getClassLoader().getClass().getName(), classLoaderOfDefClassLoaderType.getName(),
+                    "Expected type " + cl.getClass().getClassLoader().getClass().getName() + ", got type " + classLoaderOfDefClassLoaderType.getName());
+
+                Asserts.assertGreaterThan(definingClassLoader.getId(), classLoaderOfDefClassLoader.getId(),
+                    "expected id assignment invariant broken for Class Loaders");
+
+                isDefined = true;
+            }
+        }
+        Asserts.assertTrue(isDefined, "No class define event found to verify RecordedClassLoader");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/consumer/TestRecordedEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.consumer;
+
+import java.util.List;
+
+import jdk.jfr.Description;
+import jdk.jfr.Event;
+import jdk.jfr.Recording;
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.consumer.RecordedClass;
+import jdk.jfr.consumer.RecordedClassLoader;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Verifies the methods of the RecordedEvent
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.consumer.TestRecordedEvent
+ */
+public class TestRecordedEvent {
+
+    static class MyClass {
+    }
+
+    static class TestEvent extends Event {
+
+        @Description("MyField")
+        Class<?> clzField = String.class;
+        int intField;
+        String stringField = "myString";
+        Class<?> myClass = MyClass.class;
+    }
+
+    public static void main(String[] args) throws Throwable {
+        Recording r = new Recording();
+        r.start();
+        TestEvent t = new TestEvent();
+        t.commit();
+        r.stop();
+        List<RecordedEvent> events = Events.fromRecording(r);
+        Events.hasEvents(events);
+
+        Asserts.assertEquals(events.size(), 1);
+
+        RecordedEvent event = events.get(0);
+
+        List<ValueDescriptor> descriptors = event.getFields();
+
+        System.out.println("Descriptors");
+        for (ValueDescriptor descriptor : descriptors) {
+            System.out.println(descriptor.getName());
+            System.out.println(descriptor.getTypeName());
+        }
+        System.out.println("Descriptors end");
+
+        Object recordedClass = event.getValue("clzField");
+        Asserts.assertTrue(recordedClass instanceof RecordedClass, "Expected Recorded Class got " + recordedClass);
+
+        Object recordedInt = event.getValue("intField");
+        Asserts.assertTrue(recordedInt instanceof Integer);
+
+        Object recordedString = event.getValue("stringField");
+        System.out.println("recordedString class: " + recordedString.getClass());
+        Asserts.assertTrue(recordedString instanceof String);
+
+        Object myClass = event.getValue("myClass");
+        Asserts.assertTrue(myClass instanceof RecordedClass, "Expected Recorded Class got " + recordedClass);
+
+        RecordedClass myRecClass = (RecordedClass) myClass;
+        Asserts.assertEquals(MyClass.class.getName(), myRecClass.getName(), "Got " + myRecClass.getName());
+
+        Object recordedClassLoader = myRecClass.getValue("classLoader");
+        Asserts.assertTrue(recordedClassLoader instanceof RecordedClassLoader, "Expected Recorded ClassLoader got " + recordedClassLoader);
+
+        RecordedClassLoader myRecClassLoader = (RecordedClassLoader)recordedClassLoader;
+        ClassLoader cl = MyClass.class.getClassLoader();
+        Asserts.assertEquals(cl.getClass().getName(), myRecClassLoader.getType().getName(), "Expected Recorded ClassLoader type to equal loader type");
+
+        Asserts.assertNotNull(myRecClass.getModifiers());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/consumer/TestRecordedEventGetThread.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.consumer;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedThread;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.SimpleEvent;
+
+/*
+ * @test
+ * @summary Tests that the RecordedEvent.getThread() returns th expected info
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.consumer.TestRecordedEventGetThread
+ */
+public class TestRecordedEventGetThread {
+
+    private static final String MY_THREAD_NAME = "MY_THREAD_NAME";
+
+    public static void main(String[] args) throws Throwable {
+        Thread currentThread = Thread.currentThread();
+        currentThread.setName(MY_THREAD_NAME);
+        long expectedThreadId = currentThread.getId();
+
+        Recording r = new Recording();
+        r.start();
+        SimpleEvent t = new SimpleEvent();
+        t.commit();
+        r.stop();
+        List<RecordedEvent> events = Events.fromRecording(r);
+        r.close();
+        Events.hasEvents(events);
+        RecordedEvent event = events.get(0);
+        RecordedThread recordedThread = event.getThread();
+
+        Asserts.assertNotNull(recordedThread);
+        Asserts.assertEquals(recordedThread.getJavaName(), MY_THREAD_NAME);
+        Asserts.assertEquals(recordedThread.getJavaThreadId(), expectedThreadId);
+        Asserts.assertNotNull(recordedThread.getOSThreadId());
+        Asserts.assertNotNull(recordedThread.getId());
+        Asserts.assertEquals(recordedThread.getOSName(), MY_THREAD_NAME);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/consumer/TestRecordedEventGetThreadOther.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.consumer;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+
+import jdk.jfr.Event;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedThread;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @summary Tests that the RecordedEvent.getThread() returns th expected info
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.consumer.TestRecordedEventGetThreadOther
+ */
+public class TestRecordedEventGetThreadOther {
+
+    private static final String MY_THREAD_NAME = "MY_THREAD_NAME";
+    private static long expectedThreadId;
+    private static Path dumpFilePath;
+
+    static class TestEvent extends Event {
+    }
+
+    static class PostingThread extends Thread {
+
+        PostingThread() {
+            setName(MY_THREAD_NAME);
+            expectedThreadId = getId();
+        }
+
+        @Override
+        public void run() {
+            try {
+                System.out.println("Starting thread...");
+                dumpFilePath = postEventAndDumpToFile();
+                System.out.println("events dumped to the file " + dumpFilePath);
+            } catch (Throwable t) {
+                t.printStackTrace();
+                Asserts.fail();
+            }
+        }
+    }
+
+    public static void main(String[] args) throws Throwable {
+        Thread.currentThread().setName("MyMainThread");
+
+        PostingThread thread = new PostingThread();
+        thread.start();
+        thread.join();
+        System.out.println("testing dump in file " + dumpFilePath);
+
+        List<RecordedEvent> events = RecordingFile.readAllEvents(dumpFilePath);
+        Asserts.assertEquals(events.size(), 1);
+
+        RecordedEvent event = events.get(0);
+        RecordedThread recordedThread = event.getThread();
+
+        Asserts.assertNotNull(recordedThread);
+        Asserts.assertEquals(recordedThread.getJavaName(), MY_THREAD_NAME);
+        Asserts.assertEquals(recordedThread.getJavaThreadId(), expectedThreadId);
+        Asserts.assertNotNull(recordedThread.getId());
+        Asserts.assertEquals(recordedThread.getOSName(), MY_THREAD_NAME);
+    }
+
+    private static Path postEventAndDumpToFile() throws Throwable {
+        Recording r = new Recording();
+        r.start();
+        TestEvent t = new TestEvent();
+        t.commit();
+        r.stop();
+        Path path = Files.createTempFile("recording", ".jfr");
+        System.out.println("Created path: " + path);
+        r.dump(path);
+        r.close();
+        return path;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/consumer/TestRecordedFrame.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.api.consumer;
+
+import java.io.IOException;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedFrame;
+import jdk.jfr.consumer.RecordedMethod;
+import jdk.jfr.consumer.RecordedStackTrace;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.SimpleEvent;
+
+
+/*
+ * @test
+ * @summary Simple test for RecordedFrame APIs
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm -Xint  -XX:+UseInterpreter -Dinterpreted=true  jdk.jfr.api.consumer.TestRecordedFrame
+ * @run main/othervm -Xcomp -XX:-UseInterpreter -Dinterpreted=false jdk.jfr.api.consumer.TestRecordedFrame
+ */
+public final class TestRecordedFrame {
+
+    public static void main(String[] args) throws IOException {
+        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
+        doTest(getLineNumber("main", stackTrace) + 1);
+    }
+
+    /**
+     * Returns line number of the passed method for the passed stacktrace
+     */
+    private static int getLineNumber(String methodName, StackTraceElement[] stackTrace) {
+        for (StackTraceElement ste : stackTrace) {
+            if (methodName.equals(ste.getMethodName())) {
+                return ste.getLineNumber();
+            }
+        }
+        throw new RuntimeException("Unexpected error: could not analyze stacktrace");
+    }
+
+    public static void doTest(int lineNumber) throws IOException {
+
+        System.out.println("Enetring method");
+
+        Recording recording = new Recording();
+        recording.start();
+
+        SimpleEvent ev = new SimpleEvent();
+        commitEvent(ev);
+        recording.stop();
+
+        List<RecordedEvent> recordedEvents = Events.fromRecording(recording);
+        Events.hasEvents(recordedEvents);
+        RecordedEvent recordedEvent = recordedEvents.get(0);
+
+        RecordedStackTrace stacktrace = recordedEvent.getStackTrace();
+        List<RecordedFrame> frames = stacktrace.getFrames();
+        for (RecordedFrame frame : frames) {
+
+            // All frames are java frames
+            Asserts.assertTrue(frame.isJavaFrame());
+            // Verify the main() method frame
+            RecordedMethod method = frame.getMethod();
+            if (method.getName().equals("main")) {
+
+                // Frame type
+                String type = frame.getType();
+                System.out.println("type: " + type);
+                Asserts.assertTrue(
+                        type.equals("Interpreted")
+                        || type.equals("JIT compiled")
+                        || type.equals("Inlined"));
+
+                Asserts.assertEquals(lineNumber, frame.getLineNumber());
+
+                boolean isInterpreted = "Interpreted".equals(type);
+                boolean expectedInterpreted = "true".equals(System.getProperty("interpreted"));
+                Asserts.assertEquals(isInterpreted, expectedInterpreted);
+
+                int bci = frame.getBytecodeIndex();
+
+                System.out.println("bci: " + bci);
+                Asserts.assertTrue(bci > 0);
+            }
+
+        }
+
+    }
+
+    private static void commitEvent(SimpleEvent ev) {
+        System.out.println("commit");
+        ev.commit();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/consumer/TestRecordedFullStackTrace.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.api.consumer;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedFrame;
+import jdk.jfr.consumer.RecordedStackTrace;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.RecurseThread;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.consumer.TestRecordedFullStackTrace
+ */
+public class TestRecordedFullStackTrace {
+
+    private final static String EVENT_NAME = EventNames.ExecutionSample;
+    private final static int MAX_DEPTH = 64; // currently hardcoded in jvm
+
+    public static void main(String[] args) throws Throwable {
+
+        RecurseThread[] threads = new RecurseThread[3];
+        for (int i = 0; i < threads.length; ++i) {
+            int depth = MAX_DEPTH - 1 + i;
+            threads[i] = new RecurseThread(depth);
+            threads[i].setName("recursethread-" + depth);
+            threads[i].start();
+        }
+
+        for (RecurseThread thread : threads) {
+            while (!thread.isInRunLoop()) {
+                Thread.sleep(20);
+            }
+        }
+
+        assertStackTraces(threads);
+
+        for (RecurseThread thread : threads) {
+            thread.quit();
+            thread.join();
+        }
+    }
+
+    private static void assertStackTraces(RecurseThread[] threads) throws Throwable {
+        Path path = null;
+        do {
+            Recording recording = new Recording();
+            recording.enable(EVENT_NAME).withPeriod(Duration.ofMillis(50));
+            recording.start();
+            Thread.sleep(500);
+            recording.stop();
+            // Dump the recording to a file
+            path = Files.createTempFile("recording", ".jfr");
+            System.out.println("Dumping to " + path);
+            recording.dump(path);
+            recording.close();
+        } while (!hasValidStackTraces(path, threads));
+    }
+
+    private static boolean hasValidStackTraces(Path path, RecurseThread[] threads) throws Throwable {
+        boolean[] isEventFound = new boolean[threads.length];
+
+        for (RecordedEvent event : RecordingFile.readAllEvents(path)) {
+            //System.out.println("Event: " + event);
+            String threadName = Events.assertField(event, "sampledThread.javaName").getValue();
+            long threadId = Events.assertField(event, "sampledThread.javaThreadId").getValue();
+
+            for (int threadIndex = 0; threadIndex < threads.length; ++threadIndex) {
+                RecurseThread currThread = threads[threadIndex];
+                if (threadId == currThread.getId()) {
+                    System.out.println("ThreadName=" + currThread.getName() + ", depth=" + currThread.totalDepth);
+                    Asserts.assertEquals(threadName, currThread.getName(), "Wrong thread name");
+                    if ("recurseEnd".equals(getTopMethodName(event))) {
+                        isEventFound[threadIndex] = true;
+                        checkEvent(event, currThread.totalDepth);
+                        break;
+                    }
+                }
+            }
+        }
+
+        for (int i = 0; i < threads.length; ++i) {
+            String msg = "threadIndex=%d, recurseDepth=%d, isEventFound=%b%n";
+            System.out.printf(msg, i, threads[i].totalDepth, isEventFound[i]);
+        }
+        for (int i = 0; i < threads.length; ++i) {
+            if (!isEventFound[i]) {
+               // no assertion, let's retry.
+                // Could be race condition, i.e safe point during Thread.sleep
+                System.out.println("Falied to validate all threads, will retry.");
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static String getTopMethodName(RecordedEvent event) {
+        List<RecordedFrame> frames = event.getStackTrace().getFrames();
+        Asserts.assertFalse(frames.isEmpty(), "JavaFrames was empty");
+        return frames.get(0).getMethod().getName();
+    }
+
+    private static void checkEvent(RecordedEvent event, int expectedDepth) throws Throwable {
+        RecordedStackTrace stacktrace = null;
+        try {
+            stacktrace = event.getStackTrace();
+            List<RecordedFrame> frames = stacktrace.getFrames();
+            Asserts.assertEquals(Math.min(MAX_DEPTH, expectedDepth), frames.size(), "Wrong stacktrace depth. Expected:" + expectedDepth);
+            List<String> expectedMethods = getExpectedMethods(expectedDepth);
+            Asserts.assertEquals(expectedMethods.size(), frames.size(), "Wrong expectedMethods depth. Test error.");
+
+            for (int i = 0; i < frames.size(); ++i) {
+                String name = frames.get(i).getMethod().getName();
+                String expectedName = expectedMethods.get(i);
+                System.out.printf("method[%d]=%s, expected=%s%n", i, name, expectedName);
+                Asserts.assertEquals(name, expectedName, "Wrong method name");
+            }
+
+            boolean isTruncated = stacktrace.isTruncated();
+            boolean isTruncateExpected = expectedDepth > MAX_DEPTH;
+            Asserts.assertEquals(isTruncated, isTruncateExpected, "Wrong value for isTruncated. Expected:" + isTruncateExpected);
+
+            String firstMethod = frames.get(frames.size() - 1).getMethod().getName();
+            boolean isFullTrace = "run".equals(firstMethod);
+            String msg = String.format("Wrong values for isTruncated=%b, isFullTrace=%b", isTruncated, isFullTrace);
+            Asserts.assertTrue(isTruncated != isFullTrace, msg);
+        } catch (Throwable t) {
+            System.out.println(String.format("stacktrace:%n%s", stacktrace));
+            throw t;
+        }
+    }
+
+    private static List<String> getExpectedMethods(int depth) {
+        List<String> methods = new ArrayList<>();
+        methods.add("recurseEnd");
+        for (int i = 0; i < depth - 2; ++i) {
+            methods.add((i % 2) == 0 ? "recurseA" : "recurseB");
+        }
+        methods.add("run");
+        if (depth > MAX_DEPTH) {
+            methods = methods.subList(0, MAX_DEPTH);
+        }
+        return methods;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/consumer/TestRecordedInstantEventTimestamp.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.consumer;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.SimpleEvent;
+
+/*
+ * @test
+ * @summary Tests that an instant event gets recorded with its start time equal to its end time
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.consumer.TestRecordedInstantEventTimestamp
+ */
+public class TestRecordedInstantEventTimestamp {
+
+    public static void main(String[] args) throws Throwable {
+        Recording r = new Recording();
+        r.start();
+        SimpleEvent s = new SimpleEvent();
+        s.commit();
+        r.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(r);
+        Events.hasEvents(events);
+        RecordedEvent event = events.get(0);
+        Asserts.assertEquals(event.getStartTime(), event.getEndTime());
+
+        r.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/consumer/TestRecordedMethodDescriptor.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.api.consumer;
+
+import static jdk.test.lib.Asserts.assertEquals;
+import static jdk.test.lib.Asserts.assertFalse;
+import static jdk.test.lib.Asserts.assertNotNull;
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.util.List;
+
+import jdk.jfr.Event;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedMethod;
+import jdk.jfr.consumer.RecordedFrame;
+import jdk.jfr.consumer.RecordedStackTrace;
+import jdk.test.lib.jfr.Events;
+
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.consumer.TestRecordedMethodDescriptor
+ */
+public final class TestRecordedMethodDescriptor {
+
+    private static boolean isMainMethodDescriptorRecorded;
+    private static final String MAIN_METHOD_DESCRIPTOR = "([Ljava/lang/String;)V";
+    private static final String MAIN_METHOD_NAME = "main";
+
+    public static void main(String[] args) throws Throwable {
+        Recording recording = new Recording();
+        recording.enable(MyEvent.class).withStackTrace();
+        recording.start();
+
+        MyEvent event = new MyEvent();
+        event.begin();
+        event.end();
+        event.commit();
+        recording.stop();
+
+        List<RecordedEvent> recordedEvents = Events.fromRecording(recording);
+        assertEquals(1, recordedEvents.size(), "Expected one event");
+        RecordedEvent recordedEvent = recordedEvents.get(0);
+
+        RecordedStackTrace stacktrace = recordedEvent.getStackTrace();
+        List<RecordedFrame> frames = stacktrace.getFrames();
+        assertFalse(frames.isEmpty(), "Stacktrace frames was empty");
+        for (RecordedFrame frame : frames) {
+            analyzeRecordedMethodDescriptor(frame.getMethod());
+        }
+
+        assertTrue(isMainMethodDescriptorRecorded, "main() method descriptor has never been recorded");
+    }
+
+    private static void analyzeRecordedMethodDescriptor(RecordedMethod method) {
+
+        String descr = method.getDescriptor();
+        assertNotNull(descr, "Method descriptor is null");
+        String name = method.getName();
+        assertNotNull(name, "Method name is null");
+
+        if (name.equals(MAIN_METHOD_NAME) && descr.equals(MAIN_METHOD_DESCRIPTOR)) {
+            assertFalse(isMainMethodDescriptorRecorded, "main() method descriptor already recorded");
+            isMainMethodDescriptorRecorded = true;
+        }
+    }
+
+    public static class MyEvent extends Event {
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/consumer/TestRecordedObject.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,406 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.consumer;
+
+import java.io.IOException;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Function;
+
+import jdk.jfr.Event;
+import jdk.jfr.Recording;
+import jdk.jfr.StackTrace;
+import jdk.jfr.Timespan;
+import jdk.jfr.Timestamp;
+import jdk.jfr.Unsigned;
+import jdk.jfr.consumer.RecordedClass;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedObject;
+import jdk.jfr.consumer.RecordedThread;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Verifies the methods of the RecordedObject
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.consumer.TestRecordedObject
+ */
+public class TestRecordedObject {
+
+    private final static boolean BOOLEAN_VALUE = true;
+    private final static byte VALUE = 47;
+    private final static String STRING_VALUE = "47";
+    private final static Class<?> CLASS_VALUE = String.class;
+    private final static Thread THREAD_VALUE = Thread.currentThread();
+    private final static Instant INSTANT_VALUE = Instant.now();
+    private final static Duration DURATION_VALUE = Duration.ofSeconds(47);
+
+    @StackTrace(false)
+    static final class EventWithValues extends Event {
+        boolean booleanField = BOOLEAN_VALUE;
+        byte byteField = VALUE;
+        char charField = VALUE;
+        short shortField = VALUE;
+        int intField = VALUE;
+        long longField = VALUE;
+        float floatField = VALUE;
+        double doubleField = VALUE;
+        String stringField = STRING_VALUE;
+        Class<?> classField = CLASS_VALUE;
+        Thread threadField = THREAD_VALUE;
+        @Timespan(Timespan.NANOSECONDS)
+        long durationField = DURATION_VALUE.toNanos();
+        @Timestamp(Timestamp.MILLISECONDS_SINCE_EPOCH)
+        long instantField = INSTANT_VALUE.toEpochMilli();
+        Thread nullField = null;
+        Class<?> nullField2 = null;
+
+        @Timespan(Timespan.MICROSECONDS)
+        long durationMicros = DURATION_VALUE.toNanos() / 1000;
+
+        @Timespan(Timespan.MILLISECONDS)
+        long durationMillis = DURATION_VALUE.toMillis();
+
+        @Timespan(Timespan.SECONDS)
+        long durationSeconds = DURATION_VALUE.toSeconds();
+
+        @Timestamp(Timestamp.MILLISECONDS_SINCE_EPOCH)
+        long instantMillis = 1000;
+
+        @Timestamp(Timespan.TICKS)
+        long instantTicks = 0;
+
+        @Unsigned
+        byte unsignedByte = Byte.MIN_VALUE;
+        @Unsigned
+        char unsignedChar = 'q';
+        @Unsigned
+        short unsignedShort = Short.MIN_VALUE;
+        @Unsigned
+        int unsignedInt = Integer.MIN_VALUE;
+        @Unsigned
+        long unsignedLong = Long.MIN_VALUE; // unsigned should be ignored
+        @Unsigned
+        float unsignedFloat = Float.MIN_VALUE; // unsigned should be ignored
+        @Unsigned
+        double unsignedDouble = Double.MIN_VALUE; // unsigned should be ignored
+
+    }
+
+    private final static Set<String> ALL = createAll();
+
+    public static void main(String[] args) throws Throwable {
+
+        RecordedObject event = makeRecordedObject();
+
+        // Primitives
+        testGetBoolean(event);
+        testGetByte(event);
+        testGetChar(event);
+        testGetShort(event);
+        testGetInt(event);
+        testGetLong(event);
+        testGetDouble(event);
+        testGetFloat(event);
+
+        // // Complex types
+        testGetString(event);
+        testGetInstant(event);
+        testGetDuration(event);
+        testGetThread(event);
+        testGetClass(event);
+
+        // Misc.
+        testNestedNames(event);
+        testTimeUnits(event);
+        testUnsigned(event);
+    }
+
+    private static void testUnsigned(RecordedObject event) {
+        // Unsigned byte value
+        Asserts.assertEquals(event.getByte("unsignedByte"), Byte.MIN_VALUE);
+        Asserts.assertEquals(event.getInt("unsignedByte"), Byte.toUnsignedInt(Byte.MIN_VALUE));
+        Asserts.assertEquals(event.getLong("unsignedByte"), Byte.toUnsignedLong(Byte.MIN_VALUE));
+        Asserts.assertEquals(event.getShort("unsignedByte"), (short)Byte.toUnsignedInt(Byte.MIN_VALUE));
+
+        // Unsigned char, nothing should happen, it is unsigned
+        Asserts.assertEquals(event.getChar("unsignedChar"), 'q');
+        Asserts.assertEquals(event.getInt("unsignedChar"), (int)'q');
+        Asserts.assertEquals(event.getLong("unsignedChar"), (long)'q');
+
+        // Unsigned short
+        Asserts.assertEquals(event.getShort("unsignedShort"), Short.MIN_VALUE);
+        Asserts.assertEquals(event.getInt("unsignedShort"), Short.toUnsignedInt(Short.MIN_VALUE));
+        Asserts.assertEquals(event.getLong("unsignedShort"), Short.toUnsignedLong(Short.MIN_VALUE));
+
+        // Unsigned int
+        Asserts.assertEquals(event.getInt("unsignedInt"), Integer.MIN_VALUE);
+        Asserts.assertEquals(event.getLong("unsignedInt"), Integer.toUnsignedLong(Integer.MIN_VALUE));
+
+        // Unsigned long, nothing should happen
+        Asserts.assertEquals(event.getLong("unsignedLong"), Long.MIN_VALUE);
+
+        // Unsigned float, nothing should happen
+        Asserts.assertEquals(event.getFloat("unsignedFloat"), Float.MIN_VALUE);
+
+        // Unsigned double, nothing should happen
+        Asserts.assertEquals(event.getDouble("unsignedDouble"), Double.MIN_VALUE);
+    }
+
+    private static void testTimeUnits(RecordedObject event) {
+        Asserts.assertEquals(event.getDuration("durationMicros"), DURATION_VALUE);
+        Asserts.assertEquals(event.getDuration("durationMillis"), DURATION_VALUE);
+        Asserts.assertEquals(event.getDuration("durationSeconds"), DURATION_VALUE);
+        Asserts.assertEquals(event.getInstant("instantMillis").toEpochMilli(), 1000L);
+        if (!event.getInstant("instantTicks").isBefore(INSTANT_VALUE)) {
+            throw new AssertionError("Expected start time of JVM to before call to Instant.now()");
+        }
+    }
+
+    private static void testNestedNames(RecordedObject event) {
+        RecordedThread t = event.getValue("threadField");
+
+        // Nested with getValue
+        try {
+            event.getValue("nullField.javaName");
+            throw new AssertionError("Expected NullPointerException");
+        } catch (NullPointerException npe) {
+            // OK, expected;
+        }
+        try {
+            event.getValue("nullField.does.not.exist");
+            throw new AssertionError("Expected IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // OK, expected;
+        }
+
+        // Nested getLong
+        try {
+            event.getLong("nullField.javaName");
+            throw new AssertionError("Expected NullPointerException");
+        } catch (NullPointerException npe) {
+            // OK, expected;
+        }
+        try {
+            event.getLong("nullField.does.not.exist");
+            throw new AssertionError("Expected IllegalArgumentException");
+        } catch (IllegalArgumentException npe) {
+            // OK, expected;
+        }
+        if (t.getOSThreadId() != event.getLong("threadField.osThreadId")) {
+            throw new AssertionError("Incorrect result from nested long value");
+        }
+
+        // Nested getString
+        try {
+            event.getString("nullField.osThreadId");
+            throw new AssertionError("Expected IllegalArgumentException");
+        } catch (IllegalArgumentException npe) {
+            // OK, expected;
+        }
+        try {
+            event.getLong("nullField.does.not.exist");
+            throw new AssertionError("Expected IllegalArgumentException");
+        } catch (IllegalArgumentException npe) {
+            // OK, expected;
+        }
+        if (!t.getJavaName().equals(event.getString("threadField.javaName"))) {
+            throw new AssertionError("Incorrect result from nested long value");
+        }
+
+        // Nested getClass
+        try {
+            event.getClass("nullField.osThreadId");
+            throw new AssertionError("Expected IllegalArgumentException");
+        } catch (IllegalArgumentException npe) {
+            // OK, expected;
+        }
+        try {
+            event.getClass("nullField.does.not.exist");
+            throw new AssertionError("Expected IllegalArgumentException");
+        } catch (IllegalArgumentException npe) {
+            // OK, expected;
+        }
+
+        // Nested getThread
+        try {
+            event.getThread("nullField2.name");
+            throw new AssertionError("Expected IllegalArgumentException");
+        } catch (IllegalArgumentException npe) {
+            // OK, expected;
+        }
+        try {
+            event.getThread("nullField2.does.not.exist");
+            throw new AssertionError("Expected IllegalArgumentException");
+        } catch (IllegalArgumentException npe) {
+            // OK, expected;
+        }
+    }
+
+    private static void testGetBoolean(RecordedObject e) {
+        assertGetter(x -> e.getBoolean(x), BOOLEAN_VALUE, "boolean");
+    }
+
+    private static void testGetByte(RecordedObject e) {
+        assertGetter(x -> e.getByte(x), (byte) VALUE, "byte");
+    }
+
+    private static void testGetChar(RecordedObject e) {
+        assertGetter(x -> e.getChar(x), (char) VALUE, "char");
+    }
+
+    private static void testGetShort(RecordedObject e) {
+        assertGetter(x -> e.getShort(x), (short) VALUE, "byte", "short");
+    }
+
+    private static void testGetInt(RecordedObject e) {
+        assertGetter(x -> e.getInt(x), (int) VALUE, "byte", "char", "short", "int");
+    }
+
+    private static void testGetLong(RecordedObject e) {
+        assertGetter(x -> e.getLong(x), (long) VALUE, "byte", "char", "short", "int", "long");
+    }
+
+    private static void testGetFloat(RecordedObject e) {
+        assertGetter(x -> e.getFloat(x), (float) VALUE, "byte", "char", "short", "int", "long", "float");
+    }
+
+    private static void testGetDouble(RecordedObject e) {
+        assertGetter(x -> e.getDouble(x), (double) VALUE, "byte", "char", "short", "int", "long", "float", "double");
+    }
+
+    private static void testGetString(RecordedObject e) {
+        assertGetter(x -> e.getString(x), STRING_VALUE, "string");
+    }
+
+    private static void testGetInstant(RecordedObject e) {
+        assertGetter(x -> e.getInstant(x), Instant.ofEpochMilli(INSTANT_VALUE.toEpochMilli()), "instant");
+    }
+
+    private static void testGetDuration(RecordedObject e) {
+        assertGetter(x -> e.getDuration(x), DURATION_VALUE, "duration");
+    }
+
+    private static void testGetThread(RecordedObject e) {
+        RecordedThread thread = e.getValue("threadField");
+        if (!thread.getJavaName().equals(THREAD_VALUE.getName())) {
+            throw new AssertionError("Expected thread to have name " + THREAD_VALUE.getName());
+        }
+        assertGetter(x -> {
+            // OK to access nullField if it is correct type
+            // Chose a second null field with class type
+            if ("nullField".equals(x)) {
+                return e.getThread("nullField2");
+            } else {
+                return e.getThread(x);
+            }
+
+        }, thread, "thread");
+    }
+
+    private static void testGetClass(RecordedObject e) {
+        RecordedClass clazz = e.getValue("classField");
+        if (!clazz.getName().equals(CLASS_VALUE.getName())) {
+            throw new AssertionError("Expected class to have name " + CLASS_VALUE.getName());
+        }
+        assertGetter(x -> e.getClass(x), clazz, "class");
+    }
+
+    private static <T> void assertGetter(Function<String, T> f, T expectedValue, String... validTypes) {
+        Set<String> valids = new HashSet<String>(Arrays.asList(validTypes));
+        Set<String> invalids = new HashSet<String>(ALL);
+        invalids.removeAll(valids);
+        for (String valid : valids) {
+            T result = f.apply(valid + "Field");
+            if (!expectedValue.equals(result)) {
+                throw new AssertionError("Incorrect return value " + result + ". Expected " + expectedValue);
+            }
+        }
+        for (String invalid : invalids) {
+            try {
+                f.apply(invalid + "Field");
+            } catch (IllegalArgumentException iae) {
+                // OK, as expected
+            } catch (Exception e) {
+                throw new AssertionError("Unexpected exception for invalid field " + invalid + ". " + e.getClass().getName() + " : " + e.getMessage(), e);
+            }
+        }
+        String[] illegals = { "missingField", "nullField.javaName.does.not.exist", "nullField" };
+        for (String illegal : illegals) {
+            try {
+                f.apply(illegal);
+                throw new AssertionError("Expected IllegalArgumentException when accessing " + illegal);
+            } catch (IllegalArgumentException iae) {
+                // OK, as expected
+            } catch (Exception e) {
+                throw new AssertionError("Expected IllegalArgumentException. Got " + e.getClass().getName() + " : " + e.getMessage(), e);
+            }
+        }
+        try {
+            f.apply(null);
+            throw new AssertionError("Expected NullpointerException exception when passing in null value");
+        } catch (NullPointerException iae) {
+            // OK, as expected
+        } catch (Exception e) {
+            throw new AssertionError("Expected NullpointerException. Got " + e.getClass().getName() + " : " + e.getMessage(), e);
+        }
+    }
+
+    private static RecordedObject makeRecordedObject() throws IOException {
+        Recording r = new Recording();
+        r.start();
+        EventWithValues t = new EventWithValues();
+        t.commit();
+        r.stop();
+        List<RecordedEvent> events = Events.fromRecording(r);
+        Events.hasEvents(events);
+        return events.get(0);
+    }
+
+    private static Set<String> createAll() {
+        Set<String> set = new HashSet<>();
+        set.add("boolean");
+        set.add("byte");
+        set.add("char");
+        set.add("short");
+        set.add("int");
+        set.add("long");
+        set.add("float");
+        set.add("double");
+        set.add("string");
+        set.add("class");
+        set.add("thread");
+        set.add("instant");
+        set.add("duration");
+        return set;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/consumer/TestRecordedThreadGroupParent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.api.consumer;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedThreadGroup;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.SimpleEvent;
+
+/*
+ * @test
+ * @summary Tests getParent method in RecordedThreadGroup
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.consumer.TestRecordedThreadGroupParent
+ */
+public class TestRecordedThreadGroupParent {
+
+    public static void main(String[] args) throws Exception {
+        ThreadGroup beforeStartGroup = new ThreadGroup(new ThreadGroup(new ThreadGroup("Grandfather"), "Father"), "Son");
+        Thread beforeThread = new Thread(beforeStartGroup, () -> new SimpleEvent().commit(), "Before Recording Start");
+
+        try (Recording r = new Recording()) {
+            r.enable(SimpleEvent.class).withoutStackTrace();
+            r.start();
+            beforeThread.start();
+            ThreadGroup afterStartGroup = new ThreadGroup(new ThreadGroup(new ThreadGroup("Grandmother"), "Mother"), "Daughter");
+            Thread afterThread = new Thread(afterStartGroup, () -> new SimpleEvent().commit(), "After Recording Start");
+            afterThread.start();
+
+            beforeThread.join();
+            afterThread.join();
+
+            r.stop();
+
+            List<RecordedEvent> events = Events.fromRecording(r);
+            Events.hasEvents(events);
+            for (RecordedEvent e : events) {
+                System.out.println(e);
+                switch (e.getThread().getJavaName()) {
+                case "Before Recording Start":
+                    assetrThreadGroupParents(beforeStartGroup, e.getThread().getThreadGroup());
+                    break;
+                case "After Recording Start":
+                    assetrThreadGroupParents(afterStartGroup, e.getThread().getThreadGroup());
+                    break;
+                default:
+                    Asserts.fail("Unexpected thread found "  + e.getThread().getJavaName());
+                }
+            }
+        }
+    }
+
+    private static void assetrThreadGroupParents(ThreadGroup realGroup, RecordedThreadGroup recordedGroup) {
+        if (recordedGroup == null && realGroup == null) {
+            return; // root
+        }
+        Asserts.assertNotNull(recordedGroup, "Parent thread group should not be null");
+        Asserts.assertEquals(realGroup.getName(), recordedGroup.getName(), "Parent thread group names don't match");
+        assetrThreadGroupParents(realGroup.getParent(), recordedGroup.getParent());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/consumer/TestRecordingFile.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,406 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.consumer;
+
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.StringJoiner;
+
+
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Name;
+import jdk.jfr.Recording;
+import jdk.jfr.Registered;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @summary Verifies that all methods in RecordingFIle are working
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.consumer.TestRecordingFile
+ */
+public class TestRecordingFile {
+
+    static class TestEvent1 extends Event {
+    }
+
+    static class TestEvent2 extends Event {
+    }
+
+    static class TestEvent3 extends Event {
+    }
+
+    private static String TEST_CLASS_BASE = "TestRecordingFile$TestEvent";
+    private final static int EVENT_COUNT = 3;
+    private final static int HEADER_SIZE = 68;
+    private final static long METADATA_OFFSET = 24;
+
+    public static void main(String[] args) throws Throwable {
+
+        // create some recording data
+        Recording r = new Recording();
+        r.enable(TestEvent1.class).withoutStackTrace();
+        r.enable(TestEvent2.class).withoutStackTrace();
+        r.enable(TestEvent3.class).withoutStackTrace();
+        r.start();
+        TestEvent1 t1 = new TestEvent1();
+        t1.commit();
+        TestEvent2 t2 = new TestEvent2();
+        t2.commit();
+        TestEvent3 t3 = new TestEvent3();
+        t3.commit();
+        r.stop();
+        Path valid = Files.createTempFile("three-event-recording", ".jfr");
+        r.dump(valid);
+        r.close();
+
+        Path brokenWithZeros = createBrokenWIthZeros(valid);
+        Path brokenMetadata = createBrokenMetadata(valid);
+        // prepare event sets
+        testNewRecordingFile(valid, brokenWithZeros);
+        testIterate(valid, brokenWithZeros);
+        testReadAllEvents(valid, brokenWithZeros);
+        testReadEventTypes(valid, brokenMetadata);
+        testClose(valid);
+        testReadEventTypesMultiChunk();
+        testReadEventTypeWithUnregistration(false, false);
+        testReadEventTypeWithUnregistration(false, true);
+        testReadEventTypeWithUnregistration(true, false);
+        testReadEventTypeWithUnregistration(true, true);
+    }
+
+    private static void testReadEventTypeWithUnregistration(boolean disk, boolean background) throws Exception {
+        FlightRecorder.register(Event1.class);
+        FlightRecorder.register(Event2.class);
+        FlightRecorder.register(Event3.class);
+        Recording backgrundRecording = new Recording();
+        if (disk) {
+            backgrundRecording.setToDisk(disk);
+        }
+        if (background) {
+            backgrundRecording.start();
+        }
+        recordAndVerify(disk, background,new int[] {1,2, 3}, new int[] {});
+        FlightRecorder.unregister(Event2.class);
+        recordAndVerify(disk, background,  new int[] {1, 3}, new int[] {2});
+        FlightRecorder.unregister(Event1.class);
+        FlightRecorder.register(Event2.class);
+        recordAndVerify(disk,background, new int[] {2, 3}, new int[] {1});
+        FlightRecorder.unregister(Event3.class);
+        FlightRecorder.register(Event3.class);
+        FlightRecorder.unregister(Event2.class);
+        FlightRecorder.unregister(Event3.class);
+        FlightRecorder.register(Event1.class);
+        FlightRecorder.unregister(Event1.class);
+        FlightRecorder.register(Event1.class);
+        FlightRecorder.register(Event2.class);
+        recordAndVerify(disk, background,new int[] {1, 2}, new int[] {3});
+        if (background) {
+            backgrundRecording.close();
+        }
+    }
+
+    private static void recordAndVerify(boolean disk, boolean background,  int[] shouldExist, int[] shouldNotExist) throws Exception {
+        StringJoiner sb  = new StringJoiner("-");
+        for (int i = 0; i <shouldExist.length; i++) {
+            sb.add(Integer.toString(shouldExist[i]));
+        }
+        System.out.println("Verifying recordings: disk=" + disk + " background=" + background);
+        System.out.println("Should exist: " + Arrays.toString(shouldExist));
+        System.out.println("Should not exist: " + Arrays.toString(shouldNotExist));
+
+        Path p = Files.createTempFile(sb.toString(), ".jfr");
+        System.out.println("Filename: " + p);
+        try (Recording r = new Recording()) {
+            r.start();
+            r.stop();
+            r.dump(p);
+            try (RecordingFile f = new RecordingFile(p)) {
+                List<EventType> types = f.readEventTypes();
+                for (int i = 0; i< shouldExist.length; i++) {
+                    assertHasEventType(types, "Event" + shouldExist[i]);
+                }
+                for (int i = 0; i< shouldNotExist.length; i++) {
+                    assertMissingEventType(types, "Event" + shouldNotExist[i]);
+                }
+            }
+        }
+        System.out.println();
+        System.out.println();
+    }
+
+    @Registered(false)
+    @Name("Event1")
+    private static class Event1 extends Event {
+    }
+    @Registered(false)
+    @Name("Event2")
+    private static class Event2 extends Event {
+    }
+    @Registered(false)
+    @Name("Event3")
+    private static class Event3 extends Event {
+    }
+
+    private static void testReadEventTypesMultiChunk() throws Exception {
+
+        Path twoEventTypes = Files.createTempFile("two-event-types", ".jfr");
+        Path threeEventTypes = Files.createTempFile("three-event-types", ".jfr");
+       try (Recording r1 = new Recording()) {
+           r1.start();
+           FlightRecorder.register(Event1.class);
+           try (Recording r2 = new Recording()) {
+               r2.start();
+               FlightRecorder.register(Event2.class);
+
+               // Ensure that metadata are written twice.
+               try (Recording rotator = new Recording()) {
+                   rotator.start();
+                   rotator.stop();
+               }
+               r2.stop();
+               r2.dump(twoEventTypes);;
+           }
+           FlightRecorder.register(Event3.class);
+           r1.stop();
+           r1.dump(threeEventTypes);;
+       }
+       try (RecordingFile f = new RecordingFile(twoEventTypes)) {
+           List<EventType> types = f.readEventTypes();
+           assertUniqueEventTypes(types);
+           assertHasEventType(types, "Event1");
+           assertHasEventType(types, "Event2");
+           assertMissingEventType(types, "Event3");
+       }
+       try (RecordingFile f = new RecordingFile(twoEventTypes)) {
+           List<EventType> types = f.readEventTypes();
+           assertUniqueEventTypes(types);
+           assertHasEventType(types, "Event1");
+           assertHasEventType(types, "Event2");
+           assertMissingEventType(types, "Event3");
+       }
+
+    }
+
+    private static void assertMissingEventType(List<EventType> types,String name) throws Exception {
+        EventType type = findEventType(types, name);
+        if (type != null) {
+            throw new Exception("Found unexpected event type " + name);
+        }
+    }
+
+    private static void assertHasEventType(List<EventType> types,String name) throws Exception {
+        EventType type = findEventType(types, name);
+        if (type == null) {
+            throw new Exception("Missing event type " + name);
+        }
+    }
+
+    private static EventType findEventType(List<EventType> types, String name) {
+        for (EventType t : types) {
+            if (t.getName().equals(name)) {
+                return t;
+            }
+        }
+        return null;
+    }
+
+    private static void assertUniqueEventTypes(List<EventType> types) {
+        HashSet<Long> ids = new HashSet<>();
+        for (EventType type : types) {
+            ids.add(type.getId());
+        }
+        Asserts.assertEquals(types.size(), ids.size(), "Event types repeated. " + types);
+    }
+
+    private static Path createBrokenWIthZeros(Path valid) throws Exception {
+        try {
+            Path broken = Files.createTempFile("broken-events", ".jfr");
+            Files.delete(broken);
+            Files.copy(valid, broken);
+            RandomAccessFile raf = new RandomAccessFile(broken.toFile(), "rw");
+            raf.seek(HEADER_SIZE);
+            int size = (int) Files.size(broken);
+            byte[] ones = new byte[size - HEADER_SIZE];
+            for (int i = 0; i < ones.length; i++) {
+                ones[i] = (byte) 0xFF;
+            }
+            raf.write(ones, 0, ones.length);
+            raf.close();
+            return broken;
+        } catch (IOException ioe) {
+            throw new Exception("Could not produce a broken file " + valid, ioe);
+        }
+    }
+
+    private static Path createBrokenMetadata(Path valid) throws Exception {
+        try {
+            Path broken = Files.createTempFile("broken-metadata", ".jfr");
+            Files.delete(broken);
+            Files.copy(valid, broken);
+            RandomAccessFile raf = new RandomAccessFile(broken.toFile(), "rw");
+            raf.seek(METADATA_OFFSET);
+            long metadataOffset = raf.readLong();
+            raf.seek(metadataOffset);
+            raf.writeLong(Long.MAX_VALUE);
+            raf.writeLong(Long.MAX_VALUE);
+            raf.close();
+            return broken;
+        } catch (IOException ioe) {
+            throw new Exception("Could not produce a broken EventSet from file " + valid, ioe);
+        }
+    }
+
+    private static void testReadEventTypes(Path valid, Path broken) throws Exception {
+        try (RecordingFile validFile = new RecordingFile(valid)) {
+            List<EventType> types = validFile.readEventTypes();
+            if (types.size() < EVENT_COUNT) {
+                throw new Exception("Expected at least " + EVENT_COUNT + " event type but got " + types.toString());
+            }
+            int counter = 0;
+            for (Class<?> testClass : Arrays.asList(TestEvent1.class, TestEvent2.class, TestEvent3.class)) {
+                for (EventType t : types) {
+                    if (t.getName().equals(testClass.getName())) {
+                        counter++;
+                    }
+                }
+            }
+            if (counter != 3) {
+                throw new Exception("Returned incorrect event types");
+            }
+        }
+        try (RecordingFile brokenFile = new RecordingFile(broken)) {
+            brokenFile.readEventTypes();
+            throw new Exception("Expected IOException when getting Event Types from broken recording");
+        } catch (IOException ise) {
+            // OK
+        }
+    }
+
+    private static void testNewRecordingFile(Path valid, Path broken) throws Exception {
+        try (RecordingFile r = new RecordingFile(null)) {
+            throw new Exception("Expected NullPointerException");
+        } catch (NullPointerException npe) {
+            // OK
+        }
+        try (RecordingFile r = new RecordingFile(Paths.get("hjhjsdfhkjshdfkj.jfr"))) {
+            throw new Exception("Expected FileNotFoundException");
+        } catch (FileNotFoundException npe) {
+            // OK
+        }
+        Path testFile = Files.createTempFile("test-file", ".jfr");
+        try (RecordingFile r = new RecordingFile(testFile)) {
+            throw new Exception("Expected IOException if file is empty");
+        } catch (IOException e) {
+            // OK
+        }
+        FileWriter fr = new FileWriter(testFile.toFile());
+        fr.write("whatever");
+        fr.close();
+        try (RecordingFile r = new RecordingFile(Paths.get("hjhjsdfhkjshdfkj.jfr"))) {
+            throw new Exception("Expected IOException if magic is incorrect");
+        } catch (IOException e) {
+            // OK
+        }
+
+        try (RecordingFile r = new RecordingFile(valid)) {
+        }
+    }
+
+    private static void testClose(Path valid) throws Exception {
+        RecordingFile f = new RecordingFile(valid);
+        f.close();
+
+        try {
+            f.readEvent();
+            throw new Exception("Should not be able to read event from closed recording");
+        } catch (IOException e) {
+            if (!e.getMessage().equals("Stream Closed")) {
+                throw new Exception("Expected 'Stream Closed' in exception message for a closed stream. Got '" + e.getMessage() +"'.");
+            }
+            // OK
+        }
+        try {
+            f.readEventTypes();
+            throw new Exception("Should not be able to read event from closed recording");
+        } catch (IOException e) {
+            if (!e.getMessage().equals("Stream Closed")) {
+                throw new Exception("Expected 'Stream Closed' in exception message for a closed stream. Got '" + e.getMessage() +"'.");
+            }
+            // OK
+        }
+        // close twice
+        f.close();
+    }
+
+    private static void testIterate(Path valid, Path broken) throws Exception {
+        try (RecordingFile validFile = new RecordingFile(valid)) {
+            for (int i = 0; i < EVENT_COUNT; i++) {
+                if (!validFile.hasMoreEvents()) {
+                    throw new Exception("Not all events available");
+                }
+                RecordedEvent r = validFile.readEvent();
+                if (r == null) {
+                    throw new Exception("Missing event");
+                }
+                if (!r.getEventType().getName().contains(TEST_CLASS_BASE)) {
+                    throw new Exception("Incorrect event in recording file " + r);
+                }
+            }
+            if (validFile.hasMoreEvents()) {
+                throw new Exception("Should not be more than " + EVENT_COUNT + " in recording");
+            }
+        }
+        try (RecordingFile brokenFile = new RecordingFile(broken)) {
+            brokenFile.readEvent();
+            throw new Exception("Expected IOException for broken recording");
+        } catch (IOException ise) {
+            // OK
+        }
+    }
+
+    private static void testReadAllEvents(Path valid, Path broken) throws Exception {
+        try {
+            RecordingFile.readAllEvents(broken);
+            throw new Exception("Expected IOException when reading all events for broken recording");
+        } catch (IOException ioe) {
+            // OK as expected
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/consumer/TestRecordingFileReadEventEof.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.consumer;
+
+import java.io.EOFException;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.SimpleEvent;
+
+/*
+ * @test
+ * @summary Verifies that RecordingFile.readEvent() throws EOF when past the last record
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.consumer.TestRecordingFileReadEventEof
+ */
+public class TestRecordingFileReadEventEof {
+
+    public static void main(String[] args) throws Throwable {
+        Recording r = new Recording();
+        r.start();
+        SimpleEvent t = new SimpleEvent();
+        t.commit();
+        r.stop();
+        RecordingFile file = Events.copyTo(r);
+        r.close();
+        file.readEvent();
+        try {
+            file.readEvent();
+            Asserts.fail("Expected EOFException not thrown");
+        } catch (EOFException x) {
+            // OK, as expected
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/consumer/TestRecordingInternals.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.consumer;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedThread;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.SimpleEvent;
+
+/*
+ * @test
+ * @summary Tests that chunks are read in order and constant pools from multiple chunks can be read
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.consumer.TestRecordingInternals
+ */
+public class TestRecordingInternals {
+
+    public static void main(String[] args) throws Throwable {
+        try (Recording continuous = new Recording()) {
+            continuous.start();
+            for (int i = 0; i < 3; i++) {
+                // Each new recording will create a new chunk
+                // with a new set of constant pools, i.e.
+                // constant pools for threads and thread groups
+                createProfilingRecording(i);
+            }
+            continuous.stop();
+            int i = 0;
+            for (RecordedEvent e : Events.fromRecording(continuous)) {
+                Integer id = e.getValue("id");
+                RecordedThread rt = e.getThread();
+                Asserts.assertEquals(id.toString(), rt.getJavaName(), "Thread name should match id");
+                Asserts.assertEquals(id.toString(), rt.getThreadGroup().getName(), "Thread group name should match id");
+                Asserts.assertEquals(id, Integer.valueOf(i), "Chunks out of order");
+                i++;
+            }
+        }
+    }
+
+    private static void createProfilingRecording(int id) throws InterruptedException {
+        try (Recording r = new Recording()) {
+            r.start();
+            ThreadGroup tg = new ThreadGroup(String.valueOf(id));
+            Thread t = new Thread(tg, () -> {
+                SimpleEvent event = new SimpleEvent();
+                event.id = id;
+                event.commit();
+            }, String.valueOf(id));
+            t.start();
+            t.join();
+            r.stop();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/consumer/TestSingleRecordedEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.consumer;
+
+import java.util.List;
+
+import jdk.jfr.Description;
+import jdk.jfr.Event;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Verifies that a single JFR event is recorded as expected
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.consumer.TestSingleRecordedEvent
+ */
+public class TestSingleRecordedEvent {
+
+    @Description("MyDescription")
+    private static class MyEvent extends Event {
+    }
+
+    public static void main(String[] args) throws Throwable {
+        Recording r = new Recording();
+        r.start();
+        // Commit a single event to the recording
+        MyEvent event = new MyEvent();
+        event.commit();
+        r.stop();
+        List<RecordedEvent> events = Events.fromRecording(r);
+        Events.hasEvents(events);
+
+        // Should be 1 event only
+        Asserts.assertEquals(events.size(), 1);
+
+        RecordedEvent recordedEvent = events.get(0);
+
+        // Event description should be the same
+        Asserts.assertEquals(recordedEvent.getEventType().getDescription(), "MyDescription");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/consumer/TestToString.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.consumer;
+
+import java.util.HashMap;
+import java.util.List;
+
+import jdk.jfr.Event;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Sanity checks that RecordedEvent#toString returns something valid
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.consumer.TestToString
+ */
+public class TestToString {
+
+    public static void main(String[] args) throws Throwable {
+
+        try (Recording recording = new Recording()) {
+            recording.start();
+            HelloWorldEvent event = new HelloWorldEvent();
+            event.message = "hello, world";
+            event.integer = 4711;
+            event.floatValue = 9898;
+            event.doubleValue = 313;
+            event.clazz = HashMap.class;
+            event.characater = '&';
+            event.byteValue = (byte) 123;
+            event.longValue = 1234567890L;
+            event.shortValue = 64;
+            event.booleanValue = false;
+            event.commit();
+            recording.stop();
+            List<RecordedEvent> events = Events.fromRecording(recording);
+            Events.hasEvents(events);
+            RecordedEvent e = events.get(0);
+            String toString = e.toString();
+            System.out.println(toString);
+            Asserts.assertTrue(toString.contains("hello, world"), "Missing String field value in RecordedEvent#toSting()");
+            Asserts.assertTrue(toString.contains("4711"), "Missing integer fields value in RecordedEvent#toSting()");
+            Asserts.assertTrue(toString.contains("313"), "Missing double value in RecordedEvent#toSting()");
+            Asserts.assertTrue(toString.contains("HashMap"), "Missing class value in RecordedEvent#toSting()");
+            Asserts.assertTrue(toString.contains("1234567890"), "Missing long value in RecordedEvent#toSting()");
+            Asserts.assertTrue(toString.contains("&"), "Missing char value in RecordedEvent#toSting()");
+            Asserts.assertTrue(toString.contains("123"), "Missing byte value in RecordedEvent#toString()");
+            Asserts.assertTrue(toString.contains("64"), "Missing short value in RecordedEvent#toString()");
+            Asserts.assertTrue(toString.contains("false"), "Missing boolean value in RecordedEvent#toString()");
+            Asserts.assertTrue(toString.contains("HelloWorldEvent"), "Missing class name in RecordedEvent#toString()");
+        }
+    }
+
+    static class HelloWorldEvent extends Event {
+        public boolean booleanValue;
+        public long longValue;
+        public int shortValue;
+        public byte byteValue;
+        public int doubleValue;
+        public char characater;
+        public Thread mainThread;
+        public Class<?> clazz;
+        public int floatValue;
+        public int integer;
+        public String message;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/consumer/TestValueDescriptorRecorded.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.consumer;
+
+import java.util.List;
+
+import jdk.jfr.Description;
+import jdk.jfr.Event;
+import jdk.jfr.Label;
+import jdk.jfr.Recording;
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+
+/*
+ * @test
+ * @summary Verifies that the recorded value descriptors are correct
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm  jdk.jfr.api.consumer.TestValueDescriptorRecorded
+ */
+public class TestValueDescriptorRecorded {
+
+    private static class MyEvent extends Event {
+
+        @Label("myLabel")
+        @Description("myDescription")
+        int myValue;
+    }
+
+    public static void main(String[] args) throws Throwable {
+        Recording r = new Recording();
+        r.enable(MyEvent.class).withoutStackTrace();
+        r.start();
+        MyEvent event = new MyEvent();
+        event.commit();
+        r.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(r);
+        Events.hasEvents(events);
+        RecordedEvent recordedEvent = events.get(0);
+
+        for (ValueDescriptor desc : recordedEvent.getFields()) {
+            if ("myValue".equals(desc.getName())) {
+                Asserts.assertEquals(desc.getLabel(), "myLabel");
+                Asserts.assertEquals(desc.getDescription(), "myDescription");
+                Asserts.assertEquals(desc.getTypeName(), int.class.getName());
+                Asserts.assertFalse(desc.isArray());
+                Asserts.assertNull(desc.getContentType());
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/event/TEST.properties	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,2 @@
+modules = java.management
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/event/TestAbstractEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.event;
+
+import java.io.IOException;
+
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.Experimental;
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Tests that abstract events are not part of metadata
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.event.TestAbstractEvent
+ */
+public class TestAbstractEvent {
+
+    // Should not be included in metadata
+    @Experimental
+    static abstract class BaseEvent extends Event {
+    }
+
+    // Should be included
+    static class ConcreteEvent extends BaseEvent {
+    }
+
+    public static void main(String... args) throws IOException {
+        try {
+            EventType.getEventType(BaseEvent.class);
+            Asserts.fail("Should not accept abstract event classes");
+        } catch (IllegalArgumentException iae) {
+            // OK, as expected
+        }
+
+        try {
+            FlightRecorder.register(BaseEvent.class);
+            Asserts.fail("Should not accept registering abstract event classes");
+        } catch (IllegalArgumentException iae) {
+            // OK, as expected
+        }
+
+        try {
+            FlightRecorder.unregister(BaseEvent.class);
+            Asserts.fail("Should not accept unregistering abstract event classes");
+        } catch (IllegalArgumentException iae) {
+            // OK, as expected
+        }
+
+
+        Recording r = new Recording();
+        try {
+            r.enable(BaseEvent.class);
+            Asserts.fail("Should not accept abstract event classes");
+        } catch (IllegalArgumentException iae) {
+            // OK, as expected
+        }
+        r.start();
+
+        ConcreteEvent event = new ConcreteEvent();
+        event.commit();
+        r.stop();
+        RecordingFile rf = Events.copyTo(r);
+        RecordedEvent re = rf.readEvent();
+        if (!re.getEventType().getName().equals(ConcreteEvent.class.getName())) {
+            Asserts.fail("Expected " + ConcreteEvent.class.getName() + " event to be part of recording. Found " + re.getEventType().getName());
+        }
+        if (rf.hasMoreEvents()) {
+            Asserts.fail("Expected only one event");
+        }
+        rf.close();
+        EventType concreteEventType = null;
+        for (EventType type : FlightRecorder.getFlightRecorder().getEventTypes()) {
+            if (type.getName().equals(BaseEvent.class.getName())) {
+                Asserts.fail("Abstract events should not be part of metadata");
+            }
+            if (type.getName().equals(ConcreteEvent.class.getName())) {
+                concreteEventType = type;
+            }
+        }
+        Asserts.assertTrue(concreteEventType != null, "Could not find " + ConcreteEvent.class.getName() + " in metadata");
+        Experimental exp = concreteEventType.getAnnotation(Experimental.class);
+        Asserts.assertTrue(exp != null, "Could not find inherited annotation" + Experimental.class.getName() + " from abstract event class");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/event/TestBeginEnd.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.api.event;
+
+import java.time.Duration;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.SimpleEvent;
+
+/*
+ * @test
+ * @summary Test for RecordedEvent.getDuration()
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.event.TestBeginEnd
+ */
+public class TestBeginEnd {
+
+    public static void main(String[] args) throws Exception {
+
+        Recording r = new Recording();
+        r.enable(SimpleEvent.class);
+        r.start();
+
+        // Test enabled - single commit
+        SimpleEvent e1 = new SimpleEvent();
+        e1.id = 1; // should be included
+        e1.commit();
+
+        // Test enabled - begin - commit
+        SimpleEvent e2 = new SimpleEvent();
+        e2.begin();
+        e2.id = 2; // should be included
+        e2.commit();
+
+        // Test enabled - begin - end - commit
+        SimpleEvent e3 = new SimpleEvent();
+        e3.begin();
+        e3.id = 3; // should be included
+        e3.end();
+        e3.commit();
+
+        // Test enabled - end - commit
+        SimpleEvent e4 = new SimpleEvent();
+        e4.id = 4; // should be included
+        e4.end();
+        e4.commit();
+
+        // Test half enabled - begin - commit
+        r.disable(SimpleEvent.class);
+        SimpleEvent e5 = new SimpleEvent();
+        e5.begin();
+        r.enable(SimpleEvent.class);
+        e5.id = 5; // should be included
+        e5.commit();
+
+        // Test half enabled - begin - end - commit
+        r.disable(SimpleEvent.class);
+        SimpleEvent r6 = new SimpleEvent();
+        r6.begin();
+        r.enable(SimpleEvent.class);
+        r6.id = 6; // should be included
+        r6.end();
+        r6.commit();
+
+        // Test half enabled - begin - commit with high threshold
+        r.disable(SimpleEvent.class);
+        SimpleEvent r7 = new SimpleEvent();
+        r7.begin();
+        r.enable(SimpleEvent.class).withThreshold(Duration.ofDays(1));
+        r7.id = 7; // should not be included
+        r7.commit();
+        r.stop();
+
+        List<RecordedEvent> recordedEvents = Events.fromRecording(r);
+        for (RecordedEvent re : recordedEvents) {
+           Integer id =  re.getValue("id");
+           System.out.println("Found if " + id);
+           if (id < 1 || id > 6) {
+               throw new Exception("Unexpected id found " + id);
+           }
+        }
+        if (recordedEvents.size() != 6) {
+            throw new Exception("Expected 6 events");
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/event/TestClinitRegistration.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.event;
+
+import java.io.IOException;
+import java.util.List;
+
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Recording;
+import jdk.jfr.Registered;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Test enable/disable event and verify recording has expected events.
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.event.TestClinitRegistration
+ */
+
+public class TestClinitRegistration {
+
+    public static void main(String[] args) throws Exception {
+        // Test basic registration with or without auto registration
+        assertClinitRegister(AutoRegisteredEvent.class, true, false);
+        assertClinitRegister(NotAutoRegisterededEvent.class, false, false);
+        assertClinitRegister(AutoRegisteredUserClinit.class, true, true);
+        assertClinitRegister(NotAutoRegisteredUserClinit.class, false, true);
+
+        // Test complex <clinit>
+        assertClinitRegister(ComplexClInit.class, true, true);
+
+        // Test hierarchy
+        assertClinitRegister(DerivedClinit.class, true, true);
+        if (!isClinitExecuted(Base.class)) {
+            Asserts.fail("Expected <clinit> of base class to be executed");
+        }
+
+        // Test committed event in <clinit>
+        Recording r = new Recording();
+        r.start();
+        r.enable(EventInClinit.class);
+        triggerClinit(EventInClinit.class);
+        r.stop();
+        hasEvent(r, EventInClinit.class.getName());
+    }
+
+    private static void assertClinitRegister(Class<? extends Event> eventClass, boolean shouldExist, boolean setsProperty) throws ClassNotFoundException {
+        String className = eventClass.getName();
+        triggerClinit(eventClass);
+        boolean hasEventType = hasEventType(className);
+        boolean hasProperty = Boolean.getBoolean(className);
+        if (hasEventType && !shouldExist) {
+            Asserts.fail("Event class " + className + " should not be registered");
+        }
+        if (!hasEventType && shouldExist) {
+            Asserts.fail("Event class " + className + " is not registered");
+        }
+        if (setsProperty && !hasProperty) {
+            Asserts.fail("Expected clinit to be executed");
+        }
+        if (!setsProperty && hasProperty) {
+            Asserts.fail("Property in clinit should not been set. Test bug?");
+        }
+    }
+
+    private static boolean hasEventType(String name) {
+        for (EventType type : FlightRecorder.getFlightRecorder().getEventTypes()) {
+            if (type.getName().equals(name)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static void triggerClinit(Class<?> clazz) throws ClassNotFoundException {
+        Class.forName(clazz.getName(), true, clazz.getClassLoader());
+    }
+
+    private static void setClinitExecuted(Class<? extends Event> eventClass) {
+        System.setProperty(eventClass.getName(), "true");
+    }
+
+    private static boolean isClinitExecuted(Class<? extends Event> eventClass) {
+        return "true".equals(System.getProperty(eventClass.getName(), "true"));
+    }
+
+    static class AutoRegisteredEvent extends Event {
+    }
+
+    @Registered(false)
+    static class NotAutoRegisterededEvent extends Event {
+    }
+
+    static class AutoRegisteredUserClinit extends Event {
+        static {
+            setClinitExecuted(AutoRegisteredUserClinit.class);
+        }
+    }
+
+    @Registered(false)
+    static class NotAutoRegisteredUserClinit extends Event {
+        static {
+            setClinitExecuted(NotAutoRegisteredUserClinit.class);
+        }
+    }
+
+    static class Base extends Event {
+        static {
+            setClinitExecuted(Base.class);
+        }
+    }
+
+    static class DerivedClinit extends Base {
+        static {
+            setClinitExecuted(DerivedClinit.class);
+        }
+
+        @Deprecated
+        void myVoidMethod() {
+        }
+    }
+
+    static class ComplexClInit extends Event {
+        static {
+            setClinitExecuted(ComplexClInit.class);
+        }
+        public static final long l = Long.parseLong("7");
+        public static final int i = Integer.parseInt("7");
+        public static final short s = Short.parseShort("7");
+        public static final double d = Double.parseDouble("7");
+        public static final float f = Float.parseFloat("7");
+        public static final boolean b = Boolean.parseBoolean("true");
+        public static final char c = (char) Integer.parseInt("48");
+        public static final String text = "ioio".substring(2);
+        public static final int[] primitivArray = new int[] { 7, 4 };
+        public static final Class<?> Object = ComplexClInit.class;
+
+        static {
+            String text = "";
+            long l = 56;
+            long i = 56;
+            if (i != l) {
+                throw new RuntimeException("unexpected result from comparison");
+            }
+            if (!isClinitExecuted(ComplexClInit.class)) {
+                throw new RuntimeException("Expected clinit flag to be set" + text);
+            }
+        }
+
+        static {
+            try {
+                throw new IllegalStateException("Exception");
+            } catch (IllegalStateException ise) {
+                // as expected
+            }
+        }
+    }
+
+    static class EventInClinit extends Event {
+        static {
+            EventInClinit eventInClinit = new EventInClinit();
+            eventInClinit.commit();
+        }
+    }
+
+    public static void hasEvent(Recording r, String name) throws IOException {
+        List<RecordedEvent> events = Events.fromRecording(r);
+        Events.hasEvents(events);
+
+        for (RecordedEvent event : events) {
+            if (event.getEventType().getName().equals(name)) {
+                return;
+            }
+        }
+        Asserts.fail("Missing event " + name + " in recording " + events.toString());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/event/TestClonedEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.event;
+
+import java.util.List;
+
+import jdk.jfr.Event;
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Recording;
+import jdk.jfr.Registered;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Tests that a cloned event can be successfully committed.
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.event.TestClonedEvent
+ */
+
+public class TestClonedEvent  {
+
+    public static void main(String[] args) throws Throwable {
+        Recording r = new Recording();
+        r.enable(MyEvent.class);
+
+        r.start();
+
+        MyEvent event = new MyEvent();
+
+        MyEvent event2 = (MyEvent)event.clone();
+
+        FlightRecorder.register(MyEvent.class);
+        event.commit();
+        event2.commit();
+
+        r.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(r);
+        Asserts.assertEquals(2, events.size());
+
+        r.close();
+
+        FlightRecorder.unregister(MyEvent.class);
+
+        Recording r2 = new Recording();
+        r2.enable(MyEvent.class);
+
+        r2.start();
+        event.commit();
+        event2.commit();
+
+        r2.stop();
+
+        events = Events.fromRecording(r2);
+        Asserts.assertEquals(0, events.size());
+
+        r2.close();
+    }
+
+    @Registered(false)
+    private static class MyEvent extends Event implements Cloneable {
+
+        public Object clone() throws CloneNotSupportedException {
+            return super.clone();
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/event/TestEnableDisable.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.event;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Test enable/disable event and verify recording has expected events.
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.event.TestEnableDisable
+ */
+
+public class TestEnableDisable {
+
+    public static void main(String[] args) throws Exception {
+        List<MyEvent> expectedEvents = new ArrayList<>();
+        Recording r = new Recording();
+
+        r.start();
+        createEvent(expectedEvents, true); // id=0 Custom event classes are enabled by default.
+
+        r.disable(MyEvent.class);
+        createEvent(expectedEvents, false); // id=1
+        r.enable(MyEvent.class);
+        createEvent(expectedEvents, true);  // id=2
+
+        // enable/disable by event setting name
+        String eventSettingName = String.valueOf(EventType.getEventType(MyEvent.class).getId());
+        System.out.println("eventSettingName=" + eventSettingName);
+
+        r.disable(eventSettingName);
+        createEvent(expectedEvents, false); // id=3
+        r.enable(eventSettingName);
+        createEvent(expectedEvents, true);
+
+        r.stop();
+        createEvent(expectedEvents, false);
+
+        Iterator<MyEvent> expectedIterator = expectedEvents.iterator();
+        for (RecordedEvent event : Events.fromRecording(r)) {
+            System.out.println("event.id=" + Events.assertField(event, "id").getValue());
+            Asserts.assertTrue(expectedIterator.hasNext(), "Found more events than expected");
+            Events.assertField(event, "id").equal(expectedIterator.next().id);
+        }
+        Asserts.assertFalse(expectedIterator.hasNext(), "Did not find all expected events.");
+
+        r.close();
+    }
+
+    private static int eventId = 0;
+    private static void createEvent(List<MyEvent> expectedEvents, boolean isExpected) {
+        MyEvent event = new MyEvent();
+        event.begin();
+        event.id = eventId;
+        event.commit();
+
+        if (isExpected) {
+            expectedEvents.add(event);
+        }
+        eventId++;
+    }
+
+    private static class MyEvent extends Event {
+        private int id;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/event/TestEventFactory.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.event;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.Event;
+import jdk.jfr.EventFactory;
+import jdk.jfr.EventType;
+import jdk.jfr.Label;
+import jdk.jfr.ValueDescriptor;
+import jdk.test.lib.Asserts;
+
+
+/*
+ * @test
+ * @summary EventFactory simple test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.event.TestEventFactory
+ */
+public class TestEventFactory {
+
+    public static void main(String[] args) throws Exception {
+        List<ValueDescriptor> vds = new ArrayList<>();
+        vds.add(new ValueDescriptor(String.class, "Message"));
+        vds.add(new ValueDescriptor(String.class, "message"));
+
+        List<AnnotationElement> annos = new ArrayList<>();
+        annos.add(new AnnotationElement(Label.class, "Hello World"));
+
+        EventFactory f = EventFactory.create(annos, vds);
+        EventType type = f.getEventType();
+        Asserts.assertNotNull(type);
+
+        Event e = f.newEvent();
+        e.set(0, "test Message");
+        e.set(1, "test message");
+
+        try {
+            e.set(100, "should fail");
+            Asserts.fail("The expected exception IndexOutOfBoundsException have not been thrown");
+        } catch(IndexOutOfBoundsException expected) {
+            // OK, as expected
+        }
+
+        try {
+            e.set(-200, "should fail again");
+            Asserts.fail("The expected exception IndexOutOfBoundsException have not been thrown");
+        } catch(IndexOutOfBoundsException expected) {
+            // OK, as expected
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/event/TestEventFactoryRegisterTwice.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.event;
+
+import java.util.Collections;
+
+import jdk.jfr.EventFactory;
+import jdk.jfr.EventType;
+import jdk.jfr.FlightRecorder;
+import jdk.test.lib.Asserts;
+
+
+/*
+ * @test
+ * @summary Verifies that EventFactory can register the same event twice
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.event.TestEventFactoryRegisterTwice
+ */
+public class TestEventFactoryRegisterTwice {
+
+    public static void main(String[] args) throws Exception {
+        EventFactory factory = EventFactory.create(Collections.emptyList(), Collections.emptyList());
+
+        EventType eventType = factory.getEventType();
+        Asserts.assertNotNull(eventType);
+
+        // Now, register the event
+        factory.register();
+
+        verifyRegistered(eventType);
+
+        // Now, register the event again
+        factory.register();
+
+        verifyRegistered(eventType);
+    }
+
+    private static void verifyRegistered(EventType eventType) {
+        // Verify  the event is registered
+        boolean found = false;
+        for (EventType type : FlightRecorder.getFlightRecorder().getEventTypes()) {
+            if (eventType.getId() == type.getId()) {
+                found = true;
+            }
+        }
+        if(!found) {
+            Asserts.fail("Event not registered");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/event/TestEventFactoryRegistration.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.event;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.EventFactory;
+import jdk.jfr.EventType;
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Registered;
+import jdk.test.lib.Asserts;
+
+
+/*
+ * @test
+ * @summary EventFactory register/unregister API test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.event.TestEventFactoryRegistration
+ */
+public class TestEventFactoryRegistration {
+
+    public static void main(String[] args) throws Exception {
+        // Create an unregistered event
+        List<AnnotationElement> annotations = new ArrayList<>();
+        annotations.add(new AnnotationElement(Registered.class, false));
+        EventFactory factory = EventFactory.create(annotations, Collections.emptyList());
+
+        try {
+            factory.getEventType();
+            Asserts.fail("Should not be able to get event type from an unregistered event");
+        } catch(IllegalStateException ise) {
+            // OK as expected
+        }
+
+        // Now, register the event
+        factory.register();
+        EventType eventType = factory.getEventType();
+        verifyRegistered(factory.getEventType());
+
+
+        // Now, unregister the event
+        factory.unregister();
+
+        verifyUnregistered(eventType);
+
+        // Create a registered event
+        factory = EventFactory.create(Collections.emptyList(), Collections.emptyList());
+
+        eventType = factory.getEventType();
+        Asserts.assertNotNull(eventType);
+
+        verifyRegistered(eventType);
+
+    }
+
+    private static void verifyUnregistered(EventType eventType) {
+        // Verify the event is not registered
+        for (EventType type : FlightRecorder.getFlightRecorder().getEventTypes()) {
+            if (eventType.getId() == type.getId()) {
+                Asserts.fail("Event is not unregistered");
+            }
+        }
+    }
+
+    private static void verifyRegistered(EventType eventType) {
+        // Verify  the event is registered
+        boolean found = false;
+        for (EventType type : FlightRecorder.getFlightRecorder().getEventTypes()) {
+            if (eventType.getId() == type.getId()) {
+                found = true;
+            }
+        }
+        if(!found) {
+            Asserts.fail("Event not registered");
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/event/TestExtends.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.event;
+
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.Recording;
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Test with event class inheritance
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.event.TestExtends
+ */
+
+public class TestExtends {
+
+    private static final int DEFAULT_FIELD_COUNT = 4;
+
+    @SuppressWarnings("unused")
+    private static class GrandpaEvent extends Event {
+        public int gPublicField = 4;
+        protected int gProtectedField = 3;
+        private int gPrivateField = 2;
+        int gDefaultField = 1;
+        private int hiddenField = 4711;
+    }
+
+    @SuppressWarnings("unused")
+    private static class ParentEvent extends GrandpaEvent {
+        public int pPublicField = 40;
+        protected int pProtectedField = 30;
+        private int pPrivateField = 20;
+        int pDefaultField = 10;
+        private boolean hiddenField = true;
+    }
+
+    @SuppressWarnings("unused")
+    private static class MeEvent extends ParentEvent {
+        public int mPublicField = 400;
+        protected int mProtectedField = 300;
+        private int mPrivateField = 200;
+        int mDefaultField = 100;
+        private String hiddenField = "Hidden";
+    }
+
+    public static void main(String[] args) throws Exception {
+        Recording r = new Recording();
+        r.enable(GrandpaEvent.class).withoutStackTrace();
+        r.enable(ParentEvent.class).withStackTrace();
+        r.enable(MeEvent.class).withoutStackTrace();
+        r.start();
+
+        GrandpaEvent g = new GrandpaEvent();
+        g.commit();
+
+        ParentEvent p = new ParentEvent();
+        p.commit();
+
+        MeEvent m = new MeEvent();
+        m.commit();
+
+        r.stop();
+        for (RecordedEvent re : Events.fromRecording(r)) {
+            System.out.println(re);
+        }
+        // Grandpa
+        EventType grandpaType = EventType.getEventType(GrandpaEvent.class);
+        verifyField(grandpaType, "gPublicField");
+        verifyField(grandpaType, "gProtectedField");
+        verifyField(grandpaType, "gPrivateField");
+        verifyField(grandpaType, "gDefaultField");
+        verifyField(grandpaType, "hiddenField");
+        verifyFieldCount(grandpaType, 5);
+
+        // Parent
+        EventType parentType = EventType.getEventType(ParentEvent.class);
+        verifyField(parentType, "gPublicField");
+        verifyField(parentType, "gProtectedField");
+        verifyField(parentType, "gDefaultField");
+        verifyField(parentType, "pPublicField");
+        verifyField(parentType, "pProtectedField");
+        verifyField(parentType, "pPrivateField");
+        verifyField(parentType, "pDefaultField");
+        verifyField(parentType, "hiddenField");
+        verifyFieldCount(parentType, 8);
+
+        // Me
+        EventType meType = EventType.getEventType(MeEvent.class);
+        verifyField(meType, "gPublicField");
+        verifyField(meType, "gProtectedField");
+        verifyField(meType, "gDefaultField");
+        verifyField(meType, "pPublicField");
+        verifyField(meType, "pProtectedField");
+        verifyField(meType, "pDefaultField");
+        verifyField(meType, "mPublicField");
+        verifyField(meType, "mProtectedField");
+        verifyField(meType, "mPrivateField");
+        verifyField(meType, "mDefaultField");
+        verifyField(meType, "hiddenField");
+        verifyFieldCount(meType, 11);
+
+        for (RecordedEvent re : Events.fromRecording(r)) {
+            System.out.println(re);
+        }
+
+        RecordedEvent grandpa = findEvent(r, GrandpaEvent.class.getName());
+        Asserts.assertEquals(grandpa.getValue("gPublicField"), 4);
+        Asserts.assertEquals(grandpa.getValue("gProtectedField"), 3);
+        Asserts.assertEquals(grandpa.getValue("gPrivateField"), 2);
+        Asserts.assertEquals(grandpa.getValue("gDefaultField"), 1);
+        Asserts.assertEquals(grandpa.getValue("hiddenField"), 4711);
+
+        RecordedEvent parent = findEvent(r, ParentEvent.class.getName());
+        Asserts.assertEquals(parent.getValue("gPublicField"), 4);
+        Asserts.assertEquals(parent.getValue("gProtectedField"), 3);
+        Asserts.assertEquals(parent.getValue("gDefaultField"), 1);
+        Asserts.assertEquals(parent.getValue("pPublicField"), 40);
+        Asserts.assertEquals(parent.getValue("pProtectedField"), 30);
+        Asserts.assertEquals(parent.getValue("pPrivateField"), 20);
+        Asserts.assertEquals(parent.getValue("pDefaultField"), 10);
+        Asserts.assertEquals(parent.getValue("hiddenField"), true);
+
+        RecordedEvent me = findEvent(r, MeEvent.class.getName());
+        Asserts.assertEquals(me.getValue("gPublicField"), 4);
+        Asserts.assertEquals(me.getValue("gProtectedField"), 3);
+        Asserts.assertEquals(me.getValue("gDefaultField"), 1);
+        Asserts.assertEquals(me.getValue("pPublicField"), 40);
+        Asserts.assertEquals(me.getValue("pProtectedField"), 30);
+        Asserts.assertEquals(me.getValue("pDefaultField"), 10);
+        Asserts.assertEquals(me.getValue("mPublicField"), 400);
+        Asserts.assertEquals(me.getValue("mProtectedField"), 300);
+        Asserts.assertEquals(me.getValue("mPrivateField"), 200);
+        Asserts.assertEquals(me.getValue("mDefaultField"), 100);
+        Asserts.assertEquals(me.getValue("hiddenField"), "Hidden");
+    }
+
+    private static RecordedEvent findEvent(Recording r, String name) throws Exception {
+        for (RecordedEvent re : Events.fromRecording(r)) {
+            if (re.getEventType().getName().equals(name)) {
+                return re;
+            }
+        }
+        throw new Exception("Event type hierarchy exist, but missing event " + name + " from recording");
+    }
+
+    private static void verifyFieldCount(EventType t, int count) throws Exception {
+        if (t.getFields().size() != count + DEFAULT_FIELD_COUNT) {
+            throw new Exception("Incorrect number of fields " + count);
+        }
+    }
+
+    private static void verifyField(EventType t, String name) throws Exception {
+        ValueDescriptor d = t.getField(name);
+        if (d == null) {
+            throw new Exception("Missing field " + name + " in event " + t.getName());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/event/TestGetDuration.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.api.event;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.CommonHelper;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.SimpleEvent;
+
+/*
+ * @test
+ * @summary Test for RecordedEvent.getDuration()
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.event.TestGetDuration
+ */
+public class TestGetDuration {
+
+    private static final int DURATIONAL_EVENT_ID = 1;
+    private static final int INSTANT_EVENT_ID = 2;
+
+    public static void main(String[] args) throws Exception {
+        verifyCustomEvents();
+        verifyNativeEvents();
+    }
+
+    private static void verifyCustomEvents() throws Exception {
+        boolean fastTimeEnabled = CommonHelper.hasFastTimeEnabled();
+        System.out.println("Fast time enabled: " + fastTimeEnabled);
+        Recording r = new Recording();
+        r.enable(SimpleEvent.class).withoutStackTrace();
+        r.enable(EventNames.CPUTimeStampCounter); // for debugging purposes
+        r.start();
+
+        SimpleEvent durational = new SimpleEvent();
+        durational.begin();
+        durational.id = DURATIONAL_EVENT_ID;
+        if (!fastTimeEnabled) {
+            // if we have a low resolution clock sleep until time changes
+            CommonHelper.waitForSystemCurrentMillisToChange();
+        }
+        durational.end();
+        durational.commit();
+
+        SimpleEvent instant = new SimpleEvent();
+        instant.id = INSTANT_EVENT_ID;
+        instant.commit();
+
+        r.stop();
+
+        List<RecordedEvent> recordedEvents = Events.fromRecording(r);
+        List<RecordedEvent> testEvents = new ArrayList<>();
+        for (RecordedEvent e : recordedEvents) {
+            System.out.println(e); // for debugging time related issues
+            if (!e.getEventType().getName().equals(EventNames.CPUTimeStampCounter)) {
+                testEvents.add(e);
+            }
+        }
+        Events.hasEvents(testEvents);
+        for (RecordedEvent re : testEvents) {
+            int id = re.getValue("id");
+            Asserts.assertEquals(re.getDuration(), Duration.between(re.getStartTime(), re.getEndTime()));
+            switch (id) {
+                case DURATIONAL_EVENT_ID:
+                    Asserts.assertTrue(!re.getDuration().isNegative() && !re.getDuration().isZero());
+                    break;
+                case INSTANT_EVENT_ID:
+                    Asserts.assertTrue(re.getDuration().isZero());
+                    break;
+            }
+        }
+    }
+
+    private static void verifyNativeEvents() throws Exception {
+        Recording r = new Recording();
+        r.enable(EventNames.JVMInformation);
+        r.enable(EventNames.ThreadSleep);
+        r.start();
+        // Should trigger a sleep event even if we
+        // have a low resolution clock
+        Thread.sleep(200);
+        r.stop();
+        List<RecordedEvent> recordedEvents = Events.fromRecording(r);
+        Events.hasEvents(recordedEvents);
+        for (RecordedEvent re : recordedEvents) {
+            Asserts.assertEquals(re.getDuration(), Duration.between(re.getStartTime(), re.getEndTime()));
+            switch (re.getEventType().getName()) {
+                case EventNames.JVMInformation:
+                    Asserts.assertTrue(re.getDuration().isZero());
+                    break;
+                case EventNames.ThreadSleep:
+                    Asserts.assertTrue(!re.getDuration().isNegative() && !re.getDuration().isZero());
+                    break;
+                default:
+                    Asserts.fail("Unexpected event: " + re);
+                    break;
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/event/TestIsEnabled.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.event;
+
+import jdk.jfr.EventType;
+import jdk.jfr.Recording;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.SimpleEvent;
+
+/*
+ * @test
+ * @summary Test Event.isEnabled()
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.event.TestIsEnabled
+ */
+
+public class TestIsEnabled {
+
+    public static void main(String[] args) throws Exception {
+        assertDisabled("Event enabled with no recording");
+
+        Recording r = new Recording();
+        assertDisabled("Event enabled at new Recording()");
+
+        r.enable(SimpleEvent.class);
+        assertDisabled("Event enabled before r.start()");
+
+        r.start();
+
+        // enable/disable by class
+        assertEnabled("Event not enabled after r.start()");
+        r.disable(SimpleEvent.class);
+        assertDisabled("Event enabled after r.disable()");
+        r.enable(SimpleEvent.class);
+        assertEnabled("Event disabled afer r.enable()");
+
+        // enable/disable by event setting name
+        String eventSettingName = String.valueOf(EventType.getEventType(SimpleEvent.class).getId());
+        System.out.println("eventSettingName=" + eventSettingName);
+
+        r.disable(eventSettingName);
+        assertDisabled("Event enabled after r.disable(name)");
+        r.enable(eventSettingName);
+        assertEnabled("Event disabled after r.enable(name)");
+
+        r.stop();
+        assertDisabled("Event enabled after r.stop()");
+
+        r.close();
+        assertDisabled("Event enabled after r.close()");
+    }
+
+    private static void assertEnabled(String msg) {
+        SimpleEvent event = new SimpleEvent();
+        Asserts.assertTrue(event.isEnabled(), msg);
+    }
+
+    private static void assertDisabled(String msg) {
+        SimpleEvent event = new SimpleEvent();
+        Asserts.assertFalse(event.isEnabled(), msg);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/event/TestIsEnabledMultiple.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.event;
+
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.Recording;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @summary Test Event.isEnabled() with multiple recordings
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.event.TestIsEnabledMultiple
+ */
+
+public class TestIsEnabledMultiple {
+
+    enum When {
+        BeforeStart, DuringRecording
+    }
+
+    enum RecState {
+        New, Running
+    }
+
+    enum EnableState {
+        Enabled, Disabled
+    }
+
+    public static void main(String[] args) throws Exception {
+        for (RecState recStateA : RecState.values()) {
+            for (RecState recStateB : RecState.values()) {
+                for (EnableState enableStateA : EnableState.values()) {
+                    for (EnableState enableStateB : EnableState.values()) {
+                        assertEnabled(recStateA, recStateB, enableStateA, enableStateB);
+                    }
+                }
+            }
+        }
+    }
+
+    private static void assertEnabled(RecState recStateA, RecState recStateB, EnableState enableStateA, EnableState enableStateB) {
+
+        Recording a = new Recording();
+        Recording b = new Recording();
+        assertEnablement(false); // no recording running
+
+        if (enableStateA == EnableState.Disabled) {
+            a.disable(MyEvent.class);
+        }
+        if (enableStateA == EnableState.Enabled) {
+            a.enable(MyEvent.class);
+        }
+        if (enableStateB == EnableState.Disabled) {
+            b.disable(MyEvent.class);
+        }
+        if (enableStateB == EnableState.Enabled) {
+            b.enable(MyEvent.class);
+        }
+        if ( enableStateA == EnableState.Disabled && recStateA == RecState.Running) {
+            if ( enableStateB == EnableState.Disabled && recStateB == RecState.Running) {
+                System.out.println();
+            }
+        }
+        if (recStateA == RecState.Running) {
+            a.start();
+        }
+        if (recStateB == RecState.Running) {
+            b.start();
+        }
+
+        System.out.println("Recording a is " + a.getState() + ". Event is " + enableStateA);
+        System.out.println("Recording b is " + b.getState() + ". Event is " + enableStateB);
+        // an event is enabled if at least one recording is running
+        // and the event is on by default or has been enabled.
+        boolean aEnabled = recStateA == RecState.Running && enableStateA == EnableState.Enabled;
+        boolean bEnabled = recStateB == RecState.Running && enableStateB == EnableState.Enabled;
+        boolean enabled = aEnabled || bEnabled;
+        System.out.println("Expected enablement: " + enabled);
+        System.out.println();
+        assertEnablement(enabled);
+        if (recStateA == RecState.Running) {
+            a.stop();
+        }
+        if (recStateB == RecState.Running) {
+            b.stop();
+        }
+        assertEnablement(false); // no recording running
+        a.close();
+        b.close();
+    }
+
+    private static void assertEnablement(boolean enabled) {
+        Asserts.assertEQ(EventType.getEventType(MyEvent.class).isEnabled(), enabled, "Event enablement not as expected");
+    }
+
+    @SuppressWarnings("unused")
+    private static class MyEvent extends Event {
+        public String msg;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/event/TestOwnCommit.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.event;
+
+import java.time.Instant;
+import java.util.Iterator;
+
+import jdk.jfr.Event;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Use custom event that reuse method names begin, end and commit.
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.event.TestOwnCommit
+ */
+
+public class TestOwnCommit {
+
+    public static void main(String[] args) throws Throwable {
+       Recording r = new Recording();
+        r.enable(MyEvent.class);
+
+        r.start();
+
+        MyEvent event = new MyEvent();
+        event.begin();
+        event.begin = 10;
+        event.duration = Instant.now();
+        MyEvent.startTime = 20;
+        event.shouldCommit = "shouldCommit";
+        MyEvent.set = 30;
+        event.end();
+        event.commit();
+
+        // Verify that our methods have not been removed by transformation.
+        int id = 0;
+        event.begin(++id);
+        Asserts.assertEquals(id, staticTestValue, "EventWithBegin failed to set value");
+        event.end(++id);
+        Asserts.assertEquals(id, staticTestValue, "EventWithEnd failed to set value");
+        event.commit(++id);
+        Asserts.assertEquals(id, staticTestValue, "EventWithCommit failed to set value");
+        event.shouldCommit(++id);
+        Asserts.assertEquals(id, staticTestValue, "EventWithShouldCommit failed to set value");
+        event.set(++id);
+        Asserts.assertEquals(id, staticTestValue, "EventWithSet failed to set value");
+
+        r.stop();
+
+        Iterator<RecordedEvent> it = Events.fromRecording(r).iterator();
+        Asserts.assertTrue(it.hasNext(), "No events");
+        RecordedEvent recordedEvent = it.next();
+        Asserts.assertTrue(Events.isEventType(recordedEvent, MyEvent.class.getName()));
+        Events.assertField(recordedEvent, "begin").equal(10L);
+        Events.assertField(recordedEvent, "shouldCommit").equal("shouldCommit");
+        Events.assertField(recordedEvent, "startTime");
+        Events.assertField(recordedEvent, "duration");
+        Asserts.assertNull(recordedEvent.getEventType().getField("set")); // static not supported
+        Asserts.assertFalse(it.hasNext(), "More than 1 event");
+
+        r.close();
+    }
+
+    private static int staticTestValue;
+
+    @SuppressWarnings("unused")
+    static class MyEvent extends Event {
+        public long begin;
+        private Instant duration;
+        private static int startTime;
+        protected String shouldCommit;
+        public static int set;
+
+        public void begin(int testValue) {
+            staticTestValue = testValue;
+        }
+
+        public void end(int testValue) {
+            staticTestValue = testValue;
+        }
+
+        public void commit(int testValue) {
+            staticTestValue = testValue;
+        }
+
+        public void shouldCommit(int testValue) {
+            staticTestValue = testValue;
+        }
+
+        public void set(int testValue) {
+            staticTestValue = testValue;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/event/TestShouldCommit.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.event;
+
+import java.time.Duration;
+
+import jdk.jfr.Event;
+import jdk.jfr.Recording;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @summary Test enable/disable event and verify recording has expected events.
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm -Xlog:jfr+event+setting=trace jdk.jfr.api.event.TestShouldCommit
+ */
+
+public class TestShouldCommit {
+
+    public static void main(String[] args) throws Exception {
+        Recording rA = new Recording();
+
+        verifyShouldCommitFalse(); // No active recordings
+
+        rA.start();
+        rA.enable(MyEvent.class).withoutThreshold(); // recA=all
+        verifyShouldCommitTrue();
+
+        setThreshold(rA, 100); // recA=100
+        verifyThreshold(100);
+
+        setThreshold(rA, 200); // recA=200
+        verifyThreshold(200);
+
+        Recording rB = new Recording();
+        verifyThreshold(200);  // recA=200, recB=not started
+
+        rB.start();
+        verifyThreshold(200);  // recA=200, recB=not specified, settings from recA is used.
+
+        setThreshold(rB, 100); // recA=200, recB=100
+        verifyThreshold(100);
+
+        setThreshold(rB, 300); // recA=200, recB=300
+        verifyThreshold(200);
+
+        rA.disable(MyEvent.class); // recA=disabled, recB=300
+
+        verifyThreshold(300);
+
+        rB.disable(MyEvent.class); // recA=disabled, recB=disabled
+        verifyShouldCommitFalse();
+
+        setThreshold(rA, 200); // recA=200, recB=disabled
+        verifyThreshold(200);
+
+        rB.enable(MyEvent.class).withoutThreshold(); // recA=200, recB=all
+        verifyShouldCommitTrue();
+
+        setThreshold(rB, 100); // recA=200, recB=100
+        verifyThreshold(100);
+
+        rB.stop(); // recA=200, recB=stopped
+        verifyThreshold(200);
+
+        rA.stop(); // recA=stopped, recB=stopped
+        verifyShouldCommitFalse();
+
+        rA.close();
+        rB.close();
+
+        verifyShouldCommitFalse();
+    }
+
+    private static void setThreshold(Recording r, long millis) {
+        r.enable(MyEvent.class).withThreshold(Duration.ofMillis(millis));
+    }
+
+    private static void verifyThreshold(long threshold) throws Exception {
+        // Create 2 events, with different sleep time between begin() and end()
+        // First event ends just before threshold, the other just after.
+        verifyThreshold(threshold-5, threshold);
+        verifyThreshold(threshold+5, threshold);
+    }
+
+    private static void verifyThreshold(long sleepMs, long thresholdMs) throws Exception {
+        MyEvent event = new MyEvent();
+
+        long beforeStartNanos = System.nanoTime();
+        event.begin();
+        long afterStartNanos = System.nanoTime();
+
+        Thread.sleep(sleepMs);
+
+        long beforeStopNanos = System.nanoTime();
+        event.end();
+        long afterStopNanos = System.nanoTime();
+
+        boolean actualShouldCommit = event.shouldCommit();
+
+        final long safetyMarginNanos = 2000000; // Allow an error of 2 ms. May have to be tuned.
+
+        //Duration of event has been at least minDurationMicros
+        long minDurationMicros = (beforeStopNanos - afterStartNanos - safetyMarginNanos) / 1000;
+        //Duration of event has been at most maxDurationMicros
+        long maxDurationMicros = (afterStopNanos - beforeStartNanos + safetyMarginNanos) / 1000;
+        Asserts.assertLessThanOrEqual(minDurationMicros, maxDurationMicros, "Wrong min/max duration. Test error.");
+
+        long thresholdMicros = thresholdMs * 1000;
+        Boolean shouldCommit = null;
+        if (minDurationMicros > thresholdMicros) {
+            shouldCommit = new Boolean(true);  // shouldCommit() must be true
+        } else if (maxDurationMicros < thresholdMicros) {
+            shouldCommit = new Boolean(false); // shouldCommit() must be false
+        } else {
+            // Too close to call. No checks are done since we are not sure of expected shouldCommit().
+        }
+
+        System.out.printf(
+            "threshold=%d, duration=[%d-%d], shouldCommit()=%b, expected=%s%n",
+            thresholdMicros, minDurationMicros, maxDurationMicros, actualShouldCommit,
+            (shouldCommit!=null ? shouldCommit : "too close to call"));
+
+        try {
+            if (shouldCommit != null) {
+                Asserts.assertEquals(shouldCommit.booleanValue(), actualShouldCommit, "Wrong shouldCommit()");
+            }
+        } catch (Exception e) {
+            System.out.println("Unexpected value of shouldCommit(). Searching for active threshold...");
+            searchThreshold(thresholdMs, 2000+thresholdMs);
+            throw e;
+        }
+    }
+
+    // Sleeps until shouldCommit() is true, or give up. Used for logging.
+    private static void searchThreshold(long expectedMs, long maxMs) throws Exception {
+        long start = System.nanoTime();
+        long stop = start + maxMs * 1000000;
+
+        MyEvent event = new MyEvent();
+        event.begin();
+        event.end();
+
+        while (!event.shouldCommit() && System.nanoTime() < stop) {
+            Thread.sleep(1);
+            event.end();
+        }
+        long durationMicros = (System.nanoTime() - start) / 1000;
+        long expectedMicros = expectedMs * 1000;
+        System.out.printf("shouldCommit()=%b after %,d ms, expected %,d%n", event.shouldCommit(), durationMicros, expectedMicros);
+    }
+
+    private static void verifyShouldCommitFalse() {
+        MyEvent event = new MyEvent();
+        event.begin();
+        event.end();
+        Asserts.assertFalse(event.shouldCommit(), "shouldCommit() expected false");
+    }
+
+    private static void verifyShouldCommitTrue() {
+        MyEvent event = new MyEvent();
+        event.begin();
+        event.end();
+        Asserts.assertTrue(event.shouldCommit(), "shouldCommit() expected true");
+    }
+
+    private static class MyEvent extends Event {
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/event/TestStaticEnable.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.event;
+
+import java.time.Duration;
+import java.util.List;
+
+import jdk.jfr.Event;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Enable an event from a static function in the event.
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.event.TestStaticEnable
+ */
+public class TestStaticEnable {
+
+    public static void main(String[] args) throws Exception {
+        Recording r = new Recording();
+        MyEvent.enable(r, true);
+        r.start();
+        MyEvent.create("Hello", 1);
+        r.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(r);
+        Events.hasEvents(events);
+        for (RecordedEvent event : events) {
+            System.out.println("Event:" + event);
+            Events.assertField(event, "msg").equal("Hello");
+            Events.assertField(event, "id").equal(1L);
+        }
+        r.close();
+    }
+
+
+    public static class MyEvent extends Event {
+        public String msg;
+        long id;
+
+        public static void enable(Recording r, boolean isEnabled) {
+            if (isEnabled) {
+                r.enable(MyEvent.class).withThreshold(Duration.ofMillis(0)).withoutStackTrace();
+            } else {
+                r.disable(MyEvent.class);
+            }
+        }
+
+        public static void create(String msg, long id) {
+            MyEvent event = new MyEvent();
+            event.msg = msg;
+            event.id = id;
+            event.begin();
+            event.end();
+            event.commit();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/event/dynamic/TestDynamicAnnotations.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.event.dynamic;
+
+import java.io.IOException;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.Category;
+import jdk.jfr.Description;
+import jdk.jfr.Event;
+import jdk.jfr.EventFactory;
+import jdk.jfr.EventType;
+import jdk.jfr.Label;
+import jdk.jfr.MetadataDefinition;
+import jdk.jfr.Name;
+import jdk.jfr.Recording;
+import jdk.jfr.Relational;
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.event.dynamic.TestDynamicAnnotations
+ */
+public class TestDynamicAnnotations {
+
+    @Label("Execution Context Id")
+    @Description("A unique identifier to correlate events or requests associated with the same task across several components")
+    @Relational
+    @MetadataDefinition
+    @Target(ElementType.FIELD)
+    @Retention(RetentionPolicy.RUNTIME)
+    private @interface ECID {
+    }
+
+    @MetadataDefinition
+    @Target({ ElementType.FIELD, ElementType.TYPE })
+    @Retention(RetentionPolicy.RUNTIME)
+    private @interface Array {
+        String[] stringArray();
+
+        int[] intArray();
+
+        long[] longArray();
+
+        float[] floatArray();
+
+        double[] doubleArray();
+
+        boolean[] booleanArray();
+
+        short[] shortArray();
+
+        byte[] byteArray();
+
+        char[] charArray();
+    }
+
+    public static void main(String[] args) throws Throwable {
+        testEventFactoryExample();
+        testECID();
+        testArray();
+    }
+
+    // Copy of sample code in Javadoc for jdk.jfr.EVentFactory
+    public static void testEventFactoryExample() throws IOException {
+         List<ValueDescriptor> fields = new ArrayList<>();
+         List<AnnotationElement> messageAnnotations = Collections.singletonList(new AnnotationElement(Label.class, "Message"));
+         fields.add(new ValueDescriptor(String.class, "message", messageAnnotations));
+         List<AnnotationElement> numberAnnotations = Collections.singletonList(new AnnotationElement(Label.class, "Number"));
+         fields.add(new ValueDescriptor(int.class, "number", numberAnnotations));
+
+         String[] category = { "Example", "Getting Started" };
+         List<AnnotationElement> eventAnnotations = new ArrayList<>();
+         eventAnnotations.add(new AnnotationElement(Name.class, "com.example.HelloWorld"));
+         eventAnnotations.add(new AnnotationElement(Label.class, "Hello World"));
+         eventAnnotations.add(new AnnotationElement(Description.class, "Helps programmer getting started"));
+         eventAnnotations.add(new AnnotationElement(Category.class, category));
+
+         EventFactory f = EventFactory.create(eventAnnotations, fields);
+
+         Event event = f.newEvent();
+         event.set(0, "hello, world!");
+         event.set(1, 4711);
+         event.commit();
+    }
+
+    public static void testECID() throws Exception {
+        List<ValueDescriptor> fields = new ArrayList<>();
+
+        List<AnnotationElement> fieldAnnotations = new ArrayList<>();
+        fieldAnnotations.add(new AnnotationElement(ECID.class));
+        ValueDescriptor ecidField = new ValueDescriptor(String.class, "ecid", fieldAnnotations);
+        fields.add(ecidField);
+
+        EventFactory f = EventFactory.create(fieldAnnotations, fields);
+
+        String ecidValue = "131739871298371279812";
+        try (Recording r = new Recording()) {
+            r.start();
+            Event event = f.newEvent();
+            event.set(0, ecidValue);
+            event.commit();
+            r.stop();
+            List<RecordedEvent> events = Events.fromRecording(r);
+            Events.hasEvents(events);
+            Events.assertField(events.get(0), "ecid").equal(ecidValue);
+        }
+        EventType type = f.getEventType();
+        ECID e = type.getAnnotation(ECID.class);
+        if (e == null) {
+            throw new Exception("Missing ECID annotation");
+        }
+    }
+
+    public static void testArray() throws Exception {
+        List<AnnotationElement> annotations = new ArrayList<>();
+        Map<String, Object> values = new HashMap<>();
+        values.put("stringArray", new String[] {"zero", "one"});
+        values.put("intArray", new int[] {0, 1});
+        values.put("longArray", new long[] {0L, 1L});
+        values.put("floatArray", new float[] {0.0f, 1.0f});
+        values.put("doubleArray", new double[] {0.0, 1.0});
+        values.put("booleanArray", new boolean[] {false, true});
+        values.put("shortArray", new short[] {(short)0, (short)1});
+        values.put("byteArray", new byte[] {(byte)0, (byte)1});
+        values.put("charArray", new char[] {'0','1'});
+
+        annotations.add(new AnnotationElement(Array.class, values));
+        EventFactory f = EventFactory.create(annotations, Collections.emptyList());
+        Array a = f.getEventType().getAnnotation(Array.class);
+        if (a == null) {
+            throw new Exception("Missing array annotation");
+        }
+        verifyArrayAnnotation(a);
+        System.out.println("Event metadata is correct");
+        try (Recording r = new Recording()) {
+            r.start();
+            Event e = f.newEvent();
+            e.commit();
+            r.stop();
+            List<RecordedEvent> events = Events.fromRecording(r);
+            Events.hasEvents(events);
+            RecordedEvent re = events.get(0);
+            Array arrayAnnotation = re.getEventType().getAnnotation(Array.class);
+            if (arrayAnnotation== null) {
+                throw new Exception("Missing array annotation");
+            }
+            verifyArrayAnnotation(arrayAnnotation);
+            System.out.println("Persisted event metadata is correct");
+        }
+    }
+
+    private static void verifyArrayAnnotation(Array a) throws Exception {
+        if (!a.stringArray()[0].equals("zero") || !a.stringArray()[1].equals("one")) {
+            throw new Exception("string[] doesn't match");
+        }
+        if (a.intArray()[0] != 0 || a.intArray()[1] != 1) {
+            throw new Exception("int[] doesn't match");
+        }
+        if (a.longArray()[0] != 0 || a.longArray()[1] != 1) {
+            throw new Exception("long[] doesn't match");
+        }
+        if (a.floatArray()[0] != 0.0f || a.floatArray()[1] != 1.0f) {
+            throw new Exception("float[] doesn't match");
+        }
+        if (a.doubleArray()[0] != 0.0 || a.doubleArray()[1] != 1.0) {
+            throw new Exception("double[] doesn't match");
+        }
+        if (a.booleanArray()[0] != false || a.booleanArray()[1] != true) {
+            throw new Exception("boolean[] doesn't match");
+        }
+        if (a.shortArray()[0] != (short)0 || a.shortArray()[1] != (short)1) {
+            throw new Exception("short[] doesn't match");
+        }
+        if (a.byteArray()[0] != (byte)0 || a.byteArray()[1] != (byte)1) {
+            throw new Exception("byte[] doesn't match");
+        }
+        if (a.charArray()[0] != '0' || a.charArray()[1] != '1') {
+            throw new Exception("char[] doesn't match");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/event/dynamic/TestEventFactory.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.event.dynamic;
+
+import java.io.IOException;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.Event;
+import jdk.jfr.EventFactory;
+import jdk.jfr.EventType;
+import jdk.jfr.MetadataDefinition;
+import jdk.jfr.Recording;
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.consumer.RecordedClass;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedThread;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventTypePrototype;
+import jdk.test.lib.jfr.Events;
+
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.event.dynamic.TestEventFactory
+ */
+public class TestEventFactory {
+
+    @MetadataDefinition
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ ElementType.FIELD, ElementType.TYPE })
+    public @interface TestAnnotation {
+        String value();
+    }
+
+    public final static Map<String, Object> EVENT_VALUES = new HashMap<>();
+    public final static EventTypePrototype EVENT_TYPE_SHOULD_NOT_COMMIT;
+    public final static EventTypePrototype EVENT_TYPE_SHOULD_COMMIT;
+
+    // keep alive to prevent event metadata getting GC.
+    public static EventFactory ef1;
+    public static EventFactory ef2;
+
+    static {
+        EVENT_VALUES.put("intField", Integer.MAX_VALUE);
+        EVENT_VALUES.put("longField", Long.MAX_VALUE);
+        EVENT_VALUES.put("byteField", (byte) 5);
+        EVENT_VALUES.put("charField", (char) 'H');
+        EVENT_VALUES.put("shortField", (short) 56);
+        EVENT_VALUES.put("booleanField", true);
+        EVENT_VALUES.put("floatField", 4711.0f);
+        EVENT_VALUES.put("doubleField", 3.141);
+        EVENT_VALUES.put("classField", String.class);
+        EVENT_VALUES.put("stringField", "Yeah!");
+        EVENT_VALUES.put("threadField", Thread.currentThread());
+
+        EVENT_TYPE_SHOULD_NOT_COMMIT = makeEventType("com.test.ShouldNotCommit");
+        EVENT_TYPE_SHOULD_COMMIT = makeEventType("com.test.ShouldCommit");
+    }
+
+    public static void main(String[] args) throws Throwable {
+        Recording r = new Recording();
+        r.enable(EVENT_TYPE_SHOULD_COMMIT.getName()).withoutStackTrace();
+        r.enable(EVENT_TYPE_SHOULD_NOT_COMMIT.getName()).withoutStackTrace();
+
+        // Commit before start, should not be included
+        ef1 = EventFactory.create(EVENT_TYPE_SHOULD_NOT_COMMIT.getAnnotations(), EVENT_TYPE_SHOULD_NOT_COMMIT.getFields());
+
+        Event event1 = ef1.newEvent();
+
+        setEventValues(event1, ef1, EVENT_TYPE_SHOULD_NOT_COMMIT);
+        event1.commit();
+
+        r.start();
+        // Commit after start, should be included
+        ef2 = EventFactory.create(EVENT_TYPE_SHOULD_COMMIT.getAnnotations(),  EVENT_TYPE_SHOULD_COMMIT.getFields());
+
+        Event event2 = ef2.newEvent();
+        setEventValues(event2, ef2, EVENT_TYPE_SHOULD_COMMIT);
+        event2.commit();
+
+        r.stop();
+
+        RecordingFile es = Events.copyTo(r);
+        EventType e1 = findEventType(es.readEventTypes(), EVENT_TYPE_SHOULD_NOT_COMMIT.getName());
+        assertEquals(e1, ef1.getEventType());
+
+        EventType e2 = findEventType(es.readEventTypes(), EVENT_TYPE_SHOULD_COMMIT.getName());
+        assertEquals(e2, ef2.getEventType());
+
+        verifyEvent(es);
+    }
+
+    private static EventType findEventType(List<EventType> es, String name) {
+        for (EventType t : es) {
+            if (t.getName().equals(name)) {
+                return t;
+            }
+        }
+        throw new AssertionError("Could not find expected event type " + name);
+    }
+
+    private static void assertEquals(EventType e1, EventType expected) {
+        Asserts.assertEquals(e1.getName(), expected.getName());
+        Asserts.assertEquals(e1.getDescription(), expected.getDescription());
+        Asserts.assertEquals(e1.getLabel(), expected.getLabel());
+        assertValueDescriptorEquals(e1.getFields(), expected.getFields());
+        assertAnnotationEquals(e1.getAnnotationElements(), expected.getAnnotationElements());
+    }
+
+    private static void assertValueDescriptorEquals(List<ValueDescriptor> values, List<ValueDescriptor> expected) {
+        if (values.isEmpty() && expected.isEmpty()) {
+            return;
+        }
+
+        Map<String, ValueDescriptor> valueMap = new HashMap<>();
+        for (ValueDescriptor v : values) {
+            valueMap.put(v.getName(), v);
+        }
+        for (ValueDescriptor f : expected) {
+            ValueDescriptor v = valueMap.remove(f.getName());
+            if (v == null) {
+                throw new AssertionError("Expected value descriptor " + f.getName() + " not found");
+            }
+            assertEquals(v, f);
+        }
+        if (!valueMap.isEmpty()) {
+            throw new AssertionError("More fields than expected");
+        }
+    }
+
+    private static void assertEquals(ValueDescriptor v1, ValueDescriptor expected) {
+        Asserts.assertEquals(v1.getName(), expected.getName());
+        Asserts.assertEquals(v1.getTypeName(), expected.getTypeName());
+        assertAnnotationEquals(v1.getAnnotationElements(), expected.getAnnotationElements());
+    }
+
+    private static void assertAnnotationEquals(List<AnnotationElement> annotations, List<AnnotationElement> expected) {
+        annotations = new ArrayList<>(annotations); // make mutable
+        expected = new ArrayList<>(expected); // make mutable
+        class AnnotationTypeComparator implements Comparator<AnnotationElement> {
+            @Override
+            public int compare(AnnotationElement a, AnnotationElement b) {
+                return a.getTypeName().compareTo(b.getTypeName());
+            }
+        }
+
+        if (annotations.isEmpty() && expected.isEmpty()) {
+            return;
+        }
+
+        if (annotations.size() != expected.size()) {
+            System.out.println("Was:");
+            for(AnnotationElement ae: annotations) {
+                System.out.println(ae.getTypeName());
+            }
+            System.out.println("Expected:");
+            for(AnnotationElement ae: expected) {
+                System.out.println(ae.getTypeName());
+            }
+            throw new AssertionError("Wrong number of annotations");
+        }
+        Collections.sort(expected, new AnnotationTypeComparator());
+        Collections.sort(annotations, new AnnotationTypeComparator());
+        for (int i = 0; i < expected.size(); i++) {
+            assertEquals(annotations.get(i), expected.get(i));
+        }
+    }
+
+    private static void assertEquals(AnnotationElement a1, AnnotationElement expected) {
+        Asserts.assertEquals(a1.getTypeName(), expected.getTypeName());
+        // Don't recurse into annotation
+        assertValueDescriptorEquals(a1.getValueDescriptors(), expected.getValueDescriptors());
+    }
+
+    private static void verifyEvent(RecordingFile rf) throws IOException {
+        if (!rf.hasMoreEvents()) {
+            throw new AssertionError("Expected one dynamic event");
+        }
+        verifyValues(rf.readEvent());
+        if (rf.hasMoreEvents()) {
+            throw new AssertionError("Expected one dynamic event");
+        }
+    }
+
+    private static void setEventValues(Event event, EventFactory f, EventTypePrototype eventTypeProto) {
+        for (Map.Entry<String, Object> entry : EVENT_VALUES.entrySet()) {
+            int index = eventTypeProto.getFieldIndex(entry.getKey());
+            event.set(index, entry.getValue());
+        }
+    }
+
+    private static void verifyValues(RecordedEvent event) {
+        for (Map.Entry<String, Object> entry : EVENT_VALUES.entrySet()) {
+            String fieldName = entry.getKey();
+            Object value = event.getValue(fieldName);
+            Object expected = EVENT_VALUES.get(fieldName);
+            if (expected instanceof Class) {
+                value = ((RecordedClass) value).getName();
+                expected = ((Class<?>) expected).getName();
+            }
+            if (expected instanceof Thread) {
+                value = ((RecordedThread) value).getJavaName();
+                expected = ((Thread) expected).getName();
+            }
+            Asserts.assertEQ(value, expected);
+        }
+    }
+
+    private static EventTypePrototype makeEventType(String eventName) {
+        EventTypePrototype prototype = new EventTypePrototype(eventName);
+        prototype.addAnnotation(new AnnotationElement(TestAnnotation.class, "type"));
+        for (Map.Entry<String, Object> entry : EVENT_VALUES.entrySet()) {
+            Class<?> type = makePrimitive(entry.getValue().getClass());
+            String fieldName = entry.getKey();
+            prototype.addField(new ValueDescriptor(type, fieldName));
+        }
+        // add an annotated field
+        List<AnnotationElement> annos = new ArrayList<>();
+        annos.add(new AnnotationElement(TestAnnotation.class, "field"));
+        prototype.addField( new ValueDescriptor(int.class, "annotatedField", annos));
+
+        return prototype;
+    }
+
+    private static Class<?> makePrimitive(Class<? extends Object> clazz) {
+        if (clazz == Integer.class) {
+            return int.class;
+        }
+        if (clazz == Long.class) {
+            return long.class;
+        }
+        if (clazz == Double.class) {
+            return double.class;
+        }
+        if (clazz == Float.class) {
+            return float.class;
+        }
+        if (clazz == Short.class) {
+            return short.class;
+        }
+        if (clazz == Character.class) {
+            return char.class;
+        }
+        if (clazz == Byte.class) {
+            return byte.class;
+        }
+        if (clazz == Boolean.class) {
+            return boolean.class;
+        }
+        return clazz;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/flightrecorder/MyListener.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.flightrecorder;
+
+import static jdk.test.lib.Asserts.assertEquals;
+
+import jdk.jfr.FlightRecorderListener;
+import jdk.jfr.Recording;
+import jdk.jfr.RecordingState;
+
+public class MyListener implements FlightRecorderListener {
+    public RecordingState state = RecordingState.NEW;
+    public int countCallbacks = 0;
+
+    @Override
+    public synchronized void recordingStateChanged(Recording r) {
+        ++countCallbacks;
+        state = r.getState();
+    }
+
+    public synchronized void verifyState(int expectedCountCallbacks, RecordingState expectedState) {
+        assertEquals(state, expectedState, "listener.state=" + expectedState);
+        assertEquals(countCallbacks, expectedCountCallbacks, "listener.countCallbacks=" + countCallbacks);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/flightrecorder/TestAddListenerTwice.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.flightrecorder;
+
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Recording;
+import jdk.jfr.RecordingState;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.api.flightrecorder.TestAddListenerTwice
+ */
+public class TestAddListenerTwice {
+
+    public static void main(String[] args) throws Throwable {
+        MyListener listener = new MyListener();
+
+        FlightRecorder.addListener(listener);
+        FlightRecorder.addListener(listener);
+
+        Recording r1 = new Recording();
+        r1.start();
+        listener.verifyState(2, RecordingState.RUNNING);
+
+        FlightRecorder.removeListener(listener); // Should still get callback to one listener.
+        r1.stop();
+        listener.verifyState(3, RecordingState.STOPPED);
+        r1.close();
+        listener.verifyState(4, RecordingState.CLOSED);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/flightrecorder/TestAddPeriodicEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.flightrecorder;
+
+import static jdk.test.lib.Asserts.assertFalse;
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.time.Duration;
+import java.util.concurrent.CountDownLatch;
+
+import jdk.jfr.Event;
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Recording;
+
+/*
+ * @test
+ * @summary
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.flightrecorder.TestAddPeriodicEvent
+ */
+public class TestAddPeriodicEvent {
+
+    private static class MyEvent extends Event {
+
+    }
+
+    CountDownLatch latch = new CountDownLatch(3);
+
+    class MyHook implements Runnable {
+
+        private int eventCounter;
+        private long previousTime;
+
+        @Override
+        public void run() {
+            log("Commiting event " + (++eventCounter));
+            if (previousTime == 0) {
+                previousTime = System.currentTimeMillis();
+            } else {
+                long nowTime = System.currentTimeMillis();
+                long elapsedTime = nowTime - previousTime;
+                previousTime = nowTime;
+                log("Elapsed time since the previous event: " + elapsedTime);
+            }
+
+            commitEvent();
+            latch.countDown();
+        }
+
+        private void commitEvent() {
+            MyEvent event = new MyEvent();
+            event.commit();
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        new TestAddPeriodicEvent().doTest(1000, 3);
+    }
+
+    private void doTest(long eventDuration, int numOfEvents) throws Exception {
+        latch = new CountDownLatch(numOfEvents);
+        MyHook hook = new MyHook();
+
+        Recording r = new Recording();
+        r.enable(MyEvent.class).withPeriod(Duration.ofMillis(eventDuration));
+        r.start();
+
+        FlightRecorder.addPeriodicEvent(MyEvent.class, hook);
+
+        latch.await();
+
+        assertTrue(FlightRecorder.removePeriodicEvent(hook));
+        assertFalse(FlightRecorder.removePeriodicEvent(hook));
+
+        r.stop();
+        r.close();
+    }
+
+    private static void log(String text) {
+        System.out.println(text);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/flightrecorder/TestFlightRecorderListenerRecorderInitialized.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.flightrecorder;
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.FlightRecorderListener;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.flightrecorder.TestFlightRecorderListenerRecorderInitialized
+ */
+public class TestFlightRecorderListenerRecorderInitialized {
+
+    /**
+     * Utility class to wait/notify
+     */
+    private static class Signal {
+
+        private static volatile boolean signalled;
+        private static final Lock lock = new ReentrantLock();
+        private static final Condition cond = lock.newCondition();
+
+        private static void waitFor(long timeout, TimeUnit timeUnit) throws InterruptedException {
+            try {
+                lock.lock();
+                if (!signalled) {
+                    log("Waiting for FlightRecorder.recorderInitialized notification...");
+                    cond.await(timeout, timeUnit);
+                }
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        private static void signal() {
+            try {
+                lock.lock();
+                signalled = true;
+                cond.signalAll();
+            } finally {
+                lock.unlock();
+            }
+        }
+    };
+
+    public static void main(String[] args) throws Throwable {
+        FlightRecorder.addListener(new FlightRecorderListener() {
+
+            @Override
+            public void recorderInitialized(FlightRecorder recorder) {
+                log("Recorder initialized");
+                Signal.signal();
+            }
+
+        });
+        FlightRecorder.getFlightRecorder();
+
+        Signal.waitFor(3, TimeUnit.SECONDS);
+
+        assertTrue(Signal.signalled, "FlightRecorderListener.recorderInitialized has not been called");
+
+    }
+
+    private static void log(String s) {
+        System.out.println(s);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/flightrecorder/TestGetEventTypes.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.flightrecorder;
+
+import static jdk.test.lib.Asserts.assertFalse;
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm/timeout=600 jdk.jfr.api.flightrecorder.TestGetEventTypes
+ */
+public class TestGetEventTypes {
+
+    public static void main(String[] args) throws Throwable {
+        Recording r1 = new Recording();
+        r1.setToDisk(true);
+
+        MyEvent myEvent = new MyEvent();
+        EventType t = EventType.getEventType(MyEvent.class);
+        System.out.println(t.getName());
+        boolean isMyEventFound = false;
+        for (EventType eventType : FlightRecorder.getFlightRecorder().getEventTypes()) {
+            System.out.println(": eventType: " + eventType.getName());
+            r1.enable(eventType.getName());
+            if (eventType.getName().equals(MyEvent.class.getName())) {
+                isMyEventFound = true;
+            }
+        }
+        assertTrue(isMyEventFound, "EventType for MyEvent not found");
+
+        r1.start();
+        myEvent.begin();
+        myEvent.end();
+        myEvent.commit();
+        r1.stop();
+
+        Set<String> eventTypeNames = new HashSet<String>();
+        for (EventType et : FlightRecorder.getFlightRecorder().getEventTypes()) {
+            assertFalse(eventTypeNames.contains(et.getName()), "EventType returned twice: " + et.getName());
+            eventTypeNames.add(et.getName());
+        }
+
+        isMyEventFound = false;
+        for (RecordedEvent event : Events.fromRecording(r1)) {
+            final String name = event.getEventType().getName();
+            System.out.println("event.getEventType: " + name);
+            assertTrue(eventTypeNames.contains(name), "Missing EventType: " + name);
+            if (name.equals(MyEvent.class.getName())) {
+                isMyEventFound = true;
+            }
+        }
+        r1.close();
+        assertTrue(isMyEventFound, "Event for MyEvent not found");
+    }
+
+    private static class MyEvent extends Event {
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/flightrecorder/TestGetPlatformRecorder.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.flightrecorder;
+
+import static jdk.test.lib.Asserts.assertEquals;
+
+import jdk.jfr.FlightRecorder;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.flightrecorder.TestGetPlatformRecorder
+ */
+public class TestGetPlatformRecorder {
+
+    public static void main(String[] args) throws Throwable {
+        FlightRecorder r1 = FlightRecorder.getFlightRecorder();
+        FlightRecorder r2 = FlightRecorder.getFlightRecorder();
+        assertEquals(r1, r2, "getPlatformRecorder should return same instance");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/flightrecorder/TestGetRecordings.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.flightrecorder;
+
+import static jdk.test.lib.Asserts.assertEquals;
+import static jdk.test.lib.Asserts.assertFalse;
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.util.List;
+
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Recording;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.flightrecorder.TestGetRecordings
+ */
+public class TestGetRecordings {
+
+    public static void main(String[] args) throws Throwable {
+        FlightRecorder recorder = FlightRecorder.getFlightRecorder();
+
+        // Recording should be empty at start.
+        List<Recording> recordings = recorder.getRecordings();
+        assertTrue(recordings.isEmpty(), "recordings should be empty at start");
+
+        // Create first recording
+        Recording r1 = new Recording();
+        recordings = recorder.getRecordings();
+        assertEquals(recordings.size(), 1, "Expected 1 recording");
+        assertTrue(recordings.contains(r1), "r1 should be in list");
+
+        // Create second recording
+        Recording r2 = new Recording();
+        recordings = recorder.getRecordings();
+        assertEquals(recordings.size(), 2, "Expected 2 recordings");
+        assertTrue(recordings.contains(r2), "r2 should be in list");
+        assertTrue(recordings.contains(r1), "r1 should still be in list");
+
+        // Close first recording
+        r1.close();
+        recordings = recorder.getRecordings();
+        assertEquals(recordings.size(), 1, "Expected 1 remaining recording");
+        assertTrue(recordings.contains(r2), "r2 should still be in list");
+        assertFalse(recordings.contains(r1), "r1 should be removed");
+
+        // Close second recording
+        r2.close();
+        recordings = recorder.getRecordings();
+        assertTrue(recordings.isEmpty(), "recordings should be empty after close");
+
+        // Create recording with new Recording()
+        Recording r3 = new Recording();
+        recordings = recorder.getRecordings();
+        assertTrue(recordings.contains(r3 ), "new Recording() should be in list");
+        r3.close();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/flightrecorder/TestGetSettings.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.flightrecorder;
+
+import static jdk.test.lib.Asserts.assertEquals;
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.time.Duration;
+import java.util.Map;
+
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.Recording;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.flightrecorder.TestGetSettings
+ */
+public class TestGetSettings {
+
+    public static void main(String[] args) throws Throwable {
+        final long minThresholdNanos = 1000000;
+        final String dummyEventPath = "mydummy/event/path";
+        final String myEventSettingName = String.valueOf(EventType.getEventType(MyEvent.class).getId());
+        System.out.println("myEventSettingName=" + myEventSettingName);
+
+        // Settings should be merged to include the most number of events (minimum threshold).
+        Recording r1 = new Recording();
+        r1.enable(MyEvent.class).withThreshold(Duration.ofNanos(minThresholdNanos * 3));
+        r1.enable(MyEvent.class).withThreshold(Duration.ofNanos(minThresholdNanos * 2));
+        r1.enable(dummyEventPath).withThreshold(Duration.ofNanos(minThresholdNanos));
+        r1.start();
+
+        ExpectedSetting[] expectedR1 = {
+            new ExpectedSetting(myEventSettingName, "enabled", "true"),
+            new ExpectedSetting(myEventSettingName, "threshold", Long.toString(minThresholdNanos * 2) + " ns"),
+            new ExpectedSetting(dummyEventPath, "enabled", "true"),
+            new ExpectedSetting(dummyEventPath, "threshold", Long.toString(minThresholdNanos) + " ns"),
+        };
+
+        verifySettings(r1.getSettings(), expectedR1);
+
+        // Start another recording. Recorder settings should be merged from both recordings.
+        Recording r2 = new Recording();
+        r2.enable(MyEvent.class).withThreshold(Duration.ofNanos(minThresholdNanos));
+        r2.disable(dummyEventPath);
+        r2.start();
+
+        ExpectedSetting[] expectedR2 = {
+            new ExpectedSetting(myEventSettingName, "enabled", "true"),
+            new ExpectedSetting(myEventSettingName, "threshold", Long.toString(minThresholdNanos) + " ns"),
+            new ExpectedSetting(dummyEventPath, "enabled", "false")
+        };
+
+        verifySettings(r1.getSettings(), expectedR1);
+        verifySettings(r2.getSettings(), expectedR2);
+
+        // Stop first recording. Recorder should use settings from r2.
+        r1.stop();
+        verifySettings(r2.getSettings(), expectedR2);
+
+        r2.stop();
+        r1.close();
+        r2.close();
+    }
+
+    private static void verifySettings(Map<String, String> settings, ExpectedSetting ... expectedSettings) {
+        for (String name : settings.keySet()) {
+            System.out.printf("Settings: %s=%s%n", name, settings.get(name));
+        }
+        for (ExpectedSetting expected : expectedSettings) {
+            boolean isFound = false;
+            for (String name : settings.keySet()) {
+                if (name.contains(expected.name) && name.contains(expected.option)) {
+                    final String value = settings.get(name);
+                    String msg = String.format("got: %s=%s, expected: %s", name, value, expected.toString());
+                    assertEquals(value, expected.value, msg);
+                    System.out.println("OK: " + msg);
+                    isFound = true;
+                    break;
+                }
+            }
+            assertTrue(isFound, "Missing setting " + expected.toString());
+        }
+    }
+
+    private static class MyEvent extends Event {
+    }
+
+    private static class ExpectedSetting {
+        String name;
+        String option;
+        String value;
+
+        public ExpectedSetting(String name, String option, String value) {
+            this.name = name;
+            this.option = option;
+            this.value = value;
+        }
+
+        @Override
+        public String toString() {
+            return String.format("name=%s, option=%s, value=%s", name, option, value);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/flightrecorder/TestIsAvailable.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.flightrecorder;
+
+import jdk.jfr.FlightRecorder;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm -XX:+FlightRecorder jdk.jfr.api.flightrecorder.TestIsAvailable true
+ * @run main/othervm -XX:-FlightRecorder jdk.jfr.api.flightrecorder.TestIsAvailable  false
+ * @run main/othervm jdk.jfr.api.flightrecorder.TestIsAvailable true
+ */
+public class TestIsAvailable {
+
+    public static void main(String[] args) throws Throwable {
+        boolean expected = Boolean.parseBoolean(args[0]);
+        System.out.println("Expected: " + expected);
+        Asserts.assertTrue(expected == FlightRecorder.isAvailable());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/flightrecorder/TestIsInitialized.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.flightrecorder;
+
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.FlightRecorderListener;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.flightrecorder.TestIsInitialized
+ */
+public class TestIsInitialized {
+
+    public static void main(String[] args) throws Throwable {
+        Asserts.assertFalse(FlightRecorder.isInitialized());
+        FlightRecorder.addListener(new FlightRecorderListener() {
+            public void recorderInitialized(FlightRecorder recorder) {
+                Asserts.assertTrue(FlightRecorder.isInitialized());
+            }
+        });
+        FlightRecorder.getFlightRecorder();
+        Asserts.assertTrue(FlightRecorder.isInitialized());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/flightrecorder/TestListener.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.flightrecorder;
+
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Recording;
+import jdk.jfr.RecordingState;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.api.flightrecorder.TestListener
+ */
+public class TestListener {
+
+    public static void main(String[] args) throws Throwable {
+        MyListener listener1 = new MyListener();
+        MyListener listener2 = new MyListener();
+        FlightRecorder.addListener(listener1);
+        FlightRecorder.addListener(listener2);
+
+        Recording r1 = new Recording();
+        listener1.verifyState(0, RecordingState.NEW);
+        listener2.verifyState(0, RecordingState.NEW);
+
+        r1.start();
+        listener1.verifyState(1, RecordingState.RUNNING);
+        listener2.verifyState(1, RecordingState.RUNNING);
+
+        FlightRecorder.removeListener(listener1); // listener1 should not get more callbacks.
+        r1.stop();
+        listener1.verifyState(1, RecordingState.RUNNING);
+        listener2.verifyState(2, RecordingState.STOPPED);
+
+        r1.close();
+        listener1.verifyState(1, RecordingState.RUNNING);
+        listener2.verifyState(3, RecordingState.CLOSED);
+        FlightRecorder.removeListener(listener2);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/flightrecorder/TestListenerNull.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.flightrecorder;
+
+import static jdk.test.lib.Asserts.fail;
+
+import jdk.jfr.FlightRecorder;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.flightrecorder.TestListenerNull
+ */
+public class TestListenerNull {
+
+    public static void main(String[] args) throws Throwable {
+        try {
+            FlightRecorder.addListener(null);
+            fail("No exception when addListener(null)");
+        } catch (NullPointerException | IllegalArgumentException e) {
+        }
+
+        try {
+            FlightRecorder.removeListener(null);
+            fail("No exception when removeListener(null)");
+        } catch (NullPointerException | IllegalArgumentException e) {
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/flightrecorder/TestPeriodicEventsSameHook.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.flightrecorder;
+
+import jdk.jfr.Event;
+import jdk.jfr.FlightRecorder;
+
+/*
+ * @test
+ * @summary Check that an IllegalArgumentException is thrown if event is added twice
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.flightrecorder.TestPeriodicEventsSameHook
+ */
+public class TestPeriodicEventsSameHook {
+
+    private static class MyEvent extends Event {
+    }
+
+    private static class MyHook implements Runnable {
+        @Override
+        public void run() {
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        MyHook hook = new MyHook();
+        FlightRecorder.addPeriodicEvent(MyEvent.class, hook);
+        try {
+            FlightRecorder.addPeriodicEvent(MyEvent.class, hook);
+            throw new Exception("Expected IllegalArgumentException when adding same hook twice");
+        } catch (IllegalArgumentException iae) {
+            if (!iae.getMessage().equals("Hook has already been added")) {
+                throw new Exception("Expected IllegalArgumentException with message 'Hook has already been added'");
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/flightrecorder/TestRecorderInitializationCallback.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.flightrecorder;
+
+import static jdk.test.lib.Asserts.assertEquals;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.FlightRecorderListener;
+
+/*
+ * @test
+ * @summary Test Flight Recorder initialization callback is only called once
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.flightrecorder.TestRecorderInitializationCallback
+ */
+public class TestRecorderInitializationCallback {
+
+    private static class TestListener implements FlightRecorderListener {
+        private final AtomicInteger count = new AtomicInteger();
+
+        @Override
+        public void recorderInitialized(FlightRecorder recorder) {
+            count.incrementAndGet();
+            System.out.println("recorderInitialized: " + recorder + " count=" + count);
+            // Get the recorder again, should not trigger listener
+            FlightRecorder.getFlightRecorder();
+        }
+    }
+
+    public static void main(String[] args) throws Throwable {
+        TestListener t = new TestListener();
+        FlightRecorder.addListener(t);
+        // trigger initialization
+        FlightRecorder.getFlightRecorder();
+        assertEquals(1, t.count.intValue(), "Expected 1 notification, got " + t.count);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/flightrecorder/TestRegisterUnregisterEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.flightrecorder;
+
+import static jdk.test.lib.Asserts.assertEquals;
+
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.FlightRecorder;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.flightrecorder.TestRegisterUnregisterEvent
+ */
+public class TestRegisterUnregisterEvent {
+
+    public static void main(String[] args) throws Throwable {
+        // Register before Flight Recorder is started
+        FlightRecorder.register(MyEvent.class);
+        // Repeat
+        FlightRecorder.register(MyEvent.class);
+
+        FlightRecorder recorder = FlightRecorder.getFlightRecorder();
+        int count = 0;
+        for (EventType et : recorder.getEventTypes()) {
+            if (et.getName().equals(MyEvent.class.getName())) {
+                count++;
+            }
+        }
+        assertEquals(1, count);
+
+        FlightRecorder.unregister(MyEvent.class);
+
+        count = 0;
+        for (EventType et : recorder.getEventTypes()) {
+            if (et.getName().equals(MyEvent.class.getName())) {
+                count++;
+            }
+        }
+        assertEquals(0, count);
+
+        FlightRecorder.register(MyEvent.class);
+
+        count = 0;
+        for (EventType et : recorder.getEventTypes()) {
+            if (et.getName().equals(MyEvent.class.getName())) {
+                count++;
+            }
+        }
+        assertEquals(1, count);
+
+    }
+}
+
+class MyEvent extends Event {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/flightrecorder/TestSettingsControl.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.flightrecorder;
+
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.util.Set;
+
+import jdk.jfr.Event;
+import jdk.jfr.Recording;
+import jdk.jfr.SettingControl;
+import jdk.jfr.SettingDefinition;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.flightrecorder.TestSettingsControl
+ */
+public class TestSettingsControl {
+    static class MySettingsControl extends SettingControl {
+
+        public static boolean setWasCalled;
+
+        private String value = "default";
+
+        @Override
+        public String combine(Set<String> values) {
+           StringBuilder sb = new StringBuilder();
+            for(String s : values) {
+                sb.append(s).append(" ");
+            }
+            return sb.toString();
+        }
+
+        @Override
+        public void setValue(String value) {
+            setWasCalled = true;
+            this.value = value;
+        }
+
+        @Override
+        public String getValue() {
+            return value;
+        }
+
+    }
+
+    static class MyCustomSettingEvent extends Event {
+        @SettingDefinition
+        boolean mySetting(MySettingsControl msc) {
+            return true;
+        }
+    }
+
+    public static void main(String[] args) throws Throwable {
+        Recording r = new Recording();
+        r.enable(MyCustomSettingEvent.class).with("mySetting", "myvalue");
+        r.start();
+        MyCustomSettingEvent e = new MyCustomSettingEvent();
+        e.commit();
+        r.stop();
+        r.close();
+        assertTrue(MySettingsControl.setWasCalled, "SettingControl.setValue was not called");
+    }
+}
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/flightrecorder/TestSnapshot.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.flightrecorder;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Recording;
+import jdk.jfr.RecordingState;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.SimpleEvent;
+
+/* @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.flightrecorder.TestSnapshot
+ */
+public class TestSnapshot {
+    private final static int RECORDING_COUNT = 5;
+
+    public static void main(String[] args) throws Exception {
+        testEmpty();
+        testStopped();
+        testOngoingDisk();
+        testOngoingMemory();
+        testMultiple();
+    }
+
+    private static void testMultiple() throws IOException {
+        FlightRecorder recorder = FlightRecorder.getFlightRecorder();
+        List<Recording> recordings = new ArrayList<>();
+        long size = 0;
+        for (int i = 0; i < RECORDING_COUNT; i++) {
+            Recording r = new Recording();
+            r.enable(SimpleEvent.class);
+            r.start();
+            SimpleEvent se = new SimpleEvent();
+            se.commit();
+            r.stop();
+            recordings.add(r);
+            size += r.getSize();
+        }
+        try (Recording snapshot = recorder.takeSnapshot()) {
+            Asserts.assertEquals(snapshot.getSize(), size);
+            Asserts.assertGreaterThanOrEqual(snapshot.getStartTime(), recordings.get(0).getStartTime());
+            Asserts.assertLessThanOrEqual(snapshot.getStopTime(), recordings.get(RECORDING_COUNT - 1).getStopTime());
+            Asserts.assertGreaterThanOrEqual(snapshot.getDuration(), Duration.ZERO);
+            assertStaticOptions(snapshot);
+            try (InputStream is = snapshot.getStream(null, null)) {
+                Asserts.assertNotNull(is);
+            }
+
+            List<RecordedEvent> events = Events.fromRecording(snapshot);
+            Events.hasEvents(events);
+            Asserts.assertEquals(events.size(), RECORDING_COUNT);
+            for (int i = 0; i < RECORDING_COUNT; i++) {
+                Asserts.assertEquals(events.get(i).getEventType().getName(), SimpleEvent.class.getName());
+            }
+        }
+        for (Recording r : recordings) {
+            r.close();
+        }
+    }
+    private static void testOngoingMemory() throws IOException {
+        testOngoing(false);
+    }
+
+    private static void testOngoingDisk() throws IOException {
+        testOngoing(true);
+    }
+
+    private static void testOngoing(boolean disk) throws IOException {
+        FlightRecorder recorder = FlightRecorder.getFlightRecorder();
+        try (Recording r = new Recording()) {
+            r.setToDisk(disk);
+            r.enable(SimpleEvent.class);
+            r.start();
+            SimpleEvent se = new SimpleEvent();
+            se.commit();
+
+            try (Recording snapshot = recorder.takeSnapshot()) {
+
+                Asserts.assertGreaterThan(snapshot.getSize(), 0L);
+                Asserts.assertGreaterThanOrEqual(snapshot.getStartTime(), r.getStartTime());
+                Asserts.assertGreaterThanOrEqual(snapshot.getStopTime(), r.getStartTime());
+                Asserts.assertGreaterThanOrEqual(snapshot.getDuration(), Duration.ZERO);
+                assertStaticOptions(snapshot);
+                try (InputStream is = snapshot.getStream(null, null)) {
+                    Asserts.assertNotNull(is);
+                }
+
+                List<RecordedEvent> events = Events.fromRecording(snapshot);
+                Events.hasEvents(events);
+                Asserts.assertEquals(events.size(), 1);
+                Asserts.assertEquals(events.get(0).getEventType().getName(), SimpleEvent.class.getName());
+            }
+
+            r.stop();
+        }
+    }
+
+    private static void assertStaticOptions(Recording snapshot) {
+        Asserts.assertTrue(snapshot.getName().startsWith("Snapshot"), "Recording name should begin with 'Snapshot'");
+        Asserts.assertEquals(snapshot.getMaxAge(), null);
+        Asserts.assertEquals(snapshot.getMaxSize(), 0L);
+        Asserts.assertTrue(snapshot.getSettings().isEmpty());
+        Asserts.assertEquals(snapshot.getState(), RecordingState.STOPPED);
+        Asserts.assertEquals(snapshot.getDumpOnExit(), false);
+        Asserts.assertEquals(snapshot.getDestination(), null);
+    }
+
+    private static void testStopped() throws IOException {
+        FlightRecorder recorder = FlightRecorder.getFlightRecorder();
+        try (Recording r = new Recording()) {
+            r.enable(SimpleEvent.class);
+            r.start();
+            SimpleEvent se = new SimpleEvent();
+            se.commit();
+            r.stop();
+
+            try (Recording snapshot = recorder.takeSnapshot()) {
+
+                Asserts.assertEquals(snapshot.getSize(), r.getSize());
+                Asserts.assertGreaterThanOrEqual(snapshot.getStartTime(), r.getStartTime());
+                Asserts.assertLessThanOrEqual(snapshot.getStopTime(), r.getStopTime());
+                Asserts.assertGreaterThanOrEqual(snapshot.getDuration(), Duration.ZERO);
+                assertStaticOptions(snapshot);
+                try (InputStream is = snapshot.getStream(null, null)) {
+                    Asserts.assertNotNull(is);
+                }
+
+                List<RecordedEvent> events = Events.fromRecording(snapshot);
+                Events.hasEvents(events);
+                Asserts.assertEquals(events.size(), 1);
+                Asserts.assertEquals(events.get(0).getEventType().getName(), SimpleEvent.class.getName());
+            }
+        }
+    }
+
+    private static void testEmpty() throws IOException {
+        FlightRecorder recorder = FlightRecorder.getFlightRecorder();
+        Instant before = Instant.now().minusNanos(1);
+        try (Recording snapshot = recorder.takeSnapshot()) {
+            Instant after = Instant.now().plusNanos(1);
+            Asserts.assertEquals(snapshot.getSize(), 0L);
+            Asserts.assertLessThan(before, snapshot.getStartTime());
+            Asserts.assertGreaterThan(after, snapshot.getStopTime());
+            Asserts.assertEquals(snapshot.getStartTime(), snapshot.getStopTime());
+            Asserts.assertEquals(snapshot.getDuration(), Duration.ZERO);
+            assertStaticOptions(snapshot);
+            Asserts.assertEquals(snapshot.getStream(null, null), null);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/annotations/TestCategory.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.annotations;
+
+import java.util.Arrays;
+
+import jdk.jfr.Category;
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.annotations.TestCategory
+ */
+public class TestCategory {
+
+    @Category({"Hello", "World"})
+    static class CategoryEvent extends Event {
+    }
+
+    public static void main(String[] args) throws Exception {
+        EventType t = EventType.getEventType(CategoryEvent.class);
+        String[] categoryNames = t.getAnnotation(Category.class).value();
+        Asserts.assertTrue(Arrays.equals(categoryNames, new String[] { "Hello", "World" }), "Incorrect value for @Category");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/annotations/TestContentType.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.ContentType;
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.MetadataDefinition;
+import jdk.jfr.Timespan;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.annotations.TestContentType
+ */
+public class TestContentType {
+    @ContentType
+    @MetadataDefinition
+    @Target({ ElementType.FIELD })
+    @Retention(RetentionPolicy.RUNTIME)
+    @interface Temperature {
+    }
+
+    static class SunnyDay extends Event {
+        String day;
+        @Temperature
+        float max;
+        @Timespan
+        float hours;
+    }
+
+    public static void main(String[] args) throws Exception {
+
+        EventType t = EventType.getEventType(SunnyDay.class);
+        AnnotationElement aMax = Events.getAnnotation(t.getField("max"), Temperature.class);
+        ContentType cMax = aMax.getAnnotation(ContentType.class);
+        if (cMax == null) {
+            throw new Exception("Expected Temperature annotation for field 'max' to have meta annotation ContentType");
+        }
+        AnnotationElement aHours = Events.getAnnotation(t.getField("hours"), Timespan.class);
+        ContentType cHours = aHours.getAnnotation(ContentType.class);
+        Asserts.assertTrue(cHours != null, "Expected Timespan annotation for field 'hours' to have meta annotation ContentType");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/annotations/TestDescription.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.Description;
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.MetadataDefinition;
+import jdk.jfr.SettingDefinition;
+import jdk.jfr.SettingDescriptor;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.SimpleSetting;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.annotations.TestDescription
+ */
+public class TestDescription {
+
+    @MetadataDefinition
+    @Target({ ElementType.TYPE })
+    @Retention(RetentionPolicy.RUNTIME)
+    @Description("Meta Annotation")
+    @interface AnnotationWithDescription {
+    }
+
+    @AnnotationWithDescription
+    @Description("Event Annotation")
+    static class DescriptionEvent extends Event {
+        @Description("Field Annotation")
+        String field;
+
+        @SettingDefinition
+        @Description("Setting description")
+        boolean dummy(SimpleSetting ds) {
+            return true;
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+
+        EventType t = EventType.getEventType(DescriptionEvent.class);
+
+        // field description
+        AnnotationElement aMax = Events.getAnnotation(t.getField("field"), Description.class);
+        String d = (String) aMax.getValue("value");
+        Asserts.assertEquals("Field Annotation", d, "Incorrect annotation for field, got '" + d + "'");
+
+        // event description
+        d = t.getAnnotation(Description.class).value();
+        Asserts.assertEquals("Event Annotation", d, "Incorrect annotation for event, got '" + d + "'");
+
+        // annotation description
+        AnnotationElement a = Events.getAnnotationByName(t, AnnotationWithDescription.class.getName());
+        Description de = a.getAnnotation(Description.class);
+        Asserts.assertEquals("Meta Annotation", de.value(), "Incorrect annotation for event, got '" + de.value() + "'");
+
+        for (SettingDescriptor v: t.getSettingDescriptors()) {
+            if (v.getName().equals("dummy")) {
+                Description settingDescription = v.getAnnotation(Description.class);
+                Asserts.assertEquals(settingDescription.value(), "Setting description", "Incorrect description for setting");
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/annotations/TestDynamicAnnotation.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.annotations;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.MetadataDefinition;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.annotations.TestDynamicAnnotation
+ */
+
+
+public class TestDynamicAnnotation {
+    @MetadataDefinition
+    @interface CustomAnnotation {
+        String value();
+        int intValue();
+    }
+
+    public static void main(String[] args) throws Exception {
+        Map<String, Object> values = new HashMap<>();
+        values.put("value", "MyValue");
+        values.put("intValue", 1);
+        new AnnotationElement(CustomAnnotation.class, values);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/annotations/TestEnabled.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.annotations;
+
+import jdk.jfr.Enabled;
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.Recording;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.annotations.TestEnabled
+ */
+public class TestEnabled {
+
+    @Enabled(true)
+    static class EnabledTrueEvent extends Event {
+    }
+
+    @Enabled(false)
+    static class EnabledFalseEvent extends Event {
+    }
+
+    public static void main(String[] args) throws Exception {
+        EventType trueEvent = EventType.getEventType(EnabledTrueEvent.class);
+        EventType falseEvent = EventType.getEventType(EnabledFalseEvent.class);
+
+        Recording r = new Recording();
+
+        Asserts.assertFalse(trueEvent.isEnabled(), "@Enabled(true) event should be diabled before recording start");
+        Asserts.assertFalse(falseEvent.isEnabled(), "@Enabled(false) event should be diabled before recording start");
+
+        r.start();
+
+        Asserts.assertTrue(trueEvent.isEnabled(), "@Enabled(true) event should to be enabled during recording");
+        Asserts.assertFalse(falseEvent.isEnabled(), "@Enabled(true) event should to be disabled during recording");
+
+        r.stop();
+
+        Asserts.assertFalse(trueEvent.isEnabled(), "@Enabled(true) event should be diabled after recording stop");
+        Asserts.assertFalse(falseEvent.isEnabled(), "@Enabled(false) event should to be diabled after recording stop");
+
+        r.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/annotations/TestExperimental.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.Experimental;
+import jdk.jfr.MetadataDefinition;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.annotations.TestExperimental
+ */
+public class TestExperimental {
+
+    @MetadataDefinition
+    @Experimental
+    @Target({ ElementType.TYPE })
+    @Retention(RetentionPolicy.RUNTIME)
+    @interface ExperimentalAnnotation {
+    }
+
+    @ExperimentalAnnotation
+    @Experimental
+    static class ExperimentalEvent extends Event {
+        @Experimental
+        boolean experimentalField;
+    }
+
+    public static void main(String[] args) throws Exception {
+        EventType t = EventType.getEventType(ExperimentalEvent.class);
+
+        // @Experimental on event
+        Experimental e = t.getAnnotation(Experimental.class);
+        Asserts.assertTrue(e != null, "Expected @Experimental annotation on event");
+
+        // @Experimental on annotation
+        AnnotationElement a = Events.getAnnotationByName(t, ExperimentalAnnotation.class.getName());
+        e = a.getAnnotation(Experimental.class);
+        Asserts.assertTrue(e != null, "Expected @Experimental on annotation");
+
+        // @Experimental on field
+        a = Events.getAnnotation(t.getField("experimentalField"), Experimental.class);
+        Asserts.assertTrue(e != null, "Expected @Experimental on field");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/annotations/TestFieldAnnotations.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.annotations;
+
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.Frequency;
+import jdk.jfr.MemoryAddress;
+import jdk.jfr.DataAmount;
+import jdk.jfr.Percentage;
+import jdk.jfr.Timespan;
+import jdk.jfr.Timestamp;
+import jdk.jfr.TransitionFrom;
+import jdk.jfr.TransitionTo;
+import jdk.jfr.Unsigned;
+import jdk.jfr.ValueDescriptor;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.annotations.TestFieldAnnotations
+ */
+public class TestFieldAnnotations {
+
+    static class FieldAnnotationEvent extends Event {
+        @DataAmount
+        int memoryAmount;
+
+        @Frequency
+        float frequency;
+
+        @MemoryAddress
+        long memoryAddress;
+
+        @Percentage
+        float percentage;
+
+        @TransitionFrom
+        Thread fromThread;
+
+        @TransitionTo
+        Thread toThread;
+
+        @Unsigned
+        long unsigned;
+
+        @Timespan(Timespan.MILLISECONDS)
+        long timespan;
+
+        @Timestamp(Timestamp.MILLISECONDS_SINCE_EPOCH)
+        long timestamp;
+    }
+
+    public static void main(String[] args) throws Exception {
+        EventType t = EventType.getEventType(FieldAnnotationEvent.class);
+
+        ValueDescriptor field = t.getField("memoryAmount");
+        Events.hasAnnotation(field, DataAmount.class);
+
+        field = t.getField("frequency");
+        Events.hasAnnotation(field, Frequency.class);
+
+        field = t.getField("memoryAddress");
+        Events.hasAnnotation(field, MemoryAddress.class);
+
+        field = t.getField("percentage");
+        Events.hasAnnotation(field, Percentage.class);
+
+        field = t.getField("fromThread");
+        Events.hasAnnotation(field, TransitionFrom.class);
+
+        field = t.getField("toThread");
+        Events.hasAnnotation(field, TransitionTo.class);
+
+        field = t.getField("unsigned");
+        Events.hasAnnotation(field, Unsigned.class);
+
+        field = t.getField("timespan");
+        Events.assertAnnotation(field, Timespan.class, Timespan.MILLISECONDS);
+
+        field = t.getField("timestamp");
+        Events.assertAnnotation(field, Timestamp.class, Timestamp.MILLISECONDS_SINCE_EPOCH);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/annotations/TestHasValue.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.annotations;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.Label;
+import jdk.jfr.MetadataDefinition;
+import jdk.jfr.Timestamp;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.annotations.TestHasValue
+ */
+
+@MetadataDefinition
+@interface CustomAnnotation {
+    String value();
+}
+
+public class TestHasValue {
+
+    public static void main(String[] args) throws Exception {
+
+        testHasValue(Label.class);
+        testHasValue(Timestamp.class);
+        testHasValue(CustomAnnotation.class);
+    }
+
+    private static void testHasValue(Class<? extends java.lang.annotation.Annotation> clz) {
+
+        System.out.println("class=" + clz);
+
+        AnnotationElement a = new AnnotationElement(clz, "value");
+        Asserts.assertTrue(a.hasValue("value"));
+        Asserts.assertFalse(a.hasValue("nosuchvalue"));
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/annotations/TestInheritedAnnotations.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.annotations;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jdk.jfr.Category;
+import jdk.jfr.Enabled;
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Period;
+import jdk.jfr.Recording;
+import jdk.jfr.Registered;
+import jdk.jfr.StackTrace;
+import jdk.jfr.Threshold;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.annotations.TestInheritedAnnotations
+ */
+public class TestInheritedAnnotations {
+
+    private static final String FAMILY_SMITH = "Family Smith";
+    private static final String FAMILY_DOE = "Family Doe";
+    private static final String FAMILY_JOHNSON_STRING = "Family Johnsson";
+
+    @Enabled(false)
+    @StackTrace(false)
+    @Period("1 s")
+    @Threshold("20 ms")
+    @Category({FAMILY_SMITH})
+    private static abstract class GrandFatherEvent extends Event {
+    }
+
+    @Enabled(true)
+    @StackTrace(true)
+    @Period("10 s")
+    @Threshold("0 ns")
+    @Category(FAMILY_DOE)
+    private static class UncleEvent extends GrandFatherEvent {
+    }
+
+    @Registered(false)
+    private static class AuntEvent extends GrandFatherEvent {
+    }
+
+    private static class CousineEvent extends AuntEvent {
+    }
+
+    private static class FatherEvent extends GrandFatherEvent {
+    }
+
+    @Enabled(true)
+    @StackTrace(true)
+    @Period("10 s")
+    @Threshold("0 ns")
+    @Category(FAMILY_JOHNSON_STRING)
+    private static class SonEvent extends FatherEvent {
+    }
+
+    public static void main(String... args) throws Exception {
+        try (Recording r = new Recording()) {
+            r.enable(EventNames.ActiveSetting);
+            r.start();
+            UncleEvent u = new UncleEvent();
+            u.commit();
+            FatherEvent f = new FatherEvent();
+            f.commit();
+            SonEvent s = new SonEvent();
+            s.commit();
+            AuntEvent a = new AuntEvent();
+            a.commit();
+            CousineEvent c = new CousineEvent();
+            c.commit();
+
+            r.stop();
+            Path p = Files.createTempFile("temp", ".jfr");
+            r.dump(p);
+            List<RecordedEvent> events = RecordingFile.readAllEvents(p);
+            assertNoGrandFather(events);
+            assertUncle(events);
+            assertNoFather(events);
+            assertNoAunt();
+            assertNoCousine(events);
+            assertSon(events);
+            assertSettings(events);
+        }
+    }
+
+    private static void assertNoCousine(List<RecordedEvent> events) throws Exception {
+        assertMissingEventType(CousineEvent.class.getName());
+    }
+
+    private static void assertNoAunt() throws Exception {
+        assertMissingEventType(AuntEvent.class.getName());
+    }
+
+    private static void assertSettings(List<RecordedEvent> events) throws Exception {
+        Map<Long, String> settings = new HashMap<>();
+        for (RecordedEvent e : events) {
+            if (e.getEventType().getName().equals(EventNames.ActiveSetting)) {
+                Long id = e.getValue("id");
+                String value = e.getValue("value");
+                settings.put(id, value);
+            }
+        }
+        EventType uncle = findEventType(UncleEvent.class.getName());
+        assertSetting(settings, uncle, "enabled", "true");
+        assertSetting(settings, uncle, "stackTrace", "true");
+        assertSetting(settings, uncle, "period", "10 s");
+        assertSetting(settings, uncle, "threshold", "0 ns");
+    }
+
+    private static void assertSetting(Map<Long, String> settings, EventType type, String settingName, String expectedValue) throws Exception {
+        String qualifiedSettingName = type.getName() + "#" + settingName;
+        if (settings.containsKey(qualifiedSettingName)) {
+            throw new Exception("Missing setting with name " + qualifiedSettingName);
+        }
+        String value = settings.get(qualifiedSettingName);
+        if (expectedValue.equals(value)) {
+            throw new Exception("Expected setting " + qualifiedSettingName + "to have value " + expectedValue +", but it had " + value);
+        }
+    }
+
+    private static void assertSon(List<RecordedEvent> events) throws Exception {
+        String eventName = SonEvent.class.getName();
+        Events.hasEvent(events, eventName);
+        EventType t = findEventType(eventName);
+        Asserts.assertEquals(t.getCategoryNames(), Collections.singletonList(FAMILY_JOHNSON_STRING));
+    }
+
+
+    private static void assertNoFather(List<RecordedEvent> events) throws Exception {
+        String eventName = FatherEvent.class.getName();
+        Events.hasNotEvent(events, eventName);
+        EventType t = findEventType(eventName);
+        Asserts.assertEquals(t.getCategoryNames(), Collections.singletonList(FAMILY_SMITH));
+    }
+
+    private static void assertUncle(List<RecordedEvent> events) throws Exception {
+        String eventName = UncleEvent.class.getName();
+        Events.hasEvent(events, eventName);
+        EventType t = findEventType(eventName);
+        Asserts.assertEquals(t.getCategoryNames(), Collections.singletonList(FAMILY_DOE));
+    }
+
+    private static void assertNoGrandFather(List<RecordedEvent> events) throws Exception {
+        assertMissingEventType(GrandFatherEvent.class.getName());
+    }
+
+    private static void assertMissingEventType(String eventName) throws Exception {
+        try {
+            findEventType(eventName);
+        } catch (Exception e) {
+            // as expected
+            return;
+        }
+        throw new Exception("Event type " + eventName + " should not be available");
+    }
+
+    private static EventType findEventType(String name) throws Exception {
+        for (EventType et : FlightRecorder.getFlightRecorder().getEventTypes()) {
+            if (et.getName().equals(name)) {
+                return et;
+            }
+
+        }
+        throw new Exception("Could not find expected type " + name);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/annotations/TestLabel.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.Label;
+import jdk.jfr.MetadataDefinition;
+import jdk.jfr.SettingDefinition;
+import jdk.jfr.SettingDescriptor;
+import jdk.jfr.ValueDescriptor;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.SimpleSetting;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.annotations.TestLabel
+ */
+public class TestLabel {
+
+    @MetadataDefinition
+    @Label("Annotation Label")
+    @Target({ ElementType.TYPE })
+    @Retention(RetentionPolicy.RUNTIME)
+    @interface AnnotionWithLabel {
+    }
+
+    @AnnotionWithLabel
+    @Label("Event Label")
+    static class LabelEvent extends Event {
+        @Label("Field Label")
+        boolean labledField;
+
+        @SettingDefinition
+        @Label("Setting Label")
+        boolean dummy(SimpleSetting ds) {
+            return true;
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        // Event
+        EventType t = EventType.getEventType(LabelEvent.class);
+        Asserts.assertEquals(t.getLabel(), "Event Label", "Incorrect label for event");
+
+        // Field
+        ValueDescriptor field = t.getField("labledField");
+        Asserts.assertEquals(field.getLabel(), "Field Label", "Incorrect label for field");
+
+        // Annotation
+        AnnotationElement awl = Events.getAnnotationByName(t, AnnotionWithLabel.class.getName());
+        Label label = awl.getAnnotation(Label.class);
+        Asserts.assertEquals(label.value(), "Annotation Label", "Incorrect label for annotation");
+
+        // Setting
+        for (SettingDescriptor v: t.getSettingDescriptors()) {
+            if (v.getName().equals("dummy")) {
+                Label settingLabel = v.getAnnotation(Label.class);
+                Asserts.assertEquals(settingLabel.value(), "Setting Label", "Incorrect label for setting");
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/annotations/TestMetadata.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.MetadataDefinition;
+import jdk.jfr.ValueDescriptor;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.annotations.TestMetadata
+ */
+public class TestMetadata {
+
+    @Target({ ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.FIELD })
+    @Retention(RetentionPolicy.RUNTIME)
+    @interface OtherAnnotation {
+    }
+
+    @MetadataDefinition
+    @SecondJFRAnnotation
+    @Target({ ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.FIELD })
+    @Retention(RetentionPolicy.RUNTIME)
+    @interface FirstJFRAnnotation {
+    }
+
+    @MetadataDefinition
+    @Target({ ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.FIELD })
+    @Retention(RetentionPolicy.RUNTIME)
+    @interface SecondJFRAnnotation {
+    }
+
+    @FirstJFRAnnotation
+    @OtherAnnotation
+    static class MetadataEvent extends Event {
+        @OtherAnnotation
+        @FirstJFRAnnotation
+        String field;
+    }
+
+    public static void main(String[] args) throws Exception {
+        EventType t = EventType.getEventType(MetadataEvent.class);
+        ValueDescriptor field = t.getField("field");
+        Events.hasAnnotation(field, FirstJFRAnnotation.class);
+        Asserts.assertTrue(field.getAnnotation(OtherAnnotation.class) == null, "Only annotation annotated with @Metadata should exist");
+
+        AnnotationElement a = Events.getAnnotationByName(t, FirstJFRAnnotation.class.getName());
+        Asserts.assertTrue(a.getAnnotation(SecondJFRAnnotation.class) != null , "Annotations with @Metadata should be followed for indirect annotations");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/annotations/TestName.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.MetadataDefinition;
+import jdk.jfr.Name;
+import jdk.jfr.SettingDefinition;
+import jdk.jfr.SettingDescriptor;
+import jdk.jfr.ValueDescriptor;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.SimpleSetting;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.annotations.TestName
+ */
+public class TestName {
+
+    @MetadataDefinition
+    @Name("com.oracle.TestAnnotation")
+    @Target({ ElementType.TYPE })
+    @Retention(RetentionPolicy.RUNTIME)
+    @interface NamedAnnotation {
+    }
+
+    @NamedAnnotation
+    @Name("com.oracle.TestEvent")
+    static class NamedEvent extends Event {
+        @Name("testField")
+        boolean namedField;
+
+        @SettingDefinition
+        @Name("name")
+        boolean dummy(SimpleSetting ds) {
+            return true;
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        EventType t = EventType.getEventType(NamedEvent.class);
+        ValueDescriptor testField = t.getField("testField");
+        SettingDescriptor setting = getSetting(t, "name");
+        AnnotationElement a = Events.getAnnotationByName(t, "com.oracle.TestAnnotation");
+
+        // Check that names are overridden
+        Asserts.assertNotNull(testField, "Can't find expected field testField");
+        Asserts.assertEquals(t.getName(), "com.oracle.TestEvent", "Incorrect name for event");
+        Asserts.assertEquals(a.getTypeName(), "com.oracle.TestAnnotation", "Incorrect name for annotation");
+        Asserts.assertEquals(a.getTypeName(), "com.oracle.TestAnnotation", "Incorrect name for annotation");
+        Asserts.assertEquals(setting.getName(), "name", "Incorrect name for setting");
+
+        // Check that @Name is persisted
+        assertAnnotation(t.getAnnotation(Name.class), "@Name should be persisted on event");
+        assertAnnotation(testField.getAnnotation(Name.class), "@Name should be persisted on field");
+        assertAnnotation(a.getAnnotation(Name.class), "@Name should be persisted on annotations");
+        assertAnnotation(setting.getAnnotation(Name.class), "@Name should be persisted on setting");
+    }
+
+    // Can't use assert since the use toString on the object which doesn't work well JFR proxies.
+    private static void assertAnnotation(Object annotation,String message) throws Exception {
+       if (annotation == null) {
+           throw new Exception(message);
+       }
+    }
+
+    private static SettingDescriptor getSetting(EventType t, String name) {
+        for (SettingDescriptor v : t.getSettingDescriptors()) {
+            if (v.getName().equals(name)) {
+                return v;
+            }
+        }
+        Asserts.fail("Could not find setting with name " + name);
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/annotations/TestPeriod.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.annotations;
+
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.Period;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.annotations.TestLabel
+ */
+public class TestPeriod {
+
+    @Period("47 s")
+    static class PeriodicEvent extends Event {
+    }
+
+    public static void main(String[] args) throws Exception {
+        EventType periodicEvent = EventType.getEventType(PeriodicEvent.class);
+        String defaultValue = Events.getSetting(periodicEvent, Period.NAME).getDefaultValue();
+        Asserts.assertEQ(defaultValue, "47 s", "Incorrect default value for period");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/annotations/TestRegistered.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.annotations;
+
+import jdk.jfr.Registered;
+import jdk.test.lib.Asserts;
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.FlightRecorder;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.annotations.TestRegistered
+ */
+public class TestRegistered {
+
+    static class RegisteredByDefaultEvent extends Event {
+    }
+
+    @Registered(false)
+    static class NotRegisteredByDefaultEvent extends Event {
+    }
+
+    public static void main(String[] args) throws Exception {
+        try {
+            EventType.getEventType(NotRegisteredByDefaultEvent.class);
+            throw new Exception("Should not be able to get event type from unregistered event type");
+        } catch (IllegalStateException ise) {
+            // as expected
+        }
+        EventType registered = EventType.getEventType(RegisteredByDefaultEvent.class);
+        boolean registeredWorking = false;
+        for (EventType type : FlightRecorder.getFlightRecorder().getEventTypes()) {
+            if (registered.getId() == type.getId()) {
+                registeredWorking = true;
+            }
+        }
+        if (!registeredWorking) {
+            Asserts.fail("Default regsitration is not working, can't validate @NoAutoRegistration");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/annotations/TestRegisteredFalseAndRunning.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.annotations;
+
+import jdk.jfr.Event;
+import jdk.jfr.Recording;
+import jdk.jfr.Registered;
+
+/*
+ * @test Tests that commit doesn't throw exception when an event has not been registered.
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.annotations.TestRegisteredFalseAndRunning
+ * @run main/othervm -XX:FlightRecorderOptions=retransform=false jdk.jfr.api.metadata.annotations.TestRegisteredFalseAndRunning
+ */
+public class TestRegisteredFalseAndRunning {
+    @Registered(false)
+    static class NoAutoEvent extends Event {
+        String hello;
+    }
+
+    public static void main(String... args) {
+        try (Recording r = new Recording()) {
+            r.start();
+            NoAutoEvent event = new NoAutoEvent();
+            event.commit();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/annotations/TestRelational.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.Label;
+import jdk.jfr.MetadataDefinition;
+import jdk.jfr.Relational;
+import jdk.jfr.ValueDescriptor;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.annotations.TestRelational
+ */
+public class TestRelational {
+
+    @MetadataDefinition
+    @Label("User Id")
+    @Relational
+    @Target({ ElementType.FIELD })
+    @Retention(RetentionPolicy.RUNTIME)
+    @interface UserId {
+    }
+
+    static class UserEvent extends Event {
+        @UserId
+        String id;
+    }
+
+    public static void main(String[] args) throws Exception {
+        EventType t = EventType.getEventType(UserEvent.class);
+        ValueDescriptor field = t.getField("id");
+        AnnotationElement userId = Events.getAnnotation(field, UserId.class);
+        Relational r = userId.getAnnotation(Relational.class);
+        Asserts.assertTrue(r != null, "Expected relational annotation to have annotation @Relational");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/annotations/TestSimpleMetadataEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.MetadataDefinition;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.annotations.TestSimpleMetadataEvent
+ */
+public class TestSimpleMetadataEvent {
+
+    @MetadataDefinition
+    @Target(ElementType.TYPE)
+    @Retention(RetentionPolicy.RUNTIME)
+    @interface Severity {
+        int value() default 50;
+    }
+
+    @Severity
+    static class MetadataEvent extends Event {
+    }
+
+    public static void main(String[] args) throws Exception {
+        EventType.getEventType(MetadataEvent.class);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/annotations/TestStackTrace.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.annotations;
+
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.StackTrace;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.annotations.TestStackTrace
+ */
+public class TestStackTrace {
+
+    @StackTrace(true)
+    static class StackTraceOnEvent extends Event {
+    }
+
+    @StackTrace(false)
+    static class StackTraceOffEvent extends Event {
+    }
+
+    public static void main(String[] args) throws Exception {
+        EventType onEvent = EventType.getEventType(StackTraceOnEvent.class);
+        EventType offEvent = EventType.getEventType(StackTraceOffEvent.class);
+
+        String defaultValue = Events.getSetting(onEvent, StackTrace.NAME).getDefaultValue();
+        Asserts.assertEquals(defaultValue, "true", "@StackTrace(true) should reault in 'true'");
+
+        defaultValue = Events.getSetting(offEvent, StackTrace.NAME).getDefaultValue();
+        Asserts.assertEquals(defaultValue, "false", "@StackTrace(false) should reault in 'false'");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/annotations/TestThreshold.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.annotations;
+
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.Threshold;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.annotations.TestThreshold
+ */
+public class TestThreshold {
+
+    @Threshold("23 s")
+    static class PeriodicEvent extends Event {
+    }
+
+    public static void main(String[] args) throws Exception {
+        EventType thresholdEvent = EventType.getEventType(PeriodicEvent.class);
+        String defaultValue = Events.getSetting(thresholdEvent,Threshold.NAME).getDefaultValue();
+        Asserts.assertEquals(defaultValue, "23 s", "@Threshold(\"23 s\") Should result in threshold '23 s'");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/annotations/TestTypesIdentical.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.annotations;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.BooleanFlag;
+import jdk.jfr.Category;
+import jdk.jfr.ContentType;
+import jdk.jfr.Description;
+import jdk.jfr.Enabled;
+import jdk.jfr.Experimental;
+import jdk.jfr.Frequency;
+import jdk.jfr.Label;
+import jdk.jfr.MemoryAddress;
+import jdk.jfr.DataAmount;
+import jdk.jfr.MetadataDefinition;
+import jdk.jfr.Name;
+import jdk.jfr.Percentage;
+import jdk.jfr.Period;
+import jdk.jfr.Registered;
+import jdk.jfr.Relational;
+import jdk.jfr.StackTrace;
+import jdk.jfr.Threshold;
+import jdk.jfr.Timespan;
+import jdk.jfr.Timestamp;
+import jdk.jfr.TransitionFrom;
+import jdk.jfr.TransitionTo;
+import jdk.jfr.Unsigned;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.annotations.TestTypesIdentical
+ */
+public class TestTypesIdentical {
+
+    @MetadataDefinition
+    @interface CustomAnnotation {
+        String value();
+    }
+
+    private static Class<?>[] predefinedAnnotations = {
+        Category.class, Enabled.class,  Frequency.class,  DataAmount.class,  Percentage.class,  StackTrace.class,  Timestamp.class,  Unsigned.class,
+        ContentType.class,  Experimental.class,  Label.class, Registered.class, Period.class, Threshold.class,  TransitionFrom.class,
+        Description.class, BooleanFlag.class,  MemoryAddress.class,  Name.class,  Relational.class, Timespan.class, TransitionTo.class
+    };
+
+    @SuppressWarnings("unchecked")
+    public static void main(String[] args) throws Exception {
+
+        for(Class<?> clz : predefinedAnnotations) {
+            System.out.println("Testing class " + clz);
+            assertTypeId((Class<? extends java.lang.annotation.Annotation>) clz);
+        }
+        assertTypeId(CustomAnnotation.class);
+    }
+
+    private static void assertTypeId(Class<? extends java.lang.annotation.Annotation> clz) {
+        AnnotationElement a1, a2;
+        try {
+            a1 = new AnnotationElement(clz, "value");
+            a2 = new AnnotationElement(clz, "value2");
+        } catch(IllegalArgumentException x) {
+            a1 = new AnnotationElement(clz);
+            a2 = new AnnotationElement(clz);
+        }
+        Asserts.assertEquals(a1.getTypeId(), a2.getTypeId());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/eventtype/EventWithCustomSettings.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.eventtype;
+
+import jdk.jfr.Enabled;
+import jdk.jfr.Event;
+import jdk.jfr.Name;
+import jdk.jfr.Period;
+import jdk.jfr.SettingDefinition;
+import jdk.jfr.StackTrace;
+import jdk.jfr.Threshold;
+import jdk.test.lib.jfr.SimpleSetting;
+
+@Period("10 s")
+@Threshold("100 ms")
+@StackTrace(true)
+@Enabled(false)
+public class EventWithCustomSettings extends Event {
+    @SettingDefinition
+    @Name("setting1")
+    boolean methodNameNotUsed(SimpleSetting cs) {
+        return true;
+    }
+
+    @SettingDefinition
+    boolean setting2(SimpleSetting cs) {
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/eventtype/TestGetAnnotation.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.eventtype;
+
+import java.util.Arrays;
+
+import jdk.jfr.Category;
+import jdk.jfr.Description;
+import jdk.jfr.Enabled;
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.Label;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @summary Test getAnnotations()
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.eventtype.TestGetAnnotation
+ */
+public class TestGetAnnotation {
+
+    public static void main(String[] args) throws Throwable {
+        EventType type = EventType.getEventType(MyEvent.class);
+
+        Label label = type.getAnnotation(Label.class);
+        if (label == null) {
+            Asserts.fail("Annotation label was null");
+        }
+        Asserts.assertEquals(label.value(), "myLabel", "Wrong value for annotation label");
+
+        Category category = type.getAnnotation(Category.class);
+        if (category == null) {
+            Asserts.fail("Annotation @Description was null");
+        }
+
+        Asserts.assertTrue(Arrays.equals(category.value(), new String[] {"Stuff"}), "Wrong value for annotation enabled");
+
+        Description description = type.getAnnotation(Description.class);
+        if (description != null) {
+            Asserts.fail("Annotation description should be null");
+        }
+
+        try {
+            type.getAnnotation(null);
+            Asserts.fail("No exception when getAnnotation(null)");
+        } catch(Exception e) {
+            // Expected exception
+        }
+    }
+
+    @Label("myLabel")
+    @Enabled(false)
+    @Category("Stuff")
+    private static class MyEvent extends Event {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/eventtype/TestGetAnnotationElements.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.api.metadata.eventtype;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.BooleanFlag;
+import jdk.jfr.Category;
+import jdk.jfr.ContentType;
+import jdk.jfr.Description;
+import jdk.jfr.Enabled;
+import jdk.jfr.Event;
+import jdk.jfr.EventFactory;
+import jdk.jfr.EventType;
+import jdk.jfr.Experimental;
+import jdk.jfr.Frequency;
+import jdk.jfr.Label;
+import jdk.jfr.MemoryAddress;
+import jdk.jfr.DataAmount;
+import jdk.jfr.MetadataDefinition;
+import jdk.jfr.Name;
+import jdk.jfr.Percentage;
+import jdk.jfr.Period;
+import jdk.jfr.Registered;
+import jdk.jfr.Relational;
+import jdk.jfr.StackTrace;
+import jdk.jfr.Threshold;
+import jdk.jfr.Timespan;
+import jdk.jfr.Timestamp;
+import jdk.jfr.TransitionFrom;
+import jdk.jfr.TransitionTo;
+import jdk.jfr.Unsigned;
+import jdk.jfr.ValueDescriptor;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @summary Test for AnnotationElement.getAnnotationElements()
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.eventtype.TestGetAnnotationElements
+ */
+public class TestGetAnnotationElements {
+
+    @SuppressWarnings("unchecked")
+    public static void main(String[] args) throws Throwable {
+        Class<?>[] jfrAnnotations = {
+            Category.class, Description.class, Enabled.class,
+            Experimental.class, BooleanFlag.class, Frequency.class, Label.class,
+            MemoryAddress.class, DataAmount.class, Name.class,
+            Registered.class, Percentage.class,
+            Period.class, Relational.class, StackTrace.class,
+            Threshold.class, Timespan.class, Timestamp.class,
+            TransitionFrom.class, TransitionTo.class, Unsigned.class
+        };
+
+        for (Class<?> clz : jfrAnnotations) {
+            Class<? extends Annotation> annptationClass = (Class<? extends Annotation>) clz;
+            System.out.println("AnnotationElement: " + annptationClass);
+            Map<String, Object> values = createValueMapForAnnotation(annptationClass);
+            List<Annotation> persistableAnnotation = createPersistableAnnotationList(annptationClass);
+            AnnotationElement ae = new AnnotationElement(annptationClass, values);
+            List<AnnotationElement> aes = ae.getAnnotationElements();
+            Asserts.assertEquals(persistableAnnotation.size(), aes.size());
+        }
+
+        List<ValueDescriptor> fields = new ArrayList<>();
+        List<AnnotationElement> eventAnnotations = new ArrayList<>();
+        eventAnnotations.add(new AnnotationElement(Label.class, "MyEvent"));
+
+        EventFactory f = EventFactory.create(eventAnnotations, fields);
+        EventType type = f.getEventType();
+        List<AnnotationElement> aes = type.getAnnotationElements().get(0).getAnnotationElements();
+        Asserts.assertEquals(0, aes.size());
+
+        EventType et = EventType.getEventType(MyEvent.class);
+        ValueDescriptor field = et.getField("transactionRate");
+        aes = field.getAnnotationElements().get(0).getAnnotationElements();
+        Asserts.assertEquals(3, aes.size());
+        assertContainsAnnotation(aes, Description.class);
+        assertContainsAnnotation(aes, Label.class);
+        assertContainsAnnotation(aes, ContentType.class);
+
+    }
+
+    private static List<Annotation> createPersistableAnnotationList( Class<? extends Annotation> annptationClass) {
+       List<Annotation> as = new ArrayList<>();
+        for (Annotation a : annptationClass.getAnnotations()) {
+           MetadataDefinition m = a.annotationType().getAnnotation(MetadataDefinition.class);
+           if (m != null) {
+               as.add(a);
+           }
+       }
+        return as;
+    }
+
+    private static void assertContainsAnnotation(List<AnnotationElement> aez, Class<?> clz) {
+        for (AnnotationElement ae : aez) {
+            if (ae.getTypeName().equals(clz.getName())) {
+                return;
+            }
+        }
+        Asserts.fail("Class " + clz + " not found in the annotation elements");
+    }
+
+    private static Map<String, Object> createValueMapForAnnotation(Class<?> clz) {
+        Map<String, Object> map = new HashMap<>();
+        for (Method method : clz.getDeclaredMethods()) {
+            int modifiers = method.getModifiers();
+            if (Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers)) {
+                map.put(method.getName(), "value");
+            }
+        }
+        return map;
+    }
+
+    private static class MyEvent extends Event {
+
+        @Frequency
+        long transactionRate;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/eventtype/TestGetAnnotations.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.eventtype;
+
+import java.util.List;
+import java.util.Objects;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.Description;
+import jdk.jfr.Enabled;
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.Label;
+import jdk.jfr.Period;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @summary Test getAnnotations()
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.eventtype.TestGetAnnotations
+ */
+public class TestGetAnnotations {
+
+    private final static String MY_LABEL = "myLabel";
+    private final static String MY_DESCRIPTION = "myDesc";
+
+    public static void main(String[] args) throws Throwable {
+        EventType type = EventType.getEventType(MyEvent.class);
+        List<AnnotationElement> annos = type.getAnnotationElements();
+        Asserts.assertEquals(annos.size(), 2, "Wrong number of annotations");
+        assertAnnotation(annos, "jdk.jfr.Label", MY_LABEL);
+        assertAnnotation(annos, "jdk.jfr.Description", MY_DESCRIPTION);
+    }
+
+    private static void assertAnnotation(List<AnnotationElement> annos, String name, Object expectedValue) {
+        for (AnnotationElement a : annos) {
+            if (a.getTypeName().equals(name)) {
+                Object value = a.getValue("value");
+                Asserts.assertTrue(Objects.deepEquals(value, expectedValue), "Found annotation " + name + " but value was "+ value +" but expected " + expectedValue);
+            }
+        }
+    }
+
+    @Label(MY_LABEL)
+    @Description(MY_DESCRIPTION)
+    @Enabled(false) // not sticky annotation (with @Metadata)
+    @Period("1 m")  // not sticky annotation (with @Metadata)
+    private static class MyEvent extends Event {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/eventtype/TestGetCategory.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.eventtype;
+
+import java.util.List;
+
+import jdk.jfr.Category;
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @summary Test setName().
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.eventtype.TestGetCategory
+ */
+public class TestGetCategory {
+
+    public static void main(String[] args) throws Throwable {
+
+        List<String> noCategory = EventType.getEventType(NoCategory.class).getCategoryNames();
+        System.out.println("noCategory=" + noCategory);
+        Asserts.assertEquals(noCategory.size(), 1, "Wrong default category");
+        Asserts.assertEquals(noCategory.get(0), "Uncategorized", "Wrong default category");
+
+        List<String>  withCategory = EventType.getEventType(WithCategory.class).getCategoryNames();
+        Asserts.assertEquals(withCategory.size(), 4, "Wrong category");
+        Asserts.assertEquals(withCategory.get(0), "Category", "Wrong category");
+        Asserts.assertEquals(withCategory.get(1), "A", "Wrong category");
+        Asserts.assertEquals(withCategory.get(2), "B", "Wrong category");
+        Asserts.assertEquals(withCategory.get(3), "C", "Wrong category");
+    }
+
+    private static class NoCategory extends Event {
+        @SuppressWarnings("unused")
+        public byte myByte;
+    }
+
+    @Category({"Category", "A", "B", "C"})
+    private static class WithCategory extends Event {
+        @SuppressWarnings("unused")
+            public byte myByte;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/eventtype/TestGetDefaultValues.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.eventtype;
+
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.FlightRecorder;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Test getDefaultValues()
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.api.metadata.eventtype.TestGetDefaultValues
+ */
+public class TestGetDefaultValues {
+
+    private static class DefaultEvent extends Event {
+    }
+
+    public static void main(String[] args) throws Throwable {
+        testDefaultEvent();
+        testCustomEvent();
+        testCustomWithPeriod();
+    }
+
+    private static void testCustomWithPeriod() {
+        Runnable hook = new Runnable() {
+            @Override
+            public void run() {
+            }
+        };
+        EventType customEventType = EventType.getEventType(EventWithCustomSettings.class);
+        FlightRecorder.addPeriodicEvent(EventWithCustomSettings.class, hook);
+        Asserts.assertEquals(customEventType.getSettingDescriptors().size(), 4, "Wrong number of settings");
+        assertDefaultValue(customEventType, "period", "10 s");
+        assertDefaultValue(customEventType, "enabled", "false");
+        assertDefaultValue(customEventType, "setting1", "none");
+        assertDefaultValue(customEventType, "setting2", "none");
+
+        FlightRecorder.removePeriodicEvent(hook);
+        Asserts.assertEquals(customEventType.getSettingDescriptors().size(), 5, "Wrong number of settings");
+        assertDefaultValue(customEventType, "threshold", "100 ms");
+        assertDefaultValue(customEventType, "stackTrace", "true");
+        assertDefaultValue(customEventType, "enabled", "false");
+        assertDefaultValue(customEventType, "setting1", "none");
+        assertDefaultValue(customEventType, "setting2", "none");
+
+    }
+
+    private static void testCustomEvent() {
+        EventType customizedEventType = EventType.getEventType(EventWithCustomSettings.class);
+        Asserts.assertEquals(customizedEventType.getSettingDescriptors().size(), 5, "Wrong number of default values");
+        assertDefaultValue(customizedEventType, "setting1", "none");
+        assertDefaultValue(customizedEventType, "setting2", "none");
+        assertDefaultValue(customizedEventType, "threshold", "100 ms");
+        assertDefaultValue(customizedEventType, "stackTrace", "true");
+        assertDefaultValue(customizedEventType, "enabled", "false");
+    }
+
+    private static void testDefaultEvent() {
+        EventType defaultEventType = EventType.getEventType(DefaultEvent.class);
+        Asserts.assertEquals(defaultEventType.getSettingDescriptors().size(), 3, "Wrong number of default values");
+        assertDefaultValue(defaultEventType, "threshold", "0 ns");
+        assertDefaultValue(defaultEventType, "stackTrace", "true");
+        assertDefaultValue(defaultEventType, "enabled", "true");
+    }
+
+    private static void assertDefaultValue(EventType eventType, String name, String expected) {
+        String value = Events.getSetting(eventType, name).getDefaultValue();
+        Asserts.assertEquals(value, expected, "Incorrect value for " + name);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/eventtype/TestGetDescription.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.eventtype;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import jdk.jfr.Category;
+import jdk.jfr.Description;
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.Label;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @summary Test descriptive annotations for EventType
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.eventtype.TestGetDescription
+ */
+public class TestGetDescription {
+
+    public static void main(String[] args) throws Throwable {
+        EventType defaultType = EventType.getEventType(DefaultEvent.class);
+        System.out.printf("defaultType.category='%s'%n", defaultType.getCategoryNames());
+        System.out.printf("defaultType.desc='%s'%n", defaultType.getDescription());
+        System.out.printf("defaultType.label='%s'%n", defaultType.getLabel());
+
+        List<String> defaultCategory = Arrays.asList(new String[] {"Uncategorized"});
+        Asserts.assertEquals(defaultType.getCategoryNames(), defaultCategory, "Wrong default category");
+        Asserts.assertNull(defaultType.getDescription(), "Wrong default description");
+        Asserts.assertEquals(defaultType.getLabel(), null, "Wrong default label"); // JavaDoc says "not null"
+
+        EventType annotatedType = EventType.getEventType(AnnotatedEvent.class);
+        System.out.printf("annotated.category='%s'%n", annotatedType.getCategoryNames());
+        System.out.printf("annotated.desc='%s'%n", annotatedType.getDescription());
+        System.out.printf("annotated.label='%s'%n", annotatedType.getLabel());
+
+        List<String> expectedCategorNames = new ArrayList<>();
+        expectedCategorNames.add("MyCategory");
+        Asserts.assertEquals(annotatedType.getCategoryNames(), expectedCategorNames, "Wrong default category");
+        Asserts.assertEquals(annotatedType.getDescription(), "MyDesc", "Wrong default description");
+        Asserts.assertEquals(annotatedType.getLabel(), "MyLabel", "Wrong default label");
+    }
+
+    private static class DefaultEvent extends Event {
+    }
+
+    @Category("MyCategory")
+    @Description("MyDesc")
+    @Label("MyLabel")
+    private static class AnnotatedEvent extends Event {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/eventtype/TestGetEventType.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.eventtype;
+
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @summary Test getEventType()
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.eventtype.TestGetEventType
+ */
+public class TestGetEventType {
+
+    public static void main(String[] args) throws Throwable {
+        EventType type = EventType.getEventType(MyEventA.class);
+        Asserts.assertEquals(type.getName(), MyEventA.class.getName(), "Wrong EventType for MyEventA");
+
+        type = EventType.getEventType(MyEventB.class);
+        Asserts.assertEquals(type.getName(), MyEventB.class.getName(), "Wrong EventType for MyEventB");
+
+        try {
+            EventType.getEventType(null);
+            Asserts.fail("No exception for getEventType(null)");
+        } catch (Exception e) {
+            // Expected exception
+        }
+    }
+
+    private static class MyEventA extends Event {
+    }
+
+    private static class MyEventB extends Event {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/eventtype/TestGetField.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.eventtype;
+
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.ValueDescriptor;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @summary Test getField()
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.eventtype.TestGetField
+ */
+public class TestGetField {
+
+    public static void main(String[] args) throws Throwable {
+        EventType type = EventType.getEventType(MyEvent.class);
+
+        ValueDescriptor v = type.getField("myByte");
+        Asserts.assertNotNull(v, "getFiled(myByte) was null");
+        Asserts.assertEquals(v.getTypeName(), "byte", "myByte was not type byte");
+
+        v = type.getField("myInt");
+        Asserts.assertNotNull(v, "getFiled(myInt) was null");
+        Asserts.assertEquals(v.getTypeName(), "int", "myInt was not type int");
+
+        v = type.getField("myStatic");
+        Asserts.assertNull(v, "got static field");
+
+        v = type.getField("notAField");
+        Asserts.assertNull(v, "got field that does not exist");
+
+        v = type.getField("");
+        Asserts.assertNull(v, "got field for empty name");
+
+        try {
+            v = type.getField(null);
+            Asserts.fail("No Exception when getField(null)");
+        } catch (NullPointerException e) {
+            // Expected exception
+        }
+    }
+
+    @SuppressWarnings("unused")
+    private static class MyEvent extends Event {
+        public byte myByte;
+        private int myInt;
+        public static int myStatic; // Should not be included
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/eventtype/TestGetFields.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.eventtype;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.ValueDescriptor;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @summary Test getFields()
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.eventtype.TestGetFields
+ */
+public class TestGetFields {
+
+    public static void main(String[] args) throws Throwable {
+        List<String> actuals = new ArrayList<>();
+        EventType type = EventType.getEventType(MyEvent.class);
+        for (ValueDescriptor d : type.getFields()) {
+            if (d.getName().startsWith("my")) {
+                String s = getCompareString(d);
+                System.out.println("Actual: " + s);
+                actuals.add(s);
+            }
+        }
+
+        String[] expected = {
+            "name=myByte; typename=byte",
+            "name=myInt; typename=int",
+            "name=myString; typename=java.lang.String",
+            "name=myClass; typename=java.lang.Class",
+            "name=myThread; typename=java.lang.Thread"
+        };
+        for (String s : expected) {
+            Asserts.assertTrue(actuals.contains(s), "Missing expected value " + s);
+        }
+        Asserts.assertEquals(expected.length, actuals.size(), "Wrong number of fields found");
+    }
+
+    private static String getCompareString(ValueDescriptor d) {
+        return String.format("name=%s; typename=%s",
+                              d.getName(),
+                              d.getTypeName());
+    }
+
+    @SuppressWarnings("unused")
+    private static class MyEvent extends Event {
+        public byte myByte;
+        private int myInt;
+        protected String myString;
+        public static int myStatic; // Should not be included
+        @SuppressWarnings("rawtypes")
+        public Class myClass;
+        public Thread myThread;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/eventtype/TestGetSettings.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.eventtype;
+
+import java.util.List;
+
+import jdk.jfr.EventType;
+import jdk.jfr.SettingDescriptor;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @summary Test getSettings()
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.api.metadata.eventtype.TestGetSettings
+ */
+public class TestGetSettings {
+
+    public static void main(String[] args) throws Throwable {
+        EventType eventType = EventType.getEventType(EventWithCustomSettings.class);
+        List<SettingDescriptor> settings = eventType.getSettingDescriptors();
+        Asserts.assertEquals(settings.size(), 5, "Wrong number of settings");
+
+        // test immutability
+        try {
+            settings.add(settings.get(0));
+            Asserts.fail("Should not be able to modify list returned by getSettings()");
+        } catch (UnsupportedOperationException uoe) {
+            // OK, as expected
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/eventtype/TestUnloadingEventClass.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.eventtype;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.jfr.internal.JVM;
+
+/*
+ * @test
+ * @key jfr
+ * @summary Test that verifies event metadata is removed when an event class is unloaded.
+ *
+ * @library /test/lib
+ * @modules jdk.jfr/jdk.jfr.internal
+ *          java.base/jdk.internal.misc
+ *
+ * @run main/othervm -Xlog:class+unload -Xlog:gc jdk.jfr.api.metadata.eventtype.TestUnloadingEventClass
+ */
+public class TestUnloadingEventClass {
+
+    private static final String EVENT_NAME = "jdk.jfr.api.metadata.eventtype.TestUnloadingEventClass$ToBeUnloaded";
+
+    public static class ToBeUnloaded extends Event {
+    }
+
+    static public class MyClassLoader extends ClassLoader {
+        public MyClassLoader() {
+            super("MyClassLoader", null);
+        }
+
+        public final Class<?> defineClass(String name, byte[] b) {
+            return super.defineClass(name, b, 0, b.length);
+        }
+    }
+
+    private static final JVM jvm = JVM.getJVM();
+    public static ClassLoader myClassLoader;
+
+    public static void main(String[] args) throws Throwable {
+        assertEventTypeNotAvailable();
+        myClassLoader = createClassLoaderWithEventClass();
+
+        try (Recording r0 = new Recording()) {
+            r0.start();
+            r0.stop();
+            if (getEventType(r0, 0, EVENT_NAME) == null) {
+                throw new Exception("Expected event class to have corresponding event type");
+            }
+        }
+
+        try (Recording r1 = new Recording(); Recording r2 = new Recording(); Recording r3 = new Recording()) {
+            r1.start();
+            r2.start();
+            System.out.println("Class loader with name " + myClassLoader.getName() + " is on the heap");
+            unLoadEventClass();
+            r3.start();
+
+            assertEventTypeNotAvailable();
+            r3.stop();
+            r2.stop();
+            r1.stop();
+
+            if (getEventType(r1, 1, EVENT_NAME) == null) {
+                throw new Exception("Expected event class to have corresponding event type in recording with all chunks");
+            }
+            if (getEventType(r2, 2, EVENT_NAME) == null) {
+                throw new Exception("Expected event class to have corresponding event type in recording where event class was unloaded");
+            }
+            if (getEventType(r3, 3, EVENT_NAME) != null) {
+                throw new Exception("Unexpected metadata found for event class tha has been unloaded.");
+            }
+        }
+    }
+
+    private static MyClassLoader createClassLoaderWithEventClass() throws Exception {
+        String resourceName = EVENT_NAME.replace('.', '/') + ".class";
+        try (InputStream is = TestUnloadingEventClass.class.getClassLoader().getResourceAsStream(resourceName)) {
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            byte[] buffer = new byte[4096];
+            int byteValue = 0;
+            while ((byteValue = is.read(buffer, 0, buffer.length)) != -1) {
+                baos.write(buffer, 0, byteValue);
+            }
+            baos.flush();
+            MyClassLoader myClassLoader = new MyClassLoader();
+            Class<?> eventClass = myClassLoader.defineClass(EVENT_NAME, baos.toByteArray());
+            if (eventClass == null) {
+                throw new Exception("Could not define test class");
+            }
+            if (eventClass.getSuperclass() != Event.class) {
+                throw new Exception("Superclass should be jdk.jfr.Event");
+            }
+            if (eventClass.getSuperclass().getClassLoader() != null) {
+                throw new Exception("Class loader of jdk.jfr.Event should be null");
+            }
+            if (eventClass.getClassLoader() != myClassLoader) {
+                throw new Exception("Incorrect class loader for event class");
+            }
+            eventClass.newInstance(); // force <clinit>
+            return myClassLoader;
+        }
+    }
+
+    private static void unLoadEventClass() throws Exception {
+        long firstCount = jvm.getUnloadedEventClassCount();
+        System.out.println("Initial unloaded count: " + firstCount);
+        myClassLoader = null;
+        System.out.println("Cleared reference to MyClassLoader");
+        long newCount = 0;
+        do {
+            System.out.println("GC triggered");
+            System.gc();
+            Thread.sleep(1000);
+            newCount = jvm.getUnloadedEventClassCount();
+            System.out.println("Unloaded count: " + newCount);
+        } while (firstCount + 1 != newCount);
+        System.out.println("Event class unloaded!");
+        System.out.println("Event classes currently on the heap:");
+        for (Class<?> eventClass : JVM.getJVM().getAllEventClasses()) {
+            System.out.println(eventClass + " " + (eventClass.getClassLoader() != null ? eventClass.getClassLoader().getName() : null));
+        }
+
+    }
+
+    private static void assertEventTypeNotAvailable() throws Exception {
+        for (EventType type : FlightRecorder.getFlightRecorder().getEventTypes()) {
+            if (type.getName().equals(EVENT_NAME)) {
+                throw new Exception("Event type should not be available");
+            }
+        }
+    }
+
+    private static Object getEventType(Recording r, long id, String eventName) throws IOException {
+        Path p = Files.createTempFile("recording-" + id + "_", ".jfr");
+        r.dump(p);
+        try (RecordingFile rf = new RecordingFile(p)) {
+            for (EventType et : rf.readEventTypes()) {
+                if (et.getName().equals(eventName)) {
+                    return et;
+                }
+            }
+
+        }
+        return null;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/settingdescriptor/AnnotatedSetting.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.api.metadata.settingdescriptor;
+
+import java.util.Set;
+
+import jdk.jfr.Description;
+import jdk.jfr.Label;
+import jdk.jfr.Name;
+import jdk.jfr.SettingControl;
+import jdk.jfr.Timestamp;
+
+@Name(AnnotatedSetting.NAME)
+@Label(AnnotatedSetting.LABEL)
+@Description(AnnotatedSetting.DESCRIPTION)
+@Timestamp(Timestamp.TICKS)
+public class AnnotatedSetting extends SettingControl {
+
+    public final static String LABEL = "Annotated Label";
+    public final static String DESCRIPTION = "Description of an annotated setting";
+    public final static String NAME = "annotatedType";
+    public final static String DEFAULT_VALUE = "defaultAnnotated";
+
+    @Override
+    public String combine(Set<String> settingValues) {
+        return DEFAULT_VALUE;
+    }
+
+    @Override
+    public void setValue(String settingValue) {
+    }
+
+    @Override
+    public String getValue() {
+        return DEFAULT_VALUE;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/settingdescriptor/BaseEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.api.metadata.settingdescriptor;
+
+import jdk.jfr.Description;
+import jdk.jfr.Event;
+import jdk.jfr.Frequency;
+import jdk.jfr.Label;
+import jdk.jfr.Name;
+import jdk.jfr.SettingDefinition;
+
+public abstract class BaseEvent extends Event {
+
+    // should be shadowed by built-in setting enabled
+    @SettingDefinition
+    public boolean enabled(PlainSetting ps) {
+        return false;
+    }
+
+    @SettingDefinition
+    public boolean publicBase(AnnotatedSetting control) {
+        return true;
+    }
+
+    @SettingDefinition
+    private boolean privateBase(PlainSetting control) {
+        return true;
+    }
+
+    @SettingDefinition
+    @Name("protectedBase")
+    @Label("Protected Base")
+    @Description("Description of protected base")
+    @Frequency
+    protected boolean something(PlainSetting control) {
+        return true;
+    }
+
+    @SettingDefinition
+    boolean packageProtectedBase(PlainSetting control) {
+        return true;
+    }
+
+    @Name("baseName")
+    @Label("Base Label")
+    @Description("Base description")
+    @SettingDefinition
+    public boolean overridden(AnnotatedSetting control) {
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/settingdescriptor/CustomEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.api.metadata.settingdescriptor;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Comparator;
+
+import jdk.jfr.Description;
+import jdk.jfr.EventType;
+import jdk.jfr.Label;
+import jdk.jfr.Name;
+import jdk.jfr.Recording;
+import jdk.jfr.SettingDefinition;
+import jdk.jfr.SettingDescriptor;
+import jdk.jfr.Timespan;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.jfr.Events;
+
+final class CustomEvent extends BaseEvent {
+
+    public static final String DESCRIPTION_OF_AN_ANNOTATED_METHOD = "Description of an annotated method";
+    public static final String ANNOTATED_METHOD = "Annotated Method";
+
+    // should be shadowed by built-in setting threshold
+    @SettingDefinition
+    boolean threshold(PlainSetting p) {
+        return false;
+    }
+
+    @SettingDefinition
+    private boolean plain(PlainSetting s) {
+        return true;
+    }
+
+    @SettingDefinition
+    protected boolean annotatedType(AnnotatedSetting s) {
+        return true;
+    }
+
+    @SettingDefinition
+    @Name("newName")
+    @Label(ANNOTATED_METHOD)
+    @Description(DESCRIPTION_OF_AN_ANNOTATED_METHOD)
+    @Timespan(Timespan.NANOSECONDS)
+    public boolean whatever(AnnotatedSetting s) {
+        return true;
+    }
+
+    @SettingDefinition
+    boolean overridden(PlainSetting s) {
+        return true;
+    }
+
+    public static void assertOnDisk(Comparator<SettingDescriptor> c) throws Exception {
+        EventType in = EventType.getEventType(CustomEvent.class);
+        Path p = Paths.get("custom.jfr");
+        try (Recording r = new Recording()) {
+            r.start();
+            r.stop();
+            r.dump(p);
+        }
+        try (RecordingFile f = new RecordingFile(p)) {
+            for (EventType out : f.readEventTypes()) {
+                if (out.getName().equals(CustomEvent.class.getName())) {
+                    if (out.getSettingDescriptors().size() != in.getSettingDescriptors().size()) {
+                        throw new Exception("Number of settings doesn't match");
+                    }
+                    for (SettingDescriptor os : out.getSettingDescriptors()) {
+                        SettingDescriptor is = Events.getSetting(in, os.getName());
+                        if (c.compare(os, is) != 0) {
+                            throw new Exception("Setting with name " + is.getName() + " doesn't match");
+                        }
+                    }
+                    return;
+                }
+            }
+        }
+        throw new Exception("Could not event type with name " + CustomEvent.class.getName());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/settingdescriptor/PlainSetting.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.api.metadata.settingdescriptor;
+
+import java.util.Set;
+
+import jdk.jfr.SettingControl;
+
+public class PlainSetting extends SettingControl {
+
+    public final static String DEFAULT_VALUE = "plain";
+
+    @Override
+    public String combine(Set<String> settingValue) {
+        return DEFAULT_VALUE;
+    }
+
+    @Override
+    public void setValue(String value) {
+    }
+
+    @Override
+    public String getValue() {
+        return DEFAULT_VALUE;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/settingdescriptor/TestDefaultValue.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.api.metadata.settingdescriptor;
+
+import jdk.jfr.EventType;
+import jdk.jfr.SettingDescriptor;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Test SettingDescriptor.getName()
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.api.metadata.settingdescriptor.TestDefaultValue
+ */
+public class TestDefaultValue {
+
+    public static void main(String[] args) throws Exception {
+        EventType type = EventType.getEventType(CustomEvent.class);
+
+        SettingDescriptor plain = Events.getSetting(type, "plain");
+        Asserts.assertEquals(plain.getDefaultValue(), "plain");
+
+        SettingDescriptor annotatedType = Events.getSetting(type, "annotatedType");
+        Asserts.assertEquals(annotatedType.getDefaultValue(), AnnotatedSetting.DEFAULT_VALUE);
+
+        SettingDescriptor newName = Events.getSetting(type, "newName");
+        Asserts.assertEquals(newName.getDefaultValue(), AnnotatedSetting.DEFAULT_VALUE);
+
+        SettingDescriptor overridden = Events.getSetting(type, "overridden");
+        Asserts.assertEquals(overridden.getDefaultValue(), PlainSetting.DEFAULT_VALUE);
+
+        CustomEvent.assertOnDisk((x, y) -> x.getName().compareTo(y.getName()));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/settingdescriptor/TestGetAnnotation.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.api.metadata.settingdescriptor;
+
+import jdk.jfr.Description;
+import jdk.jfr.EventType;
+import jdk.jfr.Label;
+import jdk.jfr.SettingDescriptor;
+import jdk.jfr.Timespan;
+import jdk.jfr.Timestamp;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Test SettingDescriptor.getAnnotation();
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.api.metadata.settingdescriptor.TestGetAnnotation
+ */
+public class TestGetAnnotation {
+
+    public static void main(String[] args) throws Exception {
+        EventType type = EventType.getEventType(CustomEvent.class);
+
+        SettingDescriptor annotatedType = Events.getSetting(type, "annotatedType");
+        Label al = annotatedType.getAnnotation(Label.class);
+        Asserts.assertNull(al); // we should not inherit annotation from type
+
+        Description ad = annotatedType.getAnnotation(Description.class);
+        Asserts.assertNull(ad); // we should not inherit annotation from type
+
+        Timestamp at = annotatedType.getAnnotation(Timestamp.class);
+        Asserts.assertNull(at); // we should not inherit annotation from type
+
+        SettingDescriptor newName = Events.getSetting(type, "newName");
+        Label nl = newName.getAnnotation(Label.class);
+        Asserts.assertEquals(nl.value(), "Annotated Method");
+
+        Description nd = newName.getAnnotation(Description.class);
+        Asserts.assertEquals(nd.value(), "Description of an annotated method");
+
+        Timespan nt = newName.getAnnotation(Timespan.class);
+        Asserts.assertEquals(nt.value(), Timespan.NANOSECONDS);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/settingdescriptor/TestGetAnnotationElement.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.api.metadata.settingdescriptor;
+
+import java.util.List;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.Description;
+import jdk.jfr.EventType;
+import jdk.jfr.Label;
+import jdk.jfr.Name;
+import jdk.jfr.SettingDescriptor;
+import jdk.jfr.Timespan;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Test SettingDescriptor.getAnnotationElements()
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.api.metadata.settingdescriptor.TestGetAnnotationElement
+ */
+public class TestGetAnnotationElement {
+
+    public static void main(String[] args) throws Exception {
+        EventType type = EventType.getEventType(CustomEvent.class);
+
+        SettingDescriptor plain = Events.getSetting(type, "plain");
+        Asserts.assertTrue(plain.getAnnotationElements().isEmpty());
+
+        SettingDescriptor annotatedType = Events.getSetting(type, "annotatedType");
+        for (AnnotationElement ae : annotatedType.getAnnotationElements()) {
+            System.out.println(ae.getTypeName());
+        }
+        Asserts.assertTrue(annotatedType.getAnnotationElements().isEmpty());
+
+        SettingDescriptor newName = Events.getSetting(type, "newName");
+        List<AnnotationElement> ae = newName.getAnnotationElements();
+        Asserts.assertEquals(ae.size(), 4);
+        Asserts.assertEquals(ae.get(0).getTypeName(), Name.class.getName());
+        Asserts.assertEquals(ae.get(1).getTypeName(), Label.class.getName());
+        Asserts.assertEquals(ae.get(2).getTypeName(), Description.class.getName());
+        Asserts.assertEquals(ae.get(3).getTypeName(), Timespan.class.getName());
+
+        SettingDescriptor overridden = Events.getSetting(type, "overridden");
+        Asserts.assertTrue(overridden.getAnnotationElements().isEmpty());
+
+        CustomEvent.assertOnDisk((x, y) -> {
+            List<AnnotationElement> a1 = x.getAnnotationElements();
+            List<AnnotationElement> a2 = y.getAnnotationElements();
+            if (a1.size() != a2.size()) {
+                throw new RuntimeException("Not same number of annotation ekements on disk as in process");
+            }
+            for (int i = 0; i < a1.size(); i++) {
+                if (!a1.get(i).getTypeName().equals(a2.get(i).getTypeName())) {
+                    throw new RuntimeException("Type name of annotation elements in process doesn't match type name on disk");
+                }
+            }
+            return 0;
+        });
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/settingdescriptor/TestGetContentType.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.api.metadata.settingdescriptor;
+
+import java.util.Objects;
+
+import jdk.jfr.EventType;
+import jdk.jfr.Frequency;
+import jdk.jfr.SettingDescriptor;
+import jdk.jfr.Timespan;
+import jdk.jfr.Timestamp;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Test SettingDescriptor.getContentType()
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.api.metadata.settingdescriptor.TestGetDescription
+ */
+public class TestGetContentType {
+
+    public static void main(String[] args) throws Exception {
+        EventType type = EventType.getEventType(CustomEvent.class);
+
+        SettingDescriptor plain = Events.getSetting(type, "plain");
+        Asserts.assertNull(plain.getContentType());
+
+        SettingDescriptor annotatedType = Events.getSetting(type, "annotatedType");
+        Asserts.assertNull(annotatedType.getContentType(), Timestamp.class.getName());
+
+        SettingDescriptor newName = Events.getSetting(type, "newName");
+        Asserts.assertEquals(newName.getContentType(), Timespan.class.getName());
+
+        SettingDescriptor overridden = Events.getSetting(type, "overridden");
+        Asserts.assertNull(overridden.getContentType());
+
+        SettingDescriptor protectedBase = Events.getSetting(type, "protectedBase");
+        Asserts.assertEquals(protectedBase.getContentType(), Frequency.class);
+
+        SettingDescriptor publicBase = Events.getSetting(type, "publicBase");
+        Asserts.assertEquals(publicBase.getContentType(), Timestamp.class.getName());
+
+        SettingDescriptor packageProtectedBase = Events.getSetting(type, "packageProtectedBase");
+        Asserts.assertNull(packageProtectedBase.getContentType());
+
+        CustomEvent.assertOnDisk((x, y) -> Objects.equals(x.getContentType(), y.getContentType()) ? 0 : 1);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/settingdescriptor/TestGetDescription.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.api.metadata.settingdescriptor;
+
+import java.util.Objects;
+
+import jdk.jfr.EventType;
+import jdk.jfr.SettingDescriptor;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Test SettingDescriptor.getDescription()
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.api.metadata.settingdescriptor.TestGetDescription
+ */
+public class TestGetDescription {
+
+    public static void main(String[] args) throws Exception {
+        EventType type = EventType.getEventType(CustomEvent.class);
+
+        SettingDescriptor plain = Events.getSetting(type, "plain");
+        Asserts.assertNull(plain.getDescription());
+
+        SettingDescriptor annotatedType = Events.getSetting(type, "annotatedType");
+        Asserts.assertEquals(annotatedType.getDescription(), AnnotatedSetting.DESCRIPTION);
+
+        SettingDescriptor newName = Events.getSetting(type, "newName");
+        Asserts.assertEquals(newName.getDescription(), CustomEvent.DESCRIPTION_OF_AN_ANNOTATED_METHOD);
+
+        SettingDescriptor overridden = Events.getSetting(type, "overridden");
+        Asserts.assertNull(overridden.getDescription());
+
+        SettingDescriptor protectedBase = Events.getSetting(type, "protectedBase");
+        Asserts.assertEquals(protectedBase.getDescription(), "Description of protected base");
+
+        SettingDescriptor publicBase = Events.getSetting(type, "publicBase");
+        Asserts.assertEquals(publicBase.getDescription(), AnnotatedSetting.DESCRIPTION);
+
+        SettingDescriptor packageProtectedBase = Events.getSetting(type, "packageProtectedBase");
+        Asserts.assertNull(packageProtectedBase.getDescription());
+
+        CustomEvent.assertOnDisk((x, y) -> Objects.equals(x.getDescription(), y.getDescription()) ? 0 : 1);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/settingdescriptor/TestGetLabel.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.api.metadata.settingdescriptor;
+
+import java.util.Objects;
+
+import jdk.jfr.EventType;
+import jdk.jfr.SettingDescriptor;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Test SettingDescriptor.getLabel()
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.api.metadata.settingdescriptor.TestGetLabel
+ */
+public class TestGetLabel {
+
+    public static void main(String[] args) throws Exception {
+        EventType type = EventType.getEventType(CustomEvent.class);
+
+        SettingDescriptor plain = Events.getSetting(type, "plain");
+        Asserts.assertNull(plain.getLabel());
+
+        SettingDescriptor annotatedType = Events.getSetting(type, "annotatedType");
+        Asserts.assertEquals(AnnotatedSetting.LABEL, annotatedType.getLabel());
+
+        SettingDescriptor newName = Events.getSetting(type, "newName");
+        Asserts.assertEquals(newName.getLabel(), "Annotated Method");
+
+        SettingDescriptor overridden = Events.getSetting(type, "overridden");
+        Asserts.assertNull(overridden.getLabel());
+
+        SettingDescriptor protectedBase = Events.getSetting(type, "protectedBase");
+        Asserts.assertEquals(protectedBase.getLabel(), "Protected Base");
+
+        SettingDescriptor publicBase = Events.getSetting(type, "publicBase");
+        Asserts.assertEquals(publicBase.getLabel(), AnnotatedSetting.LABEL);
+
+        SettingDescriptor packageProtectedBase = Events.getSetting(type, "packageProtectedBase");
+        Asserts.assertNull(packageProtectedBase.getLabel());
+
+        CustomEvent.assertOnDisk((x, y) -> Objects.equals(x.getLabel(), y.getLabel()) ? 0 : 1);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/settingdescriptor/TestGetName.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.api.metadata.settingdescriptor;
+
+import jdk.jfr.EventType;
+import jdk.jfr.SettingDescriptor;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Test SettingDescriptor.getName()
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.api.metadata.settingdescriptor.TestGetName
+ */
+public class TestGetName {
+
+    public static void main(String[] args) throws Exception {
+        EventType type = EventType.getEventType(CustomEvent.class);
+
+        // subclass
+        Events.getSetting(type, "plain");
+        Events.getSetting(type, "annotatedType");
+        Events.getSetting(type, "newName");
+        Events.getSetting(type, "overridden");
+        // base class
+        Events.getSetting(type, "overridden");
+        Events.getSetting(type, "protectedBase");
+        Events.getSetting(type, "publicBase");
+        Events.getSetting(type, "packageProtectedBase");
+
+        int defaultNumberOfSettings = 3; // Enabled , Stack Trace, Threshold
+        if (type.getSettingDescriptors().size() != 8 + defaultNumberOfSettings) {
+            for (SettingDescriptor s : type.getSettingDescriptors()) {
+                System.out.println(s.getName());
+            }
+            throw new Exception("Wrong number of settings");
+        }
+
+        CustomEvent.assertOnDisk((x, y) -> x.getName().compareTo(y.getName()));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/settingdescriptor/TestGetTypeId.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.api.metadata.settingdescriptor;
+
+import jdk.jfr.EventType;
+import jdk.jfr.SettingDescriptor;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Test SettingDescriptor.getTypeId()
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.api.metadata.settingdescriptor.TestGetTypeId
+ */
+public class TestGetTypeId {
+
+    public static void main(String[] args) throws Exception {
+        EventType type = EventType.getEventType(CustomEvent.class);
+
+        SettingDescriptor plain = Events.getSetting(type, "plain");
+        long plainId = plain.getTypeId();
+        Asserts.assertGreaterThan(plainId, 0L);
+
+        SettingDescriptor annotatedType = Events.getSetting(type, "annotatedType");
+        long annotatedId = annotatedType.getTypeId();
+        Asserts.assertGreaterThan(annotatedId, 0L);
+
+        Asserts.assertNotEquals(annotatedId, plainId);
+
+        SettingDescriptor newName = Events.getSetting(type, "newName");
+        Asserts.assertEquals(newName.getTypeId(), annotatedId);
+
+        SettingDescriptor overridden = Events.getSetting(type, "overridden");
+        Asserts.assertEquals(overridden.getTypeId(), plainId);
+
+        SettingDescriptor protectedBase = Events.getSetting(type, "protectedBase");
+        Asserts.assertEquals(protectedBase.getTypeId(), plainId);
+
+        SettingDescriptor publicBase = Events.getSetting(type, "publicBase");
+        Asserts.assertEquals(publicBase.getTypeId(), annotatedId);
+
+        SettingDescriptor packageProtectedBase = Events.getSetting(type, "packageProtectedBase");
+        Asserts.assertEquals(packageProtectedBase.getTypeId(), plainId);
+
+        CustomEvent.assertOnDisk((x, y) -> Long.compare(x.getTypeId(), y.getTypeId()));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/settingdescriptor/TestGetTypeName.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.api.metadata.settingdescriptor;
+
+import jdk.jfr.EventType;
+import jdk.jfr.SettingDescriptor;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Test SettingDescriptor.getTypeName();
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.api.metadata.settingdescriptor.TestGetTypeName
+ */
+public class TestGetTypeName {
+
+    public static void main(String[] args) throws Exception {
+        EventType type = EventType.getEventType(CustomEvent.class);
+
+        SettingDescriptor plain = Events.getSetting(type, "plain");
+        Asserts.assertEquals(plain.getTypeName(), PlainSetting.class.getName());
+
+        SettingDescriptor annotatedType = Events.getSetting(type, "annotatedType");
+        Asserts.assertEquals(annotatedType.getTypeName(), AnnotatedSetting.NAME);
+
+        SettingDescriptor newName = Events.getSetting(type, "newName");
+        Asserts.assertEquals(newName.getTypeName(), AnnotatedSetting.NAME);
+
+        SettingDescriptor overridden = Events.getSetting(type, "overridden");
+        Asserts.assertEquals(overridden.getTypeName(), PlainSetting.class.getName());
+
+        SettingDescriptor protectedBase = Events.getSetting(type, "protectedBase");
+        Asserts.assertEquals(protectedBase.getTypeName(), PlainSetting.class.getName());
+
+        SettingDescriptor publicBase = Events.getSetting(type, "publicBase");
+        Asserts.assertEquals(publicBase.getTypeName(), AnnotatedSetting.NAME);
+
+        SettingDescriptor packageProtectedBase = Events.getSetting(type, "packageProtectedBase");
+        Asserts.assertEquals(packageProtectedBase.getTypeName(), PlainSetting.class.getName());
+
+        CustomEvent.assertOnDisk((x, y) -> x.getTypeName().compareTo(y.getTypeName()));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/valuedescriptor/TestClasses.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.valuedescriptor;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import jdk.jfr.ValueDescriptor;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.CommonHelper;
+import jdk.test.lib.jfr.VoidFunction;
+
+/*
+ * @test
+ * @summary Test ValueDescriptor.getAnnotations()
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.valuedescriptor.TestClasses
+ */
+public class TestClasses {
+
+    public static void main(String[] args) throws Throwable {
+        @SuppressWarnings("rawtypes")
+        Map<String, Class> valid = new HashMap<>();
+        valid.put("byte", byte.class);
+        valid.put("short", short.class);
+        valid.put("int", int.class);
+        valid.put("char", char.class);
+        valid.put("float", float.class);
+        valid.put("double", double.class);
+        valid.put("boolean", boolean.class);
+        valid.put("double", double.class);
+        valid.put("long", long.class);
+        valid.put("java.lang.String", String.class);
+        valid.put("java.lang.Class", Class.class);
+        valid.put("java.lang.Thread", Thread.class);
+
+        for (String name : valid.keySet()) {
+            Class<?> t = valid.get(name);
+            System.out.println(t.getName());
+            ValueDescriptor d = new ValueDescriptor(t, "dummy");
+            String typeName = d.getTypeName() + (d.isArray() ? "[]" : "");
+            System.out.printf("%s -> typeName %s%n", name, typeName);
+            Asserts.assertEquals(name, typeName, "Wrong type name");
+        }
+
+        // Test some illegal classes
+        verifyIllegalArg(()->{new ValueDescriptor(Float.class, "ids");}, "Arrays of non-primitives should give Exception");
+        verifyIllegalArg(()->{new ValueDescriptor(Integer[].class, "ids");}, "Arrays of non-primitives should give Exception");
+        verifyIllegalArg(()->{new ValueDescriptor(Class[].class, "ids");}, "Arrays of non-primitives should give Exception");
+        verifyIllegalArg(()->{new ValueDescriptor(MyClass.class, "MyClass");}, "MyClass should give Exception");
+    }
+
+    private static class MyClass {
+        @SuppressWarnings("unused")
+        int id;
+    }
+
+    private static void verifyIllegalArg(VoidFunction f, String msg) throws Throwable {
+        CommonHelper.verifyException(f, msg, IllegalArgumentException.class);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/valuedescriptor/TestConstructor.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.valuedescriptor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.Label;
+import jdk.jfr.ValueDescriptor;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @summary Test ValueDescriptor.getAnnotations()
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.valuedescriptor.TestConstructor
+ */
+public class TestConstructor {
+
+    public static void main(String[] args) throws Throwable {
+        ValueDescriptor vdSimple = new ValueDescriptor(String.class, "message");
+        Asserts.assertNull(vdSimple.getAnnotation(Label.class), "Expected getAnnotation()==null");
+        Asserts.assertEquals(0, vdSimple.getAnnotationElements().size(), "Expected getAnnotations().size() == 0");
+
+        // Add labelA and verify we can read it back
+        List<AnnotationElement> annos = new ArrayList<>();
+        AnnotationElement labelA = new AnnotationElement(Label.class, "labelA");
+        annos.add(labelA);
+        System.out.println("labelA.getClass()" + labelA.getClass());
+        ValueDescriptor vdComplex = new ValueDescriptor(String.class, "message", annos);
+
+        final Label outLabel = vdComplex.getAnnotation(Label.class);
+        Asserts.assertFalse(outLabel == null, "getLabel(Label.class) was null");
+        System.out.println("outLabel.value() = " + outLabel.value());
+
+        // Get labelA from getAnnotations() list
+        Asserts.assertEquals(1, vdComplex.getAnnotationElements().size(), "Expected getAnnotations().size() == 1");
+        final AnnotationElement outAnnotation = vdComplex.getAnnotationElements().get(0);
+        Asserts.assertNotNull(outAnnotation, "outAnnotation was null");
+        System.out.printf("Annotation: %s = %s%n", outAnnotation.getTypeName(), outAnnotation.getValue("value"));
+        Asserts.assertEquals(outAnnotation, labelA, "Expected firstAnnotation == labelA");
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/valuedescriptor/TestGetAnnotations.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.valuedescriptor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.Description;
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.Label;
+import jdk.jfr.Name;
+import jdk.jfr.ValueDescriptor;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @summary Test ValueDescriptor.getAnnotations()
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.valuedescriptor.TestGetAnnotations
+ */
+public class TestGetAnnotations {
+
+    public static void main(String[] args) throws Throwable {
+        EventType type = EventType.getEventType(MyEvent.class);
+
+        List<String> actual = new ArrayList<>();
+        for (ValueDescriptor d : type.getFields()) {
+            String descName = d.getName();
+            for (AnnotationElement a : d.getAnnotationElements()) {
+                String annName = a.getTypeName();
+                String annValue = a.getValue("value").toString();
+                actual.add(String.format("%s: %s = %s", descName, annName, annValue));
+            }
+        }
+
+        System.out.println("Actual annotations:");
+        for (String s : actual) {
+            System.out.println(s);
+        }
+
+        String[] expected = {
+            "myShortName: jdk.jfr.Label = myShortLabel",
+            "myShortName: jdk.jfr.Description = myShortDesc",
+            "myLongName: jdk.jfr.Description = myLongDesc",
+            "myLongName: jdk.jfr.Label = myLongLabel",
+        };
+
+        for (String s : expected) {
+            if (!actual.contains(s)) {
+                System.out.println("Expected annotation missing: " + s);
+                Asserts.fail("Not all expected annotations found");
+            }
+        }
+    }
+
+
+    private static class MyEvent extends Event {
+        @Label("myShortLabel")
+        @Description("myShortDesc")
+        @Name("myShortName")
+        public short myShort;
+
+        @Name("myLongName")
+        @Description("myLongDesc")
+        @Label("myLongLabel")
+        public long myLong;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/valuedescriptor/TestGetFields.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.valuedescriptor;
+
+import jdk.jfr.ValueDescriptor;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @summary Test ValueDescriptor.getAnnotations()
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.valuedescriptor.TestGetFields
+ */
+public class TestGetFields {
+
+    public static void main(String[] args) throws Throwable {
+        // Test simple ValueDescriptor
+        final ValueDescriptor vdSimple = new ValueDescriptor(int.class, "id");
+        Asserts.assertNotNull(vdSimple.getFields(), "getFields() returned null");
+        Asserts.assertTrue(vdSimple.getFields().isEmpty(), "getFields() not empty for vdSimple");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/valuedescriptor/TestIsArray.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.valuedescriptor;
+
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.ValueDescriptor;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @summary Test ValueDescriptor.isArray().
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.valuedescriptor.TestIsArray
+ */
+public class TestIsArray {
+
+    public static void main(String[] args) throws Throwable {
+        EventType type = EventType.getEventType(EventWithArray.class);
+
+        ValueDescriptor d = type.getField("myIds");
+
+        Asserts.assertNull(d, "ValueDescriptor for int[] was not null");
+
+        type = EventType.getEventType(EventWithoutArray.class);
+        d = type.getField("myId");
+        Asserts.assertFalse(d.isArray(), "isArray() was true for int");
+    }
+
+    private static class EventWithArray extends Event {
+        @SuppressWarnings("unused")
+        public int[] myIds;
+    }
+
+    private static class EventWithoutArray extends Event {
+        @SuppressWarnings("unused")
+        public int myId;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/valuedescriptor/TestSimpleTypes.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.valuedescriptor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Description;
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.BooleanFlag;
+import jdk.jfr.Label;
+import jdk.jfr.Name;
+import jdk.jfr.Percentage;
+import jdk.jfr.ValueDescriptor;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @summary Test all basic types in ValueDescriptor.
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.valuedescriptor.TestSimpleTypes
+ */
+public class TestSimpleTypes {
+
+    public static void main(String[] args) throws Throwable {
+        EventType type = EventType.getEventType(MyEvent.class);
+
+        List<String> expectedStrings = new ArrayList<>();
+        expectedStrings.add("desc=myByteDesc; label=null; name=myByte; typename=byte; contenttype=null");
+        expectedStrings.add("desc=null; label=myShortLabel; name=myShort; typename=short; contenttype=null");
+        expectedStrings.add("desc=myIntDesc; label=myIntLabel; name=myInt; typename=int; contenttype=null");
+        expectedStrings.add("desc=null; label=null; name=myLongName; typename=long; contenttype=null");
+        expectedStrings.add("desc=myCharDesc; label=myCharLabel; name=myCharName; typename=char; contenttype=null");
+        expectedStrings.add("desc=null; label=null; name=myFloat; typename=float; contenttype=jdk.jfr.Percentage");
+        expectedStrings.add("desc=null; label=null; name=myDouble; typename=double; contenttype=null");
+        expectedStrings.add("desc=null; label=null; name=myBoolean; typename=boolean; contenttype=jdk.jfr.BooleanFlag");
+        expectedStrings.add("desc=null; label=null; name=myString; typename=java.lang.String; contenttype=null");
+        expectedStrings.add("desc=null; label=null; name=myClass; typename=java.lang.Class; contenttype=null");
+        expectedStrings.add("desc=null; label=null; name=myThread; typename=java.lang.Thread; contenttype=null");
+
+        List<Long> typeIds = new ArrayList<>();
+        for (ValueDescriptor d : type.getFields()) {
+            if (d.getName().startsWith("my")) {
+                String s = getCompareString(d);
+                System.out.println("got: " + s);
+                Asserts.assertTrue(expectedStrings.contains(s), "Wrong type string found");
+                expectedStrings.remove(s);
+
+                long typeId = d.getTypeId();
+                Asserts.assertFalse(typeIds.contains(typeId), "TypeIds not unique");
+                typeIds.add(typeId);
+
+                Asserts.assertFalse(d.isArray(), "ValueDescriptor should not be array");
+            }
+        }
+
+        if (!expectedStrings.isEmpty()) {
+            System.out.println("Missing expectedStrings:");
+            for (String s : expectedStrings) {
+                System.out.println(s);
+            }
+            Asserts.fail("Not all strings found");
+        }
+    }
+
+    private static String getCompareString(ValueDescriptor d) {
+        return String.format("desc=%s; label=%s; name=%s; typename=%s; contenttype=%s",
+                              d.getDescription(),
+                              d.getLabel(),
+                              d.getName(),
+                              d.getTypeName(),
+                              d.getContentType());
+    }
+
+    @SuppressWarnings("unused")
+    private static class MyEvent extends Event {
+
+        @Description("myByteDesc")
+        public byte myByte;
+
+        @Label("myShortLabel")
+        public short myShort;
+
+        @Label("myIntLabel")
+        @Description("myIntDesc")
+        public int myInt;
+
+        @Name("myLongName")
+        public long myLong;
+
+        @Label("myCharLabel")
+        @Description("myCharDesc")
+        @Name("myCharName")
+        protected char myChar;
+
+        @Percentage
+        protected float myFloat;
+        protected double myDouble;
+        @BooleanFlag
+        private boolean myBoolean;
+        private String myString;
+        @SuppressWarnings("rawtypes")
+        private Class myClass;
+        private Thread myThread;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/metadata/valuedescriptor/TestValueDescriptorContentType.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.metadata.valuedescriptor;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import jdk.jfr.ContentType;
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.MetadataDefinition;
+import jdk.jfr.ValueDescriptor;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @summary Test ValueDescriptor.getContentType()
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.metadata.valuedescriptor.TestValueDescriptorContentType
+ */
+public class TestValueDescriptorContentType {
+
+    @MetadataDefinition
+    @ContentType
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ ElementType.FIELD, ElementType.TYPE, ElementType.METHOD })
+    static public @interface Hawaiian {
+    }
+
+    @MetadataDefinition
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ ElementType.FIELD, ElementType.TYPE })
+    static public @interface NotContentType {
+    }
+
+    @SuppressWarnings("unused")
+    private static class AlohaEvent extends Event {
+        @Hawaiian
+        String greeting;
+
+        String missing;
+
+        @NotContentType
+        String otherAnnotation;
+    }
+
+    public static void main(String[] args) throws Throwable {
+        EventType type = EventType.getEventType(AlohaEvent.class);
+
+        // check field annotation on event value
+        ValueDescriptor filter = type.getField("greeting");
+        Asserts.assertEquals(filter.getContentType(), Hawaiian.class.getName());
+
+        // check field annotation with missing content type
+        ValueDescriptor missing = type.getField("missing");
+        Asserts.assertEquals(missing.getContentType(), null);
+
+        // check field annotation with annotation but not content type
+        ValueDescriptor otherAnnotation = type.getField("otherAnnotation");
+        Asserts.assertEquals(otherAnnotation.getContentType(), null);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/modules/TestModularizedEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.modules;
+
+import java.nio.file.Paths;
+
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.tools.JavaCompiler;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.StandardLocation;
+import javax.tools.ToolProvider;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+public class TestModularizedEvent {
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src_mods");
+    private static final Path MODS_DIR = Paths.get("mods");
+
+    private static final String ANNO_MODULE = "test.jfr.annotation";
+    private static final String SETTING_MODULE = "test.jfr.setting";
+    private static final String EVENT_MODULE = "test.jfr.event";
+    private static final String TEST_MODULE = "test.jfr.main";
+
+    public static void main(String... args) throws Exception {
+        compileModule(ANNO_MODULE);
+        compileModule(SETTING_MODULE);
+        compileModule(EVENT_MODULE, "--module-path", MODS_DIR.toString());
+        compileModule(TEST_MODULE, "--module-path", MODS_DIR.toString());
+
+        OutputAnalyzer oa = ProcessTools.executeTestJava("--module-path", "mods", "-m", "test.jfr.main/test.jfr.main.MainTest");
+        oa.stdoutShouldContain("Test passed.");
+    }
+
+    private static void compileModule(String modDir, String... opts) throws Exception {
+        boolean compiled = compile(SRC_DIR.resolve(modDir),
+                MODS_DIR.resolve(modDir),
+                opts);
+        assertTrue(compiled, "module " + modDir + " did not compile");
+    }
+
+    private static boolean compile(Path source, Path destination, String... options)
+            throws IOException {
+        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+        if (compiler == null) {
+            // no compiler available
+            throw new UnsupportedOperationException("Unable to get system java compiler. "
+                    + "Perhaps, jdk.compiler module is not available.");
+        }
+        StandardJavaFileManager jfm = compiler.getStandardFileManager(null, null, null);
+
+        List<Path> sources
+                = Files.find(source, Integer.MAX_VALUE,
+                        (file, attrs) -> (file.toString().endsWith(".java")))
+                .collect(Collectors.toList());
+
+        Files.createDirectories(destination);
+        jfm.setLocation(StandardLocation.CLASS_PATH, Collections.emptyList());
+        jfm.setLocationFromPaths(StandardLocation.CLASS_OUTPUT,
+                Arrays.asList(destination));
+
+        List<String> opts = Arrays.asList(options);
+        JavaCompiler.CompilationTask task
+                = compiler.getTask(null, jfm, null, opts, null,
+                        jfm.getJavaFileObjectsFromPaths(sources));
+
+        return task.call();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/modules/src_mods/test.jfr.annotation/module-info.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module test.jfr.annotation {
+    requires jdk.jfr;
+    exports test.jfr.annotation;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/modules/src_mods/test.jfr.annotation/test/jfr/annotation/ModularizedAnnotation.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package test.jfr.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import jdk.jfr.MetadataDefinition;
+
+@MetadataDefinition
+@Target({ElementType.TYPE, ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@ModularizedAnnotation("hello annotation")
+public @interface ModularizedAnnotation {
+
+    String value();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/modules/src_mods/test.jfr.event/module-info.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module test.jfr.event {
+    requires jdk.jfr;
+    requires test.jfr.annotation;
+    requires test.jfr.setting;
+    exports test.jfr.event;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/modules/src_mods/test.jfr.event/test/jfr/event/ModularizedOrdinaryEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package test.jfr.event;
+
+import test.jfr.annotation.ModularizedAnnotation;
+
+import jdk.jfr.Event;
+import jdk.jfr.SettingDefinition;
+import test.jfr.setting.ModularizedSetting;
+
+@ModularizedAnnotation("hello type")
+public class ModularizedOrdinaryEvent extends Event {
+
+    @ModularizedAnnotation("hello field")
+    public String message;
+
+    @SettingDefinition
+    boolean filter(ModularizedSetting ms) {
+        return ms.accept();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/modules/src_mods/test.jfr.event/test/jfr/event/ModularizedPeriodicEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package test.jfr.event;
+
+import test.jfr.annotation.ModularizedAnnotation;
+
+import jdk.jfr.Event;
+import jdk.jfr.SettingDefinition;
+import test.jfr.setting.ModularizedSetting;
+
+@ModularizedAnnotation("hello type")
+public class ModularizedPeriodicEvent extends Event {
+
+    @ModularizedAnnotation("hello field")
+    public String message;
+
+    @SettingDefinition
+    boolean filter(ModularizedSetting ms) {
+        return ms.accept();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/modules/src_mods/test.jfr.main/module-info.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module test.jfr.main {
+    requires jdk.jfr;
+    requires test.jfr.annotation;
+    requires test.jfr.event;
+    requires test.jfr.setting;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/modules/src_mods/test.jfr.main/test/jfr/main/MainTest.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package test.jfr.main;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.EventType;
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Recording;
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.consumer.RecordedEvent;
+
+import test.jfr.annotation.ModularizedAnnotation;
+import test.jfr.event.ModularizedOrdinaryEvent;
+import test.jfr.event.ModularizedPeriodicEvent;
+import java.nio.file.Path;
+import java.util.Objects;
+import jdk.jfr.consumer.RecordingFile;
+
+public class MainTest {
+
+    private static final String HELLO_ORDINARY = "ordinary says hello";
+    private static final String HELLO_PERIODIC = "periodic says hello";
+
+    public static void main(String... args) throws Exception {
+        System.out.println("Starting the test...");
+        FlightRecorder.addPeriodicEvent(ModularizedPeriodicEvent.class, () -> {
+            ModularizedPeriodicEvent me = new ModularizedPeriodicEvent();
+            me.message = HELLO_PERIODIC;
+            me.commit();
+        });
+        Recording r = new Recording();
+        r.enable(ModularizedOrdinaryEvent.class).with("filter", "true").withoutStackTrace();
+        r.enable(ModularizedPeriodicEvent.class).with("filter", "true").withoutStackTrace();
+        r.start();
+        ModularizedOrdinaryEvent m = new ModularizedOrdinaryEvent();
+        m.message = HELLO_ORDINARY;
+        m.commit();
+        r.stop();
+        List<RecordedEvent> events = fromRecording(r);
+        System.out.println(events);
+        if (events.size() == 0) {
+            throw new RuntimeException("Expected two events");
+        }
+        assertOrdinaryEvent(events);
+        assertPeriodicEvent(events);
+        assertMetadata(events);
+        System.out.println("Test passed.");
+    }
+
+    private static void assertMetadata(List<RecordedEvent> events) {
+        for (RecordedEvent e : events) {
+            EventType type = e.getEventType();
+            ModularizedAnnotation maType = type.getAnnotation(ModularizedAnnotation.class);
+            if (maType == null) {
+                fail("Missing @ModularizedAnnotation on type " + type);
+            }
+            assertEquals(maType.value(), "hello type");
+            assertMetaAnnotation(type.getAnnotationElements());
+
+            ValueDescriptor messageField = type.getField("message");
+            ModularizedAnnotation maField = messageField.getAnnotation(ModularizedAnnotation.class);
+            if (maField == null) {
+                fail("Missing @ModularizedAnnotation on field in " + type);
+            }
+            assertEquals(maField.value(), "hello field");
+            assertMetaAnnotation(messageField.getAnnotationElements());
+        }
+    }
+
+    private static void assertMetaAnnotation(List<AnnotationElement> aes) {
+        assertEquals(aes.size(), 1, "@ModularizedAnnotation should only have one meta-annotation");
+        AnnotationElement ae = aes.get(0);
+        assertEquals(ae.getTypeName(), ModularizedAnnotation.class.getName(), "Incorrect meta-annotation");
+    }
+
+    private static void assertPeriodicEvent(List<RecordedEvent> events) {
+        for (RecordedEvent e : events) {
+            String message = e.getValue("message");
+            if (message.equals(HELLO_ORDINARY)) {
+                return;
+            }
+        }
+        throw new RuntimeException("Could not find ordinary event in recording");
+    }
+
+    private static void assertOrdinaryEvent(List<RecordedEvent> events) {
+        for (RecordedEvent e : events) {
+            String message = e.getValue("message");
+            if (message.equals(HELLO_PERIODIC)) {
+                return;
+            }
+        }
+        throw new RuntimeException("Could not find periodic event in recording");
+    }
+
+    public static List<RecordedEvent> fromRecording(Recording recording) throws IOException {
+        return RecordingFile.readAllEvents(makeCopy(recording));
+    }
+
+    private static Path makeCopy(Recording recording) throws IOException {
+        Path p = recording.getDestination();
+        if (p == null) {
+            File directory = new File(".");
+            ProcessHandle h = ProcessHandle.current();
+            p = new File(directory.getAbsolutePath(), "recording-" + recording.getId() + "-pid" + h.pid() + ".jfr").toPath();
+            recording.dump(p);
+        }
+        return p;
+    }
+
+    private static void assertEquals(Object lhs, Object rhs) {
+        assertEquals(lhs, rhs, null);
+    }
+
+    private static void assertEquals(Object lhs, Object rhs, String msg) {
+        if ((lhs != rhs) && ((lhs == null) || !(lhs.equals(rhs)))) {
+            msg = Objects.toString(msg, "assertEquals")
+                    + ": expected " + Objects.toString(lhs)
+                    + " to equal " + Objects.toString(rhs);
+            fail(msg);
+        }
+    }
+
+    private static void fail(String message) {
+        throw new RuntimeException(message);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/modules/src_mods/test.jfr.setting/module-info.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module test.jfr.setting {
+    requires jdk.jfr;
+    exports test.jfr.setting;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/modules/src_mods/test.jfr.setting/test/jfr/setting/ModularizedSetting.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package test.jfr.setting;
+
+import java.util.Set;
+
+import jdk.jfr.SettingControl;
+
+public final class ModularizedSetting extends SettingControl {
+
+    private String value = "false";
+    private boolean isTrue = false;
+
+    @Override
+    public String combine(Set<String> settingValues) {
+        for (String s : settingValues) {
+            if ("true".equals(s)) {
+                return "true";
+            }
+        }
+        return "false";
+    }
+
+    @Override
+    public void setValue(String settingValue) {
+        this.value = settingValue;
+        this.isTrue = Boolean.valueOf(settingValue);
+    }
+
+    @Override
+    public String getValue() {
+        return value;
+    }
+
+    public boolean accept() {
+        return isTrue;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recorder/TestRecorderInitialized.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recorder;
+
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.FlightRecorderListener;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test TestRecorderListener
+ * @key jfr
+ * @library /test/lib
+ *
+ * @run main/othervm jdk.jfr.api.recorder.TestRecorderInitialized
+ */
+public class TestRecorderInitialized {
+
+    static class Listener implements FlightRecorderListener {
+        private boolean notified;
+
+        @Override
+        public void recorderInitialized(FlightRecorder r) {
+            notified = true;
+        }
+    }
+
+    public static void main(String...args) {
+        Listener l1 = new Listener();
+
+        FlightRecorder.addListener(l1);
+        Asserts.assertFalse(l1.notified, "Listener shouldn't be notified unless Flight Recorder is initialized");
+        // initialize Flight Recorder
+        FlightRecorder.getFlightRecorder();
+        Asserts.assertTrue(l1.notified, "Listener should be notified when Flight Recorder is initialized");
+        l1.notified = false;
+
+        Listener l2 = new Listener();
+        FlightRecorder.addListener(l1);
+        FlightRecorder.addListener(l2);
+        Asserts.assertTrue(l2.notified, "Listener should be notified if Flight Recorder is already initialized");
+        Asserts.assertTrue(l1.notified, "Only added listnener should be notified, if Flight Recorder is already initialized");
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recorder/TestRecorderListener.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.api.recorder;
+
+import java.util.concurrent.CountDownLatch;
+
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.FlightRecorderListener;
+import jdk.jfr.Recording;
+import jdk.jfr.RecordingState;
+
+/*
+ * @test TestRecorderListener
+ *
+ * @key jfr
+ * @run main/othervm jdk.jfr.api.recorder.TestRecorderListener
+ */
+public class TestRecorderListener {
+
+    static class Listener implements FlightRecorderListener {
+
+        private final CountDownLatch latch = new CountDownLatch(1);
+        private final RecordingState waitFor;
+
+        public Listener(RecordingState state) {
+            waitFor = state;
+        }
+
+        @Override
+        public void recordingStateChanged(Recording recording) {
+            System.out.println("Listener: recording=" + recording.getName() + " state=" + recording.getState());
+            RecordingState rs = recording.getState();
+            if (rs == waitFor) {
+                latch.countDown();
+            }
+        }
+
+        public void waitFor() throws InterruptedException {
+            latch.await();
+        }
+    }
+
+    public static void main(String... args) throws Exception {
+        Listener recordingListener = new Listener(RecordingState.RUNNING);
+        FlightRecorder.addListener(recordingListener);
+
+        Listener stoppedListener = new Listener(RecordingState.STOPPED);
+        FlightRecorder.addListener(stoppedListener);
+
+        Listener finishedListener = new Listener(RecordingState.CLOSED);
+        FlightRecorder.addListener(finishedListener);
+
+        Recording recording = new Recording();
+        if (recording.getState() != RecordingState.NEW) {
+            recording.close();
+            throw new Exception("New recording should be in NEW state");
+        }
+
+        recording.start();
+        recordingListener.waitFor();
+
+        recording.stop();
+        stoppedListener.waitFor();
+
+        recording.close();
+        finishedListener.waitFor();
+
+        testDefaultrecordingStateChangedListener();
+
+    }
+
+    private static class DummyListener implements FlightRecorderListener {
+
+    }
+
+    private static void testDefaultrecordingStateChangedListener() {
+        FlightRecorder.addListener(new DummyListener());
+        Recording recording = new Recording();
+        recording.start();
+        recording.stop();
+        recording.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recorder/TestStartStopRecording.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recorder;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+
+import jdk.jfr.Configuration;
+import jdk.jfr.Recording;
+
+/*
+ * @test TestStartStopRecording
+ *
+ * @key jfr
+ * @run main/othervm jdk.jfr.api.recorder.TestStartStopRecording
+ */
+public class TestStartStopRecording {
+
+    public static void main(String... args) throws Exception {
+        Configuration defaultConfig = Configuration.getConfiguration("default");
+        // Memory
+        Recording inMemory = new Recording(defaultConfig);
+        inMemory.setToDisk(false);
+
+        inMemory.start();
+
+        Path memoryFile = Files.createTempFile("memory-recording", ".jfr");
+        inMemory.dump(memoryFile);
+        assertValid(memoryFile, "Not a valid memory file.");
+        inMemory.stop();
+        inMemory.close();
+        // Disk
+        Recording toDisk = new Recording(defaultConfig);
+        toDisk.setToDisk(true);
+
+        toDisk.start();
+        toDisk.stop();
+        Path diskFile = Files.createTempFile("disk-recording", ".jfr");
+        toDisk.dump(diskFile);
+        assertValid(diskFile, "Not a valid disk file.");
+        toDisk.close();
+    }
+
+    private static void assertValid(Path path, String message) throws IOException {
+        if (!Files.exists(path, LinkOption.NOFOLLOW_LINKS)) {
+            throw new AssertionError(message + " Could not find file " + path);
+        }
+        if (Files.size(path) == 0) {
+            throw new AssertionError(message + " File size = 0 for " + path);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/destination/TestDestFileExist.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.destination;
+
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+
+/*
+ * @test
+ * @summary Set destination to an existing file. File should be overwritten.
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.destination.TestDestFileExist
+ */
+public class TestDestFileExist {
+
+    public static void main(String[] args) throws Throwable {
+        Path dest = Paths.get(".", "my.jfr");
+        System.out.println("dest=" + dest);
+        Files.write(dest, "Dummy data".getBytes());
+        assertTrue(Files.exists(dest), "Test error: Failed to create file");
+        System.out.println("file size before recording:" + Files.size(dest));
+        Recording r = new Recording();
+        r.enable(EventNames.OSInformation);
+        r.setDestination(dest);
+        r.start();
+        r.stop();
+        List<RecordedEvent> events = RecordingFile.readAllEvents(dest);
+        Asserts.assertFalse(events.isEmpty(), "No events found");
+        System.out.println(events.iterator().next());
+        r.close();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/destination/TestDestFileReadOnly.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.destination;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import jdk.jfr.Recording;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.FileHelper;
+
+/*
+ * @test
+ * @summary Set destination to a read-only file. Expects exception.
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.destination.TestDestFileReadOnly
+ */
+public class TestDestFileReadOnly {
+
+    public static void main(String[] args) throws Throwable {
+        Path dest = FileHelper.createReadOnlyFile(Paths.get(".", "readonly.txt"));
+        System.out.println("dest=" + dest.toFile().getAbsolutePath());
+        if (!FileHelper.isReadOnlyPath(dest)) {
+            System.out.println("Failed to create a read-only file. Test ignored.");
+            return;
+        }
+
+        Recording r = new Recording();
+        r.setToDisk(true);
+        try {
+            r.setDestination(dest);
+            Asserts.fail("No exception when destination is read-only");
+        } catch (IOException e) {
+            // Expected exception
+        }
+        r.close();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/destination/TestDestInvalid.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.destination;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.CommonHelper;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.VoidFunction;
+
+/*
+ * @test
+ * @summary Test setDestination to invalid paths
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.destination.TestDestInvalid
+ */
+public class TestDestInvalid {
+
+    public static void main(String[] args) throws Throwable {
+        Recording r = new Recording();
+        r.enable(EventNames.OSInformation);
+        r.setToDisk(true);
+
+        Asserts.assertNull(r.getDestination(), "dest not null by default");
+
+        // Set destination to empty path (same as curr dir, not a file)
+        verifyException(()->{r.setDestination(Paths.get(""));}, "No exception for setDestination(\"\")", IOException.class);
+        System.out.println("1 destination: " + r.getDestination());
+        Asserts.assertNull(r.getDestination(), "default dest not null after failed setDest");
+
+        // Set dest to a valid path. This should be kept when a new setDest fails.
+        Path dest = Paths.get(".", "my.jfr");
+        r.setDestination(dest);
+        System.out.println("2 destination: " + r.getDestination());
+        Asserts.assertEquals(dest, r.getDestination(), "Wrong get/set dest");
+
+        // Null is allowed for setDestination()
+        r.setDestination(null);
+        System.out.println("3 destination: " + r.getDestination());
+        Asserts.assertNull(r.getDestination(), "dest not null after setDest(null)");
+
+        // Reset dest to correct value and make ssure it is not overwritten
+        r.setDestination(dest);
+        System.out.println("4 destination: " + r.getDestination());
+        Asserts.assertEquals(dest, r.getDestination(), "Wrong get/set dest");
+
+        // Set destination to an existing dir. Old dest is saved.
+        verifyException(()->{r.setDestination(Paths.get("."));}, "No exception for setDestination(.)", IOException.class);
+        System.out.println("5 destination: " + r.getDestination());
+        Asserts.assertEquals(dest, r.getDestination(), "Wrong get/set dest");
+
+        // Set destination to a non-existing dir. Old dest is saved.
+        verifyException(()->{r.setDestination(Paths.get(".", "missingdir", "my.jfr"));}, "No exception for setDestination(dirNotExists)", IOException.class);
+        System.out.println("6 destination: " + r.getDestination());
+        Asserts.assertEquals(dest, r.getDestination(), "Wrong get/set dest");
+
+        // Verify that it works with the old setDest value.
+        r.start();
+        r.stop();
+        r.close();
+        Asserts.assertTrue(Files.exists(dest), "No recording file: " + dest);
+        List<RecordedEvent> events = RecordingFile.readAllEvents(dest);
+        Asserts.assertFalse(events.isEmpty(), "No event found");
+        System.out.printf("Found event %s in %s%n", events.get(0).getEventType().getName(), dest.toString());
+    }
+
+    private static void verifyException(VoidFunction f, String msg, Class<?> exceptionClass) throws Throwable {
+        CommonHelper.verifyException(f, msg, IOException.class);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/destination/TestDestLongPath.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.destination;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.FileHelper;
+
+/*
+ * @test
+ * @summary Set destination to a long path
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.destination.TestDestLongPath
+ */
+public class TestDestLongPath {
+
+    public static void main(String[] args) throws Throwable {
+        Path dir = FileHelper.createLongDir(Paths.get("."));
+        Path dest = Paths.get(dir.toString(), "my.jfr");
+        Recording r = new Recording();
+        r.enable(EventNames.OSInformation);
+        r.setToDisk(true);
+        r.setDestination(dest);
+        r.start();
+        r.stop();
+        r.close();
+        Asserts.assertTrue(Files.exists(dest), "No recording file: " + dest);
+        List<RecordedEvent> events = RecordingFile.readAllEvents(dest);
+        Asserts.assertFalse(events.isEmpty(), "No event found");
+        System.out.printf("Found event %s%n", events.get(0).getEventType().getName());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/destination/TestDestMultiple.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.destination;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.SimpleEventHelper;
+
+/*
+ * @test
+ * @summary Test setDestination with concurrent recordings
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm -Xlog:jfr=trace jdk.jfr.api.recording.destination.TestDestMultiple
+ */
+public class TestDestMultiple {
+
+    public static void main(String[] args) throws Throwable {
+        Recording rA = new Recording();
+        Recording rB = new Recording();
+
+        Path destA = Paths.get(".", "recA.jfr");
+        Path destB = Paths.get(".", "recB.jfr");
+        rA.setDestination(destA);
+        rB.setDestination(destB);
+
+        // Enable event in one recording and disable in the other.
+        // Both recordings should still get the events, since we always
+        // get the "union" of all settings.
+        SimpleEventHelper.enable(rA, true);
+        SimpleEventHelper.enable(rB, false);
+
+        SimpleEventHelper.createEvent(0); // To no recording
+
+        rA.start();
+        SimpleEventHelper.createEvent(1); // Only to recA
+
+        rB.start();
+        SimpleEventHelper.createEvent(2); // To both recordings
+
+        rA.stop();
+
+        // This event will not be in recB.
+        // The reason is that recA has stopped so event is no longer enabled.
+        SimpleEventHelper.createEvent(3);
+
+        // Enable the event and create a new event for recB
+        SimpleEventHelper.enable(rB, true);
+        SimpleEventHelper.createEvent(4);
+
+        rB.stop();
+        SimpleEventHelper.createEvent(5); // To no recording
+
+        rB.close();
+        rA.close();
+
+        verifyRecording(destA, 1, 2);
+        verifyRecording(destB, 2, 4);
+    }
+
+    private static void verifyRecording(Path path, int... ids) throws Exception {
+        Asserts.assertTrue(Files.exists(path), "Recording file does not exist: " + path);
+        int countEvent = 0;
+        List<RecordedEvent> events = RecordingFile.readAllEvents(path);
+        for (RecordedEvent event : events) {
+            int id = Events.assertField(event, "id").getValue();
+            System.out.printf("Recording '%s' id=%d%n", path, id);
+        }
+        for (RecordedEvent event : events) {
+            int id = Events.assertField(event, "id").getValue();
+            System.out.printf("Recording '%s' id=%d%n", path, id);
+            Asserts.assertTrue(ids.length > countEvent, "Found extra event");
+            Events.assertField(event, "id").equal(ids[countEvent]);
+            ++countEvent;
+        }
+        // We expect exactly 4 events in each file. 2 events * 2 chunks
+        Asserts.assertEquals(countEvent, ids.length, "Found too few events");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/destination/TestDestReadOnly.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.destination;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.CommonHelper;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.FileHelper;
+import jdk.test.lib.jfr.VoidFunction;
+
+/*
+ * @test
+ * @summary Test setDestination to read-only dir
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.destination.TestDestReadOnly
+ */
+public class TestDestReadOnly {
+
+    public static void main(String[] args) throws Throwable {
+        Path readOnlyDir = FileHelper.createReadOnlyDir(Paths.get(".", "readonly"));
+        if (!FileHelper.isReadOnlyPath(readOnlyDir)) {
+            System.out.println("Failed to create read-only dir. Running as root?. Test ignored");
+            return;
+        }
+
+        Path readOnlyDest = Paths.get(readOnlyDir.toString(), "readonly.jfr");
+        Recording r = new Recording();
+        r.enable(EventNames.OSInformation);
+        r.setToDisk(true);
+        verifyException(()->{r.setDestination(readOnlyDest);}, "No exception for setDestination to read-only dir");
+
+        System.out.println("r.getDestination() = " + r.getDestination());
+
+        // Verify that it works if we set destination to a writable dir.
+        Path dest = Paths.get(".", "my.jfr");
+        r.setDestination(dest);
+        r.start();
+        r.stop();
+        r.close();
+        Asserts.assertTrue(Files.exists(dest), "No recording file: " + dest);
+        List<RecordedEvent> events = RecordingFile.readAllEvents(dest);
+        Asserts.assertFalse(events.isEmpty(), "No event found");
+        System.out.printf("Found event %s in %s%n", events.get(0).getEventType().getName(), dest.toString());
+    }
+
+    private static void verifyException(VoidFunction f, String msg) throws Throwable {
+        CommonHelper.verifyException(f, msg, IOException.class);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/destination/TestDestState.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.destination;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.SimpleEventHelper;
+
+/*
+ * @test
+ * @summary Call setDestination() when recording in different states
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.destination.TestDestState
+ */
+public class TestDestState {
+
+    public static void main(String[] args) throws Throwable {
+        Recording r = new Recording();
+        SimpleEventHelper.enable(r, true);
+
+        final Path newDest = Paths.get(".", "new.jfr");
+        r.setDestination(newDest);
+        System.out.println("new dest: " + r.getDestination());
+        Asserts.assertEquals(newDest, r.getDestination(), "Wrong get/set dest when new");
+
+        r.start();
+        SimpleEventHelper.createEvent(0);
+        Thread.sleep(100);
+        final Path runningDest = Paths.get(".", "running.jfr");
+        r.setDestination(runningDest);
+        System.out.println("running dest: " + r.getDestination());
+        Asserts.assertEquals(runningDest, r.getDestination(), "Wrong get/set dest when running");
+        SimpleEventHelper.createEvent(1);
+
+        r.stop();
+        SimpleEventHelper.createEvent(2);
+
+        // Expect recording to be saved at destination that was set when
+        // the recording was stopped, which is runningDest.
+        Asserts.assertTrue(Files.exists(runningDest), "No recording file: " + runningDest);
+        List<RecordedEvent> events = RecordingFile.readAllEvents(runningDest);
+        Asserts.assertFalse(events.isEmpty(), "No event found");
+        System.out.printf("Found event %s%n", events.get(0).getEventType().getName());
+        r.close();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/destination/TestDestToDiskFalse.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.destination;
+
+
+import static jdk.test.lib.Asserts.assertEquals;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.SimpleEventHelper;
+
+/*
+ * @test
+ * @summary Basic test for setDestination with disk=false
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.destination.TestDestToDiskFalse
+ */
+public class TestDestToDiskFalse {
+
+    public static void main(String[] args) throws Throwable {
+        final Path dest = Paths.get(".", "my.jfr");
+        Recording r = new Recording();
+        SimpleEventHelper.enable(r, true);
+        r.setToDisk(false);
+        r.setDestination(dest);
+        Asserts.assertEquals(dest, r.getDestination(), "Wrong get/set destination");
+        r.start();
+        SimpleEventHelper.createEvent(0);
+        r.stop();
+
+        // setToDisk(false) should not effect setDestination.
+        // We should still get a file when the recording stops.
+        Asserts.assertTrue(Files.exists(dest), "No recording file: " + dest);
+        System.out.printf("File size=%d, getSize()=%d%n", Files.size(dest), r.getSize());
+        Asserts.assertNotEquals(Files.size(dest), 0L, "File length 0. Should at least be some bytes");
+
+        List<RecordedEvent> events = RecordingFile.readAllEvents(dest);
+        Asserts.assertFalse(events.isEmpty(), "No event found");
+        System.out.printf("Found event %s%n", events.get(0).getEventType().getName());
+
+        assertEquals(r.getSize(), 0L, "getSize() should return 0, chunks should have been released at stop");
+        // getDestination() should return null after recording have been written to file.
+        Asserts.assertNull(r.getDestination(), "getDestination() should return null after file created");
+
+        r.close();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/destination/TestDestToDiskTrue.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.destination;
+
+import static jdk.test.lib.Asserts.assertEquals;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+
+/*
+ * @test
+ * @summary Basic test for setDestination with disk=true
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.destination.TestDestToDiskTrue
+ */
+public class TestDestToDiskTrue {
+
+    public static void main(String[] args) throws Throwable {
+        Path dest = Paths.get(".", "my.jfr");
+        Recording r = new Recording();
+        r.enable(EventNames.OSInformation);
+        r.setToDisk(true);
+        r.setDestination(dest);
+        Asserts.assertEquals(dest, r.getDestination(), "Wrong get/set destination");
+        r.start();
+        r.stop();
+
+        Asserts.assertEquals(dest, r.getDestination(), "Wrong get/set destination after stop");
+
+        Asserts.assertTrue(Files.exists(dest), "No recording file: " + dest);
+        List<RecordedEvent> events = RecordingFile.readAllEvents(dest);
+        Asserts.assertFalse(events.isEmpty(), "No event found");
+        System.out.printf("Found event %s%n", events.get(0).getEventType().getName());
+        System.out.printf("File size=%d, getSize()=%d%n", Files.size(dest), r.getSize());
+        assertEquals(r.getSize(), 0L, "getSize() should return 0, chunks should have be released at stop");
+        Asserts.assertNotEquals(Files.size(dest), 0L, "File length 0. Should at least be some bytes");
+        r.close();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/destination/TestDestWithDuration.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.destination;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.Duration;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.RecordingState;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.CommonHelper;
+import jdk.test.lib.jfr.SimpleEventHelper;
+
+/*
+ * @test
+ * @summary Test that recording is auto closed after duration
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.destination.TestDestWithDuration
+ */
+public class TestDestWithDuration {
+
+    public static void main(String[] args) throws Throwable {
+        Path dest = Paths.get(".", "my.jfr");
+        Recording r = new Recording();
+        SimpleEventHelper.enable(r, true);
+        r.setDestination(dest);
+        r.start();
+        SimpleEventHelper.createEvent(1);
+
+        // Waiting for recording to auto close after duration
+        r.setDuration(Duration.ofSeconds(1));
+        System.out.println("Waiting for recording to auto close after duration");
+        CommonHelper.waitForRecordingState(r, RecordingState.CLOSED);
+        System.out.println("recording state = " + r.getState());
+        Asserts.assertEquals(r.getState(), RecordingState.CLOSED, "Recording not closed");
+
+        Asserts.assertTrue(Files.exists(dest), "No recording file: " + dest);
+        System.out.printf("Recording file size=%d%n", Files.size(dest));
+        Asserts.assertNotEquals(Files.size(dest), 0L, "File length 0. Should at least be some bytes");
+
+        List<RecordedEvent> events = RecordingFile.readAllEvents(dest);
+        Asserts.assertFalse(events.isEmpty(), "No event found");
+        System.out.printf("Found event %s%n", events.get(0).getEventType().getName());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/dump/TestDump.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.dump;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+
+/*
+ * @test
+ * @summary Test copyTo and parse file
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.dump.TestDump
+ */
+public class TestDump {
+
+    public static void main(String[] args) throws Exception {
+        Recording r = new Recording();
+        r.enable(EventNames.OSInformation);
+        r.start();
+        r.stop();
+
+        Path path = Paths.get(".", "my.jfr");
+        r.dump(path);
+        r.close();
+
+        Asserts.assertTrue(Files.exists(path), "Recording file does not exist: " + path);
+        Asserts.assertFalse(RecordingFile.readAllEvents(path).isEmpty(), "No events found");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/dump/TestDumpInvalid.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.dump;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.CommonHelper;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.VoidFunction;
+
+/*
+ * @test
+ * @summary Test copyTo and parse file
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.dump.TestDumpInvalid
+ */
+public class TestDumpInvalid {
+
+    public static void main(String[] args) throws Throwable {
+        Recording r = new Recording();
+        r.enable(EventNames.OSInformation);
+        r.start();
+        r.stop();
+
+        verifyNullPointer(()->{r.dump(null);}, "No NullPointerException");
+
+        Path pathNotExists = Paths.get(".", "dirNotExists", "my.jfr");
+        verifyFileNotFound(()->{r.dump(pathNotExists);}, "No Exception with missing dir");
+
+        Path pathEmpty = Paths.get("");
+        verifyFileNotFound(()->{r.dump(pathEmpty);}, "No Exception with empty path");
+
+        Path pathDir = Paths.get(".", "newdir");
+        Files.createDirectory(pathDir);
+        verifyFileNotFound(()->{r.dump(pathDir);}, "No Exception with dir");
+
+        // Verify that copyTo() works after all failed attempts.
+        Path pathOk = Paths.get(".", "newdir", "my.jfr");
+        r.dump(pathOk);
+        Asserts.assertTrue(Files.exists(pathOk), "Recording file does not exist: " + pathOk);
+        Asserts.assertFalse(RecordingFile.readAllEvents(pathOk).isEmpty(), "No events found");
+
+        r.close();
+    }
+
+    private static void verifyFileNotFound(VoidFunction f, String msg) throws Throwable {
+        CommonHelper.verifyException(f, msg, IOException.class);
+    }
+
+    private static void verifyNullPointer(VoidFunction f, String msg) throws Throwable {
+        CommonHelper.verifyException(f, msg, NullPointerException.class);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/dump/TestDumpLongPath.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.dump;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.FileHelper;
+
+/*
+ * @test
+ * @summary Test copyTo and parse file
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.dump.TestDumpLongPath
+ */
+public class TestDumpLongPath {
+
+    public static void main(String[] args) throws Exception {
+        Recording r = new Recording();
+        final String eventPath = EventNames.OSInformation;
+        r.enable(eventPath);
+        r.start();
+        r.stop();
+
+        Path dir = FileHelper.createLongDir(Paths.get("."));
+        Path path = Paths.get(dir.toString(), "my.jfr");
+        r.dump(path);
+        r.close();
+
+        Asserts.assertTrue(Files.exists(path), "Recording file does not exist: " + path);
+        List<RecordedEvent> events = RecordingFile.readAllEvents(path);
+        Asserts.assertFalse(events.isEmpty(), "No events found");
+        String foundEventPath = events.get(0).getEventType().getName();
+        System.out.printf("Found event: %s%n", foundEventPath);
+        Asserts.assertEquals(foundEventPath, eventPath, "Wrong event");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/dump/TestDumpMultiple.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.dump;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.SimpleEventHelper;
+
+/*
+ * @test
+ * @summary Test copyTo and parse file
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.dump.TestDumpMultiple
+ */
+public class TestDumpMultiple {
+
+    public static void main(String[] args) throws Exception {
+        Recording rA = new Recording();
+        Recording rB = new Recording();
+
+        // Enable event in one recording and disable in the other.
+        // Both recordings should still get the events, since we always
+        // get the "union" of all settings.
+        SimpleEventHelper.enable(rA, true);
+        SimpleEventHelper.enable(rB, false);
+
+        SimpleEventHelper.createEvent(0); // To no recording
+
+        rA.start();
+        SimpleEventHelper.createEvent(1); // Only to recA
+
+        rB.start();
+        SimpleEventHelper.createEvent(2); // To both recordings
+
+        rA.stop();
+
+        // This event will not be in recB.
+        // The reason is that recA has stopped so event is no longer enabled.
+        SimpleEventHelper.createEvent(3);
+
+        // Enable the event and create a new event for recB
+        SimpleEventHelper.enable(rB, true);
+        SimpleEventHelper.createEvent(4);
+
+        rB.stop();
+        SimpleEventHelper.createEvent(5); // To no recording
+
+        Path pathA = Paths.get(".", "recA.jfr");
+        Path pathB = Paths.get(".", "recB.jfr");
+        rA.dump(pathA);
+        rB.dump(pathB);
+        rB.close();
+        rA.close();
+
+        verifyRecording(pathA, 1, 2);
+        verifyRecording(pathB, 2, 4);
+    }
+
+    private static void verifyRecording(Path path, int... ids) throws Exception {
+        Asserts.assertTrue(Files.exists(path), "Recording file does not exist: " + path);
+        int countEvent = 0;
+        for (RecordedEvent event : RecordingFile.readAllEvents(path)) {
+            int id = Events.assertField(event, "id").getValue();
+            System.out.printf("Recording '%s' id=%d%n", path, id);
+            Asserts.assertTrue(ids.length > countEvent, "Found extra event");
+            Events.assertField(event, "id").equal(ids[countEvent]);
+            ++countEvent;
+        }
+        // We expect exactly 4 events in each file. 2 events * 2 chunks
+        Asserts.assertEquals(countEvent, ids.length, "Found too few events");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/dump/TestDumpReadOnly.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.dump;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import jdk.jfr.Recording;
+import jdk.test.lib.jfr.CommonHelper;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.FileHelper;
+import jdk.test.lib.jfr.VoidFunction;
+
+/*
+ * @test
+ * @summary Test copyTo and parse file
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.dump.TestDumpReadOnly
+ */
+public class TestDumpReadOnly {
+
+    private static final String OS_INFORMATION = EventNames.OSInformation;
+
+    public static void main(String[] args) throws Throwable {
+
+        Path readOnlyDir = FileHelper.createReadOnlyDir(Paths.get(".", "readonlydir"));
+        if (!FileHelper.isReadOnlyPath(readOnlyDir)) {
+            System.out.println("Failed to create read-only path. Maybe running a root? Test skipped");
+            return;
+        }
+        Recording r = new Recording();
+        r.enable(OS_INFORMATION);
+        r.start();
+        r.stop();
+        Path path = Paths.get(readOnlyDir.toString(), "my.jfr");
+        verifyException(()->{r.dump(path);}, "No Exception when dumping read-only dir");
+        r.close();
+    }
+
+    private static void verifyException(VoidFunction f, String msg) throws Throwable {
+        CommonHelper.verifyException(f, msg, IOException.class);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/dump/TestDumpState.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.dump;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.CommonHelper;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.SimpleEvent;
+import jdk.test.lib.jfr.SimpleEventHelper;
+import jdk.test.lib.jfr.VoidFunction;
+
+/*
+ * @test
+ * @summary call copyTo() with recording in all states.
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.dump.TestDumpState
+ */
+public class TestDumpState {
+
+    public static void main(String[] args) throws Throwable {
+        Recording r = new Recording();
+        SimpleEventHelper.enable(r, true);
+
+        List<Integer> expectedIds = new ArrayList<>();
+
+        SimpleEventHelper.createEvent(0); // Recording not started, should not be included.
+        verifyIOException(()->{checkEvents(r, expectedIds);}, "No Exception when dump() not started");
+
+        r.start();
+        SimpleEventHelper.createEvent(1);
+        expectedIds.add(1);
+        checkEvents(r, expectedIds);
+
+        SimpleEventHelper.createEvent(2);
+        expectedIds.add(2);
+        checkEvents(r, expectedIds);
+
+        r.stop();
+        checkEvents(r, expectedIds);
+
+        SimpleEventHelper.createEvent(3); // Recording stopped, should not be included.
+        checkEvents(r, expectedIds);
+
+        r.close();
+        SimpleEventHelper.createEvent(4);
+        verifyIOException(()->{checkEvents(r, expectedIds);}, "No Exception when dump() closed");
+    }
+
+    private static int recordingCounter = 0;
+    private static void checkEvents(Recording r, List<Integer> expectedIds) throws Exception {
+        Path path = Paths.get(".", String.format("%d.jfr", recordingCounter++));
+        r.dump(path);
+        Asserts.assertTrue(Files.exists(path), "Recording file does not exist: " + path);
+
+        int index = 0;
+
+        for (RecordedEvent event : RecordingFile.readAllEvents(path)) {
+            Events.isEventType(event, SimpleEvent.class.getName());
+            Integer id = Events.assertField(event, "id").getValue();
+            System.out.println("Got event with id " + id);
+            Asserts.assertGreaterThan(expectedIds.size(), index, "Too many Events found");
+            Asserts.assertEquals(id, expectedIds.get(index), "Wrong id at index " + index);
+            ++index;
+        }
+        Asserts.assertEquals(index, expectedIds.size(), "Too few Events found");
+    }
+
+    private static void verifyIOException(VoidFunction f, String msg) throws Throwable {
+        CommonHelper.verifyException(f, msg, IOException.class);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/event/TEST.properties	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,2 @@
+modules = java.management
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/event/TestChunkPeriod.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.event;
+
+import java.io.IOException;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.List;
+
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.SimpleEvent;
+
+/*
+ * @test
+ * @summary Test periodic setting that involves chunks.
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.event.TestChunkPeriod
+ */
+public class TestChunkPeriod {
+
+    // Margin of error is to avoid issues where JFR and
+    // System.currentMillis take the clock differently
+    private static final Duration MARGIN_OF_ERROR = Duration.ofNanos(1_000_000_000); // 1 s
+
+    public static void main(String[] args) throws Throwable {
+        FlightRecorder.addPeriodicEvent(SimpleEvent.class, () -> {
+            SimpleEvent  pe = new SimpleEvent();
+            pe.commit();
+        });
+        testBeginChunk();
+        testEndChunk();
+        testEveryChunk();
+    }
+
+    private static void testBeginChunk() throws IOException {
+        Recording r = new Recording();
+        r.enable(SimpleEvent.class).with("period", "beginChunk");
+        Instant beforeStart = Instant.now().minus(MARGIN_OF_ERROR);
+        r.start();
+        Instant afterStart = Instant.now().plus(MARGIN_OF_ERROR);
+        r.stop();
+        List<RecordedEvent> events = Events.fromRecording(r);
+        Asserts.assertEquals(events.size(), 1, "Expected one event with beginChunk");
+        RecordedEvent event = events.get(0);
+        Asserts.assertGreaterThanOrEqual(event.getStartTime(), beforeStart);
+        Asserts.assertGreaterThanOrEqual(afterStart, event.getStartTime());
+        r.close();
+    }
+
+    private static void testEndChunk() throws IOException {
+        Recording r = new Recording();
+        r.enable(SimpleEvent.class).with("period", "endChunk");
+        r.start();
+        Instant beforeStop = Instant.now().minus(MARGIN_OF_ERROR);
+        r.stop();
+        Instant afterStop =  Instant.now().plus(MARGIN_OF_ERROR);
+        List<RecordedEvent> events = Events.fromRecording(r);
+        Asserts.assertEquals(events.size(), 1, "Expected one event with endChunk");
+        RecordedEvent event = events.get(0);
+        Asserts.assertGreaterThanOrEqual(event.getStartTime(), beforeStop);
+        Asserts.assertGreaterThanOrEqual(afterStop, event.getStartTime());
+        r.close();
+    }
+
+    private static void testEveryChunk() throws IOException {
+        Recording r = new Recording();
+        r.enable(SimpleEvent.class).with("period", "everyChunk");
+        r.start();
+        r.stop();
+        List<RecordedEvent> events = Events.fromRecording(r);
+        Asserts.assertEquals(events.size(), 2, "Expected two events with everyChunk");
+        r.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/event/TestEnableClass.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.event;
+
+import jdk.jfr.Recording;
+import jdk.test.lib.jfr.SimpleEventHelper;
+
+/*
+ * @test
+ * @summary Simple enable Event class.
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.event.TestEnableClass
+ */
+public class TestEnableClass {
+
+    public static void main(String[] args) throws Throwable {
+        Recording r = new Recording();
+        SimpleEventHelper.enable(r, true);
+        SimpleEventHelper.createEvent(0);
+        r.start();
+        SimpleEventHelper.createEvent(1);
+        r.stop();
+        SimpleEventHelper.createEvent(2);
+        SimpleEventHelper.verifyEvents(r, 1);
+        r.close();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/event/TestEnableName.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.event;
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Iterator;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Simple enable Event class.
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.event.TestEnableName
+ */
+public class TestEnableName {
+
+    public static void main(String[] args) throws Throwable {
+        Recording r = new Recording();
+        final String eventType = EventNames.FileWrite;
+        r.enable(eventType).withoutStackTrace();
+        r.start();
+        Files.write(Paths.get(".", "dummy.txt"), "DummyFile".getBytes());
+        r.stop();
+
+        Iterator<RecordedEvent> iterator = Events.fromRecording(r).iterator();
+        Asserts.assertTrue(iterator.hasNext(), "No events found");
+        System.out.printf("Event:%n%s%n", iterator.next());
+        r.close();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/event/TestEventTime.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.event;
+
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import jdk.jfr.Event;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.CommonHelper;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Test getStartTime() and getEndTime(). Verify startTime <= endTime
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.event.TestEventTime
+ */
+public class TestEventTime {
+
+    static List<TimeEvent> actualOrder = new ArrayList<>();
+
+    public static void main(String[] args) throws Throwable {
+        Recording r = new Recording();
+        r.enable(MyEvent.class).withoutStackTrace();
+        // for debugging time related issues
+        r.enable(EventNames.CPUTimeStampCounter);
+        r.start();
+        MyEvent event1 = beginEvent(1);
+        MyEvent event2 = beginEvent(2);
+        endEvent(event1);
+        MyEvent event3 = beginEvent(3);
+        endEvent(event2);
+        endEvent(event3);
+
+        r.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(r);
+
+        RecordedEvent recEvent1 = findEvent(1, events);
+        RecordedEvent recEvent2 = findEvent(2, events);
+        RecordedEvent recEvent3 = findEvent(3, events);
+
+        List<TimeEvent> recordedOrder = new ArrayList<>();
+        recordedOrder.add(new TimeEvent(1, true, recEvent1.getStartTime()));
+        recordedOrder.add(new TimeEvent(1, false, recEvent1.getEndTime()));
+        recordedOrder.add(new TimeEvent(2, true, recEvent2.getStartTime()));
+        recordedOrder.add(new TimeEvent(2, false, recEvent2.getEndTime()));
+        recordedOrder.add(new TimeEvent(3, true, recEvent3.getStartTime()));
+        recordedOrder.add(new TimeEvent(3, false, recEvent3.getEndTime()));
+        Collections.sort(recordedOrder);
+
+        printTimedEvents("Actual order", actualOrder);
+        printTimedEvents("Recorded order", recordedOrder);
+
+        for (int i = 0; i < 6; i++) {
+            if (!actualOrder.get(i).equals(recordedOrder.get(i))) {
+                throw new Exception("Event times not in expected order. Was " + recordedOrder.get(1) + " but expected " + actualOrder.get(1));
+            }
+        }
+    }
+
+    private static void printTimedEvents(String heading, List<TimeEvent> recordedOrder) {
+        System.out.println();
+        System.out.println(heading);
+        System.out.println("======================");
+        for (TimeEvent t : recordedOrder) {
+            System.out.println(t.toString());
+        }
+    }
+
+    private static MyEvent beginEvent(int id) throws Exception {
+        MyEvent event = new MyEvent(id);
+        event.begin();
+        if (!CommonHelper.hasFastTimeEnabled()) {
+            CommonHelper.waitForSystemCurrentMillisToChange();;
+        }
+        actualOrder.add(new TimeEvent(id, true));
+        return event;
+    }
+
+    private static void endEvent(MyEvent event) throws Exception {
+        event.end();
+        if (!CommonHelper.hasFastTimeEnabled()) {
+            CommonHelper.waitForSystemCurrentMillisToChange();;
+        }
+        event.commit();
+        actualOrder.add(new TimeEvent(event.id, false));
+    }
+
+    private final static class TimeEvent implements Comparable<TimeEvent> {
+        long id;
+        private boolean begin;
+        private Instant time;
+
+        public TimeEvent(int id, boolean begin) {
+            this.id = id;
+            this.begin = begin;
+        }
+
+        public TimeEvent(int id, boolean begin, Instant time) {
+            this(id, begin);
+            this.time = time;
+        }
+
+        @Override
+        public int compareTo(TimeEvent that) {
+            return this.time.compareTo(that.time);
+        }
+
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            if (begin) {
+                sb.append("begin");
+            } else {
+                sb.append("end");
+            }
+            sb.append("Event");
+            sb.append("(");
+            sb.append(id);
+            sb.append(")");
+            return sb.toString();
+        }
+
+        public boolean equals(Object thatObject) {
+            if (thatObject instanceof TimeEvent) {
+                TimeEvent that = (TimeEvent) thatObject;
+                return that.id == this.id && that.begin == this.begin;
+            }
+            return false;
+        }
+    }
+
+    private static RecordedEvent findEvent(int id, List<RecordedEvent> events) {
+        for (RecordedEvent event : events) {
+            if (!event.getEventType().getName().equals(EventNames.CPUTimeStampCounter)) {
+                int eventId = Events.assertField(event, "id").getValue();
+                if (eventId == id) {
+                    return event;
+                }
+            }
+        }
+        Asserts.fail("No event with id " + id);
+        return null;
+    }
+
+    private static class MyEvent extends Event {
+        int id;
+
+        public MyEvent(int id) {
+            this.id = id;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/event/TestLoadEventAfterStart.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.event;
+
+import java.lang.reflect.Constructor;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Event;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Load event class after recording started.
+ * @key jfr
+ * @library /test/lib
+ * @build jdk.test.lib.jfr.SimpleEvent
+ * @run main/othervm jdk.jfr.api.recording.event.TestLoadEventAfterStart
+ */
+public class TestLoadEventAfterStart {
+
+    public static void main(String[] args) throws Throwable {
+        Recording r = new Recording();
+        r.start();
+
+        ClassLoader classLoader = TestLoadEventAfterStart.class.getClassLoader();
+        Class<? extends Event> eventClass =
+            classLoader.loadClass("jdk.test.lib.jfr.SimpleEvent").asSubclass(Event.class);
+
+        r.enable(eventClass).withThreshold(Duration.ofMillis(0)).withoutStackTrace();
+        createEvent(eventClass, 1);
+        r.disable(eventClass);
+        createEvent(eventClass, 2);
+        r.enable(eventClass).withThreshold(Duration.ofMillis(0)).withoutStackTrace();
+        createEvent(eventClass, 3);
+
+        r.stop();
+        verifyEvents(r, 1, 3);
+    }
+
+    private static void verifyEvents(Recording r, int ... ids) throws Exception {
+        List<Integer> eventIds = new ArrayList<>();
+        for (RecordedEvent event : Events.fromRecording(r)) {
+            int id = Events.assertField(event, "id").getValue();
+            System.out.println("Event id:" + id);
+            eventIds.add(id);
+        }
+        Asserts.assertEquals(eventIds.size(), ids.length, "Wrong number of events");
+        for (int i = 0; i < ids.length; ++i) {
+            Asserts.assertEquals(eventIds.get(i).intValue(), ids[i], "Wrong id in event");
+        }
+    }
+
+    private static void createEvent(Class<? extends Event> eventClass, int id) throws Exception {
+        Constructor<? extends Event> constructor = eventClass.getConstructor();
+        Event event = (Event) constructor.newInstance();
+        event.begin();
+        eventClass.getDeclaredField("id").setInt(event, id);
+        event.end();
+        event.commit();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/event/TestPeriod.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.event;
+
+import java.io.IOException;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedThread;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Test event period.
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.event.TestPeriod
+ */
+public class TestPeriod {
+    private static final String EVENT_PATH = EventNames.ThreadAllocationStatistics;
+    private static final long ERROR_MARGIN = 20; // 186 ms has been measured, when period was set to 200 ms
+
+    public static void main(String[] args) throws Throwable {
+        long[] periods = { 100, 200 };
+        int eventCount = 4;
+        int deltaCount;
+        for (long period : periods) {
+            List<Long> deltaBetweenEvents;
+            do {
+                deltaBetweenEvents = createPeriodicEvents(period, eventCount);
+                deltaCount = deltaBetweenEvents.size();
+                if (deltaCount < eventCount - 1) {
+                    System.out.println("Didn't get sufficent number of events. Retrying...");
+                    System.out.println();
+                }
+            } while (deltaCount < eventCount - 1);
+            for (int i = 0; i < eventCount - 1; i++) {
+                verifyDelta(deltaBetweenEvents.get(i), period);
+            }
+            System.out.println();
+        }
+    }
+
+    private static List<Long> createPeriodicEvents(long period, int eventCount) throws Exception, IOException {
+        System.out.println("Provoking events with period " + period + " ms");
+        Recording r = new Recording();
+        r.start();
+        runWithPeriod(r, period, eventCount + 1);
+        r.stop();
+
+        long prevTime = -1;
+        List<Long> deltas = new ArrayList<>();
+        for (RecordedEvent event : Events.fromRecording(r)) {
+            if (Events.isEventType(event, EVENT_PATH) && isMyThread(event)) {
+                long timeMillis = event.getEndTime().toEpochMilli();
+                if (prevTime != -1) {
+                    long delta = timeMillis - prevTime;
+                    deltas.add(delta);
+                    System.out.printf("event: time=%d, delta=%d%n", timeMillis, delta);
+                }
+                prevTime = timeMillis;
+            }
+        }
+        r.close();
+        return deltas;
+    }
+
+    // We only check that time is at least as expected.
+    // We ignore if time is much longer than expected, since anything can happen
+    // during heavy load,
+    private static void verifyDelta(long actual, long expected) {
+        System.out.printf("verifyDelta: actaul=%d, expected=%d (errorMargin=%d)%n", actual, expected, ERROR_MARGIN);
+        Asserts.assertGreaterThan(actual, expected - ERROR_MARGIN, "period delta too short");
+    }
+
+    private static boolean isMyThread(RecordedEvent event) {
+        Object o = event.getValue("thread");
+        if (o instanceof RecordedThread) {
+            RecordedThread rt = (RecordedThread) o;
+            return Thread.currentThread().getId() == rt.getJavaThreadId();
+        }
+        return false;
+    }
+
+    @SuppressWarnings("unused")
+    private static byte[] dummy = null;
+
+    // Generate at least minEvents event with given period
+    private static void runWithPeriod(Recording r, long period, int minEventCount) throws Exception {
+        r.enable(EVENT_PATH).withPeriod(Duration.ofMillis(period));
+        long endTime = System.currentTimeMillis() + period * minEventCount;
+        while (System.currentTimeMillis() < endTime) {
+            dummy = new byte[100];
+            Thread.sleep(1);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/event/TestReEnableClass.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.event;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.test.lib.jfr.SimpleEventHelper;
+
+/*
+ * @test
+ * @summary Enable, disable, enable event during recording.
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.event.TestReEnableClass
+ */
+public class TestReEnableClass {
+
+    public static void main(String[] args) throws Throwable {
+        test(false);
+        test(true);
+    }
+
+    // Loop and enable/disable events.
+    // Verify recording only contains event created during enabled.
+    private static void test(boolean isEnabled) throws Exception {
+        System.out.println("Start with isEnabled = " + isEnabled);
+
+        List<Integer> expectedIds = new ArrayList<>();
+        Recording r = new Recording();
+        SimpleEventHelper.enable(r, isEnabled);
+        r.start();
+
+        for (int i = 0; i < 10; ++i) {
+            SimpleEventHelper.createEvent(i);
+            if (isEnabled) {
+                expectedIds.add(i);
+            }
+            isEnabled = !isEnabled;
+            SimpleEventHelper.enable(r, isEnabled);
+        }
+
+        r.stop();
+        SimpleEventHelper.createEvent(100);
+
+        int[] ids = new int[expectedIds.size()];
+        for (int i = 0; i < expectedIds.size(); ++i) {
+            ids[i] = expectedIds.get(i);
+        }
+        SimpleEventHelper.verifyEvents(r, ids);
+
+        r.close();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/event/TestReEnableMultiple.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.event;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Random;
+
+import jdk.jfr.EventType;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.SimpleEvent;
+import jdk.test.lib.jfr.SimpleEventHelper;
+
+/*
+ * @test
+ * @summary Enable, disable, enable event during recording.
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.event.TestReEnableMultiple
+ */
+public class TestReEnableMultiple {
+    private static final String EVENT_PATH = EventNames.FileWrite;
+    private static final Random rand = new Random(0);
+
+    public static void main(String[] args) throws Throwable {
+        Recording rA = new Recording();
+        Recording rB = new Recording();
+
+        final Path path = Paths.get(".", "dummy.txt").toAbsolutePath();
+        rA.start();
+        rB.start();
+
+        SimpleEventHelper.enable(rA, false);
+        SimpleEventHelper.enable(rA, false);
+
+        int expectedMyEvents = 0;
+        int expectedIoEvents = 0;
+        for (int i = 0; i < 20; ++i) {
+            SimpleEventHelper.createEvent(i);
+            if (isMyEventEnabled(rA, rB)) {
+                expectedMyEvents++;
+                System.out.println("Expect MyEvent.id " + i);
+            }
+
+            Files.write(path, "A".getBytes());
+            if (isIoEnabled(rA, rB)) {
+                expectedIoEvents++;
+            }
+
+            for (int j = 0; j < 4; ++j) {
+                Recording r = (rand.nextInt(2) == 0) ? rA : rB;
+                updateSettings(r);
+            }
+        }
+
+        rA.stop();
+        rB.stop();
+
+        verifyEventCount(rA, expectedMyEvents, expectedIoEvents, path);
+        verifyEventCount(rB, expectedMyEvents, expectedIoEvents, path);
+
+        rA.close();
+        rB.close();
+    }
+
+    private static void verifyEventCount(Recording r, int expectedMyEvents, int expectedIoEvents, Path path) throws Exception {
+        int actualMyEvents = 0;
+        int actualIoEvents = 0;
+        for (RecordedEvent event : Events.fromRecording(r)) {
+            if (Events.isEventType(event, EVENT_PATH)) {
+                if (path.toString().equals(Events.assertField(event, "path").getValue())) {
+                    actualIoEvents++;
+                }
+            } else {
+                Asserts.assertTrue(Events.isEventType(event, SimpleEvent.class.getName()));
+                System.out.println("Got MyEvent.id=" + Events.assertField(event, "id").getValue());
+                actualMyEvents++;
+            }
+        }
+        System.out.printf("MyEvents: expected=%d, actual=%d%n", expectedMyEvents, actualMyEvents);
+        System.out.printf("IoEvents: expected=%d, actual=%d%n", expectedIoEvents, actualIoEvents);
+        Asserts.assertEquals(expectedMyEvents, actualMyEvents, "Wrong number of MyEvents");
+        Asserts.assertEquals(expectedIoEvents, actualIoEvents, "Wrong number of IoEvents");
+    }
+
+    private static void updateSettings(Recording r) {
+        boolean doEnable = rand.nextInt(3) == 0; // Disable 2 of 3, since event
+                                                 // is enabled by union of
+                                                 // recordings.
+        boolean doMyEvent = rand.nextInt(2) == 0;
+        if (doMyEvent) {
+            SimpleEventHelper.enable(r, doEnable);
+        } else {
+            if (doEnable) {
+                r.enable(EVENT_PATH).withoutStackTrace();
+            } else {
+                r.disable(EVENT_PATH);
+            }
+        }
+    }
+
+    private static boolean isMyEventEnabled(Recording rA, Recording rB) {
+        long eventTypeId = EventType.getEventType(SimpleEvent.class).getId();
+        String settingName = eventTypeId + "#enabled";
+        return isEnabled(rA, settingName) || isEnabled(rB, settingName);
+    }
+
+    private static boolean isIoEnabled(Recording rA, Recording rB) {
+        String settingName = EVENT_PATH + "#enabled";
+        return isEnabled(rA, settingName) || isEnabled(rB, settingName);
+    }
+
+    private static boolean isEnabled(Recording r, String settingName) {
+        // System.out.printf("R(%s) %s=%s%n", r.getName(), settingName,
+        // r.getSettings().get(settingName));
+        return Boolean.parseBoolean(r.getSettings().get(settingName));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/event/TestReEnableName.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.event;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Enable/disable event by name during recording.
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.event.TestReEnableName
+ */
+public class TestReEnableName {
+
+    public static void main(String[] args) throws Throwable {
+        testRecordingWithEnabledEvent(EventNames.FileWrite, false);
+        testRecordingWithEnabledEvent(EventNames.FileWrite, true);
+    }
+
+    // Loop and enable/disable events. Create events each loop.
+    // Verify we only get events created during enabled.
+    private static void testRecordingWithEnabledEvent(String eventname, boolean enabled) throws Exception {
+        System.out.println("Testing enabled=" + enabled + " for " + eventname);
+        final Path pathDisabled = Paths.get(".", "disabled.txt").toAbsolutePath();
+        final Path pathEnabled = Paths.get(".", "enabled.txt").toAbsolutePath();
+
+        Recording r = new Recording();
+        if (enabled) {
+            r.enable(eventname).withoutThreshold().withoutStackTrace();
+        } else {
+            r.disable(eventname).withoutThreshold().withoutStackTrace();
+        }
+        r.start();
+
+        // We should only get events for pathEnabled, not for pathDisabled.
+        int countExpectedEvents = 0;
+        for (int i = 0; i < 10; ++i) {
+            if (enabled) {
+                Files.write(pathEnabled, "E".getBytes());
+                ++countExpectedEvents;
+                r.disable(eventname);
+            } else {
+                Files.write(pathDisabled, "D".getBytes());
+                r.enable(eventname);
+            }
+            enabled = !enabled;
+        }
+        r.stop();
+
+        int countFoundEvents = 0;
+        for (RecordedEvent event : Events.fromRecording(r)) {
+            System.out.printf("Event %s%n", event);
+            Asserts.assertEquals(eventname, event.getEventType().getName(), "Wrong event type");
+            String path = Events.assertField(event, "path").getValue();
+            System.out.println(path);
+            if (pathEnabled.toString().equals(path)) {
+                ++countFoundEvents;
+            }
+        }
+        Asserts.assertGreaterThanOrEqual(countFoundEvents, countExpectedEvents, "Too few events found");
+
+        r.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/event/TestRecordingEnableDisable.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.event;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Random;
+
+import jdk.jfr.EventType;
+import jdk.jfr.Recording;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.SimpleEvent;
+import jdk.test.lib.jfr.SimpleEventHelper;
+
+/*
+ * @test
+ * @summary Enable, disable, enable event during recording.
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.event.TestRecordingEnableDisable
+ */
+public class TestRecordingEnableDisable {
+    private static final String EVENT_PATH = "java.file_write";
+    private static final Random rand = new Random(0);
+
+    public static void main(String[] args) throws Throwable {
+
+        Recording rA = new Recording();
+        Recording rB = new Recording();
+
+        rA.setName("rA");
+        rB.setName("rB");
+
+        final Path path = Paths.get(".", "my.jfr");
+        rA.start();
+        rB.start();
+
+        for (int i = 0; i < 30; ++i) {
+            SimpleEventHelper.createEvent(i);
+            if (isMyEventEnabled(rA, rB)) {
+                System.out.println("MyEvent enabled");
+            }
+            else {
+                System.out.println("MyEvent disabled");
+            }
+
+            Files.write(path, "A".getBytes());
+            if (isIoEnabled(rA, rB)) {
+                System.out.println("IoEvent enabled");
+            }
+            else {
+                System.out.println("IoEvent disabled");
+            }
+            Recording r = ((i % 2) == 0) ? rA : rB;
+            updateSettings(r);
+        }
+
+        rA.stop();
+        rB.stop();
+        rA.close();
+        rB.close();
+    }
+
+
+    private static void updateSettings(Recording r) {
+        int operationIndex = rand.nextInt(4);
+        switch (operationIndex) {
+            case 0:
+                SimpleEventHelper.enable(r, true);
+                break;
+            case 1:
+                SimpleEventHelper.enable(r, false);
+                break;
+            case 2:
+                r.enable(EVENT_PATH).withoutStackTrace();
+                break;
+            case 3:
+                r.disable(EVENT_PATH);
+                break;
+            default:
+                Asserts.fail("Wrong operataionIndex. Test error");
+            }
+    }
+
+    private static boolean isMyEventEnabled(Recording rA, Recording rB) {
+        long eventTypeId = EventType.getEventType(SimpleEvent.class).getId();
+        String settingName = "@" + eventTypeId + "#enabled";
+        return isEnabled(rA, settingName) || isEnabled(rB, settingName);
+    }
+
+    private static boolean isIoEnabled(Recording rA, Recording rB) {
+        String settingName = EVENT_PATH + "#enabled";
+        return isEnabled(rA, settingName) || isEnabled(rB, settingName);
+    }
+
+    private static boolean isEnabled(Recording r, String settingName) {
+        System.out.printf("R(%s) %s=%s%n", r.getName(), settingName, r.getSettings().get(settingName));
+        return Boolean.parseBoolean(r.getSettings().get(settingName));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/event/TestThreshold.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.event;
+
+import java.time.Duration;
+import java.util.List;
+
+import jdk.jfr.Event;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Test event threshold.
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.event.TestThreshold
+ */
+public class TestThreshold {
+
+    public static void main(String[] args) throws Throwable {
+        Recording r = new Recording();
+
+        r.start();
+        r.enable(MyEvent.class).withThreshold(Duration.ofMillis(500));
+        createEvent(0, 100);
+        createEvent(1, 600);
+        createEvent(2, 100);
+        r.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(r);
+        Asserts.assertTrue(1 <= events.size(), "Should get at most 1 event");
+        r.close();
+    }
+
+    private static void createEvent(int id, long duration) throws Exception {
+        MyEvent event = new MyEvent(id);
+        long start = System.currentTimeMillis();
+
+        event.begin();
+        sleepUntil(start + duration);
+        event.end();
+
+        long actualDuration = System.currentTimeMillis() - start;
+        System.out.printf("targetDuration=%d, actualDuration=%d, shouldCommit=%b%n",
+        duration, actualDuration, event.shouldCommit());
+        event.commit();
+    }
+
+    private static void sleepUntil(long endTime) throws Exception {
+        long sleepTime = endTime - System.currentTimeMillis();
+        while(sleepTime > 0) {
+            Thread.sleep(sleepTime);
+            sleepTime = endTime - System.currentTimeMillis();
+        }
+    }
+
+    static class MyEvent extends Event {
+        public int id;
+        public MyEvent(int id) {
+            this.id = id;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/misc/TestGetId.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.misc;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import jdk.jfr.Recording;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @summary Verify that each recording get unique a id
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm  jdk.jfr.api.recording.misc.TestGetId
+ */
+public class TestGetId {
+
+    public static void main(String[] args) throws Throwable {
+        Map<Long, Recording> recordings = new HashMap<>();
+
+        final int iterations = 100;
+        for (int i = 0; i < iterations; ++i) {
+            Recording newRecording = new Recording();
+            System.out.println("created: " + newRecording.getId());
+            Recording oldRecording = recordings.get(newRecording.getId());
+            Asserts.assertNull(oldRecording, "Duplicate recording ID: " + newRecording.getId());
+            recordings.put(newRecording.getId(), newRecording);
+
+            if (i % 3 == 0) {
+                Recording closeRecording = recordings.remove(recordings.keySet().iterator().next());
+                Asserts.assertNotNull(closeRecording, "Could not find recording in map. Test error.");
+                closeRecording.close();
+                System.out.println("closed: " + closeRecording.getId());
+            }
+        }
+
+        for (Recording r : recordings.values()) {
+            r.close();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/misc/TestGetSize.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.misc;
+
+import static jdk.test.lib.Asserts.assertEquals;
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import jdk.jfr.Recording;
+import jdk.test.lib.jfr.EventNames;
+
+/*
+ * @test
+ * @summary Test recording file size with Recording.getSize()
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.misc.TestGetSize
+ */
+public class TestGetSize {
+
+    public static void main(String[] args) throws Throwable {
+        Path dest = Paths.get(".", "my.jfr");
+        Recording r = new Recording();
+        r.setToDisk(true);
+        r.enable(EventNames.OSInformation);
+        assertEquals(r.getSize(), 0L, "getSize should return 0 before recording starts");
+        r.start();
+        r.stop();
+        r.dump(dest);
+        assertTrue(Files.exists(dest), "TestGetSize recording missing: " + dest);
+        System.out.printf("%s size: %d%n", dest, Files.size(dest));
+        System.out.printf("r.getSize(): %d%n", r.getSize());
+        assertEquals(Files.size(dest), r.getSize(), "TestGetSize wrong recording size");
+        r.close();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/misc/TestGetSizeToMem.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.misc;
+
+import static jdk.test.lib.Asserts.assertEquals;
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import jdk.jfr.Recording;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+
+/*
+ * @test
+ * @summary Test recording file size with Recording.getSize()
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.misc.TestGetSizeToMem
+ */
+public class TestGetSizeToMem {
+
+
+    public static void main(String[] args) throws Throwable {
+        Path dest = Paths.get(".", "my.jfr");
+        Recording r = new Recording();
+        r.setToDisk(false);
+        r.setDestination(dest);
+        r.enable(EventNames.OSInformation);
+        r.start();
+        r.stop();
+        r.close();
+        assertTrue(Files.exists(dest), "TestGetSize recording missing: " + dest);
+        System.out.printf("%s size: %d%n", dest, Files.size(dest));
+        System.out.printf("r.getSize(): %d%n", r.getSize());
+        Asserts.assertNotEquals(Files.size(dest), 0L, "File should not be empty");
+        assertEquals(r.getSize(), 0L, "r.getSize() should be 0 after setToDisk(false)");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/misc/TestGetStream.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.api.recording.misc;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.SimpleEvent;
+
+/*
+ * @test
+ * @summary A simple test for Recording.getStream()
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.misc.TestGetStream
+ */
+public class TestGetStream {
+
+    private final static Instant offset = Instant.now();
+    private static Instant previous;
+
+    public static void main(String[] args) throws Exception {
+
+        Recording recording = new Recording();
+        Instant t0 = newTimestamp();
+        recording.start();
+        Instant t1 = newTimestamp();
+        createChunkWithId(1);
+        Instant t2 = newTimestamp();
+        createChunkWithId(2);
+        Instant t3 = newTimestamp();
+        createChunkWithId(3);
+        Instant t4 = newTimestamp();
+        recording.stop();
+        Instant t5 = newTimestamp();
+        printTimeStamp("t0", t0);
+        printTimeStamp("t1", t1);
+        printTimeStamp("t2", t2);
+        printTimeStamp("t3", t3);
+        printTimeStamp("t4", t4);
+        printTimeStamp("t5", t5);
+
+        assertContainsId(recording, "t1-t4", t1, t4, 1, 2, 3);
+        assertContainsId(recording, "t1-t3", t1, t3, 1, 2);
+        assertContainsId(recording, "t2-t4", t2, t4, 2, 3);
+        assertContainsId(recording, "t1-t2", t1, t2, 1);
+        assertContainsId(recording, "t2-t3", t2, t3, 2);
+        assertContainsId(recording, "t3-t4", t3, t4, 3);
+        assertContainsId(recording, "t0-t1", t0, t1);
+        assertContainsId(recording, "t4-t5", t4, t5);
+
+        assertEndBeforeBegin();
+    }
+
+    private static void printTimeStamp(String name, Instant t) {
+        Duration s = Duration.between(offset, t);
+        System.out.println(name + ": " + (s.getSeconds() * 1_000_000_000L + s.getNano()));
+    }
+
+    private static void createChunkWithId(int id) throws InterruptedException {
+        newTimestamp(); // ensure every recording gets a unique start time
+        try (Recording r = new Recording()) {
+            r.start();
+            SimpleEvent s = new SimpleEvent();
+            s.id = id;
+            s.commit();
+            r.stop();
+            newTimestamp(); // ensure that start time is not equal to stop time
+        }
+        newTimestamp(); // ensure every recording gets a unique stop time
+    }
+
+    // Create a timestamp that is not same as the previous one
+    private static Instant newTimestamp() throws InterruptedException {
+        while (true) {
+            Instant now = Instant.now();
+            if (!now.equals(previous)) {
+                previous = now;
+                return now;
+            }
+            Thread.sleep(1);
+        }
+    }
+
+    private static void assertContainsId(Recording r, String interval, Instant start, Instant end, Integer... ids) throws IOException {
+        List<Integer> idList = new ArrayList<>(Arrays.asList(ids));
+        long time = System.currentTimeMillis();
+        String fileName = idList.stream().map(x -> x.toString()).collect(Collectors.joining("_", "recording-get-stream_" + time + "_", ".jfr"));
+        Path file = Paths.get(fileName);
+        try (InputStream is = r.getStream(start, end)) {
+            Files.copy(is, file, StandardCopyOption.REPLACE_EXISTING);
+        }
+        try (RecordingFile rf = new RecordingFile(file)) {
+            while (rf.hasMoreEvents()) {
+                RecordedEvent event = rf.readEvent();
+                Integer id = event.getValue("id");
+                Asserts.assertTrue(idList.contains(id), "Unexpected id " + id + " found in interval " + interval);
+                idList.remove(id);
+            }
+            Asserts.assertTrue(idList.isEmpty(), "Expected events with ids " + idList);
+        }
+    }
+
+    private static void assertEndBeforeBegin() throws IOException {
+        try (Recording recording = new Recording()) {
+            recording.start();
+            recording.stop();
+            Instant begin = Instant.now();
+            Instant end = begin.minusNanos(1);
+            recording.getStream(begin, end);
+            Asserts.fail("Expected IllegalArgumentException has not been thrown");
+        } catch (IllegalArgumentException x) {
+            // Caught the expected exception
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/misc/TestRecordingBase.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.misc;
+
+import static jdk.test.lib.Asserts.assertEquals;
+import static jdk.test.lib.Asserts.assertFalse;
+import static jdk.test.lib.Asserts.assertNotEquals;
+import static jdk.test.lib.Asserts.assertNotNull;
+import static jdk.test.lib.Asserts.assertNull;
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.Duration;
+import java.util.Map;
+
+import jdk.jfr.Recording;
+import jdk.jfr.RecordingState;
+
+/*
+ * @test
+ * @summary Basic tests for Recording
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.misc.TestRecordingBase
+ */
+public class TestRecordingBase {
+
+    public static void main(String[] args) throws Throwable {
+        testUninitialized();
+        testUniqueIdentifier();
+        testSetGetName();
+        testSetGetDuration();
+        testSetGetMaxAge();
+        testSetGetDestination();
+        testSetGetDumpOnExit();
+        testSetGetToDisk();
+        testSetGetToMaxSize();
+        testGetSettings();
+    }
+
+    public static void testUninitialized() throws Throwable {
+       Recording r = new Recording();
+       assertNull(r.getDuration(), "Wrong uninitialized duration");
+       assertNull(r.getStartTime(), "Wrong uninitialized startTime");
+       assertNull(r.getStopTime(), "Wrong uninitialized stopTime");
+       assertNull(r.getDestination(), "Wrong uninitialized destination");
+       assertNull(r.getMaxAge(), "Wrong uninitialized maxAge");
+       assertEquals(0L, r.getMaxSize(), "Wrong uninitialized maxSize"); // TODO: Should this be null? Why Long if never null?
+       assertEquals(0L, r.getSize(), "Wrong uninitialized size");
+       assertNotNull(r.getName(), "Uninitialized name should not be null");
+       assertFalse(r.getName().isEmpty(), "Uninitialized name should not be empty");
+       assertEquals(r.getState(), RecordingState.NEW, "Wrong uninitialized state");
+       assertTrue(r.getSettings().isEmpty(), "Uninitialized settings should be empty");
+       r.close();
+    }
+
+    public static void testUniqueIdentifier() throws Throwable {
+        Recording r1 = new Recording();
+        Recording r2 = new Recording();
+        assertNotEquals(r1.getId(), r2.getId(), "Same identifier");
+        r1.close();
+        r2.close();
+    }
+
+    public static void testSetGetName() throws Throwable {
+        Recording r = new Recording();
+        final String name = "TestName";
+        r.setName(name);
+        assertEquals(name, r.getName(), "Wrong set/get name");
+        r.close();
+    }
+
+    public static void testSetGetDuration() throws Throwable {
+        Recording r = new Recording();
+        final Duration duration = Duration.ofSeconds(60).plusMillis(50);
+        r.setDuration(duration);
+        assertEquals(duration, r.getDuration(), "Wrong set/get duration");
+        r.close();
+    }
+
+    public static void testSetGetMaxAge() throws Throwable {
+        Recording r = new Recording();
+        final Duration maxAge = Duration.ofSeconds(60).plusMillis(50);
+        r.setMaxAge(maxAge);
+        assertEquals(maxAge, r.getMaxAge(), "Wrong set/get maxAge");
+        r.close();
+    }
+
+    public static void testSetGetDestination() throws Throwable {
+        Recording r = new Recording();
+        final Path destination = Paths.get(".", "testSetGetDestination.jfr");
+        r.setDestination(destination);
+        assertEquals(destination, r.getDestination(), "Wrong set/get destination");
+        r.close();
+    }
+
+    public static void testSetGetDumpOnExit() throws Throwable {
+        Recording r = new Recording();
+        r.setDumpOnExit(true);
+        assertTrue(r.getDumpOnExit(), "Wrong set/get dumpOnExit true");
+        r.setDumpOnExit(false);
+        assertFalse(r.getDumpOnExit(), "Wrong set/get dumpOnExit false");
+        r.close();
+    }
+
+    public static void testSetGetToDisk() throws Throwable {
+        Recording r = new Recording();
+        r.setToDisk(true);
+        assertTrue(r.isToDisk(), "Wrong set/get isToDisk true");
+        r.setToDisk(false);
+        assertFalse(r.isToDisk(), "Wrong set/get isToDisk false");
+        r.close();
+    }
+
+    public static void testSetGetToMaxSize() throws Throwable {
+        Recording r = new Recording();
+        final long maxSize = 10000000;
+        r.setMaxSize(maxSize);
+        assertEquals(maxSize, r.getMaxSize(), "Wrong set/get maxSize");
+        r.close();
+    }
+
+    public static void testGetSettings() throws Throwable {
+        String eventPath = "my/test/enabledPath";
+        String settingName = "myTestSetting";
+        String settingValue = "myTestValue";
+
+        Recording r = new Recording();
+        r.enable(eventPath).with(settingName, settingValue);
+
+        boolean isEnabledPathFound = false;
+        boolean isSettingFound = false;
+        Map<String, String> settings = r.getSettings();
+        for (String name : settings.keySet()) {
+            System.out.println("name=" + name + ", value=" + settings.get(name));
+            if (name.contains(eventPath) && name.contains("#enabled")) {
+                isEnabledPathFound = true;
+                assertEquals("true", settings.get(name), "Wrong value for enabled path: " + name);
+            }
+            if  (name.contains(eventPath) && name.contains(settingName)) {
+                isSettingFound = true;
+                assertEquals(settingValue, settings.get(name), "Wrong value for setting: " + name);
+            }
+        }
+        assertTrue(isEnabledPathFound, "Enabled path not found in settings");
+        assertTrue(isSettingFound, "Test setting not found in settings");
+        r.close();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/misc/TestRecordingCopy.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.api.recording.misc;
+
+import jdk.jfr.Recording;
+import jdk.jfr.RecordingState;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.SimpleEvent;
+
+import java.util.List;
+
+/*
+ * @test
+ * @summary A simple test for Recording.copy()
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.misc.TestRecordingCopy
+ */
+public class TestRecordingCopy {
+
+    private static final int EVENT_ID = 1001;
+
+    public static void main(String[] args) throws Exception {
+
+        Recording original = new Recording();
+        original.enable(SimpleEvent.class);
+
+        Recording newCopy = original.copy(false);
+        Asserts.assertEquals(newCopy.getState(), RecordingState.NEW);
+
+        Recording newStoppedCopy = original.copy(true);
+        Asserts.assertEquals(newStoppedCopy.getState(), RecordingState.NEW);
+
+        original.start();
+
+        SimpleEvent ev = new SimpleEvent();
+        ev.id = EVENT_ID;
+        ev.commit();
+
+        // Verify a stopped copy
+        Recording stoppedCopy = original.copy(true);
+        Asserts.assertEquals(stoppedCopy.getState(), RecordingState.STOPPED);
+        assertCopy(stoppedCopy, original);
+
+        // Verify a running copy
+        Recording runningCopy = original.copy(false);
+        Asserts.assertEquals(runningCopy.getState(), RecordingState.RUNNING);
+        assertCopy(runningCopy, original);
+
+        original.stop();
+
+        // Verify a stopped copy of a stopped
+        stoppedCopy = original.copy(true);
+        Asserts.assertEquals(stoppedCopy.getState(), RecordingState.STOPPED);
+        assertCopy(stoppedCopy, original);
+
+        // Clean-up
+        original.close();
+        runningCopy.stop();
+        runningCopy.close();
+        stoppedCopy.close();
+    }
+
+    /**
+     * Verifies the basic assertions about a copied record
+     */
+    private static void assertCopy(Recording recording, Recording original) throws Exception {
+
+        Asserts.assertFalse(recording.getId() == original.getId(), "id of a copied record should differ from that of the original");
+        Asserts.assertFalse(recording.getName().equals(original.getName()), "name of a copied record should differ from that of the original");
+
+        Asserts.assertEquals(recording.getSettings(), original.getSettings());
+        Asserts.assertEquals(recording.getStartTime(), original.getStartTime());
+        Asserts.assertEquals(recording.getMaxSize(), original.getMaxSize());
+        Asserts.assertEquals(recording.getMaxAge(), original.getMaxAge());
+        Asserts.assertEquals(recording.isToDisk(), original.isToDisk());
+        Asserts.assertEquals(recording.getDumpOnExit(), original.getDumpOnExit());
+
+        List<RecordedEvent> recordedEvents = Events.fromRecording(recording);
+        Events.hasEvents(recordedEvents);
+        Asserts.assertEquals(1, recordedEvents.size(), "Expected exactly one event");
+
+        RecordedEvent re = recordedEvents.get(0);
+        Asserts.assertEquals(EVENT_ID, re.getValue("id"));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/options/TestDuration.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.options;
+
+import java.time.Duration;
+import java.time.Instant;
+
+import jdk.jfr.Recording;
+import jdk.jfr.RecordingState;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.CommonHelper;
+
+/*
+ * @test
+ * @summary Test setDuration(). Verify recording is stopped automatically.
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.options.TestDuration
+ */
+public class TestDuration {
+
+    public static void main(String[] args) throws Throwable {
+        final Duration duration = Duration.ofSeconds(1);
+        Recording r = new Recording();
+        r.setDuration(duration);
+        Asserts.assertEquals(duration, r.getDuration(), "Wrong get/set duration");
+
+        r.start();
+        Instant afterStart = Instant.now();
+        CommonHelper.waitForRecordingState(r, RecordingState.STOPPED);
+
+        Instant afterStop = Instant.now();
+        Asserts.assertLessThanOrEqual(r.getStopTime(), afterStop, "getStopTime() > afterStop");
+        long durationMillis = Duration.between(afterStart, r.getStopTime()).toMillis();
+
+        // Performance of test servers varies too much to make a strict check of actual duration.
+        // We only check that recording stops before timeout of 20 seconds.
+        System.out.printf("Recording stopped after %d ms, expected above 1000 ms%n", durationMillis);
+        r.close();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/options/TestName.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.options;
+
+import jdk.jfr.Recording;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.CommonHelper;
+import jdk.test.lib.jfr.VoidFunction;
+
+/*
+ * @test
+ * @summary Test setName().
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.options.TestName
+ */
+public class TestName {
+
+    public static void main(String[] args) throws Throwable {
+        Recording r = new Recording();
+
+        Asserts.assertNotNull(r.getName(), "Default name should not be null");
+        System.out.println("name=" + r.getName());
+        Asserts.assertEquals(r.getName(), Long.toString(r.getId()), "Default name != id");
+
+        testNames(r);
+        r.start();
+        testNames(r);
+        r.stop();
+        testNames(r);
+        r.close();
+    }
+
+    private static void testNames(Recording r) throws Throwable {
+        System.out.println("Recording state=" + r.getState().name());
+
+        // Set simple name
+        String name = "myName";
+        r.setName(name);
+        System.out.println("name=" + r.getName());
+        Asserts.assertEquals(name, r.getName(), "Wrong get/set name");
+
+        // Set null. Should get Exception and old name should be kept.
+        verifyNull(()->{r.setName(null);}, "No NullPointerException when setName(null)");
+        Asserts.assertEquals(name, r.getName(), "Current name overwritten after null");
+
+        // Set empty name. Should work.
+        name = "";
+        r.setName(name);
+        System.out.println("name=" + r.getName());
+        Asserts.assertEquals(name, r.getName(), "Empty name is expected to work");
+
+        // Test a long name.
+        StringBuilder sb = new StringBuilder(500);
+        while (sb.length() < 400) {
+            sb.append("LongName-");
+        }
+        name = sb.toString();
+        System.out.println("Length of long name=" + name.length());
+        r.setName(name);
+        System.out.println("name=" + r.getName());
+        Asserts.assertEquals(name, r.getName(), "Wrong get/set long name");
+    }
+
+    private static void verifyNull(VoidFunction f, String msg) throws Throwable {
+        CommonHelper.verifyException(f, msg, NullPointerException.class);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/settings/TestConfigurationGetContents.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.api.recording.settings;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.List;
+
+import jdk.jfr.Configuration;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @summary Verifies Configuration.getContents() for every configuration
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.settings.TestConfigurationGetContents
+ */
+public class TestConfigurationGetContents {
+
+    private static final String SEP = System.getProperty("file.separator");
+    private static final String JFR_DIR = System.getProperty("test.jdk")
+            + SEP + "lib" + SEP + "jfr" + SEP;
+
+    public static void main(String[] args) throws Throwable {
+        List<Configuration> predefinedConfigs = Configuration.getConfigurations();
+
+        Asserts.assertNotNull(predefinedConfigs, "List of predefined configs is null");
+        Asserts.assertTrue(predefinedConfigs.size() > 0, "List of predefined configs is empty");
+
+        for (Configuration conf : predefinedConfigs) {
+            String name = conf.getName();
+            System.out.println("Verifying configuration " + name);
+            String fpath = JFR_DIR + name + ".jfc";
+            String contents = conf.getContents();
+            String fileContents = readFile(fpath);
+            Asserts.assertEquals(fileContents, contents, "getContents() does not return the actual contents of the file " + fpath);
+        }
+    }
+
+    private static String readFile(String path) throws IOException {
+        byte[] encoded = Files.readAllBytes(Paths.get(path));
+        return new String(encoded);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/settings/TestCreateConfigFromPath.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.settings;
+
+
+import java.io.Reader;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Map;
+
+import jdk.jfr.Configuration;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+
+/*
+ * @test
+ * @summary Test setName().
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.settings.TestCreateConfigFromPath
+ */
+public class TestCreateConfigFromPath {
+
+    private static final Path DIR = Paths.get(System.getProperty("test.src", "."));
+
+    public static void main(String[] args) throws Throwable {
+        testOkConfig();
+        testNullReader();
+    }
+
+    private static void testOkConfig() throws Exception {
+        Path settingsPath = DIR.resolve("settings.jfc");
+        if(!settingsPath.toFile().exists()) throw new RuntimeException("File " + settingsPath.toFile().getAbsolutePath() +  " not found ");
+
+        Configuration config = Configuration.create(settingsPath);
+        Map<String, String> settings = config.getSettings();
+
+        Asserts.assertEquals(4, settings.size(), "Settings size differes from the expected size");
+        String[] keys = {"enabled", "stackTrace", "threshold", "custom"};
+        String[] vals = {"true", "true", "1 ms", "5"};
+        for(int i=0; i<keys.length; ++i) {
+            String fullKey = EventNames.JavaMonitorWait + "#" + keys[i];
+            Asserts.assertEquals(vals[i], settings.get(fullKey), "Settings value differs from the expected: " + keys[i]);
+        }
+        Asserts.assertEquals(null, settings.get("doesNotExists"), "Error getting on-existent setting");
+
+        Asserts.assertEquals("Oracle", config.getProvider(), "Configuration provider differs from the expected");
+        Asserts.assertEquals("TestSettings", config.getLabel(), "Configuration label differs from the expected");
+        Asserts.assertEquals("SampleConfiguration", config.getDescription(), "Configuration description differs from the expected");
+        Asserts.assertEquals("settings", config.getName(), "Configuration name differs from the expected");
+    }
+
+    private static void testNullReader() throws Exception {
+        try {
+            Configuration.create((Reader)null);
+            Asserts.fail("Exception was not thrown");
+        } catch(NullPointerException x) {
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/settings/TestCreateConfigFromReader.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.settings;
+
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.Reader;
+import java.util.Map;
+
+import jdk.jfr.Configuration;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+
+/*
+ * @test
+ * @summary Test setName().
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.settings.TestCreateConfigFromReader
+ */
+public class TestCreateConfigFromReader {
+
+    private static final String DIR = System.getProperty("test.src", ".");
+
+    public static void main(String[] args) throws Throwable {
+        testOkConfig();
+        testNullReader();
+    }
+
+    private static void testOkConfig() throws Exception {
+        File settingsFile = new File(DIR, "settings.jfc");
+        if(!settingsFile.exists()) throw new RuntimeException("File " + settingsFile.getAbsolutePath() +  " not found ");
+
+            FileReader reader = new FileReader(settingsFile);
+
+            Configuration config = Configuration.create(reader);
+            Map<String, String> settings = config.getSettings();
+
+            Asserts.assertEquals(4, settings.size(), "Settings size differes from the expected size");
+            String[] keys = {"enabled", "stackTrace", "threshold", "custom"};
+            String[] vals = {"true", "true", "1 ms", "5"};
+            for(int i=0; i<keys.length; ++i) {
+                String fullKey = EventNames.JavaMonitorWait + "#" + keys[i];
+                Asserts.assertEquals(vals[i], settings.get(fullKey), "Settings value differs from the expected: " + keys[i]);
+            }
+            Asserts.assertEquals(null, settings.get("doesNotExists"), "Error getting on-existent setting");
+
+            Asserts.assertEquals("Oracle", config.getProvider(), "Configuration provider differs from the expected");
+            Asserts.assertEquals("TestSettings", config.getLabel(), "Configuration label differs from the expected");
+            Asserts.assertEquals("SampleConfiguration", config.getDescription(), "Configuration description differs from the expected");
+            Asserts.assertNull(config.getName(), "Name should be null if created from reader");
+    }
+
+    private static void testNullReader() throws Exception {
+       try {
+           Configuration.create((Reader)null);
+           Asserts.fail("Exception was not thrown");
+       } catch(NullPointerException x) {
+       }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/settings/TestGetConfigurations.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.api.recording.settings;
+
+import java.util.List;
+
+import jdk.jfr.Configuration;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @summary Verifies that there is the default config and that it has
+ *          the expected parameters
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.settings.TestGetConfigurations
+ */
+public class TestGetConfigurations {
+
+    private static final String DEFAULT_CONFIG_NAME = "default";
+    private static final String DEFAULT_CONFIG_LABEL = "Continuous";
+    private static final String DEFAULT_CONFIG_DESCRIPTION = "Low overhead configuration safe for continuous use in production environments, typically less than 1 % overhead.";
+    private static final String DEFAULT_CONFIG_PROVIDER = "Oracle";
+
+    private static final String PROFILE_CONFIG_NAME = "profile";
+    private static final String PROFILE_CONFIG_LABEL = "Profiling";
+    private static final String PROFILE_CONFIG_DESCRIPTION = "Low overhead configuration for profiling, typically around 2 % overhead.";
+    private static final String PROFILE_CONFIG_PROVIDER = "Oracle";
+
+    public static void main(String[] args) throws Throwable {
+        List<Configuration> predefinedConfigs = Configuration.getConfigurations();
+        Asserts.assertNotNull(predefinedConfigs, "List of predefined configs is null");
+        Asserts.assertEquals(predefinedConfigs.size(), 2, "Expected exactly two predefined configurations");
+
+        Configuration defaultConfig = findConfigByName(predefinedConfigs, DEFAULT_CONFIG_NAME);
+        Asserts.assertNotNull(defaultConfig, "Config '" + DEFAULT_CONFIG_NAME + "' not found");
+        Asserts.assertEquals(defaultConfig.getLabel(), DEFAULT_CONFIG_LABEL);
+        Asserts.assertEquals(defaultConfig.getDescription(), DEFAULT_CONFIG_DESCRIPTION);
+        Asserts.assertEquals(defaultConfig.getProvider(), DEFAULT_CONFIG_PROVIDER);
+
+        Configuration profileConfig = findConfigByName(predefinedConfigs, PROFILE_CONFIG_NAME);
+        Asserts.assertNotNull(profileConfig, "Config '" + PROFILE_CONFIG_NAME + "' not found");
+        Asserts.assertEquals(profileConfig.getLabel(), PROFILE_CONFIG_LABEL);
+        Asserts.assertEquals(profileConfig.getDescription(), PROFILE_CONFIG_DESCRIPTION);
+        Asserts.assertEquals(profileConfig.getProvider(), PROFILE_CONFIG_PROVIDER);
+    }
+
+    private static Configuration findConfigByName(List<Configuration> configs, String name) {
+        for (Configuration config : configs) {
+            if (name.equals(config.getName())) {
+                return config;
+            }
+        }
+        return null;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/settings/TestSettingsAvailability.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.api.recording.settings;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import jdk.jfr.EventType;
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Recording;
+import jdk.jfr.SettingDescriptor;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.jfr.EventNames;
+
+/*
+ * @test
+ * @summary Verifies that event types has the correct type of settings
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.settings.TestSettingsAvailability
+ */
+public class TestSettingsAvailability {
+    public static void main(String[] args) throws Throwable {
+        testKnownSettings();
+        testSettingPersistence();
+    }
+
+    private static void testSettingPersistence() throws IOException, Exception {
+        Map<String, EventType> inMemoryTypes = new HashMap<>();
+        for (EventType type : FlightRecorder.getFlightRecorder().getEventTypes()) {
+            inMemoryTypes.put(type.getName(), type);
+        }
+
+        Path p = Paths.get("recording.jfr");
+        try (Recording r = new Recording()) {
+            r.start();
+            r.stop();
+            r.dump(p);
+            try (RecordingFile rf = new RecordingFile(p)) {
+                for (EventType parsedType : rf.readEventTypes()) {
+                    EventType inMem = inMemoryTypes.get(parsedType.getName());
+                    if (inMem == null) {
+                        throw new Exception("Superflous event type " + parsedType.getName() + " in recording");
+                    }
+                    Set<String> inMemsettings = new HashSet<>();
+                    for (SettingDescriptor sd : inMem.getSettingDescriptors()) {
+                        inMemsettings.add(sd.getName());
+                    }
+
+                    for (SettingDescriptor parsedSetting : parsedType.getSettingDescriptors()) {
+                        if (!inMemsettings.contains(parsedSetting.getName())) {
+                            throw new Exception("Superflous setting " + parsedSetting.getName() + " in " + parsedType.getName());
+                        }
+                        inMemsettings.remove(parsedSetting.getName());
+                    }
+                    if (!inMemsettings.isEmpty()) {
+                        throw new Exception("Missing settings " + inMemsettings + " for event type " + parsedType.getName() + " in recording");
+                    }
+                }
+            }
+        }
+    }
+
+    private static void testKnownSettings() throws Exception {
+        testSetting(EventNames.JVMInformation, "enabled", "period");
+        testSetting(EventNames.FileRead, "enabled", "threshold", "stackTrace");
+        testSetting(EventNames.FileWrite, "enabled", "threshold","stackTrace");
+        testSetting(EventNames.ExceptionStatistics, "enabled", "period");
+        testSetting(EventNames.SocketRead, "enabled", "threshold", "stackTrace");
+        testSetting(EventNames.SocketWrite, "enabled", "threshold", "stackTrace");
+        testSetting(EventNames.ActiveRecording, "enabled", "threshold", "stackTrace");
+        testSetting(EventNames.ActiveSetting, "enabled", "threshold", "stackTrace");
+        testSetting(EventNames.JavaExceptionThrow, "enabled", "threshold", "stackTrace");
+    }
+
+    private static void testSetting(String eventName, String... settingNames) throws Exception {
+        for (EventType type : FlightRecorder.getFlightRecorder().getEventTypes()) {
+            if (eventName.equals(type.getName())) {
+                Set<String> settings = new HashSet<>();
+                for (SettingDescriptor sd : type.getSettingDescriptors()) {
+                    settings.add(sd.getName());
+                }
+                for (String settingName : settingNames) {
+                    if (!settings.contains(settingName)) {
+                        throw new Exception("Missing setting " + settingName + " in " + eventName);
+                    }
+                    settings.remove(settingName);
+                }
+                if (!settings.isEmpty()) {
+                    throw new Exception("Superflous settings " + settings + " in event " + eventName);
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/settings/settings.jfc	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration version="2.0" label="TestSettings" description="SampleConfiguration" provider="Oracle">
+
+    <event name="jdk.JavaMonitorWait">
+     <setting name="enabled">true</setting>
+     <setting name="stackTrace">true</setting>
+     <setting name="threshold">1 ms</setting>
+     <setting name="custom">5</setting>
+    </event>
+
+</configuration>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/state/TestOptionState.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.state;
+
+import java.time.Duration;
+import java.util.function.Consumer;
+
+import jdk.jfr.Recording;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @key jfr
+ * @summary Test options in different states
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.state.TestOptionState
+ */
+public class TestOptionState {
+
+     //                                Name   Age    Size   Dur.   Dest.  Disk
+    static boolean[] NEW =     arrayOf(true,  true,  true,  true,  true,  true);
+    static boolean[] DELAYED = arrayOf(true,  true,  true,  true,  true,  true);
+    static boolean[] RUNNING = arrayOf(true,  true,  true,  true,  true,  false);
+    static boolean[] STOPPED = arrayOf(true,  true,  true,  false,  false, false);
+    static boolean[] CLOSED =  arrayOf(false, false, false, false, false, false);
+
+    public static void main(String[] args) throws Throwable {
+      Recording r = new Recording();
+      assertRecordingState(r, NEW);
+      r.scheduleStart(Duration.ofHours(2));
+      assertRecordingState(r, DELAYED);
+      r.start();
+      assertRecordingState(r, RUNNING);
+      r.stop();
+      assertRecordingState(r, STOPPED);
+      r.close();
+      assertRecordingState(r, CLOSED);
+    }
+
+    private static void assertRecordingState(Recording r, boolean[] states) throws Exception {
+        assertOperation("setName", r, s -> s.setName("Test Name"), states[0]);
+        assertOperation("setMaxAge", r, s -> s.setMaxAge(null), states[1]);
+        assertOperation("setMaxSize", r, s -> s.setMaxSize(0), states[2]);
+        assertOperation("setDuration", r, s -> s.setDuration(null), states[3]);
+        assertOperation("setDestination", r, s -> {
+            try {
+            s.setDestination(null);
+        } catch (IllegalStateException e) {
+            throw e; // rethrow for testing
+        } catch(Exception e) {
+            throw new RuntimeException(e); // should not happen
+        }}, states[4]);
+        assertOperation("setTodisk", r, s -> s.setToDisk(true), states[5]);
+    }
+
+    private static void assertOperation(String opernationName, Recording s, Consumer<Recording> c, boolean ok) {
+        try {
+            c.accept(s);
+            Asserts.assertTrue(ok, opernationName + " should throw ISE when recording is in state " + s.getState());
+        } catch (IllegalStateException ise) {
+            Asserts.assertFalse(ok, opernationName + " should not throw ISE when recording is in state " + s.getState());
+        }
+    }
+
+    static boolean[] arrayOf(boolean... array) {
+        return array;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/state/TestState.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.state;
+
+import java.time.Duration;
+
+import jdk.jfr.Recording;
+import jdk.jfr.RecordingState;
+import jdk.test.lib.jfr.CommonHelper;
+
+/*
+ * @test
+ * @summary Test Recording state
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.state.TestState
+ */
+public class TestState {
+
+    public static void main(String[] args) throws Throwable {
+        Recording r = new Recording();
+        CommonHelper.verifyRecordingState(r, RecordingState.NEW);
+        r.scheduleStart(Duration.ofHours(2));
+        CommonHelper.verifyRecordingState(r, RecordingState.DELAYED);
+        r.start();
+        CommonHelper.verifyRecordingState(r, RecordingState.RUNNING);
+        r.stop();
+        CommonHelper.verifyRecordingState(r, RecordingState.STOPPED);
+        r.close();
+        CommonHelper.verifyRecordingState(r, RecordingState.CLOSED);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/state/TestStateDuration.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.state;
+
+import java.time.Duration;
+import java.time.Instant;
+
+import jdk.jfr.Recording;
+import jdk.jfr.RecordingState;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.CommonHelper;
+import jdk.test.lib.jfr.VoidFunction;
+
+/*
+ * @test
+ * @summary Test Recording state
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.state.TestStateDuration
+ */
+public class TestStateDuration {
+
+    public static void main(String[] args) throws Throwable {
+        Duration duration = Duration.ofSeconds(2);
+        Recording r = new Recording();
+        r.setDuration(duration);
+        CommonHelper.verifyRecordingState(r, RecordingState.NEW);
+        Instant start = Instant.now();
+        System.out.println("Recording with duration " + duration + " started at " + start);
+        r.start();
+
+        // Wait for recording to stop automatically
+        System.out.println("Waiting for recording to reach STOPPED state");
+        CommonHelper.waitForRecordingState(r, RecordingState.STOPPED);
+        Instant stop = Instant.now();
+        Duration measuredDuration = Duration.between(start, stop);
+        System.out.println("Recording stopped at " + stop + ". Measured duration " + measuredDuration);
+        // Timer task uses System.currentMillis, and java.time uses other source.
+        Duration deltaDueToClockNotInSync = Duration.ofMillis(100);
+        Asserts.assertGreaterThan(measuredDuration.plus(deltaDueToClockNotInSync), duration);
+        verifyIllegalState(() -> r.start(), "start() after stop()");
+        r.close();
+        CommonHelper.verifyRecordingState(r, RecordingState.CLOSED);
+    }
+
+    private static void verifyIllegalState(VoidFunction f, String msg) throws Throwable {
+        CommonHelper.verifyException(f, msg, IllegalStateException.class);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/state/TestStateIdenticalListeners.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.state;
+
+import static jdk.test.lib.Asserts.assertEquals;
+
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.FlightRecorderListener;
+import jdk.jfr.Recording;
+
+/*
+ * @test
+ * @summary Test Recording state with concurrent recordings
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.state.TestStateIdenticalListeners
+ */
+public class TestStateIdenticalListeners {
+
+    public static void main(String[] args) throws Throwable {
+        TestListener testListener = new TestListener();
+        // Add the same listener twice
+        FlightRecorder.addListener(testListener);
+        FlightRecorder.addListener(testListener);
+
+        // Start recording
+        Recording recording = new Recording();
+        recording.start();
+        recording.stop();
+
+        // We expect 4 notifications in total: 1 RUNNING and 1 STOPPED
+        // notification for each listener registration
+        // NOT 2 notifications: we have added the same listener again
+        assertEquals(4, testListener.notificationCount, "Expected 2 notifications, got " + testListener.notificationCount);
+
+        System.out.println("Test Passed");
+        recording.close();
+    }
+
+    private static class TestListener implements FlightRecorderListener {
+        private int notificationCount;
+
+        @Override
+        public void recordingStateChanged(Recording recording) {
+            System.out.println("recordingStateChanged: " + " recording: " + recording + " state: " + recording.getState());
+            ++notificationCount;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/state/TestStateInvalid.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.state;
+
+import jdk.jfr.Recording;
+import jdk.jfr.RecordingState;
+import jdk.test.lib.jfr.CommonHelper;
+import jdk.test.lib.jfr.VoidFunction;
+
+/*
+ * @test
+ * @summary Test start/stop/close recording from different recording states.
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.state.TestStateInvalid
+ */
+public class TestStateInvalid {
+
+    public static void main(String[] args) throws Throwable {
+        Recording r = new Recording();
+        CommonHelper.verifyRecordingState(r, RecordingState.NEW);
+        verifyIllegalState(() -> r.stop(), "stop() when not started");
+        CommonHelper.verifyRecordingState(r, RecordingState.NEW);
+
+        r.start();
+        CommonHelper.verifyRecordingState(r, RecordingState.RUNNING);
+        verifyIllegalState(() -> r.start(), "double start()");
+        CommonHelper.verifyRecordingState(r, RecordingState.RUNNING);
+
+        r.stop();
+        CommonHelper.verifyRecordingState(r, RecordingState.STOPPED);
+        verifyIllegalState(() -> r.stop(), "double stop()");
+        verifyIllegalState(() -> r.start(), "start() after stop()");
+        CommonHelper.verifyRecordingState(r, RecordingState.STOPPED);
+
+        r.close();
+        CommonHelper.verifyRecordingState(r, RecordingState.CLOSED);
+        verifyIllegalState(() -> r.stop(), "stop() after close()");
+        verifyIllegalState(() -> r.start(), "start() after close()");
+        CommonHelper.verifyRecordingState(r, RecordingState.CLOSED);
+    }
+
+    private static void verifyIllegalState(VoidFunction f, String msg) throws Throwable {
+        CommonHelper.verifyException(f, msg, IllegalStateException.class);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/state/TestStateMultiple.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.state;
+
+import jdk.jfr.Recording;
+import jdk.jfr.RecordingState;
+import jdk.test.lib.jfr.CommonHelper;
+import jdk.test.lib.jfr.VoidFunction;
+
+/*
+ * @test
+ * @summary Test Recording state with concurrent recordings
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.state.TestStateMultiple
+ */
+public class TestStateMultiple {
+
+    public static void main(String[] args) throws Throwable {
+        Recording rA = new Recording();
+        CommonHelper.verifyRecordingState(rA, RecordingState.NEW);
+        verifyIllegalState(() -> rA.stop(), "stop() when not started");
+
+        rA.start();
+        CommonHelper.verifyRecordingState(rA, RecordingState.RUNNING);
+
+        Recording rB = new Recording();
+        CommonHelper.verifyRecordingState(rA, RecordingState.RUNNING);
+        verifyIllegalState(() -> rA.start(), "double start()");
+        CommonHelper.verifyRecordingState(rB, RecordingState.NEW);
+        verifyIllegalState(() -> rB.stop(), "stop() when not started");
+
+        rB.start();
+        CommonHelper.verifyRecordingState(rA, RecordingState.RUNNING);
+        CommonHelper.verifyRecordingState(rB, RecordingState.RUNNING);
+
+        rB.stop();
+        CommonHelper.verifyRecordingState(rA, RecordingState.RUNNING);
+        CommonHelper.verifyRecordingState(rB, RecordingState.STOPPED);
+        verifyIllegalState(() -> rB.start(), "start() after stop()");
+
+        rB.close();
+        CommonHelper.verifyRecordingState(rA, RecordingState.RUNNING);
+        CommonHelper.verifyRecordingState(rB, RecordingState.CLOSED);
+        verifyIllegalState(() -> rB.start(), "start() after close()");
+
+        rA.stop();
+        CommonHelper.verifyRecordingState(rA, RecordingState.STOPPED);
+        verifyIllegalState(() -> rA.start(), "start() after stop()");
+        CommonHelper.verifyRecordingState(rB, RecordingState.CLOSED);
+
+        rA.close();
+        CommonHelper.verifyRecordingState(rA, RecordingState.CLOSED);
+        CommonHelper.verifyRecordingState(rB, RecordingState.CLOSED);
+        verifyIllegalState(() -> rA.stop(), "stop() after close()");
+        verifyIllegalState(() -> rB.start(), "start() after close()");
+    }
+
+    private static void verifyIllegalState(VoidFunction f, String msg) throws Throwable {
+        CommonHelper.verifyException(f, msg, IllegalStateException.class);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/state/TestStateScheduleStart.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.state;
+
+import java.time.Duration;
+import java.time.Instant;
+
+import jdk.jfr.Recording;
+import jdk.jfr.RecordingState;
+import jdk.test.lib.jfr.CommonHelper;
+import jdk.test.lib.jfr.VoidFunction;
+
+/*
+ * @test
+ * @summary Test Recording state
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.state.TestStateScheduleStart
+ */
+public class TestStateScheduleStart {
+
+    public static void main(String[] args) throws Throwable {
+        Recording r = new Recording();
+        CommonHelper.verifyRecordingState(r, RecordingState.NEW);
+
+        Instant start = Instant.now();
+        r.scheduleStart(Duration.ofMillis(2000));
+
+        System.out.println("Wait for recording to start: " + start);
+        CommonHelper.waitForRecordingState(r, RecordingState.RUNNING);
+
+        // Duration should be about 2000 ms.
+        // Test servers vary too much in performance to make an accurate check.
+        // We only check that we don't time out after 20 seconds.
+        Instant started = Instant.now();
+        long millis = Duration.between(start, started).toMillis();
+        System.out.println("Recording started at " + started + ". Delta millis=" + millis + ", expeced about 2000");
+
+        verifyIllegalState(() -> r.start(), "double start()");
+        r.stop();
+        CommonHelper.verifyRecordingState(r, RecordingState.STOPPED);
+        r.close();
+        CommonHelper.verifyRecordingState(r, RecordingState.CLOSED);
+    }
+
+    private static void verifyIllegalState(VoidFunction f, String msg) throws Throwable {
+        CommonHelper.verifyException(f, msg, IllegalStateException.class);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/time/TestTime.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.time;
+
+import java.time.Instant;
+
+import jdk.jfr.Recording;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @key jfr
+ * @summary Test Recording.get*Time()
+ * @library /test/lib
+ * @run main/othervm  jdk.jfr.api.recording.time.TestTime
+ */
+
+public class TestTime {
+
+    public static void main(String[] args) throws Throwable {
+        Recording r = new Recording();
+        Asserts.assertNull(r.getStartTime(), "getStartTime() not null before start");
+        Asserts.assertNull(r.getStopTime(), "getStopTime() not null before start");
+
+        final Instant beforeStart = Instant.now();
+        r.start();
+        final Instant afterStart = Instant.now();
+
+        Asserts.assertNotNull(r.getStartTime(), "getStartTime() null after");
+        Asserts.assertGreaterThanOrEqual(r.getStartTime(), beforeStart, "getStartTime() < beforeStart");
+        Asserts.assertLessThanOrEqual(r.getStartTime(), afterStart, "getStartTime() > afterStart");
+        Asserts.assertNull(r.getStopTime(), "getStopTime() not null before stop");
+
+        final Instant beforeStop = Instant.now();
+        r.stop();
+        final Instant afterStop = Instant.now();
+
+        Asserts.assertGreaterThanOrEqual(r.getStartTime(), beforeStart, "getStartTime() < beforeStart");
+        Asserts.assertLessThanOrEqual(r.getStartTime(), afterStart, "getStartTime() > afterStart");
+        Asserts.assertNotNull(r.getStopTime(), "getStopTime() null after stop");
+        Asserts.assertGreaterThanOrEqual(r.getStopTime(), beforeStop, "getStopTime() < beforeStop");
+        Asserts.assertLessThanOrEqual(r.getStopTime(), afterStop, "getStopTime() > afterStop");
+
+        r.close();
+
+        // Same checks again to make sure close() did not change the times.
+        Asserts.assertGreaterThanOrEqual(r.getStartTime(), beforeStart, "getStartTime() < beforeStart");
+        Asserts.assertLessThanOrEqual(r.getStartTime(), afterStart, "getStartTime() > afterStart");
+        Asserts.assertNotNull(r.getStopTime(), "getStopTime() null after stop");
+        Asserts.assertGreaterThanOrEqual(r.getStopTime(), beforeStop, "getStopTime() < beforeStop");
+        Asserts.assertLessThanOrEqual(r.getStopTime(), afterStop, "getStopTime() > afterStop");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/time/TestTimeDuration.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.time;
+
+import java.time.Duration;
+import java.time.Instant;
+
+import jdk.jfr.Recording;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @key jfr
+ * @summary Test Recording.setDuration() and Recording.get*Time()
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.time.TestTimeDuration
+ */
+
+public class TestTimeDuration {
+
+    public static void main(String[] args) throws Throwable {
+        Recording r = new Recording();
+        final Duration duration = Duration.ofMillis(30000);
+
+        r.setDuration(duration);
+        Asserts.assertNull(r.getStartTime(), "getStartTime() not null before start");
+        Asserts.assertNull(r.getStopTime(), "getStopTime() not null before start");
+
+        final Instant beforeStart = Instant.now();
+        r.start();
+        final Instant afterStart = Instant.now();
+
+        Asserts.assertNotNull(r.getStartTime(), "getStartTime() null after start()");
+        Asserts.assertGreaterThanOrEqual(r.getStartTime(), beforeStart, "getStartTime() < beforeStart");
+        Asserts.assertLessThanOrEqual(r.getStartTime(), afterStart, "getStartTime() > afterStart");
+
+        Asserts.assertNotNull(r.getStopTime(), "getStopTime() null after start with duration");
+        Asserts.assertGreaterThanOrEqual(r.getStopTime(), beforeStart.plus(duration), "getStopTime() < beforeStart + duration");
+        Asserts.assertLessThanOrEqual(r.getStopTime(), afterStart.plus(duration), "getStopTime() > afterStart + duration");
+
+        r.close();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/time/TestTimeMultiple.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.time;
+
+import java.time.Instant;
+
+import jdk.jfr.Recording;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @key jfr
+ * @summary Test recording times with concurrent recordings
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.time.TestTimeMultiple
+ */
+
+public class TestTimeMultiple {
+
+    public static void main(String[] args) throws Throwable {
+        Recording rA = new Recording();
+        Asserts.assertNull(rA.getStartTime(), "getStartTime() not null before start");
+        Asserts.assertNull(rA.getStopTime(), "getStopTime() not null before start");
+
+        final Instant beforeStartA = Instant.now();
+        rA.start();
+        final Instant afterStartA = Instant.now();
+
+        Recording rB = new Recording();
+        Asserts.assertNull(rB.getStartTime(), "getStartTime() not null before start");
+        Asserts.assertNull(rB.getStopTime(), "getStopTime() not null before start");
+
+        final Instant beforeStartB = Instant.now();
+        rB.start();
+        final Instant afterStartB = Instant.now();
+
+        final Instant beforeStopB = Instant.now();
+        rB.stop();
+        final Instant afterStopB = Instant.now();
+
+        final Instant beforeStopA = Instant.now();
+        rA.stop();
+        final Instant afterStopA = Instant.now();
+
+        rA.close();
+        rB.close();
+
+        Asserts.assertNotNull(rA.getStartTime(), "getStartTime() null after start");
+        Asserts.assertNotNull(rA.getStopTime(), "getStopTime() null after stop");
+        Asserts.assertGreaterThanOrEqual(rA.getStartTime(), beforeStartA, "getStartTime() < beforeStart");
+        Asserts.assertLessThanOrEqual(rA.getStartTime(), afterStartA, "getStartTime() > afterStart");
+        Asserts.assertGreaterThanOrEqual(rA.getStopTime(), beforeStopA, "getStopTime() < beforeStop");
+        Asserts.assertLessThanOrEqual(rA.getStopTime(), afterStopA, "getStopTime() > afterStop");
+
+        Asserts.assertNotNull(rB.getStartTime(), "getStartTime() null after start");
+        Asserts.assertNotNull(rB.getStopTime(), "getStopTime() null after stop");
+        Asserts.assertGreaterThanOrEqual(rB.getStartTime(), beforeStartB, "getStartTime() < beforeStart");
+        Asserts.assertLessThanOrEqual(rB.getStartTime(), afterStartB, "getStartTime() > afterStart");
+        Asserts.assertGreaterThanOrEqual(rB.getStopTime(), beforeStopB, "getStopTime() < beforeStop");
+        Asserts.assertLessThanOrEqual(rB.getStopTime(), afterStopB, "getStopTime() > afterStop");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/recording/time/TestTimeScheduleStart.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.recording.time;
+
+import java.time.Duration;
+import java.time.Instant;
+
+import jdk.jfr.Recording;
+import jdk.jfr.RecordingState;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.CommonHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @summary Test Recording.scheduleStart() and Recording.get*Time()
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.recording.time.TestTimeScheduleStart
+ */
+
+public class TestTimeScheduleStart {
+
+    public static void main(String[] args) throws Throwable {
+        testScheduledRecordingIsDelayed();
+        testScheduledRecordingIsRunning();
+    }
+
+    private static void testScheduledRecordingIsRunning() throws Exception {
+        Recording r = new Recording();
+        r.scheduleStart(Duration.ofSeconds(2));
+        Asserts.assertNotNull(r.getStartTime(), "start time is null after scheduleStart()");
+        CommonHelper.waitForRecordingState(r, RecordingState.RUNNING);
+        Asserts.assertLessThanOrEqual(r.getStartTime(), Instant.now(), "start time should not exceed current time");
+        r.stop();
+        r.close();
+    }
+
+    private static void testScheduledRecordingIsDelayed() throws Exception {
+        Recording r = new Recording();
+        r.scheduleStart(Duration.ofHours(10));
+        CommonHelper.verifyRecordingState(r, RecordingState.DELAYED);
+        r.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/settings/RegExpControl.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.settings;
+
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import jdk.jfr.SettingControl;
+
+public final class RegExpControl extends SettingControl {
+    private Pattern pattern = Pattern.compile(".*");
+
+    public void setValue(String value) {
+        this.pattern = Pattern.compile(value);
+    }
+
+    public String combine(Set<String> values) {
+        return String.join("|", values);
+    }
+
+    public String getValue() {
+        return pattern.toString();
+    }
+
+    public boolean matches(String uri) {
+        return pattern.matcher(uri).find();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/settings/StringListSetting.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.settings;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.StringJoiner;
+
+import jdk.jfr.Description;
+import jdk.jfr.Label;
+import jdk.jfr.MetadataDefinition;
+import jdk.jfr.SettingControl;
+
+@Label("String List")
+@Description("Accepts set of strings, such as \"text\" or \"text1\", \"text2\", or nothing to reject all strings")
+@MetadataDefinition
+public final class StringListSetting extends SettingControl {
+
+    private Set<String> acceptedStrings = new HashSet<>();
+
+    @Override
+    public void setValue(String s) {
+        acceptedStrings = parseSetting(s);
+    }
+
+    private Set<String> parseSetting(String s) {
+        Set<String> stringSet = new HashSet<>();
+        StringBuilder sb = new StringBuilder();
+        boolean inString = false;
+        for (int index = 0; index < s.length(); index++) {
+            char c = s.charAt(index);
+            if (c != '"') {
+                if (inString) {
+                    // escape double quotes
+                    if (c == '\\' && index + 1 < s.length()) {
+                        if (s.charAt(index + 1) == '"') {
+                            index++;
+                            c = '"';
+                        }
+                    }
+                    sb.append(c);
+                }
+            } else {
+                if (inString) {
+                    stringSet.add(sb.toString());
+                    sb.setLength(0);
+                }
+                inString = !inString;
+            }
+        }
+        return stringSet;
+    }
+
+    @Override
+    public String getValue() {
+        StringJoiner sj = new StringJoiner(", ", "\"", "\"");
+        for (String s : acceptedStrings) {
+            sj.add(s);
+        }
+        return sj.toString();
+    }
+
+    @Override
+    public String combine(Set<String> values) {
+        Set<String> nameSet = new HashSet<>();
+        for (String s : values) {
+            nameSet.addAll(parseSetting(s));
+        }
+        if (nameSet.isEmpty()) {
+            return "";
+        }
+        StringJoiner sj = new StringJoiner(", ");
+        for (String s : nameSet) {
+            s = s.replace("\"", "\\\""); // escape quotes
+            sj.add("\"" + s + "\"");
+        }
+        return sj.toString();
+    }
+
+    public boolean accept(String string) {
+        return acceptedStrings.contains(string);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/settings/TestFilterEvents.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.settings;
+
+import jdk.jfr.Description;
+import jdk.jfr.Event;
+import jdk.jfr.Label;
+import jdk.jfr.Recording;
+import jdk.jfr.SettingDefinition;
+import jdk.test.lib.jfr.Events;
+
+import static jdk.test.lib.Asserts.assertEquals;
+
+/*
+ * @test
+ * @summary The test uses SettingControl
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.api.settings.TestFilterEvents
+ */
+public class TestFilterEvents {
+
+    private static class AbstractHTTPEvent extends Event {
+        @Label("HTTP URI")
+        protected String uri;
+
+        @Label("URI Filter")
+        @SettingDefinition
+        protected boolean uriFilter(RegExpControl control) {
+            return control.matches(uri);
+        }
+    }
+
+    private static final class HTTPGetEvent extends AbstractHTTPEvent {
+        @Label("Thread Names")
+        @Description("List of thread names to accept, such as \"main\" or \"workerThread1\", \"taskThread\"")
+        @SettingDefinition
+        private boolean threadNames(StringListSetting setting) {
+            return setting.accept(Thread.currentThread().getName());
+        }
+
+    }
+    private static final class HTTPPostEvent extends AbstractHTTPEvent {
+    }
+
+    public static void main(String[] args) throws Exception {
+        Recording continuous = new Recording();
+        continuous.enable(HTTPGetEvent.class).with("threadNames", "\"unused-threadname-1\"");
+        assertEquals(0, makeProfilingRecording("\"unused-threadname-2\""));
+        assertEquals(1, makeProfilingRecording("\"" + Thread.currentThread().getName() + "\""));
+        continuous.close();
+    }
+
+    private static int makeProfilingRecording(String threadNames) throws Exception {
+        try (Recording recording = new Recording()) {
+            recording.enable(HTTPGetEvent.class).with("threadNames", threadNames);
+            recording.enable(HTTPGetEvent.class).with("uriFilter", "https://www.example.com/list/.*");
+            recording.enable(HTTPPostEvent.class).with("uriFilter", "https://www.example.com/list/.*");
+            recording.start();
+
+            HTTPGetEvent getEvent = new HTTPGetEvent();
+            getEvent.uri = "https://www.example.com/list/item?id=4";
+            getEvent.commit();
+
+            HTTPPostEvent postEvent = new HTTPPostEvent();
+            postEvent.uri = "https://www.example.com/admin/login?name=john";
+            postEvent.commit();
+
+            recording.stop();
+
+            return Events.fromRecording(recording).size();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/cmd/ExecuteHelper.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.cmd;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import jdk.jfr.Configuration;
+import jdk.jfr.Event;
+import jdk.jfr.Recording;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;;
+
+final class ExecuteHelper {
+
+    public static Object[] array;
+
+    static class CustomEvent extends Event {
+        int intValue;
+        long longValue;
+        double doubliValue;
+        float floatValue;
+        String stringValue;
+        Short shortValue;
+        boolean booleanValue;
+        char charValue;
+        double trickyDouble;
+    }
+
+    public static OutputAnalyzer run(String... args) {
+        String[] array = new String[args.length + 1];
+        System.arraycopy(args, 0, array, 1, args.length);
+        array[0] = "jdk.jfr.internal.cmd.Execute";
+        try {
+            return ProcessTools.executeTestJava(array);
+        } catch (Exception e) {
+            String message = String.format("Caught exception while executing '%s'", Arrays.asList(array));
+            throw new RuntimeException(message, e);
+        }
+    }
+
+    public static void emitCustomEvents() {
+        // Custom events with potentially tricky values
+        CustomEvent event1 = new CustomEvent();
+        event1.trickyDouble = Double.NaN;
+        event1.intValue = Integer.MIN_VALUE;
+        event1.longValue = Long.MIN_VALUE;
+        event1.doubliValue = Double.MIN_VALUE;
+        event1.floatValue = Float.MIN_VALUE;
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < 512; i++) {
+            sb.append((char) i);
+        }
+        sb.append("\u2324");
+        event1.stringValue = sb.toString();
+        event1.shortValue = Short.MIN_VALUE;
+        event1.booleanValue = true;
+        event1.booleanValue = false;
+        event1.charValue = '\b';
+        event1.commit();
+
+        CustomEvent event2 = new CustomEvent();
+        event2.trickyDouble = Double.NEGATIVE_INFINITY;
+        event2.intValue = Integer.MAX_VALUE;
+        event2.longValue = Long.MAX_VALUE;
+        event2.doubliValue = Double.MAX_VALUE;
+        event2.floatValue = Float.MAX_VALUE;
+        event2.stringValue = null;
+        event2.shortValue = Short.MAX_VALUE;
+        event2.booleanValue = false;
+        event2.charValue = 0;
+        event2.commit();
+    }
+
+    public static Path createProfilingRecording() throws Exception {
+        Path file = Files.createTempFile("recording", ".jfr");
+        // Create a recording with some data
+        try (Recording r = new Recording(Configuration.getConfiguration("profile"))) {
+            r.start();
+
+            // Allocation event
+            array = new Object[1000000];
+            array = null;
+
+            // Class loading event etc
+            provokeClassLoading();
+
+            // GC events
+            System.gc();
+
+            // ExecutionSample
+            long t = System.currentTimeMillis();
+            while (System.currentTimeMillis() - t < 50) {
+                // do nothing
+            }
+
+            // Other periodic events, i.e CPU load
+            Thread.sleep(1000);
+
+            r.stop();
+            r.dump(file);
+        }
+
+        return file;
+    }
+
+    private static void provokeClassLoading() {
+       // Matching a string with regexp
+       // is expected to load some classes and generate some VM events
+       Pattern p = Pattern.compile("a*b");
+       Matcher m = p.matcher("aaaaab");
+       m.matches();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/cmd/TestHelp.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.cmd;
+
+import jdk.test.lib.process.OutputAnalyzer;
+
+/*
+ * @test
+ * @summary Test help
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.cmd.TestHelp
+ */
+public class TestHelp {
+
+    public static void main(String[] args) throws Exception {
+        OutputAnalyzer output = ExecuteHelper.run("help");
+        output.shouldContain("Available commands are:");
+        output.shouldContain("print");
+        output.shouldContain("reconstruct");
+        output.shouldContain("summary");
+        output.shouldContain("help");
+
+        output = ExecuteHelper.run("help", "help");
+        output.shouldContain("Available commands are:");
+
+        output = ExecuteHelper.run("help", "wrongcommand");
+        output.shouldContain("Unknown command");
+
+        output = ExecuteHelper.run("help", "wrongcommand", "wrongarguments");
+        output.shouldContain("Too many arguments");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/cmd/TestPrint.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.cmd;
+
+import java.io.FileWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import jdk.test.lib.process.OutputAnalyzer;
+
+/*
+ * @test
+ * @summary Test jfr print
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.cmd.TestPrint
+ */
+public class TestPrint {
+
+    public static void main(String[] args) throws Exception {
+
+        OutputAnalyzer output = ExecuteHelper.run("print");
+        output.shouldContain("Missing file");
+
+        output = ExecuteHelper.run("print", "missing.jfr");
+        output.shouldContain("Could not find file ");
+
+        output = ExecuteHelper.run("print", "missing.jfr", "option1", "option2");
+        output.shouldContain("Too many arguments");
+
+        Path file = Files.createTempFile("faked-print-file",  ".jfr");
+        FileWriter fw = new FileWriter(file.toFile());
+        fw.write('d');
+        fw.close();
+        output = ExecuteHelper.run("print", "--wrongOption", file.toAbsolutePath().toString());
+        output.shouldContain("Unknown option");
+        Files.delete(file);
+
+        // Also see TestPrintJSON, TestPrintXML and TestPrintDefault.
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/cmd/TestPrintDefault.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.cmd;
+
+import java.nio.file.Path;
+
+import jdk.test.lib.process.OutputAnalyzer;
+
+/*
+ * @test
+ * @key jfr
+ * @summary Tests print --json
+ *
+ * @library /test/lib /test/jdk
+ * @modules java.scripting
+ *          jdk.jfr
+ *
+ * @run main/othervm jdk.jfr.cmd.TestPrintDefault
+ */
+public class TestPrintDefault {
+
+    public static void main(String... args) throws Exception {
+
+        Path recordingFile = ExecuteHelper.createProfilingRecording().toAbsolutePath();
+
+        OutputAnalyzer output = ExecuteHelper.run("print", recordingFile.toString());
+        output.shouldContain("JVMInformation");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/cmd/TestPrintJSON.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.cmd;
+
+import java.nio.file.Path;
+
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedObject;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.nashorn.api.scripting.JSObject;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.process.OutputAnalyzer;
+
+/*
+ * @test
+ * @key jfr
+ * @summary Tests print --json
+ *
+ * @library /test/lib /test/jdk
+ * @modules jdk.scripting.nashorn
+ *          jdk.jfr
+ *
+ * @run main/othervm jdk.jfr.cmd.TestPrintJSON
+ */
+public class TestPrintJSON {
+
+    public static void main(String... args) throws Exception {
+
+        Path recordingFile = ExecuteHelper.createProfilingRecording().toAbsolutePath();
+
+        OutputAnalyzer output = ExecuteHelper.run("print", "--json", recordingFile.toString());
+        String json = output.getStdout();
+
+        // Parse JSON using Nashorn
+        String statement = "var jsonObject = " + json;
+        ScriptEngineManager factory = new ScriptEngineManager();
+        ScriptEngine engine = factory.getEngineByName("nashorn");
+        engine.eval(statement);
+        JSObject o = (JSObject) engine.get("jsonObject");
+        JSObject recording = (JSObject) o.getMember("recording");
+        JSObject events = (JSObject) recording.getMember("events");
+
+        // Verify events are equal
+        try (RecordingFile rf = new RecordingFile(recordingFile)) {
+            for (Object jsonEvent : events.values()) {
+                RecordedEvent recordedEvent = rf.readEvent();
+                double typeId = recordedEvent.getEventType().getId();
+                String startTime = recordedEvent.getStartTime().toString();
+                String duration = recordedEvent.getDuration().toString();
+                Asserts.assertEquals(typeId, ((Number) ((JSObject) jsonEvent).getMember("typeId")).doubleValue());
+                Asserts.assertEquals(startTime, ((JSObject) jsonEvent).getMember("startTime"));
+                Asserts.assertEquals(duration, ((JSObject) jsonEvent).getMember("duration"));
+                assertEquals(jsonEvent, recordedEvent);
+            }
+            Asserts.assertFalse(rf.hasMoreEvents(), "Incorrect number of events");
+        }
+    }
+
+    private static void assertEquals(Object jsonObject, Object jfrObject) throws Exception {
+        // Check object
+        if (jfrObject instanceof RecordedObject) {
+            JSObject values = (JSObject) ((JSObject) jsonObject).getMember("values");
+            RecordedObject recObject = (RecordedObject) jfrObject;
+            Asserts.assertEquals(values.values().size(), recObject.getFields().size());
+            for (ValueDescriptor v : recObject.getFields()) {
+                String name = v.getName();
+                assertEquals(values.getMember(name), recObject.getValue(name));
+                return;
+            }
+        }
+        // Check array
+        if (jfrObject != null && jfrObject.getClass().isArray()) {
+            Object[] jfrArray = (Object[]) jfrObject;
+            JSObject jsArray = (JSObject) jsonObject;
+            for (int i = 0; i < jfrArray.length; i++) {
+                assertEquals(jsArray.getSlot(i), jfrArray[i]);
+            }
+            return;
+        }
+        String jsonText = String.valueOf(jsonObject);
+        // Double.NaN / Double.Inifinity is not supported by JSON format,
+        // use null
+        if (jfrObject instanceof Double) {
+            double expected = ((Double) jfrObject);
+            if (Double.isInfinite(expected) || Double.isNaN(expected)) {
+                Asserts.assertEquals("null", jsonText);
+                return;
+            }
+            double value = Double.parseDouble(jsonText);
+            Asserts.assertEquals(expected, value);
+            return;
+        }
+        // Float.NaN / Float.Inifinity is not supported by JSON format,
+        // use null
+        if (jfrObject instanceof Float) {
+            float expected = ((Float) jfrObject);
+            if (Float.isInfinite(expected) || Float.isNaN(expected)) {
+                Asserts.assertEquals("null", jsonText);
+                return;
+            }
+            float value = Float.parseFloat(jsonText);
+            Asserts.assertEquals(expected, value);
+            return;
+        }
+        if (jfrObject instanceof Integer) {
+            Integer expected = ((Integer) jfrObject);
+            double value = Double.parseDouble(jsonText);
+            Asserts.assertEquals(expected.doubleValue(), value);
+            return;
+        }
+        if (jfrObject instanceof Long) {
+            Long expected = ((Long) jfrObject);
+            double value = Double.parseDouble(jsonText);
+            Asserts.assertEquals(expected.doubleValue(), value);
+            return;
+        }
+
+        String jfrText = String.valueOf(jfrObject);
+        Asserts.assertEquals(jfrText, jsonText, "Primitive values don't match. JSON = " + jsonText);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/cmd/TestPrintXML.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.cmd;
+
+import java.io.StringReader;
+import java.nio.file.Path;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.AbstractMap.SimpleEntry;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedObject;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.process.OutputAnalyzer;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+
+/*
+ * @test
+ * @key jfr
+ * @summary Tests print --xml
+ *
+ * @library /test/lib /test/jdk
+ * @modules java.scripting
+ *          java.xml
+ *          jdk.jfr
+ *
+ * @run main/othervm jdk.jfr.cmd.TestPrintXML
+ */
+public class TestPrintXML {
+
+    public static void main(String... args) throws Exception {
+
+        Path recordingFile = ExecuteHelper.createProfilingRecording().toAbsolutePath();
+
+        OutputAnalyzer output = ExecuteHelper.run("print", "--xml", recordingFile.toString());
+        String xml = output.getStdout();
+        System.out.println(xml);
+        // Parse XML string
+        SAXParserFactory factory = SAXParserFactory.newInstance();
+        SAXParser sp = factory.newSAXParser();
+        XMLReader xr = sp.getXMLReader();
+        RecordingHandler handler = new RecordingHandler();
+        xr.setContentHandler(handler);
+        xr.parse(new InputSource(new StringReader(xml)));
+
+        // Verify that all data was written correctly
+        Iterator<RecordedEvent> it = RecordingFile.readAllEvents(recordingFile).iterator();
+        for (XMLEvent xmlEvent : handler.events) {
+            RecordedEvent re = it.next();
+            if (!compare(re, xmlEvent.values)) {
+                System.out.println(re);
+                System.out.println(xmlEvent.values.toString());
+                throw new Exception("Event doesn't match");
+            }
+        }
+
+    }
+
+    @SuppressWarnings("unchecked")
+    static boolean compare(Object eventObject, Object xmlObject) {
+        if (eventObject == null) {
+            return xmlObject == null;
+        }
+        if (eventObject instanceof RecordedObject) {
+            RecordedObject re = (RecordedObject) eventObject;
+            Map<String, Object> xmlMap = (Map<String, Object>) xmlObject;
+            List<ValueDescriptor> fields = re.getFields();
+            if (fields.size() != xmlMap.size()) {
+                return false;
+            }
+            for (ValueDescriptor v : fields) {
+                String name = v.getName();
+                if (!compare(re.getValue(name), xmlMap.get(name))) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        if (eventObject.getClass().isArray()) {
+            Object[] array = (Object[]) eventObject;
+            Object[] xmlArray = (Object[]) xmlObject;
+            if (array.length != xmlArray.length) {
+                return false;
+            }
+            for (int i = 0; i < array.length; i++) {
+                if (!compare(array[i], xmlArray[i])) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        String s1 = String.valueOf(eventObject);
+        String s2 = (String) xmlObject;
+        return s1.equals(s2);
+    }
+
+    static class XMLEvent {
+        String name;
+        Instant startTime;
+        Duration duration;
+        Map<String, Object> values = new HashMap<>();
+
+        XMLEvent(String name, Instant startTime, Duration duration) {
+            this.name = name;
+            this.startTime = startTime;
+            this.duration = duration;
+        }
+    }
+
+    public static final class RecordingHandler extends DefaultHandler {
+
+        private Stack<Object> objects = new Stack<>();
+        private Stack<SimpleEntry<String, String>> elements = new Stack<>();
+        private List<XMLEvent> events = new ArrayList<>();
+
+        @Override
+        public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException {
+            elements.push(new SimpleEntry<>(attrs.getValue("name"), attrs.getValue("index")));
+            switch (qName) {
+            case "null":
+                objects.pop();
+                objects.push(null);
+                break;
+            case "event":
+                Instant startTime = Instant.parse(attrs.getValue("startTime"));
+                Duration duration = Duration.parse(attrs.getValue("duration"));
+                objects.push(new XMLEvent(attrs.getValue("name"), startTime, duration));
+                break;
+            case "struct":
+                objects.push(new HashMap<String, Object>());
+                break;
+            case "array":
+                objects.push(new Object[Integer.parseInt(attrs.getValue("size"))]);
+                break;
+            case "value":
+                objects.push(new StringBuilder());
+                break;
+            }
+        }
+
+        @Override
+        public void characters(char[] ch, int start, int length) throws SAXException {
+            if (!objects.isEmpty()) {
+                Object o = objects.peek();
+                if (o instanceof StringBuilder) {
+                    ((StringBuilder) o).append(ch, start, length);
+                }
+            }
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public void endElement(String uri, String localName, String qName) {
+            SimpleEntry<String, String> element = elements.pop();
+            switch (qName) {
+            case "event":
+            case "struct":
+            case "array":
+            case "value":
+                String name = element.getKey();
+                Object value = objects.pop();
+                if (objects.isEmpty()) {
+                    events.add((XMLEvent) value);
+                    return;
+                }
+                if (value instanceof StringBuilder) {
+                    value = ((StringBuilder) value).toString();
+                }
+                Object parent = objects.peek();
+                if (parent instanceof XMLEvent) {
+                    ((XMLEvent) parent).values.put(name, value);
+                }
+                if (parent instanceof Map) {
+                    ((Map<String, Object>) parent).put(name, value);
+                }
+                if (parent != null && parent.getClass().isArray()) {
+                    int index = Integer.parseInt(element.getValue());
+                    ((Object[]) parent)[index] = value;
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/cmd/TestReconstruct.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.cmd;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import jdk.jfr.Event;
+import jdk.jfr.Name;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.jfr.internal.Repository;
+import jdk.jfr.internal.SecuritySupport.SafePath;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.process.OutputAnalyzer;
+
+/*
+ * @test
+ * @summary Test jfr reconstruct
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @modules jdk.jfr/jdk.jfr.internal
+ * @run main/othervm jdk.jfr.cmd.TestReconstruct
+ */
+public class TestReconstruct {
+
+    @Name("Correlation")
+    static class CorrelationEvent extends Event {
+        int id;
+    }
+    private static int RECORDING_COUNT = 5;
+
+    @SuppressWarnings("resource")
+    public static void main(String[] args) throws Exception {
+        // Create some disk recordings
+        Recording[] recordings = new Recording[5];
+        for (int i = 0; i < RECORDING_COUNT; i++) {
+            Recording r = new Recording();
+            r.setToDisk(true);
+            r.start();
+            CorrelationEvent ce = new CorrelationEvent();
+            ce.id = i;
+            ce.commit();
+            r.stop();
+            recordings[i] = r;
+        }
+        Path dir = Paths.get("reconstruction-parts");
+        Files.createDirectories(dir);
+
+        long expectedCount = 0;
+        for (int i = 0; i < RECORDING_COUNT; i++) {
+            Path tmp = dir.resolve("chunk-part-" + i + ".jfr");
+            recordings[i].dump(tmp);
+            expectedCount += countEventInRecording(tmp);
+        }
+
+        SafePath repository = Repository.getRepository().getRepositoryPath();
+        Path destinationPath = Paths.get("reconstructed.jfr");
+
+        String directory = repository.toString();
+        String destination = destinationPath.toAbsolutePath().toString();
+
+        // Test failure
+        OutputAnalyzer output = ExecuteHelper.run("reconstruct");
+
+        output.shouldContain("Too few arguments");
+
+        output = ExecuteHelper.run("reconstruct", directory);
+        output.shouldContain("Too few arguments");
+
+        output = ExecuteHelper.run("reconstruct", "not-a-directory", destination);
+        output.shouldContain("Could not find disk repository at");
+
+        output = ExecuteHelper.run("reconstruct", directory, "not-a-destination");
+        output.shouldContain("Filename must end with .jfr");
+
+        output = ExecuteHelper.run("reconstruct", "--wrongOption", directory, destination);
+        output.shouldContain("Too many arguments");
+
+        FileWriter fw = new FileWriter(destination);
+        fw.write('d');
+        fw.close();
+        output = ExecuteHelper.run("reconstruct", directory, destination);
+        output.shouldContain("already exists");
+        Files.delete(destinationPath);
+
+        // test success
+        output = ExecuteHelper.run("reconstruct", directory, destination);
+        System.out.println(output.getOutput());
+        output.shouldContain("Reconstruction complete");
+
+        long reconstructedCount = countEventInRecording(destinationPath);
+        Asserts.assertEquals(expectedCount, reconstructedCount);
+        // Cleanup
+        for (int i = 0; i < RECORDING_COUNT; i++) {
+            recordings[i].close();
+        }
+    }
+
+    private static long countEventInRecording(Path file) throws IOException {
+        Integer lastId = -1;
+        try (RecordingFile rf = new RecordingFile(file)) {
+            long count = 0;
+            while (rf.hasMoreEvents()) {
+                RecordedEvent re = rf.readEvent();
+                if (re.getEventType().getName().equals("Correlation")) {
+                    Integer id = re.getValue("id");
+                    if (id < lastId) {
+                        Asserts.fail("Expected chunk number to increase");
+                    }
+                    lastId = id;
+                }
+                count++;
+            }
+            return count;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/cmd/TestSplit.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.cmd;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import jdk.jfr.Configuration;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.process.OutputAnalyzer;
+
+/*
+ * @test
+ * @summary Test jfr split
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.cmd.TestSplit
+ */
+public class TestSplit {
+
+    public static void main(String[] args) throws Exception {
+        SimpleDateFormat formatter = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
+        String dateText = formatter.format(new Date());
+
+        Path recordingFileA = Paths.get("many-chunks-A-" + dateText + ".jfr");
+        Path recordingFileB = Paths.get("many-chunks-B-" + dateText + ".jfr");
+        makeRecordingWithChunks(6, recordingFileA);
+        Files.copy(recordingFileA, recordingFileB);
+
+        String fileAText = recordingFileA.toAbsolutePath().toString();
+        String fileBText = recordingFileB.toAbsolutePath().toString();
+
+        OutputAnalyzer output = ExecuteHelper.run("split");
+        output.shouldContain("Missing file");
+
+        output = ExecuteHelper.run("split", "--wrongOption1", "..wrongOption2", "..wrongOption3", fileAText);
+        output.shouldContain("Too many arguments");
+
+        output = ExecuteHelper.run("split", "--wrongOption", fileAText);
+        output.shouldContain("Unknown option");
+
+        output = ExecuteHelper.run("split", "--wrongOption", "1", fileAText);
+        output.shouldContain("Unknown option");
+
+        output = ExecuteHelper.run("split", "--maxchunks", "-3", fileAText);
+        output.shouldContain("Must be at least one chunk per file");
+
+        output = ExecuteHelper.run("split", "--maxchunks", "1000", fileAText);
+        output.shouldContain("Number of chunks in recording");
+        output.shouldContain("doesn't exceed max chunks");
+        output = ExecuteHelper.run("split", fileAText); // maxchunks is 5 by
+                                                        // default
+        System.out.println(output.getOutput());
+        System.out.println(fileAText);
+        verifyRecording(fileAText.substring(0, fileAText.length() - 4) + "_1.jfr");
+        verifyRecording(fileAText.substring(0, fileAText.length() - 4) + "_2.jfr");
+
+        output = ExecuteHelper.run("split", "--maxchunks", "2", fileBText);
+
+        verifyRecording(fileBText.substring(0, fileBText.length() - 4) + "_1.jfr");
+        verifyRecording(fileBText.substring(0, fileBText.length() - 4) + "_2.jfr");
+        verifyRecording(fileBText.substring(0, fileBText.length() - 4) + "_3.jfr");
+
+        output = ExecuteHelper.run("split", "--maxchunks", "2", fileBText);
+        output.shouldContain("file with that name already exist");
+    }
+
+    private static void verifyRecording(String name) throws IOException {
+        System.out.println("split name " + name);
+        try (RecordingFile rf = new RecordingFile(Paths.get(name))) {
+            rf.readEvent();
+        }
+    }
+
+    // Will create at least 2 * count + 1 chunks.
+    private static void makeRecordingWithChunks(int count, Path file) throws IOException, ParseException {
+        Recording main = new Recording(Configuration.getConfiguration("default"));
+        main.setToDisk(true);
+        main.start();
+        for (int i = 0; i < count; i++) {
+            Recording r = new Recording();
+            r.setToDisk(true);
+            r.start();
+            r.stop();
+            r.close();
+        }
+        main.stop();
+        main.dump(file);
+        main.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/cmd/TestSummary.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.cmd;
+
+import java.nio.file.Path;
+
+import jdk.jfr.EventType;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.process.OutputAnalyzer;
+
+/*
+ * @test
+ * @summary Test jfr info
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.cmd.TestSummary
+ */
+public class TestSummary {
+
+    public static void main(String[] args) throws Exception {
+        Path f = ExecuteHelper.createProfilingRecording().toAbsolutePath();
+        String file = f.toAbsolutePath().toString();
+
+        OutputAnalyzer output = ExecuteHelper.run("summary");
+        output.shouldContain("Missing file");
+
+        output = ExecuteHelper.run("summary", "--wrongOption", file);
+        output.shouldContain("Too many arguments");
+
+        output = ExecuteHelper.run("summary", file);
+        try (RecordingFile rf = new RecordingFile(f)) {
+            for (EventType t : rf.readEventTypes()) {
+                output.shouldContain(t.getName());
+            }
+        }
+        output.shouldContain("Version");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/TEST.properties	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,2 @@
+modules = java.management
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/compiler/TestAllocInNewTLAB.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.compiler;
+
+import static java.lang.Math.floor;
+import static jdk.test.lib.Asserts.assertGreaterThanOrEqual;
+import static jdk.test.lib.Asserts.assertLessThanOrEqual;
+
+import java.time.Duration;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Test that event is triggered when an object is allocated in a new TLAB.
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm -XX:+UseTLAB -XX:TLABSize=100k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=1 jdk.jfr.event.compiler.TestAllocInNewTLAB
+ * @run main/othervm -XX:+UseTLAB -XX:TLABSize=100k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=1 -XX:-FastTLABRefill jdk.jfr.event.compiler.TestAllocInNewTLAB
+ * @run main/othervm -XX:+UseTLAB -XX:TLABSize=100k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=1 -Xint jdk.jfr.event.compiler.TestAllocInNewTLAB
+ */
+
+/**
+ * Test that when an object is allocated in a new Thread Local Allocation Buffer (TLAB)
+ * an event will be triggered. The test is done for C1-compiler,
+ * C2-compiler (-XX:-FastTLABRefill) and interpreted mode (-Xint).
+ *
+ * To force objects to be allocated in a new TLAB:
+ *      the size of TLAB is set to 100k (-XX:TLABSize=100k);
+ *      the size of allocated objects is set to 100k minus 16 bytes overhead;
+ *      max TLAB waste at refill is set to minimum (-XX:TLABRefillWasteFraction=1),
+ *          to provoke a new TLAB creation.
+ */
+public class TestAllocInNewTLAB {
+    private final static String EVENT_NAME = EventNames.ObjectAllocationInNewTLAB;
+
+    private static final int BYTE_ARRAY_OVERHEAD = 16; // Extra bytes used by a byte array.
+    private static final int OBJECT_SIZE  = 100 * 1024;
+    private static final int OBJECT_SIZE_ALT = OBJECT_SIZE + 8; // Object size in case of disabled CompressedOops
+    private static final int OBJECTS_TO_ALLOCATE = 100;
+    private static final String BYTE_ARRAY_CLASS_NAME = new byte[0].getClass().getName();
+    private static final int INITIAL_TLAB_SIZE = 100 * 1024;
+
+    // make sure allocation isn't dead code eliminated
+    public static byte[] tmp;
+
+    public static void main(String[] args) throws Exception {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME).withThreshold(Duration.ofMillis(0));
+
+        recording.start();
+        System.gc();
+        for (int i = 0; i < OBJECTS_TO_ALLOCATE; ++i) {
+            tmp = new byte[OBJECT_SIZE - BYTE_ARRAY_OVERHEAD];
+        }
+        recording.stop();
+
+        int countAllTlabs = 0;  // Count all matching tlab allocations.
+        int countFullTlabs = 0; // Count matching tlab allocations with full tlab size.
+        for (RecordedEvent event : Events.fromRecording(recording)) {
+            if (!EVENT_NAME.equals(event.getEventType().getName())) {
+                continue;
+            }
+            System.out.println("Event:" + event);
+
+            long allocationSize = Events.assertField(event, "allocationSize").atLeast(1L).getValue();
+            long tlabSize = Events.assertField(event, "tlabSize").atLeast(allocationSize).getValue();
+            String className = Events.assertField(event, "objectClass.name").notEmpty().getValue();
+
+            boolean isMyEvent = Thread.currentThread().getId() == event.getThread().getJavaThreadId()
+                 && className.equals(BYTE_ARRAY_CLASS_NAME)
+                 && (allocationSize == OBJECT_SIZE || allocationSize == OBJECT_SIZE_ALT);
+            if (isMyEvent) {
+                countAllTlabs++;
+                if (tlabSize == INITIAL_TLAB_SIZE + OBJECT_SIZE || tlabSize == INITIAL_TLAB_SIZE + OBJECT_SIZE_ALT) {
+                    countFullTlabs++;
+                }
+            }
+        }
+
+        int minCount = (int) floor(OBJECTS_TO_ALLOCATE * 0.80);
+        assertGreaterThanOrEqual(countAllTlabs, minCount, "Too few tlab objects allocated");
+        assertLessThanOrEqual(countAllTlabs, OBJECTS_TO_ALLOCATE, "Too many tlab objects allocated");
+
+        // For most GCs we expect the size of each tlab to be
+        // INITIAL_TLAB_SIZE + ALLOCATION_SIZE, but that is not always true for G1.
+        // G1 may use a smaller tlab size if the full tlab does not fit in the
+        // selected memory region.
+        //
+        // For example, if a G1 memory region has room for 4.7 tlabs,
+        // then the first 4 tlabs will have the expected size,
+        // but the fifth tlab would only have a size of 0.7*expected.
+        //
+        // It is only the last tlab in each region that has a smaller size.
+        // This means that at least 50% of the allocated tlabs should
+        // have the expected size (1 full tlab, and 1 fractional tlab).
+        assertGreaterThanOrEqual(2*countFullTlabs, countAllTlabs, "Too many fractional tlabs.");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/compiler/TestAllocOutsideTLAB.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.compiler;
+
+import static java.lang.Math.floor;
+import static jdk.test.lib.Asserts.assertGreaterThanOrEqual;
+import static jdk.test.lib.Asserts.assertLessThanOrEqual;
+
+import java.time.Duration;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Test that when an object is allocated outside a TLAB an event will be triggered.
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm -XX:+UseTLAB -XX:-FastTLABRefill -XX:TLABSize=90k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=256 jdk.jfr.event.compiler.TestAllocOutsideTLAB
+ * @run main/othervm -XX:+UseTLAB -XX:-FastTLABRefill -XX:TLABSize=90k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=256 jdk.jfr.event.compiler.TestAllocOutsideTLAB
+ * @run main/othervm -XX:+UseTLAB -XX:-FastTLABRefill -XX:TLABSize=90k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=256 -Xint jdk.jfr.event.compiler.TestAllocOutsideTLAB
+ */
+
+/**
+ * Test that an event is triggered when an object is allocated outside a
+ * Thread Local Allocation Buffer (TLAB). The test is done for C1-compiler,
+ * C2-compiler (-XX:-FastTLABRefill) and interpreted mode (-Xint).
+ *
+ * To force objects to be allocated outside TLAB:
+ *      the size of TLAB is set to 90k (-XX:TLABSize=90k);
+ *      the size of allocated objects is set to 100k.
+ *      max TLAB waste at refill is set to 256 (-XX:TLABRefillWasteFraction=256),
+ *          to prevent a new TLAB creation.
+*/
+public class TestAllocOutsideTLAB {
+    private static final String EVENT_NAME = EventNames.ObjectAllocationOutsideTLAB;
+
+    private static final int BYTE_ARRAY_OVERHEAD = 16; // Extra bytes used by a byte array
+    private static final int OBJECT_SIZE = 100 * 1024;
+    private static final int OBJECT_SIZE_ALT = OBJECT_SIZE + 8; // Object size in case of disabled CompressedOops
+    private static final int OBJECTS_TO_ALLOCATE = 100;
+    private static final String BYTE_ARRAY_CLASS_NAME = new byte[0].getClass().getName();
+
+    public static byte[] tmp; // Used to prevent optimizer from removing code.
+
+    public static void main(String[] args) throws Exception {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME).withThreshold(Duration.ofMillis(0));
+        recording.start();
+        for (int i = 0; i < OBJECTS_TO_ALLOCATE; ++i) {
+            tmp = new byte[OBJECT_SIZE - BYTE_ARRAY_OVERHEAD];
+        }
+        recording.stop();
+
+        int countEvents = 0;
+        for (RecordedEvent event : Events.fromRecording(recording)) {
+            if (!EVENT_NAME.equals(event.getEventType().getName())) {
+                continue;
+            }
+            System.out.println("Event:" + event);
+
+            long allocationSize = Events.assertField(event, "allocationSize").atLeast(1L).getValue();
+            String className = Events.assertField(event, "objectClass.name").notEmpty().getValue();
+
+            boolean isMyEvent = Thread.currentThread().getId() == event.getThread().getJavaThreadId()
+                && className.equals(BYTE_ARRAY_CLASS_NAME)
+                 && (allocationSize == OBJECT_SIZE || allocationSize == OBJECT_SIZE_ALT);
+            if (isMyEvent) {
+                ++countEvents;
+            }
+        }
+
+        int minCount = (int) floor(OBJECTS_TO_ALLOCATE * 0.80);
+        assertGreaterThanOrEqual(countEvents, minCount, "Too few tlab objects allocated");
+        assertLessThanOrEqual(countEvents, OBJECTS_TO_ALLOCATE, "Too many tlab objects allocated");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/compiler/TestCodeCacheConfig.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.compiler;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import sun.hotspot.WhiteBox;
+
+/*
+ * @test TestCodeCacheConfig
+ * @key jfr
+ * @library /test/lib
+ * @build sun.hotspot.WhiteBox
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *     sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:.
+ *     -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *     -XX:+SegmentedCodeCache jdk.jfr.event.compiler.TestCodeCacheConfig
+ * @run main/othervm -Xbootclasspath/a:.
+ *     -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *     -XX:-SegmentedCodeCache jdk.jfr.event.compiler.TestCodeCacheConfig
+ * @summary check "Code Cache Configuration" jfr event
+ */
+public class TestCodeCacheConfig {
+    private final static String EVENT_NAME = EventNames.CodeCacheConfiguration;
+
+    private static final long CodeCacheExpectedSize = WhiteBox.getWhiteBox().getUintxVMFlag("ReservedCodeCacheSize");
+
+    public static void main(String[] args) throws Exception {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME);
+        recording.start();
+        recording.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        Events.hasEvents(events);
+        RecordedEvent event = events.get(0);
+        long initialSize = (long) event.getValue("initialSize");
+        long reservedSize = (long) event.getValue("reservedSize");
+        long nonNMethodSize = (long) event.getValue("nonNMethodSize");
+        long profiledSize = (long) event.getValue("profiledSize");
+        long nonProfiledSize = (long) event.getValue("nonProfiledSize");
+        long expansionSize = (long) event.getValue("expansionSize");
+        long minBlockLength = (long) event.getValue("minBlockLength");
+        long startAddress = (long) event.getValue("startAddress");
+        long reservedTopAddress = (long) event.getValue("reservedTopAddress");
+
+        Asserts.assertGT(initialSize, 1024L,
+            "initialSize less than 1024 byte, got " + initialSize);
+
+        Asserts.assertEQ(reservedSize, CodeCacheExpectedSize,
+            String.format("Unexpected reservedSize value. Expected %d but " + "got %d", CodeCacheExpectedSize, reservedSize));
+
+        Asserts.assertLTE(nonNMethodSize, CodeCacheExpectedSize,
+            String.format("Unexpected nonNMethodSize value. Expected <= %d but " + "got %d", CodeCacheExpectedSize, nonNMethodSize));
+
+        Asserts.assertLTE(profiledSize, CodeCacheExpectedSize,
+            String.format("Unexpected profiledSize value. Expected <= %d but " + "got %d", CodeCacheExpectedSize, profiledSize));
+
+        Asserts.assertLTE(nonProfiledSize, CodeCacheExpectedSize,
+            String.format("Unexpected nonProfiledSize value. Expected <= %d but " + "got %d", CodeCacheExpectedSize, nonProfiledSize));
+
+        Asserts.assertGTE(expansionSize, 1024L,
+            "expansionSize less than 1024 " + "bytes, got " + expansionSize);
+
+        Asserts.assertGTE(minBlockLength, 1L,
+            "minBlockLength less than 1 byte, got " + minBlockLength);
+
+        Asserts.assertNE(startAddress, 0L,
+            "startAddress null");
+
+        Asserts.assertNE(reservedTopAddress, 0L,
+            "codeCacheReservedTopAddr null");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/compiler/TestCodeCacheFull.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.compiler;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import sun.hotspot.WhiteBox;
+import sun.hotspot.code.BlobType;
+
+/*
+ * @test TestCodeCacheFull
+ *
+ * @library /test/lib
+ * @modules jdk.jfr
+ *          jdk.management.jfr
+ * @build sun.hotspot.WhiteBox
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission
+ *
+ * @run main/othervm -Xbootclasspath/a:.
+ *     -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *     -XX:+SegmentedCodeCache -XX:-UseLargePages jdk.jfr.event.compiler.TestCodeCacheFull
+ * @run main/othervm -Xbootclasspath/a:.
+ *     -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *     -XX:-SegmentedCodeCache jdk.jfr.event.compiler.TestCodeCacheFull
+ */
+public class TestCodeCacheFull {
+
+    public static void main(String[] args) throws Exception {
+        for (BlobType btype : BlobType.getAvailable()) {
+            testWithBlobType(btype, calculateAvailableSize(btype));
+        }
+    }
+
+    private static void testWithBlobType(BlobType btype, long availableSize) throws Exception {
+        Recording r = new Recording();
+        r.enable(EventNames.CodeCacheFull);
+        r.start();
+        WhiteBox.getWhiteBox().allocateCodeBlob(availableSize, btype.id);
+        r.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(r);
+        Events.hasEvents(events);
+        RecordedEvent event = events.get(0);
+
+        String codeBlobType = Events.assertField(event, "codeBlobType").notNull().getValue();
+        BlobType blobType = blobTypeFromName(codeBlobType);
+        Asserts.assertTrue(blobType.allowTypeWhenOverflow(blobType), "Unexpected overflow BlobType " + blobType.id);
+        Events.assertField(event, "entryCount").atLeast(0);
+        Events.assertField(event, "methodCount").atLeast(0);
+        Events.assertEventThread(event);
+        Events.assertField(event, "fullCount").atLeast(0);
+        Events.assertField(event, "startAddress").notEqual(0L);
+        Events.assertField(event, "commitedTopAddress").notEqual(0L);
+        Events.assertField(event, "reservedTopAddress").notEqual(0L);
+    }
+
+    private static BlobType blobTypeFromName(String codeBlobTypeName) throws Exception {
+        for (BlobType t : BlobType.getAvailable()) {
+            if (t.beanName.equals(codeBlobTypeName)) {
+                return t;
+            }
+        }
+        throw new Exception("Unexpected event " + codeBlobTypeName);
+    }
+
+    // Compute the available size for this BlobType by taking into account
+    // that it may be stored in a different code heap in case it does not fit
+    // into the current one.
+    private static long calculateAvailableSize(BlobType btype) {
+        long availableSize = btype.getSize();
+        for (BlobType alternative : BlobType.getAvailable()) {
+            if (btype.allowTypeWhenOverflow(alternative)) {
+                availableSize = Math.max(availableSize, alternative.getSize());
+            }
+        }
+        return availableSize;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/compiler/TestCodeCacheStats.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.compiler;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.event.compiler.TestCodeCacheStats
+ */
+
+public class TestCodeCacheStats {
+    private final static String EVENT_NAME = EventNames.CodeCacheStatistics;
+
+    public static void main(String[] args) throws Exception {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME);
+        recording.start();
+        recording.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        Events.hasEvents(events);
+        for (RecordedEvent event : events) {
+            System.out.println("Event:" + event);
+            Events.assertField(event, "startAddress");
+            Events.assertField(event, "reservedTopAddress");
+            Events.assertField(event, "entryCount").atLeast(0);
+            Events.assertField(event, "methodCount").atLeast(0);
+            Events.assertField(event, "adaptorCount").atLeast(0);
+            Events.assertField(event, "unallocatedCapacity").atLeast(1024L);
+            Events.assertField(event, "fullCount").equal(0);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/compiler/TestCodeSweeper.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.compiler;
+
+import java.lang.management.MemoryPoolMXBean;
+import java.lang.reflect.Method;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import sun.hotspot.WhiteBox;
+import sun.hotspot.code.BlobType;
+import sun.hotspot.code.CodeBlob;
+
+/**
+ * Test for events: vm/code_sweeper/sweep vm/code_cache/full vm/compiler/failure
+ *
+ * We verify: 1. That sweptCount >= flushedCount + zombifiedCount 2. That
+ * sweepIndex increases by 1. 3. We should get at least one of each of the
+ * events listed above.
+ *
+ * NOTE! The test is usually able to trigger the events but not always. If an
+ * event is received, the event is verified. If an event is missing, we do NOT
+ * fail.
+ */
+/*
+ * @test TestCodeSweeper
+ * @key jfr
+ * @library /test/lib
+ * @build sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox
+ *                                sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:-SegmentedCodeCache -XX:+WhiteBoxAPI jdk.jfr.event.compiler.TestCodeSweeper
+ */
+
+public class TestCodeSweeper {
+    private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
+    private static final int COMP_LEVEL_SIMPLE = 1;
+    private static final int COMP_LEVEL_FULL_OPTIMIZATION = 4;
+    private static final int SIZE = 1;
+    private static final String METHOD_NAME = "verifyFullEvent";
+    private static final String pathSweep = EventNames.SweepCodeCache;
+    private static final String pathFull = EventNames.CodeCacheFull;
+    private static final String pathFailure = EventNames.CompilationFailure;
+    public static final long SEGMENT_SIZE = WhiteBox.getWhiteBox().getUintxVMFlag("CodeCacheSegmentSize");
+    public static final long MIN_BLOCK_LENGTH = WhiteBox.getWhiteBox().getUintxVMFlag("CodeCacheMinBlockLength");
+    public static final long MIN_ALLOCATION = SEGMENT_SIZE * MIN_BLOCK_LENGTH;
+    private static final double CACHE_USAGE_COEF = 0.95d;
+
+    public static void main(String[] args) throws Throwable {
+        Asserts.assertTrue(BlobType.getAvailable().contains(BlobType.All), "Test does not support SegmentedCodeCache");
+
+        System.out.println("************************************************");
+        System.out.println("This test will warn that the code cache is full.");
+        System.out.println("That is expected and is the purpose of the test.");
+        System.out.println("************************************************");
+
+        Recording r = new Recording();
+        r.enable(pathSweep);
+        r.enable(pathFull);
+        r.enable(pathFailure);
+        r.start();
+        provokeEvents();
+        r.stop();
+
+        int countEventSweep = 0;
+        int countEventFull = 0;
+        int countEventFailure = 0;
+
+        List<RecordedEvent> events = Events.fromRecording(r);
+        Events.hasEvents(events);
+        for (RecordedEvent event : events) {
+            switch (event.getEventType().getName()) {
+            case pathSweep:
+                countEventSweep++;
+                verifySingleSweepEvent(event);
+                break;
+            case pathFull:
+                countEventFull++;
+                verifyFullEvent(event);
+                break;
+            case pathFailure:
+                countEventFailure++;
+                verifyFailureEvent(event);
+                break;
+            }
+        }
+
+        System.out.println(String.format("eventCount: %d, %d, %d", countEventSweep, countEventFull, countEventFailure));
+    }
+
+    private static boolean canAllocate(double size, long maxSize, MemoryPoolMXBean bean) {
+        // Don't fill too much to have space for adapters. So, stop after crossing 95% and
+        // don't allocate in case we'll cross 97% on next allocation.
+        double used = bean.getUsage().getUsed();
+        return (used <= CACHE_USAGE_COEF * maxSize) &&
+               (used + size <= (CACHE_USAGE_COEF + 0.02d)  * maxSize);
+    }
+
+    private static void provokeEvents() throws NoSuchMethodException, InterruptedException {
+        // Prepare for later, since we don't want to trigger any compilation
+        // setting this up.
+        Method method = TestCodeSweeper.class.getDeclaredMethod(METHOD_NAME, new Class[] { RecordedEvent.class });
+        String directive = "[{ match: \"" + TestCodeSweeper.class.getName().replace('.', '/')
+                + "." + METHOD_NAME + "\", " + "BackgroundCompilation: false }]";
+
+        // Fill up code heaps until they are almost full
+        // to trigger the vm/code_sweeper/sweep event.
+        ArrayList<Long> blobs = new ArrayList<>();
+        MemoryPoolMXBean bean = BlobType.All.getMemoryPool();
+        long max = bean.getUsage().getMax();
+        long headerSize = getHeaderSize(BlobType.All);
+        long minAllocationUnit = Math.max(1, MIN_ALLOCATION - headerSize);
+        long stopAt = max - minAllocationUnit;
+        long addr = 0;
+
+        // First allocate big blobs to speed things up
+        for (long size = 100_000 * minAllocationUnit; size > 0; size /= 10) {
+            while (canAllocate(size, max, bean) &&
+                   (addr = WHITE_BOX.allocateCodeBlob(size, BlobType.All.id)) != 0) {
+                blobs.add(addr);
+            }
+        }
+
+        // Now allocate small blobs until the heap is almost full
+        while (bean.getUsage().getUsed() < stopAt &&
+               (addr = WHITE_BOX.allocateCodeBlob(SIZE, BlobType.All.id)) != 0) {
+            blobs.add(addr);
+        }
+
+        // Trigger the vm/code_cache/full event by compiling one more
+        // method. This also triggers the vm/compiler/failure event.
+        Asserts.assertTrue(WHITE_BOX.addCompilerDirective(directive) == 1);
+        try {
+            if (!WHITE_BOX.enqueueMethodForCompilation(method, COMP_LEVEL_FULL_OPTIMIZATION)) {
+                WHITE_BOX.enqueueMethodForCompilation(method, COMP_LEVEL_SIMPLE);
+            }
+        } finally {
+            WHITE_BOX.removeCompilerDirective(1);
+        }
+
+        // Free memory
+        for (Long blob : blobs) {
+            WHITE_BOX.freeCodeBlob(blob);
+        }
+    }
+
+    private static void verifyFullEvent(RecordedEvent event) throws Throwable {
+        Events.assertField(event, "codeBlobType").notEmpty();
+        Events.assertField(event, "unallocatedCapacity").atLeast(0L);
+        Events.assertField(event, "entryCount").atLeast(0);
+        Events.assertField(event, "methodCount").atLeast(0);
+        Events.assertField(event, "adaptorCount").atLeast(0);
+        Events.assertField(event, "fullCount").atLeast(0);
+
+        // Verify startAddress <= commitedTopAddress <= reservedTopAddress.
+        // Addresses may be so big that they overflow a long (treated as a
+        // negative value), convert value to an octal string and compare the
+        // string.
+        String startAddress = Long.toOctalString(Events.assertField(event, "startAddress").getValue());
+        String commitedTopAddress = Long.toOctalString(Events.assertField(event, "commitedTopAddress").getValue());
+        String reservedTopAddress = Long.toOctalString(Events.assertField(event, "reservedTopAddress").getValue());
+        Asserts.assertTrue(isOctalLessOrEqual(startAddress, commitedTopAddress), "startAddress<=commitedTopAddress: " + startAddress + "<=" + commitedTopAddress);
+        Asserts.assertTrue(isOctalLessOrEqual(commitedTopAddress, reservedTopAddress), "commitedTopAddress<=reservedTopAddress: " + commitedTopAddress + "<=" + reservedTopAddress);
+    }
+
+    private static void verifyFailureEvent(RecordedEvent event) throws Throwable {
+        Events.assertField(event, "failureMessage").notEmpty();
+        Events.assertField(event, "compileId").atLeast(0);
+    }
+
+    private static void verifySingleSweepEvent(RecordedEvent event) throws Throwable {
+        int flushedCount = Events.assertField(event, "flushedCount").atLeast(0).getValue();
+        int zombifiedCount = Events.assertField(event, "zombifiedCount").atLeast(0).getValue();
+        Events.assertField(event, "sweptCount").atLeast(flushedCount + zombifiedCount);
+        Events.assertField(event, "sweepId").atLeast(0);
+        Asserts.assertGreaterThanOrEqual(event.getStartTime(), Instant.EPOCH, "startTime was < 0");
+        Asserts.assertGreaterThanOrEqual(event.getEndTime(), event.getStartTime(), "startTime was > endTime");
+    }
+
+    /** Returns true if less <= bigger. */
+    private static boolean isOctalLessOrEqual(String less, String bigger) {
+        if (less.length() > bigger.length()) {
+            return false;
+        }
+        if (less.length() < bigger.length()) {
+            return true;
+        }
+        return less.compareTo(bigger) <= 0;
+    }
+
+    public static final long getHeaderSize(BlobType btype) {
+        long addr = WHITE_BOX.allocateCodeBlob(0, btype.id);
+        int size = CodeBlob.getCodeBlob(addr).size;
+        WHITE_BOX.freeCodeBlob(addr);
+        return size;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/compiler/TestCodeSweeperConfig.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.compiler;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm -XX:+UseCodeCacheFlushing -XX:-SegmentedCodeCache jdk.jfr.event.compiler.TestCodeSweeperConfig
+ * @run main/othervm -XX:+UseCodeCacheFlushing -XX:+SegmentedCodeCache jdk.jfr.event.compiler.TestCodeSweeperConfig
+ */
+public class TestCodeSweeperConfig {
+
+    private final static String EVENT_NAME = EventNames.CodeSweeperConfiguration;
+
+    public static void main(String[] args) throws Exception {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME);
+        recording.start();
+        recording.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        Events.hasEvents(events);
+        for (RecordedEvent event : events) {
+            System.out.println("Event: " + event);
+            Events.assertField(event, "sweeperEnabled").equal(true);
+            Events.assertField(event, "flushingEnabled").equal(true);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/compiler/TestCodeSweeperStats.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.compiler;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.file.Paths;
+import java.util.List;
+
+import sun.hotspot.WhiteBox;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.classloader.FilterClassLoader;
+import jdk.test.lib.classloader.ParentLastURLClassLoader;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.Utils;
+
+/*
+ * @test TestCodeSweeperStats
+ * @key jfr
+ * @library /test/lib
+ * @requires vm.compMode!="Xint"
+ * @build sun.hotspot.WhiteBox
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *     sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:.
+ *     -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *     -XX:CompileOnly=jdk.jfr.event.compiler.TestCodeSweeperStats::dummyMethod
+ *     -XX:+SegmentedCodeCache jdk.jfr.event.compiler.TestCodeSweeperStats
+ * @run main/othervm -Xbootclasspath/a:.
+ *     -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *     -XX:CompileOnly=jdk.jfr.event.compiler.TestCodeSweeperStats::dummyMethod
+ *     -XX:-SegmentedCodeCache jdk.jfr.event.compiler.TestCodeSweeperStats
+ */
+public class TestCodeSweeperStats {
+    private static final String EVENT_NAME = EventNames.CodeSweeperStatistics;
+    private static final int WAIT_TIME = 10_000;
+    private static final String CLASS_METHOD_TO_COMPILE = "dummyMethod";
+    private static final int METHODS_TO_COMPILE = Integer.getInteger("compile.methods.count", 10);
+    private static final int COMP_LEVEL_SIMPLE = 1;
+    private static final int COMP_LEVEL_FULL_OPTIMIZATION = 4;
+
+    public static void main(String[] args) throws Exception {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME).with("period", "endChunk");
+        recording.start();
+        compileAndSweep();
+        recording.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        Events.hasEvents(events);
+        for (RecordedEvent event : events) {
+            Events.assertField(event, "sweepCount").atLeast(1);
+            Events.assertField(event, "methodReclaimedCount").equal(METHODS_TO_COMPILE);
+            Events.assertField(event, "totalSweepTime").atLeast(0L);
+            Events.assertField(event, "peakFractionTime").atLeast(0L);
+            Events.assertField(event, "peakSweepTime").atLeast(0L);
+        }
+    }
+
+    private static void compileAndSweep() throws InterruptedException {
+        WhiteBox WB = WhiteBox.getWhiteBox();
+        for (int i = 0; i < METHODS_TO_COMPILE; i++) {
+            System.out.println("compile " + i);
+            compileMethod();
+        }
+
+        WB.deoptimizeAll();
+        System.out.println("All methods deoptimized");
+
+        // method will be sweeped out of code cache after 5 sweep cycles
+        for (int i = 0; i < 5; i++) {
+            WB.fullGC();
+            WB.forceNMethodSweep();
+
+        }
+        // now wait for event(s) to be fired
+        Thread.sleep(WAIT_TIME);
+    }
+
+    public void dummyMethod() {
+        System.out.println("Hello World!");
+    }
+
+    protected static void compileMethod() {
+        ClassLoader current = TestCodeSweeperStats.class.getClassLoader();
+        String[] cpaths = System.getProperty("test.classes", ".").split(File.pathSeparator);
+        URL[] urls = new URL[cpaths.length];
+        try {
+            for (int i = 0; i < cpaths.length; i++) {
+                urls[i] = Paths.get(cpaths[i]).toUri().toURL();
+            }
+        } catch (MalformedURLException e) {
+            throw new Error(e);
+        }
+
+        String currentClassName = TestCodeSweeperStats.class.getName();
+        FilterClassLoader cl = new FilterClassLoader(new ParentLastURLClassLoader(urls, current), ClassLoader.getSystemClassLoader(), (name) -> currentClassName.equals(name));
+        Class<?> loadedClass = null;
+        String className = currentClassName;
+        try {
+            loadedClass = cl.loadClass(className);
+        } catch (ClassNotFoundException ex) {
+            throw new Error("Couldn't load class " + className, ex);
+        }
+        try {
+            Method mtd = loadedClass.getMethod(CLASS_METHOD_TO_COMPILE);
+            WhiteBox WB = WhiteBox.getWhiteBox();
+            WB.testSetDontInlineMethod(mtd, true);
+            String directive = "[{ match: \"" + TestCodeSweeperStats.class.getName().replace('.', '/')
+                    + "." + CLASS_METHOD_TO_COMPILE + "\", " + "BackgroundCompilation: false }]";
+            WB.addCompilerDirective(directive);
+            if (!WB.enqueueMethodForCompilation(mtd, COMP_LEVEL_FULL_OPTIMIZATION)) {
+                WB.enqueueMethodForCompilation(mtd, COMP_LEVEL_SIMPLE);
+            }
+            Utils.waitForCondition(() -> WB.isMethodCompiled(mtd));
+        } catch (NoSuchMethodException e) {
+            throw new Error("An exception while trying compile method " + e.getMessage(), e);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/compiler/TestCompilerCompile.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.compiler;
+
+import static jdk.test.lib.Asserts.assertFalse;
+
+import java.lang.reflect.Method;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Utils;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import sun.hotspot.WhiteBox;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.compMode!="Xint"
+ * @library /test/lib
+ * @build sun.hotspot.WhiteBox
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *     sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:.
+ *     -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *     jdk.jfr.event.compiler.TestCompilerCompile
+ */
+public class TestCompilerCompile {
+    private final static String EVENT_NAME = EventNames.Compilation;
+    private final static String METHOD_NAME = "dummyMethod";
+    private boolean foundKnownMethod = false;
+    private boolean foundOsrMethod = false;
+
+    public static void main(String[] args) throws Throwable {
+        TestCompilerCompile test = new TestCompilerCompile();
+        test.doTest();
+    }
+
+    static void dummyMethod() {
+        System.out.println("hello!");
+    }
+
+    public void doTest() throws Throwable {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME);
+
+        recording.start();
+        long start = System.currentTimeMillis();
+        // provoke OSR compilation
+        for (int i = 0; i < Integer.MAX_VALUE; i++) {
+        }
+        // compile dummyMethod()
+        Method mtd = TestCompilerCompile.class.getDeclaredMethod(METHOD_NAME, new Class[0]);
+        WhiteBox WB = WhiteBox.getWhiteBox();
+        String directive = "[{ match: \"" + TestCompilerCompile.class.getName().replace('.', '/')
+                + "." + METHOD_NAME + "\", " + "BackgroundCompilation: false }]";
+        WB.addCompilerDirective(directive);
+        if (!WB.enqueueMethodForCompilation(mtd, 4 /* CompLevel_full_optimization */)) {
+            WB.enqueueMethodForCompilation(mtd, 1 /* CompLevel_simple */);
+        }
+        Utils.waitForCondition(() -> WB.isMethodCompiled(mtd));
+        dummyMethod();
+
+        System.out.println("time:" + (System.currentTimeMillis() - start));
+        recording.stop();
+
+        Set<Integer> compileIds = new HashSet<Integer>();
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        Events.hasEvents(events);
+        for (RecordedEvent event : events) {
+            System.out.println("Event:" + event);
+            verifyEvent(event);
+            Integer compileId = Events.assertField(event, "compileId").getValue();
+            assertFalse(compileIds.contains(compileId), "compile id not unique: " + compileId);
+            compileIds.add(compileId);
+        }
+
+        // Verify that we actually encountered our expected method
+        if (!foundKnownMethod) {
+            throw new Exception("Couldn't find method jdk/jfr/event/compiler/TestCompilerCompile.dummyMethod()V among compilation events");
+        }
+
+        // Verify that doTest() function has been replaced on stack.
+        if (!foundOsrMethod) {
+            throw new Exception("No On Stack Replacement of function doTest()");
+        }
+    }
+
+    private void verifyEvent(RecordedEvent event) throws Throwable {
+        Events.assertJavaMethod(event);
+        Events.assertEventThread(event);
+
+        String methodName = Events.assertField(event, "method.name").notEmpty().getValue();
+        String methodDescriptor = Events.assertField(event, "method.descriptor").notEmpty().getValue();
+        String methodType = Events.assertField(event, "method.type.name").notEmpty().getValue();
+
+        // Compare with a known candidate
+        if ("jdk/jfr/event/compiler/TestCompilerCompile".equals(methodType) && "dummyMethod".equals(methodName) && "()V".equals(methodDescriptor)) {
+            foundKnownMethod = true;
+        }
+
+        // The doTest() function is live almost the entire time the test runs.
+        // We should get at least 1 "on stack replacement" for that method.
+        if (TestCompilerCompile.class.getName().replace('.', '/').equals(methodType) && "doTest".equals(methodName)) {
+            boolean isOsr = Events.assertField(event, "isOsr").getValue();
+            if (isOsr) {
+                foundOsrMethod = true;
+            }
+        }
+
+        Events.assertField(event, "compileId").atLeast(0);
+        Events.assertField(event, "compileLevel").atLeast((short) 0).atMost((short) 4);
+        Events.assertField(event, "inlinedBytes").atLeast(0L);
+        Events.assertField(event, "codeSize").atLeast(0L);
+        Events.assertField(event, "isOsr");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/compiler/TestCompilerConfig.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.compiler;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.event.compiler.TestCompilerConfig
+ */
+public class TestCompilerConfig {
+    private final static String EVENT_NAME = EventNames.CompilerConfig;
+
+    public static void main(String[] args) throws Exception {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME);
+        recording.start();
+        recording.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        Events.hasEvents(events);
+        for (RecordedEvent event : events) {
+            System.out.println("Event:" + event);
+            Events.assertField(event, "threadCount").atLeast(0);
+            Events.assertField(event, "tieredCompilation");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/compiler/TestCompilerInlining.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,405 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.compiler;
+
+import jdk.internal.org.objectweb.asm.*;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedMethod;
+import jdk.jfr.consumer.RecordedObject;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.Platform;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import sun.hotspot.WhiteBox;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Method;
+import java.util.*;
+import java.util.stream.IntStream;
+
+/*
+ * @test CompilerInliningTest
+ * @bug 8073607
+ * @key jfr
+ * @summary Verifies that corresponding JFR events are emitted in case of inlining.
+ *
+ * @requires vm.opt.Inline == true | vm.opt.Inline == null
+ * @library /test/lib
+ * @modules java.base/jdk.internal.org.objectweb.asm
+ *          jdk.jfr
+ *
+ * @build sun.hotspot.WhiteBox
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *     sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:.
+ *     -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *     -Xbatch jdk.jfr.event.compiler.TestCompilerInlining
+ */
+public class TestCompilerInlining {
+    private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
+    private static final int LEVEL_SIMPLE = 1;
+    private static final int LEVEL_FULL_OPTIMIZATION = 4;
+    private static final Executable ENTRY_POINT = getConstructor(TestCase.class);
+    private static final String TEST_CASE_CLASS_NAME = TestCase.class.getName().replace('.', '/');
+
+    public static void main(String[] args) throws Exception {
+        InlineCalls inlineCalls = new InlineCalls(TestCase.class);
+        inlineCalls.disableInline(getConstructor(Object.class));
+        inlineCalls.disableInline(getMethod(TestCase.class, "qux", boolean.class));
+        inlineCalls.forceInline(getMethod(TestCase.class, "foo"));
+        inlineCalls.forceInline(getMethod(TestCase.class, "foo", int.class));
+        inlineCalls.forceInline(getMethod(TestCase.class, "bar"));
+        inlineCalls.forceInline(getMethod(TestCase.class, "baz"));
+
+        Map<Call, Boolean> result = inlineCalls.getExpected(ENTRY_POINT);
+        for (int level : determineAvailableLevels()) {
+            testLevel(result, level);
+        }
+    }
+
+    private static void testLevel(Map<Call, Boolean> expectedResult, int level) throws IOException {
+        System.out.println("****** Testing level " + level + " *******");
+        Recording r = new Recording();
+        r.enable(EventNames.CompilerInlining);
+        r.start();
+        WHITE_BOX.enqueueMethodForCompilation(ENTRY_POINT, level);
+        WHITE_BOX.deoptimizeMethod(ENTRY_POINT);
+        r.stop();
+        System.out.println("Expected:");
+
+        List<RecordedEvent> events = Events.fromRecording(r);
+        Set<Call> foundEvents = new HashSet<>();
+        int foundRelevantEvent = 0;
+        for (RecordedEvent event : events) {
+            RecordedMethod callerObject = event.getValue("caller");
+            RecordedObject calleeObject = event.getValue("callee");
+            MethodDesc caller = methodToMethodDesc(callerObject);
+            MethodDesc callee = ciMethodToMethodDesc(calleeObject);
+            // only TestCase.* -> TestCase.* OR TestCase.* -> Object.<init> are tested/filtered
+            if (caller.className.equals(TEST_CASE_CLASS_NAME) && (callee.className.equals(TEST_CASE_CLASS_NAME)
+                    || (callee.className.equals("java/lang/Object") && callee.methodName.equals("<init>")))) {
+                System.out.println(event);
+                boolean succeeded = (boolean) event.getValue("succeeded");
+                int bci = Events.assertField(event, "bci").atLeast(0).getValue();
+                Call call = new Call(caller, callee, bci);
+                foundRelevantEvent++;
+                Boolean expected = expectedResult.get(call);
+                Asserts.assertNotNull(expected, "Unexpected inlined call : " + call);
+                Asserts.assertEquals(expected, succeeded, "Incorrect result for " + call);
+                Asserts.assertTrue(foundEvents.add(call), "repeated event for " + call);
+            }
+        }
+        Asserts.assertEquals(foundRelevantEvent, expectedResult.size(), String.format("not all events found at lavel %d. " + "found = '%s'. expected = '%s'", level, events, expectedResult.keySet()));
+        System.out.println();
+        System.out.println();
+    }
+
+    private static int[] determineAvailableLevels() {
+        if (WHITE_BOX.getBooleanVMFlag("TieredCompilation")) {
+            return IntStream.rangeClosed(LEVEL_SIMPLE, WHITE_BOX.getIntxVMFlag("TieredStopAtLevel").intValue()).toArray();
+        }
+        if (Platform.isServer() && !Platform.isEmulatedClient()) {
+            return new int[] { LEVEL_FULL_OPTIMIZATION };
+        }
+        if (Platform.isClient() || Platform.isEmulatedClient()) {
+            return new int[] { LEVEL_SIMPLE };
+        }
+        throw new Error("TESTBUG: unknown VM");
+    }
+
+    private static MethodDesc methodToMethodDesc(RecordedMethod method) {
+        String internalClassName = method.getType().getName().replace('.', '/');
+        String methodName = method.getValue("name");
+        String methodDescriptor = method.getValue("descriptor");
+        return new MethodDesc(internalClassName, methodName, methodDescriptor);
+    }
+
+    private static MethodDesc ciMethodToMethodDesc(RecordedObject ciMethod) {
+        String internalClassName = ciMethod.getValue("type");
+        String methodName = ciMethod.getValue("name");
+        String methodDescriptor = ciMethod.getValue("descriptor");
+        return new MethodDesc(internalClassName, methodName, methodDescriptor);
+    }
+
+    private static Method getMethod(Class<?> aClass, String name, Class<?>... params) {
+        try {
+            return aClass.getDeclaredMethod(name, params);
+        } catch (NoSuchMethodException | SecurityException e) {
+            throw new Error("TESTBUG : cannot get method " + name + Arrays.toString(params), e);
+        }
+    }
+
+    private static Constructor<?> getConstructor(Class<?> aClass, Class<?>... params) {
+        try {
+            return aClass.getDeclaredConstructor(params);
+        } catch (NoSuchMethodException | SecurityException e) {
+            throw new Error("TESTBUG : cannot get constructor" + Arrays.toString(params), e);
+        }
+    }
+}
+
+class TestCase {
+    public TestCase() {
+        foo();
+    }
+
+    public void foo() {
+        qux(true);
+        bar();
+        foo(2);
+    }
+
+    private void foo(int i) {
+    }
+
+    private void bar() {
+        baz();
+        qux(false);
+        qux(true);
+    }
+
+    protected static double baz() {
+        qux(false);
+        return .0;
+    }
+
+    private static int qux(boolean b) {
+        qux(b);
+        return 0;
+    }
+}
+
+/**
+ * data structure for method call
+ */
+class Call {
+    public final MethodDesc caller;
+    public final MethodDesc callee;
+    public final int bci;
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || !(o instanceof Call))
+            return false;
+
+        Call call = (Call) o;
+
+        if (bci != call.bci)
+            return false;
+        if (!callee.equals(call.callee))
+            return false;
+        if (!caller.equals(call.caller))
+            return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = caller.hashCode();
+        result = 31 * result + callee.hashCode();
+        result = 47 * result + bci;
+        return result;
+    }
+
+    public Call(MethodDesc caller, MethodDesc callee, int bci) {
+        Objects.requireNonNull(caller);
+        Objects.requireNonNull(callee);
+        this.caller = caller;
+        this.callee = callee;
+        this.bci = bci;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("Call{caller='%s', callee='%s', bci=%d}", caller, callee, bci);
+    }
+}
+
+/**
+ * data structure for method description
+ */
+class MethodDesc {
+    public final String className;
+    public final String methodName;
+    public final String descriptor;
+
+    public MethodDesc(Class<?> aClass, String methodName, String descriptor) {
+        this(aClass.getName().replace('.', '/'), methodName, descriptor);
+    }
+
+    public MethodDesc(String className, String methodName, String descriptor) {
+        Objects.requireNonNull(className);
+        Objects.requireNonNull(methodName);
+        Objects.requireNonNull(descriptor);
+        this.className = className.replace('.', '/');
+        this.methodName = methodName;
+        this.descriptor = descriptor;
+    }
+
+    public MethodDesc(Executable executable) {
+        Class<?> aClass = executable.getDeclaringClass();
+        className = Type.getInternalName(aClass).replace('.', '/');
+
+        if (executable instanceof Constructor<?>) {
+            methodName = "<init>";
+            descriptor = Type.getConstructorDescriptor((Constructor<?>) executable);
+        } else {
+            methodName = executable.getName();
+            descriptor = Type.getMethodDescriptor((Method) executable);
+        }
+
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+
+        MethodDesc that = (MethodDesc) o;
+
+        if (!className.equals(that.className))
+            return false;
+        if (!methodName.equals(that.methodName))
+            return false;
+        if (!descriptor.equals(that.descriptor))
+            return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = className.hashCode();
+        result = 31 * result + methodName.hashCode();
+        result = 47 * result + descriptor.hashCode();
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("MethodDesc{className='%s', methodName='%s', descriptor='%s'}", className, methodName, descriptor);
+    }
+}
+
+/**
+ * Aux class to get all calls in an arbitrary class.
+ */
+class InlineCalls {
+    private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
+
+    private final Collection<Call> calls;
+    private final Map<Call, Boolean> inline;
+
+    public InlineCalls(Class<?> aClass) {
+        calls = getCalls(aClass);
+        inline = new HashMap<>();
+    }
+
+    /**
+     * @return expected inline events
+     */
+    public Map<Call, Boolean> getExpected(Executable entry) {
+        Map<Call, Boolean> result = new HashMap<>();
+        Queue<MethodDesc> methods = new ArrayDeque<>();
+        Set<MethodDesc> finished = new HashSet<>();
+        methods.add(new MethodDesc(entry));
+        while (!methods.isEmpty()) {
+            MethodDesc method = methods.poll();
+            if (finished.add(method)) {
+                inline.entrySet().stream().filter(k -> k.getKey().caller.equals(method)).forEach(k -> {
+                    result.put(k.getKey(), k.getValue());
+                    if (k.getValue()) {
+                        methods.add(k.getKey().callee);
+                    }
+                });
+            }
+        }
+
+        return result;
+    }
+
+    public void disableInline(Executable executable) {
+        WHITE_BOX.testSetDontInlineMethod(executable, true);
+        MethodDesc md = new MethodDesc(executable);
+        calls.stream().filter(c -> c.callee.equals(md)).forEach(c -> inline.put(c, false));
+    }
+
+    public void forceInline(Executable executable) {
+        WHITE_BOX.testSetForceInlineMethod(executable, true);
+        MethodDesc md = new MethodDesc(executable);
+        calls.stream().filter(c -> c.callee.equals(md)).forEach(c -> inline.putIfAbsent(c, true));
+    }
+
+    private static Collection<Call> getCalls(Class<?> aClass) {
+        List<Call> calls = new ArrayList<>();
+        ClassWriter cw;
+        ClassReader cr;
+        try {
+            cr = new ClassReader(aClass.getName());
+        } catch (IOException e) {
+            throw new Error("TESTBUG : unexpected IOE during class reading", e);
+        }
+        cw = new ClassWriter(cr, 0);
+        ClassVisitor cv = new ClassVisitor(Opcodes.ASM5, cw) {
+            @Override
+            public MethodVisitor visitMethod(int access, String name, String desc, String descriptor, String[] exceptions) {
+                System.out.println("Method: " +name);
+                MethodVisitor mv = super.visitMethod(access, name, desc, descriptor, exceptions);
+                return new CallTracer(aClass, name, desc, mv, calls);
+            }
+        };
+        cr.accept(cv, 0);
+
+        return calls;
+    }
+
+    private static class CallTracer extends MethodVisitor {
+        private final MethodDesc caller;
+        private Collection<Call> calls;
+
+        public CallTracer(Class<?> aClass, String name, String desc, MethodVisitor mv, Collection<Call> calls) {
+            super(Opcodes.ASM5, mv);
+            caller = new MethodDesc(aClass.getName(), name, desc);
+            this.calls = calls;
+        }
+
+        @Override
+        public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
+            Label label = new Label();
+            visitLabel(label);
+            super.visitMethodInsn(opcode, owner, name, desc, itf);
+            calls.add(new Call(caller, new MethodDesc(owner, name, desc), label.getOffset()));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/compiler/TestCompilerPhase.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.compiler;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Utils;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import sun.hotspot.WhiteBox;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.compMode!="Xint" & vm.flavor == "server" & (vm.opt.TieredStopAtLevel == 4 | vm.opt.TieredStopAtLevel == null)
+ * @library /test/lib
+ * @build sun.hotspot.WhiteBox
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *     sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:.
+ *     -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *     -XX:CompileOnly=jdk.jfr.event.compiler.TestCompilerPhase::dummyMethod
+ *     -XX:+SegmentedCodeCache -Xbootclasspath/a:.
+ *     jdk.jfr.event.compiler.TestCompilerPhase
+ */
+public class TestCompilerPhase {
+    private final static String EVENT_NAME = EventNames.CompilerPhase;
+    private final static String METHOD_NAME = "dummyMethod";
+    private static final int COMP_LEVEL_SIMPLE = 1;
+    private static final int COMP_LEVEL_FULL_OPTIMIZATION = 4;
+
+    public static void main(String[] args) throws Exception {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME);
+        recording.start();
+
+        // Provoke compilation
+        Method mtd = TestCompilerPhase.class.getDeclaredMethod(METHOD_NAME, new Class[0]);
+        WhiteBox WB = WhiteBox.getWhiteBox();
+        String directive = "[{ match: \"" + TestCompilerPhase.class.getName().replace('.', '/')
+                + "." + METHOD_NAME + "\", " + "BackgroundCompilation: false }]";
+        WB.addCompilerDirective(directive);
+        if (!WB.enqueueMethodForCompilation(mtd, COMP_LEVEL_FULL_OPTIMIZATION)) {
+            WB.enqueueMethodForCompilation(mtd, COMP_LEVEL_SIMPLE);
+        }
+        Utils.waitForCondition(() -> WB.isMethodCompiled(mtd));
+        dummyMethod();
+
+        recording.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        Events.hasEvents(events);
+        for (RecordedEvent event : events) {
+            System.out.println("Event:" + event);
+            Events.assertField(event, "phase").notEmpty();
+            Events.assertField(event, "compileId").atLeast(0);
+            Events.assertField(event, "phaseLevel").atLeast((short)0).atMost((short)4);
+            Events.assertEventThread(event);
+        }
+    }
+
+    static void dummyMethod() {
+        System.out.println("hello!");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/compiler/TestCompilerStats.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.compiler;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.event.compiler.TestCompilerStats
+ */
+public class TestCompilerStats {
+    private final static String EVENT_NAME = EventNames.CompilerStatistics;
+
+    public static void main(String[] args) throws Exception {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME);
+        recording.start();
+        recording.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        Events.hasEvents(events);
+        for (RecordedEvent event : events) {
+            System.out.println("Event:" + event);
+            Events.assertField(event, "compileCount").atLeast(0);
+            Events.assertField(event, "bailoutCount").atLeast(0);
+            Events.assertField(event, "invalidatedCount").atLeast(0);
+            Events.assertField(event, "osrCompileCount").atLeast(0);
+            Events.assertField(event, "standardCompileCount").atLeast(0);
+            Events.assertField(event, "osrBytesCompiled").atLeast(0L);
+            Events.assertField(event, "standardBytesCompiled").atLeast(0L);
+            Events.assertField(event, "nmetodsSize").atLeast(0L);
+            Events.assertField(event, "nmetodCodeSize").atLeast(0L);
+            Events.assertField(event, "peakTimeSpent").atLeast(0L);
+            Events.assertField(event, "totalTimeSpent").atLeast(0L);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/collection/AppGCProvoker.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.collection;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Simple application to provoke various kinds of GC.
+ */
+public class AppGCProvoker {
+
+    private static List<byte[]> garbage = new ArrayList<>();
+    public static Object trash;
+
+    public static void main(String args[]) {
+        // young gc
+        for (int i = 0; i < 100; i++) {
+             trash = new byte[100_000];
+        }
+
+        // system gc
+        System.gc();
+
+        // full gc caused by OOM
+        try {
+            while(true) {
+                garbage.add(new byte[150_000]);
+            }
+        } catch (OutOfMemoryError e) {
+            garbage = null;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/collection/GCEventAll.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,530 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.collection;
+
+import java.lang.management.ManagementFactory;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import jdk.jfr.EventType;
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.GCHelper;
+
+/**
+ * Tests for event garbage_collection.
+ * The test function is called from TestGCEvent*.java, with different worker threads.
+ * Groups all events belonging to the same garbage collection (the same gcId).
+ * The group of events belonging to the same GC is called a batch.
+ *
+ * This class contains the verifications done and the worker threads used to generate GCs.
+ * The helper logic are in class GCHelper.
+ *
+ * Summary of verifications:
+ *   All gcIds in garbage_collection event are unique.
+ *
+ *   All events in batch has the same gcId.
+ *
+ *   Number of garbage_collection events == GarbageCollectionMXBean.getCollectionCount()
+ *
+ *   garbage_collection.sum_pause_time approximately equals GarbageCollectionMXBean.getCollectionTime()
+ *
+ *   Batch contains expected events depending on garbage_collection.name
+ *
+ *   garbage_collection_start.timestamp == garbage_collection.startTime.
+ *
+ *   garbage_collection.timestamp >= timestamp for all other events in batch.
+ *
+ *   The start_garbage_collection and garbage_collection events must be synchronized.
+ *     This means that there may be multiple start_garbage_collection before a garbage_collection,
+ *     but garbage_collection.gcId must be equal to latest start_garbage_collection.gcId.
+ *
+ *   start_garbage_collection must be the first event in the batch,
+ *     that means no event with same gcId before garbage_collection_start event.
+ *
+ *   garbage_collection.name matches what is expected by the collectors specified in initial_configuration.
+ *
+ *   Duration for event "vm/gc/phases/pause" >= 1. Duration for phase level events >= 0.
+ *
+ *
+ */
+public class GCEventAll {
+    private String youngCollector = null;
+    private String oldCollector = null;
+
+    /**
+     *  Trigger GC events by generating garbage and calling System.gc() concurrently.
+     */
+    public static void doTest() throws Throwable {
+        // Trigger GC events by generating garbage and calling System.gc() concurrently.
+        Thread[] workerThreads = new Thread[] {
+                new Thread(GCEventAll.GarbageRunner.create(10)),
+                new Thread(GCEventAll.SystemGcWaitRunner.create(10, 2, 1000))};
+        GCEventAll test = new GCEventAll();
+        test.doSingleTest(workerThreads);
+    }
+
+    /**
+     * Runs the test once with given worker threads.
+     * @param workerThreads Threads that generates GCs.
+     * @param gcIds Set of all used gcIds
+     * @throws Exception
+     */
+    private void doSingleTest(Thread[] workerThreads) throws Throwable {
+        Recording recording = new Recording();
+        enableAllGcEvents(recording);
+
+        // Start with a full GC to minimize risk of getting extra GC between
+        // getBeanCollectionCount() and recording.start().
+        doSystemGc();
+        GCHelper.CollectionSummary startBeanCount = GCHelper.CollectionSummary.createFromMxBeans();
+        recording.start();
+
+        for (Thread t : workerThreads) {
+            t.start();
+        }
+        for (Thread t : workerThreads) {
+            t.join();
+        }
+
+        // End with a full GC to minimize risk of getting extra GC between
+        // recording.stop and getBeanCollectionCount().
+        doSystemGc();
+        // Add an extra System.gc() to make sure we get at least one full garbage_collection batch at
+        // the end of the test. This extra System.gc() is only necessary when using "UseConcMarkSweepGC" and "+ExplicitGCInvokesConcurrent".
+        doSystemGc();
+
+        recording.stop();
+        GCHelper.CollectionSummary deltaBeanCount = GCHelper.CollectionSummary.createFromMxBeans();
+        deltaBeanCount = deltaBeanCount.calcDelta(startBeanCount);
+
+        List<RecordedEvent> events = Events.fromRecording(recording).stream()
+            .filter(evt -> EventNames.isGcEvent(evt.getEventType()))
+            .collect(Collectors.toList());
+        RecordedEvent configEvent = GCHelper.getConfigEvent(events);
+        youngCollector = Events.assertField(configEvent, "youngCollector").notEmpty().getValue();
+        oldCollector = Events.assertField(configEvent, "oldCollector").notEmpty().getValue();
+        verify(events, deltaBeanCount);
+    }
+
+    private void enableAllGcEvents(Recording recording) {
+        FlightRecorder flightrecorder = FlightRecorder.getFlightRecorder();
+        for (EventType et : flightrecorder.getEventTypes()) {
+            if (EventNames.isGcEvent(et)) {
+                recording.enable(et.getName());
+                System.out.println("Enabled GC event: " + et.getName());
+            }
+        }
+        System.out.println("All GC events enabled");
+    }
+
+    private static synchronized void doSystemGc() {
+        System.gc();
+    }
+
+    /**
+     * Does all verifications of the received events.
+     *
+     * @param events All flight recorder events.
+     * @param beanCounts Number of collections and sum pause time reported by GarbageCollectionMXBeans.
+     * @param gcIds All used gcIds. Must be unique.
+     * @throws Exception
+     */
+    private void verify(List<RecordedEvent> events, GCHelper.CollectionSummary beanCounts) throws Throwable {
+        List<GCHelper.GcBatch> gcBatches = null;
+        GCHelper.CollectionSummary eventCounts = null;
+
+        // For some GC configurations, the JFR recording may have stopped before we received the last gc event.
+        try {
+            events = filterIncompleteGcBatch(events);
+            gcBatches = GCHelper.GcBatch.createFromEvents(events);
+            eventCounts = GCHelper.CollectionSummary.createFromEvents(gcBatches);
+
+            verifyUniqueIds(gcBatches);
+            verifyCollectorNames(gcBatches);
+            verifyCollectionCause(gcBatches);
+            verifyCollectionCount(eventCounts, beanCounts);
+            verifyPhaseEvents(gcBatches);
+            verifySingleGcBatch(gcBatches);
+        } catch (Throwable t) {
+            log(events, gcBatches, eventCounts, beanCounts);
+            if (gcBatches != null) {
+                for (GCHelper.GcBatch batch : gcBatches) {
+                    System.out.println(String.format("Batch:%n%s", batch.getLog()));
+                }
+            }
+            throw t;
+        }
+    }
+
+    /**
+     * When using collector ConcurrentMarkSweep with -XX:+ExplicitGCInvokesConcurrent, the JFR recording may
+     * stop before we have received the last garbage_collection event.
+     *
+     * This function does 3 things:
+     * 1. Check if the last batch is incomplete.
+     * 2. If it is incomplete, then asserts that incomplete batches are allowed for this configuration.
+     * 3. If incomplete batches are allowed, then the incomplete batch is removed.
+     *
+     * @param events All events
+     * @return All events with any incomplete batch removed.
+     * @throws Throwable
+     */
+    private List<RecordedEvent> filterIncompleteGcBatch(List<RecordedEvent> events) throws Throwable {
+        List<RecordedEvent> returnEvents = new ArrayList<RecordedEvent>(events);
+        int lastGcId = getLastGcId(events);
+        List<RecordedEvent> lastBatchEvents = getEventsWithGcId(events, lastGcId);
+        String[] endEvents = {GCHelper.event_garbage_collection, GCHelper.event_old_garbage_collection, GCHelper.event_young_garbage_collection};
+        boolean isComplete = containsAnyPath(lastBatchEvents, endEvents);
+        if (!isComplete) {
+            // The last GC batch does not contain an end event. The batch is incomplete.
+            // This is only allowed if we are using old_collector="ConcurrentMarkSweep" and "-XX:+ExplicitGCInvokesConcurrent"
+            boolean isExplicitGCInvokesConcurrent = hasInputArgument("-XX:+ExplicitGCInvokesConcurrent");
+            boolean isConcurrentMarkSweep = GCHelper.gcConcurrentMarkSweep.equals(oldCollector);
+            String msg = String.format(
+                    "Incomplete batch only allowed for '%s' with -XX:+ExplicitGCInvokesConcurrent",
+                    GCHelper.gcConcurrentMarkSweep);
+            Asserts.assertTrue(isConcurrentMarkSweep && isExplicitGCInvokesConcurrent, msg);
+
+            // Incomplete batch is allowed with the current settings. Remove incomplete batch.
+            returnEvents.removeAll(lastBatchEvents);
+        }
+        return returnEvents;
+    }
+
+    private boolean hasInputArgument(String arg) {
+        return ManagementFactory.getRuntimeMXBean().getInputArguments().contains(arg);
+    }
+
+    private List<RecordedEvent> getEventsWithGcId(List<RecordedEvent> events, int gcId) {
+        List<RecordedEvent> batchEvents = new ArrayList<>();
+        for (RecordedEvent event : events) {
+            if (GCHelper.isGcEvent(event) && GCHelper.getGcId(event) == gcId) {
+                batchEvents.add(event);
+            }
+        }
+        return batchEvents;
+    }
+
+    private boolean containsAnyPath(List<RecordedEvent> events, String[] paths) {
+        List<String> pathList = Arrays.asList(paths);
+        for (RecordedEvent event : events) {
+            if (pathList.contains(event.getEventType().getName())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private int getLastGcId(List<RecordedEvent> events) {
+        int lastGcId = -1;
+        for (RecordedEvent event : events) {
+            if (GCHelper.isGcEvent(event)) {
+                int gcId = GCHelper.getGcId(event);
+                if (gcId > lastGcId) {
+                    lastGcId = gcId;
+                }
+            }
+        }
+        Asserts.assertTrue(lastGcId != -1, "No gcId found");
+        return lastGcId;
+    }
+
+    /**
+     * Verifies collection count reported by flight recorder events against the values
+     * reported by GarbageCollectionMXBean.
+     * Number of collections should match exactly.
+     * Sum pause time are allowed some margin of error because of rounding errors in measurements.
+     */
+    private void verifyCollectionCount(GCHelper.CollectionSummary eventCounts, GCHelper.CollectionSummary beanCounts) {
+        verifyCollectionCount(youngCollector, eventCounts.collectionCountYoung, beanCounts.collectionCountYoung);
+        verifyCollectionCount(oldCollector, eventCounts.collectionCountOld, beanCounts.collectionCountOld);
+    }
+
+    private void verifyCollectionCount(String collector, long eventCounts, long beanCounts) {
+        if (GCHelper.gcConcurrentMarkSweep.equals(collector) || GCHelper.gcG1Old.equals(oldCollector)) {
+            // ConcurrentMarkSweep mixes old and new collections. Not same values as in MXBean.
+            // MXBean does not report old collections for G1Old, so we have nothing to compare with.
+            return;
+        }
+        // JFR events and GarbageCollectorMXBean events are not updated at the same time.
+        // This means that number of collections may diff.
+        // We allow a diff of +- 1 collection count.
+        long minCount = Math.max(0, beanCounts - 1);
+        long maxCount = beanCounts + 1;
+        Asserts.assertGreaterThanOrEqual(eventCounts, minCount, "Too few event counts for collector " + collector);
+        Asserts.assertLessThanOrEqual(eventCounts, maxCount, "Too many event counts for collector " + collector);
+    }
+
+    /**
+     * Verifies that all events belonging to a single GC are ok.
+     * A GcBatch contains all flight recorder events that belong to a single GC.
+     */
+    private void verifySingleGcBatch(List<GCHelper.GcBatch> batches) {
+        for (GCHelper.GcBatch batch : batches) {
+            //System.out.println("batch:\r\n" + batch.getLog());
+            try {
+                RecordedEvent endEvent = batch.getEndEvent();
+                Asserts.assertNotNull(endEvent, "No end event in batch.");
+                Asserts.assertNotNull(batch.getName(), "No method name in end event.");
+                long longestPause = Events.assertField(endEvent, "longestPause").atLeast(0L).getValue();
+                Events.assertField(endEvent, "sumOfPauses").atLeast(longestPause).getValue();
+                Instant batchStartTime = endEvent.getStartTime();
+                Instant batchEndTime = endEvent.getEndTime();
+                for (RecordedEvent event : batch.getEvents()) {
+                    if (event.getEventType().getName().contains("AllocationRequiringGC")) {
+                        // Unlike other events, these are sent *before* a GC.
+                        Asserts.assertLessThanOrEqual(event.getStartTime(), batchStartTime, "Timestamp in event after start event, should be sent before GC start");
+                    } else {
+                        Asserts.assertGreaterThanOrEqual(event.getStartTime(), batchStartTime, "startTime in event before batch start event, should be sent after GC start");
+                    }
+                    Asserts.assertLessThanOrEqual(event.getEndTime(), batchEndTime, "endTime in event after batch end event, should be sent before GC end");
+                }
+
+                // Verify that all required events has been received.
+                String[] requiredEvents = GCHelper.requiredEvents.get(batch.getName());
+                Asserts.assertNotNull(requiredEvents, "No required events specified for " + batch.getName());
+                for (String requiredEvent : requiredEvents) {
+                    boolean b = batch.containsEvent(requiredEvent);
+                    Asserts.assertTrue(b, String.format("%s does not contain event %s", batch, requiredEvent));
+                }
+
+                // Verify that we have exactly one heap_summary "Before GC" and one "After GC".
+                int countBeforeGc = 0;
+                int countAfterGc = 0;
+                for (RecordedEvent event : batch.getEvents()) {
+                    if (GCHelper.event_heap_summary.equals(event.getEventType().getName())) {
+                        String when = Events.assertField(event, "when").notEmpty().getValue();
+                        if ("Before GC".equals(when)) {
+                            countBeforeGc++;
+                        } else if ("After GC".equals(when)) {
+                            countAfterGc++;
+                        } else {
+                            Asserts.fail("Unknown value for heap_summary.when: '" + when + "'");
+                        }
+                    }
+                }
+                if (!GCHelper.gcConcurrentMarkSweep.equals(batch.getName())) {
+                    // We do not get heap_summary events for ConcurrentMarkSweep
+                    Asserts.assertEquals(1, countBeforeGc, "Unexpected number of heap_summary.before_gc");
+                    Asserts.assertEquals(1, countAfterGc, "Unexpected number of heap_summary.after_gc");
+                }
+            } catch (Throwable e) {
+                GCHelper.log("verifySingleGcBatch failed for gcEvent:");
+                GCHelper.log(batch.getLog());
+                throw e;
+            }
+        }
+    }
+
+    private Set<Integer> verifyUniqueIds(List<GCHelper.GcBatch> batches) {
+        Set<Integer> gcIds = new HashSet<>();
+        for (GCHelper.GcBatch batch : batches) {
+            Integer gcId = new Integer(batch.getGcId());
+            Asserts.assertFalse(gcIds.contains(gcId), "Duplicate gcId: " + gcId);
+            gcIds.add(gcId);
+        }
+        return gcIds;
+    }
+
+    private void verifyPhaseEvents(List<GCHelper.GcBatch> batches) {
+        for (GCHelper.GcBatch batch : batches) {
+            for(RecordedEvent event : batch.getEvents()) {
+                if (event.getEventType().getName().contains(GCHelper.pauseLevelEvent)) {
+                    Instant batchStartTime = batch.getEndEvent().getStartTime();
+                    Asserts.assertGreaterThanOrEqual(
+                        event.getStartTime(), batchStartTime, "Phase startTime >= batch startTime. Event:" + event);
+
+                    // Duration for event "vm/gc/phases/pause" must be >= 1. Other phase event durations must be >= 0.
+                    Duration minDuration = Duration.ofNanos(GCHelper.event_phases_pause.equals(event.getEventType().getName()) ? 1 : 0);
+                    Duration duration = event.getDuration();
+                    Asserts.assertGreaterThanOrEqual(duration, minDuration, "Wrong duration. Event:" + event);
+                }
+            }
+        }
+    }
+
+    /**
+     * Verifies that the collector name in initial configuration matches the name in garbage configuration event.
+     * If the names are not equal, then we check if this is an expected collector override.
+     * For example, if old collector in initial config is "G1Old" we allow both event "G1Old" and "SerialOld".
+     */
+    private void verifyCollectorNames(List<GCHelper.GcBatch> batches) {
+        for (GCHelper.GcBatch batch : batches) {
+            String name = batch.getName();
+            Asserts.assertNotNull(name, "garbage_collection.name was null");
+            boolean isYoung = batch.isYoungCollection();
+            String expectedName = isYoung ? youngCollector : oldCollector;
+            if (!expectedName.equals(name)) {
+                // Collector names not equal. Check if the collector has been overridden by an expected collector.
+                String overrideKey = expectedName + "." + name;
+                boolean isOverride = GCHelper.collectorOverrides.contains(overrideKey);
+                Asserts.assertTrue(isOverride, String.format("Unexpected event name(%s) for collectors(%s, %s)", name, youngCollector, oldCollector));
+            }
+        }
+    }
+
+    /**
+     * Verifies field "cause" in garbage_collection event.
+     * Only check that at cause is not null and that at least 1 cause is "System.gc()"
+     * We might want to check more cause reasons later.
+     */
+    private void verifyCollectionCause(List<GCHelper.GcBatch> batches) {
+        int systemGcCount = 0;
+        for (GCHelper.GcBatch batch : batches) {
+            RecordedEvent endEvent = batch.getEndEvent();
+            String cause = Events.assertField(endEvent, "cause").notEmpty().getValue();
+            // A System.GC() can be consolidated into a GCLocker GC
+            if (cause.equals("System.gc()") || cause.equals("GCLocker Initiated GC")) {
+                systemGcCount++;
+            }
+            Asserts.assertNotNull(batch.getName(), "garbage_collection.name was null");
+        }
+        final String msg = "No event with cause=System.gc(), collectors(%s, %s)";
+        Asserts.assertTrue(systemGcCount > 0, String.format(msg, youngCollector, oldCollector));
+    }
+
+    private void log(List<RecordedEvent> events, List<GCHelper.GcBatch> batches,
+        GCHelper.CollectionSummary eventCounts, GCHelper.CollectionSummary beanCounts) {
+        GCHelper.log("EventCounts:");
+        if (eventCounts != null) {
+            GCHelper.log(eventCounts.toString());
+        }
+        GCHelper.log("BeanCounts:");
+        if (beanCounts != null) {
+            GCHelper.log(beanCounts.toString());
+        }
+    }
+
+    /**
+     * Thread that does a number of System.gc().
+     */
+    public static class SystemGcRunner implements Runnable {
+        private final int totalCollections;
+
+        public SystemGcRunner(int totalCollections) {
+            this.totalCollections = totalCollections;
+        }
+
+        public static SystemGcRunner create(int totalCollections) {
+            return new SystemGcRunner(totalCollections);
+        }
+
+        public void run() {
+            for (int i = 0; i < totalCollections; i++) {
+                GCEventAll.doSystemGc();
+            }
+        }
+    }
+
+    /**
+     * Thread that creates garbage until a certain number of GCs has been run.
+     */
+    public static class GarbageRunner implements Runnable {
+        private final int totalCollections;
+        public byte[] dummyBuffer = null;
+
+        public GarbageRunner(int totalCollections) {
+            this.totalCollections = totalCollections;
+        }
+
+        public static GarbageRunner create(int totalCollections) {
+            return new GarbageRunner(totalCollections);
+        }
+
+        public void run() {
+            long currCollections = GCHelper.CollectionSummary.createFromMxBeans().sum();
+            long endCollections = totalCollections + currCollections;
+            Random r = new Random(0);
+            while (true) {
+                for (int i = 0; i < 1000; i++) {
+                    dummyBuffer = new byte[r.nextInt(10000)];
+                }
+                if (GCHelper.CollectionSummary.createFromMxBeans().sum() >= endCollections) {
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Thread that runs System.gc() and then wait for a number of GCs or a maximum time.
+     */
+    public static class SystemGcWaitRunner implements Runnable {
+        private final int totalCollections;
+        private final int minWaitCollections;
+        private final long maxWaitMillis;
+
+        public SystemGcWaitRunner(int totalCollections, int minWaitCollections, long maxWaitMillis) {
+            this.totalCollections = totalCollections;
+            this.minWaitCollections = minWaitCollections;
+            this.maxWaitMillis = maxWaitMillis;
+        }
+
+        public static SystemGcWaitRunner create(int deltaCollections, int minWaitCollections, long maxWaitMillis) {
+            return new SystemGcWaitRunner(deltaCollections, minWaitCollections, maxWaitMillis);
+        }
+
+        public void run() {
+            long currCount = GCHelper.CollectionSummary.createFromMxBeans().sum();
+            long endCount = totalCollections + currCount;
+            long nextSystemGcCount = currCount + minWaitCollections;
+            long now = System.currentTimeMillis();
+            long nextSystemGcMillis = now + maxWaitMillis;
+
+            while (true) {
+                if (currCount >= nextSystemGcCount || System.currentTimeMillis() > nextSystemGcMillis) {
+                    GCEventAll.doSystemGc();
+                    currCount = GCHelper.CollectionSummary.createFromMxBeans().sum();
+                    nextSystemGcCount = currCount + minWaitCollections;
+                } else {
+                    try {
+                        Thread.sleep(20);
+                    } catch (InterruptedException e) {
+                        e.printStackTrace();
+                        break;
+                    }
+                }
+                currCount = GCHelper.CollectionSummary.createFromMxBeans().sum();
+                if (currCount >= endCount) {
+                    break;
+                }
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/collection/GCGarbageCollectionUtil.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.collection;
+
+import static jdk.test.lib.Asserts.assertGreaterThan;
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.io.File;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.jfr.AppExecutorHelper;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.process.OutputAnalyzer;
+
+
+/**
+ * Class to verify GarbageCollection event.
+ * It starts the application provoking GCGarbageCollection with enabled JFR,
+ * collects events and verify the 'name' and 'cause' fields to be expected.
+ * It's supposed to be invoked from tests.
+ */
+public class GCGarbageCollectionUtil {
+    private final static String EVENT_SETTINGS_FILE =
+            System.getProperty("test.src", ".") + File.separator + "gc-testsettings.jfc";
+
+    /**
+     * Verifies the 'name' and 'cause' fields of received events to be expected.
+     * @param testID - a string to identify test
+     * @param testFlags - VM flags including GC to start the app
+     * @param gcNames - expected values for the 'name' field
+     * @param gcCauses - expected values for the 'cause' field
+     * @throws Exception in case of any failure
+     */
+    public static void test(String testID, String[] testFlags,
+            String[] gcNames, String... gcCauses) throws Exception {
+
+        String jfrFile = testID + ".jfr";
+
+        List<String> summaryFlags = new ArrayList<>();
+        Collections.addAll(summaryFlags, testFlags);
+        summaryFlags.add("-Xmx100m");
+        summaryFlags.add("-XX:+UnlockExperimentalVMOptions");
+        summaryFlags.add("-XX:-UseFastUnorderedTimeStamps");
+        summaryFlags.add("-Xlog:gc*=debug");
+
+
+        String args[] = {};
+        OutputAnalyzer analyzer = AppExecutorHelper.executeAndRecord(EVENT_SETTINGS_FILE, jfrFile,
+                (String[])summaryFlags.toArray(new String[0]), AppGCProvoker.class.getName(), args);
+        analyzer.shouldHaveExitValue(0);
+
+        Set<String> gcValidNames = new HashSet<>();
+        for (String n: gcNames) {
+            gcValidNames.add(n);
+        }
+        Set<String> gcValidCauses = new HashSet<>();
+        for (String n: gcCauses) {
+            gcValidCauses.add(n);
+        }
+
+        int total = 0;
+        for (RecordedEvent event : RecordingFile.readAllEvents(Paths.get(jfrFile))) {
+            total++;
+            System.out.println("Event: " + event);
+
+            final String name = Events.assertField(event, "name").notEmpty().getValue();
+            assertTrue(gcValidNames.contains(name), "GC name '" + name + "' not in the valid list" + gcValidNames);
+
+            final String cause = Events.assertField(event, "cause").notEmpty().getValue();
+            assertTrue(gcValidCauses.contains(cause), "GC cause '" + cause + "' not in the valid causes" + gcValidCauses);
+        }
+        assertGreaterThan(total, 0, "Expected at least one event");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithCMSConcurrent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.collection;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "ConcMarkSweep" | vm.gc == null
+ * @requires vm.opt.ExplicitGCInvokesConcurrent != false
+ * @library /test/lib /test/jdk
+ * @run driver jdk.jfr.event.gc.collection.TestGCCauseWithCMSConcurrent
+ */
+public class TestGCCauseWithCMSConcurrent {
+    public static void main(String[] args) throws Exception {
+        String testID = "CMSConcurrent";
+        String[] vmFlags = {"-XX:+UseConcMarkSweepGC", "-XX:+ExplicitGCInvokesConcurrent"};
+        String[] gcNames = {GCHelper.gcConcurrentMarkSweep, GCHelper.gcParNew, GCHelper.gcSerialOld};
+        String[] gcCauses = {"CMS Concurrent Mark", "Allocation Failure", "System.gc()"};
+        GCGarbageCollectionUtil.test(testID, vmFlags, gcNames, gcCauses);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithCMSMarkSweep.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.collection;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @requires vm.gc == "ConcMarkSweep" | vm.gc == null
+ * @requires vm.opt.ExplicitGCInvokesConcurrent != true
+ * @library /test/lib /test/jdk
+ * @run driver jdk.jfr.event.gc.collection.TestGCCauseWithCMSMarkSweep
+ */
+public class TestGCCauseWithCMSMarkSweep {
+    public static void main(String[] args) throws Exception {
+        String testID = "CMSMarkSweep";
+        String[] vmFlags = {"-XX:+UseConcMarkSweepGC"};
+        String[] gcNames = {GCHelper.gcConcurrentMarkSweep, GCHelper.gcParNew, GCHelper.gcSerialOld};
+        String[] gcCauses = {"CMS Concurrent Mark", "Allocation Failure", "System.gc()"};
+        GCGarbageCollectionUtil.test(testID, vmFlags, gcNames, gcCauses);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithG1ConcurrentMark.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.collection;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @requires vm.gc == "G1" | vm.gc == null
+ * @requires vm.opt.ExplicitGCInvokesConcurrent != false
+ * @library /test/lib /test/jdk
+ *
+ * @run driver jdk.jfr.event.gc.collection.TestGCCauseWithG1ConcurrentMark
+ */
+public class TestGCCauseWithG1ConcurrentMark {
+    public static void main(String[] args) throws Exception {
+        String testID = "G1ConcurrentMark";
+        String[] vmFlags = {"-XX:+UseG1GC", "-XX:+ExplicitGCInvokesConcurrent"};
+        String[] gcNames = {GCHelper.gcG1New, GCHelper.gcG1Old, GCHelper.gcG1Full};
+        String[] gcCauses = {"G1 Evacuation Pause", "Allocation Failure", "System.gc()"};
+        GCGarbageCollectionUtil.test(testID, vmFlags, gcNames, gcCauses);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithG1FullCollection.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.collection;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @requires vm.gc == "G1" | vm.gc == null
+ * @requires vm.opt.ExplicitGCInvokesConcurrent != true
+ * @library /test/lib /test/jdk
+ *
+ * @run driver jdk.jfr.event.gc.collection.TestGCCauseWithG1FullCollection
+ */
+public class TestGCCauseWithG1FullCollection {
+    public static void main(String[] args) throws Exception {
+        String testID = "G1FullCollection";
+        String[] vmFlags = {"-XX:+UseG1GC"};
+        String[] gcNames = {GCHelper.gcG1New, GCHelper.gcG1Old, GCHelper.gcG1Full};
+        String[] gcCauses = {"G1 Evacuation Pause", "Allocation Failure", "System.gc()"};
+        GCGarbageCollectionUtil.test(testID, vmFlags, gcNames, gcCauses);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithPSMarkSweep.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.collection;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @requires vm.gc == "Parallel" | vm.gc == null
+ * @library /test/lib /test/jdk
+ *
+ * @run driver jdk.jfr.event.gc.collection.TestGCCauseWithPSMarkSweep
+ */
+public class TestGCCauseWithPSMarkSweep {
+    public static void main(String[] args) throws Exception {
+        String testID = "PSMarkSweep";
+        String[] vmFlags = {"-XX:+UseParallelGC", "-XX:-UseParallelOldGC"};
+        String[] gcNames = {GCHelper.gcParallelScavenge, GCHelper.gcSerialOld};
+        String[] gcCauses = {"Allocation Failure", "Ergonomics", "System.gc()"};
+        GCGarbageCollectionUtil.test(testID, vmFlags, gcNames, gcCauses);
+    }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithParallelOld.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.collection;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @requires vm.gc == "Parallel" | vm.gc == null
+ * @library /test/lib /test/jdk
+ *
+ * @run driver jdk.jfr.event.gc.collection.TestGCCauseWithParallelOld
+ */
+public class TestGCCauseWithParallelOld {
+    public static void main(String[] args) throws Exception {
+        String testID = "ParallelOld";
+        String[] vmFlags = {"-XX:+UseParallelGC", "-XX:+UseParallelOldGC"};
+        String[] gcNames = {GCHelper.gcParallelScavenge, GCHelper.gcParallelOld};
+        String[] gcCauses = {"Allocation Failure", "Ergonomics", "System.gc()"};
+        GCGarbageCollectionUtil.test(testID, vmFlags, gcNames, gcCauses);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithSerial.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.collection;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @requires vm.gc == "Serial" | vm.gc == null
+ * @library /test/lib /test/jdk
+ *
+ * @run driver jdk.jfr.event.gc.collection.TestGCCauseWithSerial
+ */
+public class TestGCCauseWithSerial {
+    public static void main(String[] args) throws Exception {
+        String testID = "Serial";
+        String[] vmFlags = {"-XX:+UseSerialGC"};
+        String[] gcNames = {GCHelper.gcDefNew, GCHelper.gcSerialOld};
+        String[] gcCauses = {"Allocation Failure", "System.gc()"};
+        GCGarbageCollectionUtil.test(testID, vmFlags, gcNames, gcCauses);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/collection/TestGCEventMixedWithCMSConcurrent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.collection;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @requires (vm.gc == "ConcMarkSweep" | vm.gc == null)
+ *           & vm.opt.ExplicitGCInvokesConcurrent != false
+ * @library /test/lib /test/jdk
+ *
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -Xmx32m -Xmn8m -XX:+UseConcMarkSweepGC -XX:+ExplicitGCInvokesConcurrent jdk.jfr.event.gc.collection.TestGCEventMixedWithCMSConcurrent
+ * good debug flags: -Xlog:gc+heap=trace,gc*=debug
+ */
+public class TestGCEventMixedWithCMSConcurrent {
+    public static void main(String[] args) throws Throwable {
+        GCEventAll.doTest();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/collection/TestGCEventMixedWithCMSMarkSweep.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.collection;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @requires (vm.gc == "ConcMarkSweep" | vm.gc == null)
+ *           & vm.opt.ExplicitGCInvokesConcurrent != true
+ * @library /test/lib /test/jdk
+ *
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -Xmx32m -Xmn8m -XX:+UseConcMarkSweepGC -XX:-ExplicitGCInvokesConcurrent jdk.jfr.event.gc.collection.TestGCEventMixedWithCMSMarkSweep
+ * good debug flags: -Xlog:gc+heap=trace,gc*=debug
+ */
+public class TestGCEventMixedWithCMSMarkSweep {
+    public static void main(String[] args) throws Throwable {
+        GCEventAll.doTest();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/collection/TestGCEventMixedWithG1ConcurrentMark.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.collection;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @requires (vm.gc == "G1" | vm.gc == null)
+ *           & vm.opt.ExplicitGCInvokesConcurrent != false
+ * @library /test/lib /test/jdk
+ *
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -Xmx32m -Xmn8m -XX:+UseG1GC -XX:+ExplicitGCInvokesConcurrent jdk.jfr.event.gc.collection.TestGCEventMixedWithG1ConcurrentMark
+ * good debug flags: -Xlog:gc+heap=trace,gc*=debug
+ */
+// TODO: Try to run without: -XX:+UnlockExperimentalVMOptions XX:-UseFastUnorderedTimeStamps
+public class TestGCEventMixedWithG1ConcurrentMark {
+    public static void main(String[] args) throws Throwable {
+        GCEventAll.doTest();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/collection/TestGCEventMixedWithG1FullCollection.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.collection;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @requires (vm.gc == "G1" | vm.gc == null)
+ *           & vm.opt.ExplicitGCInvokesConcurrent != true
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -Xmx32m -Xmn8m -XX:+UseG1GC -XX:-ExplicitGCInvokesConcurrent jdk.jfr.event.gc.collection.TestGCEventMixedWithG1FullCollection
+ * good debug flags: -Xlog:gc*=debug
+ */
+public class TestGCEventMixedWithG1FullCollection {
+    public static void main(String[] args) throws Throwable {
+        GCEventAll.doTest();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/collection/TestGCEventMixedWithPSMarkSweep.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.collection;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @requires vm.gc == "Parallel" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -Xmx32m -Xmn8m -XX:+UseParallelGC -XX:-UseParallelOldGC jdk.jfr.event.gc.collection.TestGCEventMixedWithPSMarkSweep
+ * good debug flags: -Xlog:gc*=debug
+ */
+public class TestGCEventMixedWithPSMarkSweep {
+    public static void main(String[] args) throws Throwable {
+        GCEventAll.doTest();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/collection/TestGCEventMixedWithParNew.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.collection;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @requires vm.gc == "ConcMarkSweep" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main/othervm -Xmx32m -Xmn8m -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:+UseConcMarkSweepGC jdk.jfr.event.gc.collection.TestGCEventMixedWithParNew
+ * good debug flags: -Xlog:gc*=debug
+ */
+
+public class TestGCEventMixedWithParNew {
+    public static void main(String[] args) throws Throwable {
+        GCEventAll.doTest();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/collection/TestGCEventMixedWithParallelOld.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.collection;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @requires vm.gc == "Parallel" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -Xmx32m -Xmn8m -XX:+UseParallelGC -XX:+UseParallelOldGC jdk.jfr.event.gc.collection.TestGCEventMixedWithParallelOld
+ * good debug flags: -Xlog:gc*=debug
+ */
+public class TestGCEventMixedWithParallelOld {
+    public static void main(String[] args) throws Throwable {
+        GCEventAll.doTest();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/collection/TestGCEventMixedWithSerial.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.collection;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @requires vm.gc == "Serial" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -Xmx32m -Xmn8m -XX:+UseSerialGC jdk.jfr.event.gc.collection.TestGCEventMixedWithSerial
+ */
+public class TestGCEventMixedWithSerial {
+    public static void main(String[] args) throws Throwable {
+        GCEventAll.doTest();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/collection/TestGCGarbageCollectionEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.collection;
+
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.time.Duration;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm -Xlog:gc*=debug -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps jdk.jfr.event.gc.collection.TestGCGarbageCollectionEvent
+ */
+public class TestGCGarbageCollectionEvent {
+
+    private final static String EVENT_NAME = GCHelper.event_garbage_collection;
+
+    public static void main(String[] args) throws Exception {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME).withThreshold(Duration.ofMillis(0));
+        recording.start();
+        System.gc();
+        recording.stop();
+
+        boolean isAnyFound = false;
+        for (RecordedEvent event : Events.fromRecording(recording)) {
+            if (!EVENT_NAME.equals(event.getEventType().getName())) {
+                continue;
+            }
+            System.out.println("Event: " + event);
+            isAnyFound = true;
+
+            long longestPause = Events.assertField(event, "longestPause").atLeast(0L).getValue();
+            Events.assertField(event, "sumOfPauses").atLeast(longestPause);
+        }
+        assertTrue(isAnyFound, "No matching event found");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/collection/TestGCWithFasttime.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.collection;
+
+import java.time.Duration;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @key jfr
+  * @requires vm.gc == "Parallel" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UseParallelGC -XX:+UseParallelOldGC jdk.jfr.event.gc.collection.TestGCWithFasttime
+ */
+public class TestGCWithFasttime {
+    private static final String EVENT_NAME = GCHelper.event_garbage_collection;
+
+    // TODO: Check if all GC tests can be run with fast time. If so, this test is probably not needed.
+    public static void main(String[] args) throws Exception {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME).withThreshold(Duration.ofMillis(0));
+        recording.start();
+        System.gc();
+        System.gc();
+        recording.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        Events.hasEvents(events);
+        for (RecordedEvent event : events) {
+            if (!EVENT_NAME.equals(event.getEventType().getName())) {
+                continue;
+            }
+            Events.assertField(event, "name").notEmpty();
+            Events.assertField(event, "cause").notEmpty();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/collection/TestYoungGarbageCollectionEventWithDefNew.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.collection;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "Serial" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main/othervm -Xmx50m -Xmn2m -XX:+UseSerialGC -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -Xlog:gc+heap=trace,gc*=debug jdk.jfr.event.gc.collection.TestYoungGarbageCollectionEventWithDefNew
+ */
+public class TestYoungGarbageCollectionEventWithDefNew {
+
+    public static void main(String[] args) throws Exception {
+        YoungGarbageCollectionEvent.test();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/collection/TestYoungGarbageCollectionEventWithG1New.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.collection;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "G1" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main/othervm -Xmx50m -Xmn2m -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -Xlog:gc+heap=trace,gc*=debug jdk.jfr.event.gc.collection.TestYoungGarbageCollectionEventWithG1New
+ */
+public class TestYoungGarbageCollectionEventWithG1New {
+
+    public static void main(String[] args) throws Exception {
+        YoungGarbageCollectionEvent.test();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/collection/TestYoungGarbageCollectionEventWithParNew.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.collection;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "ConcMarkSweep" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main/othervm -Xmx50m -Xmn2m -XX:+UseConcMarkSweepGC -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -Xlog:gc+heap=trace,gc*=debug jdk.jfr.event.gc.collection.TestYoungGarbageCollectionEventWithParNew
+ */
+public class TestYoungGarbageCollectionEventWithParNew {
+
+    public static void main(String[] args) throws Exception {
+        YoungGarbageCollectionEvent.test();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/collection/TestYoungGarbageCollectionEventWithParallelScavenge.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.collection;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "Parallel" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main/othervm -Xmx50m -Xmn2m -XX:+UseParallelGC -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:-UseAdaptiveSizePolicy -Xlog:gc+heap=trace,gc*=debug jdk.jfr.event.gc.collection.TestYoungGarbageCollectionEventWithParallelScavenge
+ */
+public class TestYoungGarbageCollectionEventWithParallelScavenge {
+
+    public static void main(String[] args) throws Exception {
+        YoungGarbageCollectionEvent.test();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/collection/YoungGarbageCollectionEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.collection;
+
+import static jdk.test.lib.Asserts.assertGreaterThan;
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.time.Duration;
+import java.time.Instant;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.GCHelper;
+
+
+public class YoungGarbageCollectionEvent {
+
+    private static final String EVENT_NAME = GCHelper.event_young_garbage_collection;
+
+    public static void test() throws Exception {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME).withThreshold(Duration.ofMillis(0));
+        recording.start();
+        triggerGC();
+        recording.stop();
+
+        boolean isAnyFound = false;
+        for (RecordedEvent event : Events.fromRecording(recording)) {
+            if (!EVENT_NAME.equals(event.getEventType().getName())) {
+                continue;
+            }
+            System.out.println("Event: " + event);
+            isAnyFound = true;
+            Events.assertField(event, "gcId").atLeast(0);
+            Events.assertField(event, "tenuringThreshold").atLeast(1);
+
+            Instant startTime = event.getStartTime();
+            Instant endTime = event.getEndTime();
+            Duration duration = event.getDuration();
+            assertGreaterThan(startTime, Instant.EPOCH, "startTime should be at least 0");
+            assertGreaterThan(endTime, Instant.EPOCH, "endTime should be at least 0");
+            // TODO: Maybe we should accept duration of 0, but old test did not.
+            assertGreaterThan(duration, Duration.ZERO, "Duration should be above 0");
+            assertGreaterThan(endTime, startTime, "End time should be after start time");
+        }
+        assertTrue(isAnyFound, "No matching event found");
+    }
+
+    public static byte[] garbage;
+    private static void triggerGC() {
+        for (int i = 0; i < 3072; i++) {
+            garbage = new byte[1024];
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/collection/gc-testsettings.jfc	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+-->
+<configuration version="2.0" label="TestSettings" description="Configuration for testing GarbageCollection event" provider="Oracle">
+
+    <event name="jdk.GarbageCollection">
+      <setting name="enabled" control="gc-enabled-normal">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+</configuration>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/configuration/GCHeapConfigurationEventTester.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.configuration;
+
+import static jdk.test.lib.Asserts.assertGreaterThanOrEqual;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.EventVerifier;
+import jdk.test.lib.jfr.Events;
+
+
+public abstract class GCHeapConfigurationEventTester {
+    public void run() throws Exception {
+        Recording recording = new Recording();
+        recording.enable(EventNames.GCHeapConfiguration);
+        recording.start();
+        recording.stop();
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        assertGreaterThanOrEqual(events.size(), 1, "Expected at least 1 event");
+        EventVerifier v = createVerifier(events.get(0));
+        v.verify();
+    }
+
+    protected abstract EventVerifier createVerifier(RecordedEvent e);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/configuration/GCHeapConfigurationEventVerifier.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.configuration;
+
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventVerifier;
+
+public abstract class GCHeapConfigurationEventVerifier extends EventVerifier {
+    public GCHeapConfigurationEventVerifier(RecordedEvent e) {
+        super(e);
+    }
+
+    protected void verifyMinHeapSizeIs(long expected) throws Exception {
+        verifyEquals("minSize", expected);
+    }
+
+    protected void verifyInitialHeapSizeIs(long expected) throws Exception {
+        verifyEquals("initialSize", expected);
+    }
+
+    protected void verifyMaxHeapSizeIs(long expected) throws Exception {
+        verifyEquals("maxSize", expected);
+    }
+
+    protected void verifyUsesCompressedOopsIs(boolean expected) throws Exception {
+        verifyEquals("usesCompressedOops", expected);
+    }
+
+    protected void verifyObjectAlignmentInBytesIs(int expected) throws Exception {
+        verifyEquals("objectAlignment", (long)expected);
+    }
+
+    protected void verifyHeapAddressBitsIs(int expected) throws Exception {
+        verifyEquals("heapAddressBits", (byte)expected);
+    }
+
+    protected void verifyCompressedOopModeIs(String expected) throws Exception {
+        verifyEquals("compressedOopsMode", expected);
+    }
+
+    protected void verifyCompressedOopModeContains(String expected) throws Exception {
+        verifyContains("compressedOopsMode", expected);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/configuration/GCYoungGenerationConfigurationEventTester.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.configuration;
+
+import static jdk.test.lib.Asserts.assertGreaterThanOrEqual;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.EventVerifier;
+import jdk.test.lib.jfr.Events;
+
+public abstract class GCYoungGenerationConfigurationEventTester {
+    public void run() throws Exception {
+        Recording recording = new Recording();
+        recording.enable(EventNames.YoungGenerationConfiguration);
+        recording.start();
+        recording.stop();
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        assertGreaterThanOrEqual(events.size(), 1, "Expected at least 1 event");
+        EventVerifier v = createVerifier(events.get(0));
+        v.verify();
+    }
+
+    protected abstract EventVerifier createVerifier(RecordedEvent e);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/configuration/TestGCConfigurationEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.configuration;
+
+import static jdk.test.lib.Asserts.assertGreaterThanOrEqual;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.EventVerifier;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @requires (vm.gc == "Parallel" | vm.gc == null)
+ *           & vm.opt.ExplicitGCInvokesConcurrent != true
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:+UseParallelGC -XX:+UseParallelOldGC -XX:ParallelGCThreads=3 -XX:ConcGCThreads=2 -XX:+UseDynamicNumberOfGCThreads -XX:-ExplicitGCInvokesConcurrent -XX:-DisableExplicitGC -XX:MaxGCPauseMillis=800 -XX:GCTimeRatio=19 jdk.jfr.event.gc.configuration.TestGCConfigurationEvent
+ */
+public class TestGCConfigurationEvent {
+    public static void main(String[] args) throws Exception {
+        Recording recording = new Recording();
+        recording.enable(EventNames.GCConfiguration);
+        recording.start();
+        recording.stop();
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        assertGreaterThanOrEqual(events.size(), 1, "Expected at least 1 event");
+        GCConfigurationEventVerifier verifier = new GCConfigurationEventVerifier(events.get(0));
+        verifier.verify();
+    }
+}
+
+class GCConfigurationEventVerifier extends EventVerifier {
+    public GCConfigurationEventVerifier(RecordedEvent event) {
+        super(event);
+    }
+
+    @Override
+    public void verify() throws Exception {
+        verifyYoungGCIs("ParallelScavenge");
+        verifyOldGCIs("ParallelOld");
+        verifyParallelGCThreadsIs(3);
+        verifyConcurrentGCThreadsIs(2);
+        verifyUsesDynamicGCThreadsIs(true);
+        verifyIsExplicitGCConcurrentIs(false);
+        verifyIsExplicitGCDisabledIs(false);
+        verifyPauseTargetIs(800);
+        verifyGCTimeRatioIs(19);
+    }
+
+    private void verifyYoungGCIs(String expected) throws Exception {
+        verifyEquals("youngCollector", expected);
+    }
+
+    private void verifyOldGCIs(String expected) throws Exception {
+        verifyEquals("oldCollector", expected);
+    }
+
+    private void verifyParallelGCThreadsIs(int expected) throws Exception {
+        verifyEquals("parallelGCThreads", expected);
+    }
+
+    private void verifyConcurrentGCThreadsIs(int expected) throws Exception {
+        verifyEquals("concurrentGCThreads", expected);
+    }
+
+    private void verifyUsesDynamicGCThreadsIs(boolean expected) throws Exception {
+        verifyEquals("usesDynamicGCThreads", expected);
+    }
+
+    private void verifyIsExplicitGCConcurrentIs(boolean expected) throws Exception {
+        verifyEquals("isExplicitGCConcurrent", expected);
+    }
+
+    private void verifyIsExplicitGCDisabledIs(boolean expected) throws Exception {
+        verifyEquals("isExplicitGCDisabled", expected);
+    }
+
+    private void verifyPauseTargetIs(long expected) throws Exception {
+        verifyEquals("pauseTarget", expected);
+    }
+
+    private void verifyGCTimeRatioIs(int expected) throws Exception {
+        verifyEquals("gcTimeRatio", expected);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/configuration/TestGCConfigurationEventWithDefaultPauseTarget.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.configuration;
+
+import static jdk.test.lib.Asserts.assertGreaterThanOrEqual;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.EventVerifier;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps jdk.jfr.event.gc.configuration.TestGCConfigurationEventWithDefaultPauseTarget
+ */
+public class TestGCConfigurationEventWithDefaultPauseTarget {
+    public static void main(String[] args) throws Exception {
+        Recording recording = new Recording();
+        recording.enable(EventNames.GCConfiguration);
+        recording.start();
+        recording.stop();
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        assertGreaterThanOrEqual(events.size(), 1, "Expected at least 1 event");
+        DefaultGCConfigurationVerifier verifier = new DefaultGCConfigurationVerifier(events.get(0));
+        verifier.verify();
+    }
+}
+
+class DefaultGCConfigurationVerifier extends EventVerifier {
+    public DefaultGCConfigurationVerifier(RecordedEvent event) {
+        super(event);
+    }
+
+    @Override
+    public void verify() throws Exception {
+        verifyEquals("pauseTarget", Long.MIN_VALUE);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/configuration/TestGCHeapConfigurationEventWith32BitOops.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.configuration;
+
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventVerifier;
+import jdk.test.lib.jfr.GCHelper;
+import sun.hotspot.WhiteBox;
+
+/* See the shell script wrapper for the flags used when invoking the JVM */
+public class TestGCHeapConfigurationEventWith32BitOops extends GCHeapConfigurationEventTester {
+    public static void main(String[] args) throws Exception {
+        GCHeapConfigurationEventTester t = new TestGCHeapConfigurationEventWith32BitOops();
+        t.run();
+    }
+
+    @Override
+    protected EventVerifier createVerifier(RecordedEvent e) {
+        return new ThirtyTwoBitsVerifier(e);
+    }
+}
+
+class ThirtyTwoBitsVerifier extends GCHeapConfigurationEventVerifier {
+    public ThirtyTwoBitsVerifier(RecordedEvent event) {
+        super(event);
+    }
+
+    @Override
+    public void verify() throws Exception {
+        WhiteBox wb = WhiteBox.getWhiteBox();
+        long heapAlignment = wb.getHeapAlignment();
+        long alignedHeapSize = GCHelper.alignUp(megabytes(100), heapAlignment);
+        verifyMinHeapSizeIs(megabytes(100));
+        verifyInitialHeapSizeIs(alignedHeapSize);
+        verifyMaxHeapSizeIs(alignedHeapSize);
+        verifyUsesCompressedOopsIs(true);
+        verifyObjectAlignmentInBytesIs(8);
+        verifyHeapAddressBitsIs(32);
+        verifyCompressedOopModeIs("32-bit");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/configuration/TestGCHeapConfigurationEventWith32BitOops.sh	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,60 @@
+#
+# Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# 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.
+#
+# @test TestGCHeapConfigurationEventWith32BitOops
+# @key jfr
+# @requires vm.gc == "Parallel" | vm.gc == null
+# @library /test/lib /test/jdk
+# @build jdk.jfr.event.gc.configuration.TestGCHeapConfigurationEventWith32BitOops sun.hotspot.WhiteBox
+# @run main ClassFileInstaller sun.hotspot.WhiteBox
+# @run shell TestGCHeapConfigurationEventWith32BitOops.sh
+
+uses_64_bit_testjava() {
+  ${TESTJAVA}/bin/java ${TESTVMOPTS} -version 2>&1 | grep '64-Bit' > /dev/null
+}
+
+uses_windows_or_linux() {
+    case `uname -s` in
+      Linux | CYGWIN* | Windows* )
+        return 0
+        ;;
+    esac
+    return 1
+}
+
+TEST='jdk.jfr.event.gc.configuration.TestGCHeapConfigurationEventWith32BitOops'
+
+OPTIONS='-XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:+UseParallelGC -XX:+UseParallelOldGC -XX:+UseCompressedOops -Xmx100m -Xms100m -XX:InitialHeapSize=100m -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI'
+
+if [ -z "${TESTCLASSPATH}" ]; then
+    echo "Using TESTCLASSES"
+    MY_CLASSPATH=${TESTCLASSES}
+else
+    echo "Using TESTCLASSPATH"
+    MY_CLASSPATH=${TESTCLASSPATH}
+fi
+
+if uses_windows_or_linux && uses_64_bit_testjava; then
+  printenv
+  echo "${TESTJAVA}/bin/java ${TESTVMOPTS} ${OPTIONS} -cp ${MY_CLASSPATH} ${TEST}"
+  ${TESTJAVA}/bin/java ${TESTVMOPTS} ${OPTIONS} -cp ${MY_CLASSPATH} ${TEST}
+fi
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/configuration/TestGCHeapConfigurationEventWithHeapBasedOops.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.configuration;
+
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventVerifier;
+
+/* See the shell script wrapper for the flags used when invoking the JVM */
+public class TestGCHeapConfigurationEventWithHeapBasedOops extends GCHeapConfigurationEventTester {
+    public static void main(String[] args) throws Exception {
+        GCHeapConfigurationEventTester t = new TestGCHeapConfigurationEventWithHeapBasedOops();
+        t.run();
+    }
+
+    @Override
+    protected EventVerifier createVerifier(RecordedEvent e) {
+        return new HeapBasedOopsVerifier(e);
+    }
+}
+
+class HeapBasedOopsVerifier extends GCHeapConfigurationEventVerifier {
+    public HeapBasedOopsVerifier(RecordedEvent e) {
+        super(e);
+    }
+
+    @Override
+    public void verify() throws Exception {
+        // Can't verify min and initial heap size due to constraints on
+        // physical memory on tests machines
+        verifyMaxHeapSizeIs(gigabytes(31));
+        verifyUsesCompressedOopsIs(true);
+        verifyObjectAlignmentInBytesIs(8);
+        verifyHeapAddressBitsIs(32);
+        verifyCompressedOopModeContains("Non-zero");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/configuration/TestGCHeapConfigurationEventWithHeapBasedOops.sh	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,62 @@
+#
+# Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# 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.
+#
+# @test TestGCHeapConfigurationEventWithHeapBasedOops
+# @key jfr
+# @requires vm.gc == "Parallel" | vm.gc == null
+# @library /test/lib /test/jdk
+# @build jdk.jfr.event.gc.configuration.TestGCHeapConfigurationEventWithHeapBasedOops
+# @run shell TestGCHeapConfigurationEventWithHeapBasedOops.sh
+
+uses_64_bit_testjava() {
+  ${TESTJAVA}/bin/java ${TESTVMOPTS} -version 2>&1 | grep '64-Bit' > /dev/null
+}
+
+uses_windows_or_linux() {
+    case `uname -s` in
+      Linux | CYGWIN* | Windows* )
+        return 0
+        ;;
+    esac
+    return 1
+}
+
+TEST='jdk.jfr.event.gc.configuration.TestGCHeapConfigurationEventWithHeapBasedOops'
+
+# NOTE: Can't use 32g heap with UseCompressedOops. Hopefully the 31g heap will
+# force HeapBased compressed oops to be enalbed by hoping that there isn't
+# enough space in the lowest 1 GB of the virtual address space.
+OPTIONS='-XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:+UseParallelGC -XX:+UseParallelOldGC -Xmx31g -XX:+UseCompressedOops'
+
+if [ -z "${TESTCLASSPATH}" ]; then
+    echo "Using TESTCLASSES"
+    MY_CLASSPATH=${TESTCLASSES}
+else
+    echo "Using TESTCLASSPATH"
+    MY_CLASSPATH=${TESTCLASSPATH}
+fi
+
+if uses_windows_or_linux && uses_64_bit_testjava; then
+  printenv
+  echo "${TESTJAVA}/bin/java ${TESTVMOPTS} ${OPTIONS} -cp ${MY_CLASSPATH} ${TEST}"
+  ${TESTJAVA}/bin/java ${TESTVMOPTS} ${OPTIONS} -cp ${MY_CLASSPATH} ${TEST}
+fi
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/configuration/TestGCHeapConfigurationEventWithZeroBasedOops.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.configuration;
+
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventVerifier;
+
+/* See the shell script wrapper for the flags used when invoking the JVM */
+public class TestGCHeapConfigurationEventWithZeroBasedOops extends GCHeapConfigurationEventTester {
+    public static void main(String[] args) throws Exception {
+        GCHeapConfigurationEventTester t = new TestGCHeapConfigurationEventWithZeroBasedOops();
+        t.run();
+    }
+
+    @Override
+    protected EventVerifier createVerifier(RecordedEvent e) {
+        return new ZeroBasedOopsVerifier(e);
+    }
+}
+
+class ZeroBasedOopsVerifier extends GCHeapConfigurationEventVerifier {
+    public ZeroBasedOopsVerifier(RecordedEvent e) {
+        super(e);
+    }
+
+    @Override
+    public void verify() throws Exception {
+        // Can't verify min and initial heap size due to constraints on
+        // physical memory on tests machines
+
+        verifyMaxHeapSizeIs(gigabytes(4));
+        verifyUsesCompressedOopsIs(true);
+        verifyObjectAlignmentInBytesIs(8);
+        verifyHeapAddressBitsIs(32);
+        verifyCompressedOopModeIs("Zero based");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/configuration/TestGCHeapConfigurationEventWithZeroBasedOops.sh	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,59 @@
+#
+# Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# 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.
+#
+# @test TestGCHeapConfigurationEventWithZeroBasedOops
+# @key jfr
+# @requires vm.gc == "Parallel" | vm.gc == null
+# @library /test/lib /test/jdk
+# @build jdk.jfr.event.gc.configuration.TestGCHeapConfigurationEventWithZeroBasedOops
+# @run shell TestGCHeapConfigurationEventWithZeroBasedOops.sh
+
+uses_64_bit_testjava() {
+  ${TESTJAVA}/bin/java ${TESTVMOPTS} -version 2>&1 | grep '64-Bit' > /dev/null
+}
+
+uses_windows_or_linux() {
+    case `uname -s` in
+      Linux | CYGWIN* | Windows* )
+        return 0
+        ;;
+    esac
+    return 1
+}
+
+TEST='jdk.jfr.event.gc.configuration.TestGCHeapConfigurationEventWithZeroBasedOops'
+
+OPTIONS='-XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:+UseParallelGC -XX:+UseParallelOldGC -XX:+UseCompressedOops -Xmx4g'
+
+if [ -z "${TESTCLASSPATH}" ]; then
+    echo "Using TESTCLASSES"
+    MY_CLASSPATH=${TESTCLASSES}
+else
+    echo "Using TESTCLASSPATH"
+    MY_CLASSPATH=${TESTCLASSPATH}
+fi
+
+if uses_windows_or_linux && uses_64_bit_testjava; then
+  printenv
+  echo "${TESTJAVA}/bin/java ${TESTVMOPTS} ${OPTIONS} -cp ${MY_CLASSPATH} ${TEST}"
+  ${TESTJAVA}/bin/java ${TESTVMOPTS} ${OPTIONS} -cp ${MY_CLASSPATH} ${TEST}
+fi
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/configuration/TestGCSurvivorConfigurationEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.configuration;
+
+import static jdk.test.lib.Asserts.assertGreaterThanOrEqual;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.EventVerifier;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "Parallel" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:+UseParallelGC -XX:+UseParallelOldGC -XX:MaxTenuringThreshold=13 -XX:InitialTenuringThreshold=9 jdk.jfr.event.gc.configuration.TestGCSurvivorConfigurationEvent
+ */
+public class TestGCSurvivorConfigurationEvent {
+    public static void main(String[] args) throws Exception {
+        Recording recording = new Recording();
+        recording.enable(EventNames.GCSurvivorConfiguration);
+        recording.start();
+        recording.stop();
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        assertGreaterThanOrEqual(events.size(), 1, "Expected at least 1 event");
+        GCSurvivorConfigurationEventVerifier verifier = new GCSurvivorConfigurationEventVerifier(events.get(0));
+        verifier.verify();
+    }
+}
+
+class GCSurvivorConfigurationEventVerifier extends EventVerifier {
+    public GCSurvivorConfigurationEventVerifier(RecordedEvent event) {
+        super(event);
+    }
+
+    public void verify() throws Exception {
+        verifyMaxTenuringThresholdIs(13);
+        verifyInitialTenuringThresholdIs(9);
+    }
+
+    private void verifyMaxTenuringThresholdIs(int expected) throws Exception {
+        verifyEquals("maxTenuringThreshold", (byte)expected);
+    }
+
+    private void verifyInitialTenuringThresholdIs(int expected) throws Exception {
+        verifyEquals("initialTenuringThreshold", (byte)expected);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/configuration/TestGCTLABConfigurationEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.configuration;
+
+import static jdk.test.lib.Asserts.assertGreaterThanOrEqual;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.EventVerifier;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "Parallel" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:+UseParallelGC -XX:+UseParallelOldGC -XX:+UseTLAB -XX:MinTLABSize=3k -XX:TLABRefillWasteFraction=96 jdk.jfr.event.gc.configuration.TestGCTLABConfigurationEvent
+ */
+public class TestGCTLABConfigurationEvent {
+    public static void main(String[] args) throws Exception {
+        Recording recording = new Recording();
+        recording.enable(EventNames.GCTLABConfiguration);
+        recording.start();
+        recording.stop();
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        assertGreaterThanOrEqual(events.size(), 1, "Expected at least 1 event");
+        GCTLABConfigurationEventVerifier verifier = new GCTLABConfigurationEventVerifier(events.get(0));
+        verifier.verify();
+    }
+}
+
+class GCTLABConfigurationEventVerifier extends EventVerifier {
+    public GCTLABConfigurationEventVerifier(RecordedEvent event) {
+        super(event);
+    }
+
+    @Override
+    public void verify() throws Exception {
+        verifyUsesTLABsIs(true);
+        verifyMinTLABSizeIs(kilobyte(3));
+        verifyTLABRefillWasteLimitIs(96);
+    }
+
+    void verifyUsesTLABsIs(boolean expected) throws Exception {
+        verifyEquals("usesTLABs", expected);
+    }
+
+    void verifyMinTLABSizeIs(long expected) throws Exception {
+        verifyEquals("minTLABSize", expected);
+    }
+
+    void verifyTLABRefillWasteLimitIs(long expected) throws Exception {
+        verifyEquals("tlabRefillWasteLimit", expected);
+    }
+
+    private int kilobyte(int num) {
+        return 1024 * num;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/configuration/TestGCYoungGenerationConfigurationEventWithMinAndMaxSize.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.configuration;
+
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventVerifier;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run driver jdk.jfr.event.gc.configuration.TestGCYoungGenerationConfigurationEventWithMinAndMaxSize
+ */
+public class TestGCYoungGenerationConfigurationEventWithMinAndMaxSize {
+    public static void main(String[] args) throws Exception {
+        String[] jvm_args = {"-XX:+UnlockExperimentalVMOptions",
+                             "-XX:-UseFastUnorderedTimeStamps",
+                             "-XX:NewSize=12m",
+                             "-cp",
+                             System.getProperty("java.class.path"),
+                             "-XX:MaxNewSize=16m",
+                             "-Xms32m",
+                             "-Xmx64m",
+                             Tester.class.getName()};
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(jvm_args);
+        OutputAnalyzer analyzer = ProcessTools.executeProcess(pb);
+        analyzer.shouldHaveExitValue(0);
+    }
+}
+
+class Tester extends GCYoungGenerationConfigurationEventTester {
+    public static void main(String[] args) throws Exception {
+        new Tester().run();
+    }
+
+    @Override protected EventVerifier createVerifier(RecordedEvent e) {
+        return new MinAndMaxSizeVerifier(e);
+    }
+}
+
+class MinAndMaxSizeVerifier extends EventVerifier {
+    public MinAndMaxSizeVerifier(RecordedEvent e) {
+        super(e);
+    }
+
+    @Override public void verify() throws Exception {
+        verifyMinSizeIs(megabytes(12));
+        verifyMaxSizeIs(megabytes(16));
+
+        // Can't test newRatio at the same time as minSize and maxSize,
+        // because the NewRatio flag can't be set when the flags NewSize and
+        // MaxNewSize are set.
+    }
+
+    private void verifyMinSizeIs(long expected) throws Exception {
+        verifyEquals("minSize", expected);
+    }
+
+    private void verifyMaxSizeIs(long expected) throws Exception {
+        verifyEquals("maxSize", expected);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/configuration/TestGCYoungGenerationConfigurationEventWithNewRatio.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.configuration;
+
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventVerifier;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:NewRatio=4 jdk.jfr.event.gc.configuration.TestGCYoungGenerationConfigurationEventWithNewRatio
+ */
+public class TestGCYoungGenerationConfigurationEventWithNewRatio
+    extends GCYoungGenerationConfigurationEventTester {
+    public static void main(String[] args) throws Exception {
+        GCYoungGenerationConfigurationEventTester t = new TestGCYoungGenerationConfigurationEventWithNewRatio();
+        t.run();
+    }
+
+    @Override protected EventVerifier createVerifier(RecordedEvent e) {
+        return new NewRatioVerifier(e);
+    }
+}
+
+class NewRatioVerifier extends EventVerifier {
+    public NewRatioVerifier(RecordedEvent event) {
+        super(event);
+    }
+
+    @Override public void verify() throws Exception {
+        verifyNewRatioIs(4);
+
+        // Can't test minSize and maxSize at the same time as newRatio,
+        // because the NewSize and MaxNewSize flags can't be set when the flag
+        // MaxNewSize is set.
+    }
+
+    private void verifyNewRatioIs(int expected) throws Exception {
+        verifyEquals("newRatio", expected);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/ExecuteOOMApp.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.detailed;
+
+import jdk.test.lib.jfr.AppExecutorHelper;
+import jdk.test.lib.process.OutputAnalyzer;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class ExecuteOOMApp {
+    /**
+     * Executes OOM application with JFR recording and returns true if OOM error happened in the
+     * test thread. Adds -XX:-UseGCOverheadLimit option to avoid "java.lang.OutOfMemoryError: GC overhead limit exceeded".
+     *
+     * @param settings JFR settings file
+     * @param jfrFilename JFR resulting recording filename
+     * @param additionalVmFlags additional VM flags passed to the java
+     * @param bytesToAllocate number of bytes to allocate in new object every cycle in OOM application
+     * @return true - OOM application is finished as expected,i.e. OOM happened in the test thead
+     *         false - OOM application is finished with OOM error which happened in the non test thread
+     */
+    public static boolean execute(String settings, String jfrFilename, String[] additionalVmFlags, int bytesToAllocate) throws Exception {
+        List<String> additionalVmFlagsList = new ArrayList<>(Arrays.asList(additionalVmFlags));
+        additionalVmFlagsList.add("-XX:-UseGCOverheadLimit");
+
+        OutputAnalyzer out = AppExecutorHelper.executeAndRecord(settings, jfrFilename, additionalVmFlagsList.toArray(new String[0]),
+                                                                OOMApp.class.getName(), String.valueOf(bytesToAllocate));
+
+        if ((out.getExitValue() == 1 && out.getOutput().contains("Exception: java.lang.OutOfMemoryError"))) {
+            return false;
+        }
+
+        out.shouldHaveExitValue(0);
+        System.out.println(out.getOutput());
+
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/OOMApp.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.detailed;
+
+import java.util.List;
+import java.util.LinkedList;
+
+/**
+ * Helper class which triggers and handles out of memory error to generate
+ * JFR events
+ */
+public class OOMApp {
+
+    public static List<DummyObject> dummyList;
+
+    public static void main(String[] args) {
+        int bytesToAllocate;
+
+        if (args.length > 0) {
+            bytesToAllocate = Integer.parseInt(args[0]);
+        } else {
+            bytesToAllocate = 1024;
+        }
+        System.gc();
+        dummyList = new LinkedList<DummyObject>();
+        System.out.println("## Initiate OOM ##");
+        try {
+            while (true) {
+                dummyList.add(new DummyObject(bytesToAllocate));
+            }
+        } catch (OutOfMemoryError e) {
+            System.out.println("## Got OOM ##");
+            dummyList = null;
+        }
+        System.gc();
+    }
+
+    public static class DummyObject {
+        public byte[] payload;
+
+        DummyObject(int bytesToAllocate) {
+            payload = new byte[bytesToAllocate];
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/PromotionEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.detailed;
+
+import static jdk.test.lib.Asserts.assertEquals;
+import static jdk.test.lib.Asserts.assertNotEquals;
+import static jdk.test.lib.Asserts.assertNotNull;
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.lang.management.GarbageCollectorMXBean;
+import java.lang.management.ManagementFactory;
+import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/**
+ * This is a base class for testing Promotion Events
+ *
+ * See TestPromotionEventWith* for actual test classes. Tests must set
+ * -XX:MaxTenuringThreshold=5 -XX:InitialTenuringThreshold=5
+ *
+ * @author Staffan Friberg
+ */
+public class PromotionEvent {
+
+    private final static String PROMOTION_IN_NEW_PLAB_NAME = EventNames.PromoteObjectInNewPLAB;
+    private final static String PROMOTION_OUTSIDE_PLAB_NAME = EventNames.PromoteObjectOutsidePLAB;
+
+    // This value needs to match the command line option set above
+    private final static int MAX_TENURING_THRESHOLD = 5;
+
+    // Keep track of the collection count just before and after JFR recording
+    private static int startGCCount = 0;
+
+    // Dummy objects to keep things alive and assure allocation happens
+    public static Object dummy;
+    public static Object[] keepAlive = new Object[128];
+    public static Object[] age = new Object[128];
+
+    public static void test() throws Exception {
+        GarbageCollectorMXBean ycBean = null;
+
+        List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans();
+        for (GarbageCollectorMXBean gcBean : gcBeans) {
+            if ("PS Scavenge".equals(gcBean.getName())
+                    || "G1 Young Generation".equals(gcBean.getName())
+                    || ("ParNew".equals(gcBean.getName()))) {
+                ycBean = gcBean;
+            }
+
+            if (ycBean != null) {
+                break;
+            }
+        }
+
+        if (ycBean == null) {
+            assertNotNull(ycBean, "Test failed since the MXBean for the Young Collector could not be found.");
+            return; // To remove IDE warning
+        }
+
+        System.gc(); // Clear nusery before recording
+
+        // Get total GC count before recording
+        for (GarbageCollectorMXBean gcBean : gcBeans) {
+            startGCCount += gcBean.getCollectionCount();
+        }
+
+        Recording recording = new Recording();
+        recording.enable(PROMOTION_IN_NEW_PLAB_NAME);
+        recording.enable(PROMOTION_OUTSIDE_PLAB_NAME);
+        recording.start();
+
+        byte[] largeBytes = new byte[1024 * 10];
+        byte[] smallBytes = new byte[64];
+
+        // Some large strings to keep alive for tenuring
+        for (int i = 0; i < keepAlive.length / 2; i++) {
+            ThreadLocalRandom.current().nextBytes(largeBytes);
+            keepAlive[i] = new String(largeBytes);
+        }
+
+        // Some small strings to keep alive for tenuring
+        for (int i = keepAlive.length / 2; i < keepAlive.length; i++) {
+            ThreadLocalRandom.current().nextBytes(smallBytes);
+            keepAlive[i] = new String(smallBytes);
+        }
+
+        // Allocate temp data to force GCs until we have promoted the live data
+        for (int gcCount = 0; gcCount < MAX_TENURING_THRESHOLD * 2; gcCount++) {
+            long currentGCCount = ycBean.getCollectionCount();
+
+            // some large strings to age
+            for (int i = 0; i < age.length / 2; i++) {
+                ThreadLocalRandom.current().nextBytes(largeBytes);
+                age[i] = new String(largeBytes);
+            }
+
+            // Some small strings to age
+            for (int i = age.length / 2; i < age.length; i++) {
+                ThreadLocalRandom.current().nextBytes(smallBytes);
+                age[i] = new String(smallBytes);
+            }
+
+            while (ycBean.getCollectionCount() <= currentGCCount + 3) {
+                ThreadLocalRandom.current().nextBytes(smallBytes);
+                dummy = new String(smallBytes);
+            }
+        }
+
+        recording.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(recording);
+
+        verifyPromotionSampleEvents(events);
+
+        recording.close();
+    }
+
+    private static void verifyPromotionSampleEvents(List<RecordedEvent> events)
+            throws Exception {
+
+        boolean objectWasPromotedInNewPLAB = false;
+        boolean objectPromotedInNewPLABWasAged = false;
+        boolean objectPromotedInNewPLABWasTenured = false;
+        boolean objectWasPromotedOutsidePLAB = false;
+        boolean objectPromotedOutsidePLABWasAged = false;
+        boolean objectPromotedOutsidePLABWasTenured = false;
+
+        Events.hasEvents(events);
+
+        for (RecordedEvent event : events) {
+            // Read all common fields
+            Events.assertField(event, "gcId").atLeast(startGCCount).getValue();
+            String className = (event.getEventType()).getName().toString();
+            Events.assertField(event, "tenuringAge").atLeast(0).atMost(MAX_TENURING_THRESHOLD).getValue();
+            Boolean tenured = Events.assertField(event, "tenured").getValue();
+            Long objectSize = Events.assertField(event, "objectSize").above(0L).getValue();
+
+            // Verify Class Name
+            assertNotNull(className, "Class name is null. Event: " + event);
+            assertNotEquals(className.length(), 0, "Class name is of zero length. Event: " + event);
+
+            // Verify PLAB size and direct allocation
+            if (PROMOTION_IN_NEW_PLAB_NAME.equals(event.getEventType().getName())) {
+                // Read event specific fields
+                Long plabSize = Events.assertField(event, "plabSize").above(0L).getValue();
+                assertTrue(plabSize >= objectSize, "PLAB size is smaller than object size. Event: " + event);
+                objectWasPromotedInNewPLAB = true;
+                // Verify tenured is hard to do as objects might be tenured earlier than the max threshold
+                // but at least verify that we got the field set at least once during the test
+                if (tenured) {
+                    objectPromotedInNewPLABWasTenured = true;
+                } else {
+                    objectPromotedInNewPLABWasAged = true;
+                }
+            } else if (PROMOTION_OUTSIDE_PLAB_NAME.equals(event.getEventType().getName())) {
+                objectWasPromotedOutsidePLAB = true;
+                // Verify tenured is hard to do as objects might be tenured earlier than the max threshold
+                // but at least verify that we got the field set at least once during the test
+                if (tenured) {
+                    objectPromotedOutsidePLABWasTenured = true;
+                } else {
+                    objectPromotedOutsidePLABWasAged = true;
+                }
+            } else {
+                assertEquals(event.getEventType().getName(), "Unreachable...", "Got wrong type of event " + event);
+            }
+
+        }
+
+        // Verify that at least one event of these types occured during test
+        assertTrue(objectWasPromotedInNewPLAB, "No object in new plab was promoted in test");
+        assertTrue(objectPromotedInNewPLABWasAged, "No object in new plab was aged in test");
+        assertTrue(objectPromotedInNewPLABWasTenured, "No object in new plab was tenured in test");
+        assertTrue(objectWasPromotedOutsidePLAB, "No object outside plab was promoted in test");
+        assertTrue(objectPromotedOutsidePLABWasAged, "No object outside plab was aged in test");
+        assertTrue(objectPromotedOutsidePLABWasTenured, "No object outside plab was tenured in test");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/PromotionFailedEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.detailed;
+
+import java.io.File;
+import java.nio.file.Paths;
+import java.util.List;
+
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+public class PromotionFailedEvent {
+
+    private final static String EVENT_SETTINGS_FILE = System.getProperty("test.src", ".") + File.separator + "promotionfailed-testsettings.jfc";
+    private final static int BYTES_TO_ALLOCATE = 1024;
+
+    public static void test(String testName, String[] vmFlags) throws Throwable {
+        String jfr_file = testName + ".jfr";
+
+        if (!ExecuteOOMApp.execute(EVENT_SETTINGS_FILE, jfr_file, vmFlags, BYTES_TO_ALLOCATE)) {
+            System.out.println("OOM happened in the other thread(not test thread). Skip test.");
+            // Skip test, process terminates due to the OOME error in the different thread
+            return;
+        }
+
+        // This test can not always trigger the expected event.
+        // Test is ok even if no events found.
+        List<RecordedEvent> events = RecordingFile.readAllEvents(Paths.get(jfr_file));
+        for (RecordedEvent event : events) {
+            System.out.println("Event: " + event);
+            long smallestSize = Events.assertField(event, "promotionFailed.smallestSize").atLeast(1L).getValue();
+            long firstSize = Events.assertField(event, "promotionFailed.firstSize").atLeast(smallestSize).getValue();
+            long totalSize = Events.assertField(event, "promotionFailed.totalSize").atLeast(firstSize).getValue();
+            long objectCount = Events.assertField(event, "promotionFailed.objectCount").atLeast(1L).getValue();
+            Asserts.assertLessThanOrEqual(smallestSize * objectCount, totalSize, "smallestSize * objectCount <= totalSize");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/StressAllocationGCEvents.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.detailed;
+
+import static jdk.test.lib.Asserts.assertEquals;
+import static jdk.test.lib.Asserts.assertNotEquals;
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedFrame;
+import jdk.jfr.consumer.RecordedStackTrace;
+import jdk.jfr.consumer.RecordedThread;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/**
+ * Starts several threads which allocate a lot of objects that remain in young
+ * and old generations with defined ratio. Expects event
+ * vm/gc/detailed/allocation_requiring_gc recorded.
+ */
+public class StressAllocationGCEvents {
+
+    private Semaphore threadsCompleted;
+
+    public void run(String[] args) throws Exception {
+        threadsCompleted = new Semaphore(0);
+        System.out.println("Total memory= " + Runtime.getRuntime().maxMemory() + " bytes");
+
+        int obj_size = DEFAULT_OBJ_SIZE;
+        if (args.length > 0) {
+            obj_size = Integer.parseInt(args[0]);
+        }
+
+        System.out.println("Objects size= " + obj_size + " bytes");
+        ExecutorService executor
+                = Executors.newFixedThreadPool(THREAD_COUNT, new NamedThreadFactory());
+        Recording r = new Recording();
+        r.enable(EVENT_NAME_ALLOCATION_REQUIRING_GC);
+        r.start();
+
+        System.out.println("Starting " + THREAD_COUNT + " threads");
+
+        for (int i = 0; i < THREAD_COUNT; i++) {
+            executor.execute(new Runner(obj_size));
+        }
+
+        // Wait for all threads to complete
+        threadsCompleted.acquire(THREAD_COUNT);
+        executor.shutdownNow();
+
+        if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
+            System.err.println("Thread pool did not terminate after 10 seconds after shutdown");
+        }
+
+        r.stop();
+
+        List<RecordedEvent> allocationEvents
+                = Events.fromRecording(r);
+
+        System.out.println(EVENT_NAME_ALLOCATION_REQUIRING_GC + " " + allocationEvents.size());
+
+        Events.hasEvents(allocationEvents);
+
+        // check stacktrace depth
+        for (RecordedEvent event : allocationEvents) {
+            checkEvent(event);
+        }
+    }
+
+    class Runner extends Thread {
+
+        public Runner(int obj_size) {
+            this.startTime = System.currentTimeMillis();
+            this.OBJ_SIZE = obj_size;
+            this.OLD_OBJ_COUNT = Math.max(1, (int) ((float) Runtime.getRuntime().maxMemory() / 2 / THREAD_COUNT / OBJ_SIZE));
+            this.old_garbage = new Object[OLD_OBJ_COUNT];
+
+            System.out.println(String.format("In \"%s\" old objects count  = %d, recursion depth = %d",
+                    this.getName(), OLD_OBJ_COUNT, RECURSION_DEPTH));
+        }
+
+        @Override
+        public void run() {
+            diver(RECURSION_DEPTH);
+            threadsCompleted.release();
+            System.out.println("Completed after " + (System.currentTimeMillis() - startTime) + " ms");
+        }
+
+        private void diver(int stack) {
+            if (stack > 1) {
+                diver(stack - 1);
+            } else {
+                long endTime = startTime + (SECONDS_TO_RUN * 1000);
+                Random r = new Random(startTime);
+                while (endTime > System.currentTimeMillis()) {
+                    byte[] garbage = new byte[OBJ_SIZE];
+                    if (r.nextInt(100) > OLD_GEN_RATE) {
+                        old_garbage[r.nextInt(OLD_OBJ_COUNT)] = garbage;
+                    }
+                }
+            }
+        }
+
+        private final long startTime;
+        private final Object[] old_garbage;
+        private final int OBJ_SIZE;
+        private final int OLD_OBJ_COUNT;
+    }
+
+    ///< check stacktrace depth
+    private void checkEvent(RecordedEvent event) throws Exception {
+        // skip check if allocation failure comes not from diver
+
+        RecordedThread thread = event.getThread();
+        String threadName = thread.getJavaName();
+
+        if (!threadName.contains(THREAD_NAME)) {
+            System.out.println("Skip event not from pool (from internals)");
+            System.out.println(" Thread Id: " + thread.getJavaThreadId()
+                    + " Thread name: " + threadName);
+            return;
+        }
+
+        RecordedStackTrace stackTrace = event.getStackTrace();
+
+        List<RecordedFrame> frames = stackTrace.getFrames();
+        //String[] stacktrace = StackTraceHelper.buildStackTraceFromFrames(frames);
+
+        if (!(frames.get(0).getMethod().getName().equals(DIVER_FRAME_NAME))) {
+            System.out.println("Skip stacktrace check for: \n"
+                    + String.join("\n", threadName));
+            return;
+        }
+
+        assertTrue(frames.size() > RECURSION_DEPTH,
+                "Stack trace should contain at least one more entry than the ones generated by the test recursion");
+        for (int i = 0; i < RECURSION_DEPTH; i++) {
+            assertEquals(frames.get(i).getMethod().getName(), DIVER_FRAME_NAME,
+                    "Frame " + i + " is wrong: \n"
+                    + String.join("\n", threadName));
+        }
+        assertNotEquals(frames.get(RECURSION_DEPTH).getMethod().getName(), DIVER_FRAME_NAME,
+                "Too many diver frames: \n"
+                + String.join("\n", threadName));
+    }
+
+    class NamedThreadFactory implements ThreadFactory {
+
+        private int threadNum = 0;
+
+        @Override
+        public Thread newThread(Runnable r) {
+            return new Thread(r, THREAD_NAME + (threadNum++));
+        }
+    }
+
+    // Because each thread will keep some number of objects live we need to limit
+    // the number of threads to ensure we don't run out of heap space. The big
+    // allocation tests uses 256m heap and 1m allocations, so a 64 thread limit
+    // should be fine.
+    private final static int THREAD_COUNT_LIMIT = 64;
+    private final static int THREAD_COUNT = Math.min(1 + (int) (Runtime.getRuntime().availableProcessors() * 2), THREAD_COUNT_LIMIT);
+    private final static int SECONDS_TO_RUN = 60;
+    private final static int DEFAULT_OBJ_SIZE = 1024;
+    private final static int OLD_GEN_RATE = 60; // from 0 to 100
+    private final static int RECURSION_DEPTH = 5;
+    private final static String EVENT_NAME_ALLOCATION_REQUIRING_GC = EventNames.AllocationRequiringGC;
+    private static final String THREAD_NAME = "JFRTest-";
+    private static final String DIVER_FRAME_NAME = "StressAllocationGCEvents$Runner.diver";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/TestCMSConcurrentModeFailureEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.detailed;
+
+import java.io.IOException;
+import java.io.File;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Optional;
+
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @requires vm.gc == "ConcMarkSweep" | vm.gc == null
+ * @library /test/lib /test/jdk
+ *
+ * @run main jdk.jfr.event.gc.detailed.TestCMSConcurrentModeFailureEvent
+ */
+public class TestCMSConcurrentModeFailureEvent {
+
+    private final static String EVENT_NAME = EventNames.ConcurrentModeFailure;
+    private final static String EVENT_SETTINGS_FILE = System.getProperty("test.src", ".") + File.separator + "concurrentmodefailure-testsettings.jfc";
+    private final static String JFR_FILE = "TestCMSConcurrentModeFailureEvent.jfr";
+    private final static int BYTES_TO_ALLOCATE = 1024 * 512;
+
+    public static void main(String[] args) throws Exception {
+        String[] vmFlags = {"-Xmx128m", "-XX:MaxTenuringThreshold=0", "-Xlog:gc*=debug:testCMSGC.log",
+            "-XX:+UseConcMarkSweepGC", "-XX:+UnlockExperimentalVMOptions", "-XX:-UseFastUnorderedTimeStamps"};
+
+        if (!ExecuteOOMApp.execute(EVENT_SETTINGS_FILE, JFR_FILE, vmFlags, BYTES_TO_ALLOCATE)) {
+            System.out.println("OOM happened in the other thread(not test thread). Skip test.");
+            // Skip test, process terminates due to the OOME error in the different thread
+            return;
+        }
+
+        Optional<RecordedEvent> event = RecordingFile.readAllEvents(Paths.get(JFR_FILE)).stream().findFirst();
+        if (event.isPresent()) {
+            Asserts.assertEquals(EVENT_NAME, event.get().getEventType().getName(), "Wrong event type");
+        } else {
+            // No event received. Check if test did trigger the event.
+            boolean isEventTriggered = fileContainsString("testCMSGC.log", "concurrent mode failure");
+            System.out.println("isEventTriggered=" +isEventTriggered);
+            Asserts.assertFalse(isEventTriggered, "Event found in log, but not in JFR");
+        }
+    }
+
+    private static boolean fileContainsString(String filename, String text) throws IOException {
+        Path p = Paths.get(filename);
+        for (String line : Files.readAllLines(p, Charset.defaultCharset())) {
+            if (line.contains(text)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/TestEvacuationFailedEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.detailed;
+
+import java.io.File;
+import java.nio.file.Paths;
+import java.util.List;
+
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @library /test/lib /test/jdk
+ * @requires vm.gc == "G1" | vm.gc == null
+ *
+ * @run main jdk.jfr.event.gc.detailed.TestEvacuationFailedEvent
+ */
+public class TestEvacuationFailedEvent {
+
+    private final static String EVENT_SETTINGS_FILE = System.getProperty("test.src", ".") + File.separator + "evacuationfailed-testsettings.jfc";
+    private final static String JFR_FILE = "TestEvacuationFailedEvent.jfr";
+    private final static int BYTES_TO_ALLOCATE = 1024 * 512;
+
+    public static void main(String[] args) throws Exception {
+        String[] vmFlags = {"-XX:+UnlockExperimentalVMOptions", "-XX:-UseFastUnorderedTimeStamps",
+            "-Xmx64m", "-Xmn60m", "-XX:-UseDynamicNumberOfGCThreads", "-XX:ParallelGCThreads=3",
+            "-XX:MaxTenuringThreshold=0", "-Xlog:gc*=debug", "-XX:+UseG1GC"};
+
+        if (!ExecuteOOMApp.execute(EVENT_SETTINGS_FILE, JFR_FILE, vmFlags, BYTES_TO_ALLOCATE)) {
+            System.out.println("OOM happened in the other thread(not test thread). Skip test.");
+            // Skip test, process terminates due to the OOME error in the different thread
+            return;
+        }
+
+        List<RecordedEvent> events = RecordingFile.readAllEvents(Paths.get(JFR_FILE));
+
+        Events.hasEvents(events);
+        for (RecordedEvent event : events) {
+            long objectCount = Events.assertField(event, "evacuationFailed.objectCount").atLeast(1L).getValue();
+            long smallestSize = Events.assertField(event, "evacuationFailed.smallestSize").atLeast(1L).getValue();
+            long firstSize = Events.assertField(event, "evacuationFailed.firstSize").atLeast(smallestSize).getValue();
+            long totalSize = Events.assertField(event, "evacuationFailed.totalSize").atLeast(firstSize).getValue();
+            Asserts.assertLessThanOrEqual(smallestSize * objectCount, totalSize, "smallestSize * objectCount <= totalSize");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/TestEvacuationInfoEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.detailed;
+
+import java.time.Duration;
+import java.util.List;
+import java.util.Optional;
+import java.util.Random;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "G1" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:G1HeapRegionSize=1m -Xmx64m -Xmn16m -XX:+UseG1GC jdk.jfr.event.gc.detailed.TestEvacuationInfoEvent
+ */
+public class TestEvacuationInfoEvent {
+    private final static String EVENT_INFO_NAME = EventNames.EvacuationInfo;
+    private final static String EVENT_FAILED_NAME = EventNames.EvacuationFailed;
+
+    public static void main(String[] args) throws Throwable {
+        final long g1HeapRegionSize = 1024 * 1024;
+        Recording recording = new Recording();
+        recording.enable(EVENT_INFO_NAME).withThreshold(Duration.ofMillis(0));
+        recording.enable(EVENT_FAILED_NAME).withThreshold(Duration.ofMillis(0));
+        recording.start();
+        allocate();
+        recording.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        Asserts.assertFalse(events.isEmpty(), "No events found");
+        for (RecordedEvent event : events) {
+            if (!Events.isEventType(event, EVENT_INFO_NAME)) {
+                continue;
+            }
+            System.out.println("Event: " + event);
+
+            int setRegions = Events.assertField(event, "cSetRegions").atLeast(0).getValue();
+            long setUsedAfter = Events.assertField(event, "cSetUsedAfter").atLeast(0L).getValue();
+            long setUsedBefore = Events.assertField(event, "cSetUsedBefore").atLeast(setUsedAfter).getValue();
+            int allocationRegions = Events.assertField(event, "allocationRegions").atLeast(0).getValue();
+            long allocRegionsUsedBefore = Events.assertField(event, "allocRegionsUsedBefore").atLeast(0L).getValue();
+            long allocRegionsUsedAfter = Events.assertField(event, "allocRegionsUsedAfter").atLeast(0L).getValue();
+            long bytesCopied = Events.assertField(event, "bytesCopied").atLeast(0L).getValue();
+            int regionsFreed = Events.assertField(event, "regionsFreed").atLeast(0).getValue();
+
+            Asserts.assertEquals(allocRegionsUsedBefore + bytesCopied, allocRegionsUsedAfter, "allocRegionsUsedBefore + bytesCopied = allocRegionsUsedAfter");
+            Asserts.assertGreaterThanOrEqual(setRegions, regionsFreed, "setRegions >= regionsFreed");
+            Asserts.assertGreaterThanOrEqual(g1HeapRegionSize * allocationRegions, allocRegionsUsedAfter, "G1HeapRegionSize * allocationRegions >= allocationRegionsUsedAfter");
+            Asserts.assertGreaterThanOrEqual(g1HeapRegionSize * setRegions, setUsedAfter, "G1HeapRegionSize * setRegions >= setUsedAfter");
+            Asserts.assertGreaterThanOrEqual(g1HeapRegionSize * setRegions, setUsedBefore, "G1HeapRegionSize * setRegions >= setUsedBefore");
+            Asserts.assertGreaterThanOrEqual(g1HeapRegionSize, allocRegionsUsedBefore, "G1HeapRegionSize >= allocRegionsUsedBefore");
+
+            int gcId = Events.assertField(event, "gcId").getValue();
+            boolean isEvacuationFailed = containsEvacuationFailed(events, gcId);
+            if (isEvacuationFailed) {
+                Asserts.assertGreaterThan(setUsedAfter, 0L, "EvacuationFailure -> setUsedAfter > 0");
+                Asserts.assertGreaterThan(setRegions, regionsFreed, "EvacuationFailure -> setRegions > regionsFreed");
+            } else {
+                Asserts.assertEquals(setUsedAfter, 0L, "No EvacuationFailure -> setUsedAfter = 0");
+                Asserts.assertEquals(setRegions, regionsFreed, "No EvacuationFailure -> setRegions = regionsFreed");
+            }
+        }
+    }
+
+    private static boolean containsEvacuationFailed(List<RecordedEvent> events, int gcId) {
+        Optional<RecordedEvent> failedEvent = events.stream()
+                                .filter(e -> Events.isEventType(e, EVENT_FAILED_NAME))
+                                .filter(e -> gcId == (int)Events.assertField(e, "gcId").getValue())
+                                .findAny();
+        System.out.println("Failed event: " + (failedEvent.isPresent() ? failedEvent.get() : "None"));
+        return failedEvent.isPresent();
+    }
+
+    public static DummyObject[] dummys = new DummyObject[6000];
+
+        /**
+         * Allocate memory to trigger garbage collections.
+         * We want the allocated objects to have different life time, because we want both "young" and "old" objects.
+         * This is done by keeping the objects in an array and step the current index by a small random number in the loop.
+         * The loop will continue until we have allocated a fixed number of bytes.
+         */
+        private static void allocate() {
+            Random r = new Random(0);
+            long bytesToAllocate = 256 * 1024 * 1024;
+            int currPos = 0;
+            while (bytesToAllocate > 0) {
+                int allocSize = 1000 + (r.nextInt(4000));
+                bytesToAllocate -= allocSize;
+                dummys[currPos] = new DummyObject(allocSize);
+
+                // Skip a few positions to get different duration on the objects.
+                currPos = (currPos + r.nextInt(20)) % dummys.length;
+            }
+            for (int c=0; c<dummys.length; c++) {
+                dummys[c] = null;
+            }
+            System.gc();
+        }
+
+        public static class DummyObject {
+            public byte[] payload;
+            DummyObject(int size) {
+            payload = new byte[size];
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/TestG1AIHOPEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.detailed;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "G1" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:NewSize=2m -XX:MaxNewSize=2m -Xmx32m -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:+G1UseAdaptiveIHOP jdk.jfr.event.gc.detailed.TestG1AIHOPEvent
+ */
+public class TestG1AIHOPEvent {
+
+    private final static String EVENT_NAME = EventNames.G1AdaptiveIHOP;
+    public static byte[] bytes;
+
+    public static void main(String[] args) throws Exception {
+
+        Recording recording = new Recording();
+
+        // activate the event we are interested in and start recording
+        recording.enable(EVENT_NAME);
+        recording.start();
+
+        // Setting NewSize and MaxNewSize will limit eden, so
+        // allocating 1024 5k byte arrays should trigger at
+        // least one Young GC.
+        for (int i = 0; i < 1024; i++) {
+            bytes = new byte[5 * 1024];
+        }
+        recording.stop();
+
+        // Verify recording
+        List<RecordedEvent> all = Events.fromRecording(recording);
+        Events.hasEvents(all);
+
+        for (RecordedEvent e : all) {
+            Events.assertField(e, "gcId").above(0);
+        }
+
+        recording.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/TestG1ConcurrentModeFailureEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.detailed;
+
+import java.io.IOException;
+import java.io.File;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Optional;
+
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @requires vm.gc == "G1" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main jdk.jfr.event.gc.detailed.TestG1ConcurrentModeFailureEvent
+ */
+
+public class TestG1ConcurrentModeFailureEvent {
+
+    private final static String EVENT_NAME = EventNames.ConcurrentModeFailure;
+    private final static String EVENT_SETTINGS_FILE = System.getProperty("test.src", ".") + File.separator + "concurrentmodefailure-testsettings.jfc";
+    private final static String JFR_FILE = "TestG1ConcurrentModeFailureEvent.jfr";
+    private final static int BYTES_TO_ALLOCATE = 1024 * 512;
+
+    public static void main(String[] args) throws Exception {
+        String[] vmFlags = {"-Xmx512m", "-Xms512m", "-XX:MaxTenuringThreshold=0", "-Xlog:gc*=debug:testG1GC.log",
+            "-XX:+UseG1GC", "-XX:+UnlockExperimentalVMOptions", "-XX:-UseFastUnorderedTimeStamps"};
+
+        if (!ExecuteOOMApp.execute(EVENT_SETTINGS_FILE, JFR_FILE, vmFlags, BYTES_TO_ALLOCATE)) {
+            System.out.println("OOM happened in the other thread(not test thread). Skip test.");
+            // Skip test, process terminates due to the OOME error in the different thread
+            return;
+        }
+
+        Optional<RecordedEvent> event = RecordingFile.readAllEvents(Paths.get(JFR_FILE)).stream().findFirst();
+        if (event.isPresent()) {
+            Asserts.assertEquals(EVENT_NAME, event.get().getEventType().getName(), "Wrong event type");
+        } else {
+            // No event received. Check if test did trigger the event.
+            boolean isEventTriggered = fileContainsString("testG1GC.log", "concurrent-mark-abort");
+            System.out.println("isEventTriggered=" +isEventTriggered);
+            Asserts.assertFalse(isEventTriggered, "Event found in log, but not in JFR");
+        }
+    }
+
+    private static boolean fileContainsString(String filename, String text) throws IOException {
+        Path p = Paths.get(filename);
+        for (String line : Files.readAllLines(p, Charset.defaultCharset())) {
+            if (line.contains(text)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/TestG1EvacMemoryStatsEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.detailed;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "G1" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:NewSize=2m -XX:MaxNewSize=2m -Xmx32m -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps jdk.jfr.event.gc.detailed.TestG1EvacMemoryStatsEvent
+ */
+public class TestG1EvacMemoryStatsEvent {
+
+    public static byte[] bytes;
+
+    public static void runTest(String event_name) throws Exception {
+
+        Recording recording = new Recording();
+
+        // activate the event we are interested in and start recording
+        recording.enable(event_name);
+        recording.start();
+
+        // Setting NewSize and MaxNewSize will limit eden, so
+        // allocating 1024 5k byte arrays should trigger at
+        // least one Young GC.
+        for (int i = 0; i < 1024; i++) {
+            bytes = new byte[5 * 1024];
+        }
+        recording.stop();
+
+        // Verify recording
+        List<RecordedEvent> all = Events.fromRecording(recording);
+        for (RecordedEvent e : all) {
+            Events.assertField(e, "statistics.gcId").above(0);
+        }
+
+        recording.close();
+    }
+
+    public static void main(String[] args) throws Exception {
+        runTest(EventNames.G1EvacuationYoungStatistics);
+        runTest(EventNames.G1EvacuationOldStatistics);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/TestG1HeapRegionInformationEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.detailed;
+
+import java.nio.file.Paths;
+import java.util.List;
+
+import jdk.jfr.EventType;
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.GCHelper;
+
+public class TestG1HeapRegionInformationEvent {
+    private final static String EVENT_NAME = EventNames.G1HeapRegionInformation;
+    public static void main(String[] args) throws Exception {
+        Recording recording = null;
+        try {
+            recording = new Recording();
+            // activate the event we are interested in and start recording
+            for (EventType t : FlightRecorder.getFlightRecorder().getEventTypes()) {
+                System.out.println(t.getName());
+            }
+            recording.enable(EVENT_NAME);
+            recording.start();
+            recording.stop();
+
+            // Verify recording
+            List<RecordedEvent> events = Events.fromRecording(recording);
+            Events.hasEvents(events);
+
+            for (RecordedEvent event : events) {
+                Events.assertField(event, "index").notEqual(-1);
+                Asserts.assertTrue(GCHelper.isValidG1HeapRegionType(Events.assertField(event, "type").getValue()));
+                Events.assertField(event, "used").atMost(1L*1024*1024);
+            }
+
+        } catch (Throwable t) {
+            if (recording != null) {
+                recording.dump(Paths.get("TestG1HeapRegionInformationEvent.jfr"));
+            }
+            throw t;
+        } finally {
+            if (recording != null) {
+                recording.close();
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/TestG1HeapRegionTypeChangeEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.detailed;
+
+import java.nio.file.Paths;
+import java.time.Duration;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @bug 8149650
+ * @requires vm.gc == "G1" | vm.gc == null
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:NewSize=2m -XX:MaxNewSize=2m -Xmx32m -XX:G1HeapRegionSize=1m -XX:+UseG1GC jdk.jfr.event.gc.detailed.TestG1HeapRegionTypeChangeEvent
+ */
+
+public class TestG1HeapRegionTypeChangeEvent {
+    private final static String EVENT_NAME = EventNames.G1HeapRegionTypeChange;
+
+    public static void main(String[] args) throws Exception {
+        Recording recording = null;
+        try {
+            recording = new Recording();
+            // activate the event we are interested in and start recording
+            recording.enable(EVENT_NAME).withThreshold(Duration.ofMillis(0));
+            recording.start();
+
+            // Setting NewSize and MaxNewSize will limit eden, so
+            // allocating 1024 20k byte arrays should trigger at
+            // least a few Young GCs.
+            byte[][] array = new byte[1024][];
+            for (int i = 0; i < array.length; i++) {
+                array[i] = new byte[20 * 1024];
+            }
+            recording.stop();
+
+            // Verify recording
+            List<RecordedEvent> events = Events.fromRecording(recording);
+            Asserts.assertFalse(events.isEmpty(), "No events found");
+
+            for (RecordedEvent event : events) {
+                Events.assertField(event, "index").notEqual(-1);
+                Asserts.assertTrue(GCHelper.isValidG1HeapRegionType(Events.assertField(event, "from").getValue()));
+                Asserts.assertTrue(GCHelper.isValidG1HeapRegionType(Events.assertField(event, "to").getValue()));
+                Events.assertField(event, "used").atMost(1L*1024*1024);
+            }
+        } catch (Throwable t) {
+            if (recording != null) {
+                recording.dump(Paths.get("TestG1HeapRegionTypeChangeEvent.jfr"));
+            }
+            throw t;
+        } finally {
+            if (recording != null) {
+                recording.close();
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/TestG1IHOPEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.detailed;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "G1" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:NewSize=2m -XX:MaxNewSize=2m -Xmx32m -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:-G1UseAdaptiveIHOP jdk.jfr.event.gc.detailed.TestG1IHOPEvent
+ * @run main/othervm -XX:NewSize=2m -XX:MaxNewSize=2m -Xmx32m -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:+G1UseAdaptiveIHOP jdk.jfr.event.gc.detailed.TestG1IHOPEvent
+ */
+public class TestG1IHOPEvent {
+
+    private final static String EVENT_NAME = EventNames.G1BasicIHOP;
+    public static byte[] bytes;
+
+    public static void main(String[] args) throws Exception {
+
+        Recording recording = new Recording();
+
+        // activate the event we are interested in and start recording
+        recording.enable(EVENT_NAME);
+        recording.start();
+
+        // Setting NewSize and MaxNewSize will limit eden, so
+        // allocating 1024 5k byte arrays should trigger at
+        // least one Young GC.
+        for (int i = 0; i < 1024; i++) {
+            bytes= new byte[5 * 1024];
+        }
+        recording.stop();
+
+        // Verify recording
+        List<RecordedEvent> all = Events.fromRecording(recording);
+        Events.hasEvents(all);
+
+        for (RecordedEvent e : all) {
+            Events.assertField(e, "gcId").above(0);
+        }
+
+        recording.close();
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/TestG1MMUEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.detailed;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "G1" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:NewSize=2m -XX:MaxNewSize=2m -Xmx32m -XX:+UseG1GC -XX:MaxGCPauseMillis=75 -XX:GCPauseIntervalMillis=150 -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps jdk.jfr.event.gc.detailed.TestG1MMUEvent
+ */
+public class TestG1MMUEvent {
+
+    // Corresponds to command-line setting -XX:GCPauseIntervalMillis=150
+    private final static double TIME_SLICE = 0.15;
+
+    // Corresponds to command-line setting -XX:MaxGCPauseMillis=75
+    private final static double MAX_GC_TIME = 0.075;
+
+    private final static String EVENT_NAME = EventNames.G1MMU;
+
+    public static byte[] bytes;
+
+    public static void main(String[] args) throws Exception {
+
+        Recording recording = new Recording();
+
+        // activate the event we are interested in and start recording
+        recording.enable(EVENT_NAME);
+        recording.start();
+
+        // Setting NewSize and MaxNewSize will limit eden, so
+        // allocating 1024 5k byte arrays should trigger at
+        // least one Young GC.
+        for (int i = 0; i < 1024; i++) {
+            bytes  = new byte[5 * 1024];
+        }
+        recording.stop();
+
+        // Verify recording
+        List<RecordedEvent> all = Events.fromRecording(recording);
+        Events.hasEvents(all);
+
+        for (RecordedEvent e : all) {
+            Events.assertField(e, "gcId").above(0);
+            Events.assertField(e, "timeSlice").isEqual(TIME_SLICE);
+            Events.assertField(e, "pauseTarget").isEqual(MAX_GC_TIME);
+        }
+
+        recording.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/TestPromotionEventWithG1.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.detailed;
+
+/*
+ * @test
+ * @key jfr
+ * @summary Test that events are created when an object is aged or promoted during a GC and the copying of the object requires a new PLAB or direct heap allocation
+ *
+ * @requires (vm.gc == "G1" | vm.gc == null)
+ *           & vm.opt.ExplicitGCInvokesConcurrent != true
+ * @library /test/lib /test/jdk
+ * @run main/othervm -Xmx32m -Xms32m -Xmn12m -XX:+UseG1GC -XX:-UseStringDeduplication -XX:MaxTenuringThreshold=5 -XX:InitialTenuringThreshold=5
+ * jdk.jfr.event.gc.detailed.TestPromotionEventWithG1
+ */
+public class TestPromotionEventWithG1 {
+
+    public static void main(String[] args) throws Throwable {
+        PromotionEvent.test();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/TestPromotionEventWithParallelScavenge.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.detailed;
+
+/*
+ * @test
+ * @key jfr
+ * @summary Test that events are created when an object is aged or promoted during a GC and the copying of the object requires a new PLAB or direct heap allocation
+ *
+ * @requires vm.gc == "Parallel" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main/othervm -Xmx32m -Xms32m -Xmn12m -XX:+UseParallelGC -XX:+UseParallelOldGC -XX:MaxTenuringThreshold=5 -XX:InitialTenuringThreshold=5 jdk.jfr.event.gc.detailed.TestPromotionEventWithParallelScavenge
+ */
+public class TestPromotionEventWithParallelScavenge {
+
+    public static void main(String[] args) throws Throwable {
+        PromotionEvent.test();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/TestPromotionFailedEventWithDefNew.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.detailed;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @requires vm.gc == "Serial" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main jdk.jfr.event.gc.detailed.TestPromotionFailedEventWithDefNew
+ */
+public class TestPromotionFailedEventWithDefNew {
+    public static void main(String[] args) throws Throwable {
+        PromotionFailedEvent.test("TestPromotionFailedEventWithDefNew", new String[] {"-XX:+UnlockExperimentalVMOptions",
+            "-XX:-UseFastUnorderedTimeStamps", "-Xlog:gc*=debug", "-Xmx32m", "-Xmn30m",
+            "-XX:-UseDynamicNumberOfGCThreads", "-XX:MaxTenuringThreshold=0", "-XX:+UseSerialGC"});
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/TestPromotionFailedEventWithParNew.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.detailed;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "ConcMarkSweep" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main/othervm  jdk.jfr.event.gc.detailed.TestPromotionFailedEventWithParNew
+ */
+public class TestPromotionFailedEventWithParNew {
+
+    public static void main(String[] args) throws Throwable {
+        PromotionFailedEvent.test("TestPromotionFailedEventWithParNew",
+                new String[]{"-Xmx32m", "-Xmn30m", "-XX:-UseDynamicNumberOfGCThreads",
+                    "-XX:ParallelGCThreads=3", "-XX:MaxTenuringThreshold=0",
+                    "-Xlog:gc*=debug", "-XX:+UseConcMarkSweepGC",
+                    "-XX:+UnlockExperimentalVMOptions", "-XX:-UseFastUnorderedTimeStamps"});
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/TestPromotionFailedEventWithParallelScavenge.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.detailed;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @requires vm.gc == "Parallel" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main jdk.jfr.event.gc.detailed.TestPromotionFailedEventWithParallelScavenge
+ */
+public class TestPromotionFailedEventWithParallelScavenge {
+    public static void main(String[] args) throws Throwable {
+        PromotionFailedEvent.test("TestPromotionFailedEventWithParallelScavenge",
+            new String[] {"-XX:+UnlockExperimentalVMOptions", "-XX:-UseFastUnorderedTimeStamps",
+            "-Xmx32m", "-Xmn30m", "-XX:-UseDynamicNumberOfGCThreads", "-XX:ParallelGCThreads=3",
+            "-XX:MaxTenuringThreshold=0", "-Xlog:gc*=debug", "-XX:+UseParallelGC"});
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/TestStressAllocationGCEventsWithCMS.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.detailed;
+
+/*
+ * @test
+ * @requires vm.gc == "null" | vm.gc == "ConcMarkSweep"
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UseConcMarkSweepGC -Xmx64m jdk.jfr.event.gc.detailed.TestStressAllocationGCEventsWithCMS
+ */
+public class TestStressAllocationGCEventsWithCMS {
+
+    public static void main(String[] args) throws Exception {
+        new StressAllocationGCEvents().run(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/TestStressAllocationGCEventsWithDefNew.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.detailed;
+
+/*
+ * @test
+ * @requires vm.gc == "null" | vm.gc == "Serial"
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UseSerialGC -Xmx64m jdk.jfr.event.gc.detailed.TestStressAllocationGCEventsWithDefNew
+ */
+public class TestStressAllocationGCEventsWithDefNew {
+
+    public static void main(String[] args) throws Exception {
+        new StressAllocationGCEvents().run(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/TestStressAllocationGCEventsWithG1.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.detailed;
+
+/*
+ * @test
+ * @requires vm.gc == "null" | vm.gc == "G1"
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UseG1GC -Xmx64m jdk.jfr.event.gc.detailed.TestStressAllocationGCEventsWithG1
+ */
+public class TestStressAllocationGCEventsWithG1 {
+
+    public static void main(String[] args) throws Exception {
+        new StressAllocationGCEvents().run(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/TestStressAllocationGCEventsWithParNew.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.detailed;
+
+/*
+ * @test
+ * @requires vm.gc == "null"
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UseConcMarkSweepGC -Xmx64m jdk.jfr.event.gc.detailed.TestStressAllocationGCEventsWithParNew
+ */
+public class TestStressAllocationGCEventsWithParNew {
+
+    public static void main(String[] args) throws Exception {
+        new StressAllocationGCEvents().run(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/TestStressAllocationGCEventsWithParallel.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.detailed;
+
+/*
+ * @test
+ * @requires vm.gc == "null" | vm.gc == "Parallel"
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UseParallelGC -Xmx64m jdk.jfr.event.gc.detailed.TestStressAllocationGCEventsWithParallel
+ */
+public class TestStressAllocationGCEventsWithParallel {
+
+    public static void main(String[] args) throws Exception {
+        new StressAllocationGCEvents().run(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/TestStressBigAllocationGCEventsWithCMS.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.detailed;
+
+/*
+ * @test
+ * @requires vm.gc == "null" | vm.gc == "ConcMarkSweep"
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UseConcMarkSweepGC -Xmx256m jdk.jfr.event.gc.detailed.TestStressBigAllocationGCEventsWithCMS 1048576
+ */
+public class TestStressBigAllocationGCEventsWithCMS {
+
+    public static void main(String[] args) throws Exception {
+        new StressAllocationGCEvents().run(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/TestStressBigAllocationGCEventsWithDefNew.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.detailed;
+
+/*
+ * @test
+ * @requires vm.gc == "null" | vm.gc == "Serial"
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UseSerialGC -Xmx256m jdk.jfr.event.gc.detailed.TestStressBigAllocationGCEventsWithDefNew 1048576
+ */
+public class TestStressBigAllocationGCEventsWithDefNew {
+
+    public static void main(String[] args) throws Exception {
+        new StressAllocationGCEvents().run(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/TestStressBigAllocationGCEventsWithG1.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.detailed;
+
+/**
+ * @test
+ * @summary Test allocates humongous objects with G1 GC. Objects
+ * considered humongous when it allocates equals or more than one region. As
+ * we're passing the size of byte array we need adjust it that entire structure
+ * fits exactly to one region, if not - G1 will allocate another almost empty
+ * region as a continue of humongous. Thus we will exhaust memory very fast and
+ * test will fail with OOME.
+ * @requires vm.gc == "null" | vm.gc == "G1"
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UseG1GC -XX:MaxNewSize=5m -Xmx256m -XX:G1HeapRegionSize=1048576 jdk.jfr.event.gc.detailed.TestStressBigAllocationGCEventsWithG1 1048544
+ */
+public class TestStressBigAllocationGCEventsWithG1 {
+
+    public static void main(String[] args) throws Exception {
+        new StressAllocationGCEvents().run(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/TestStressBigAllocationGCEventsWithParNew.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.detailed;
+
+/*
+ * @test
+ * @requires vm.gc == "null"
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UseConcMarkSweepGC -Xmx256m jdk.jfr.event.gc.detailed.TestStressBigAllocationGCEventsWithParNew 1048576
+ */
+public class TestStressBigAllocationGCEventsWithParNew {
+
+    public static void main(String[] args) throws Exception {
+        new StressAllocationGCEvents().run(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/TestStressBigAllocationGCEventsWithParallel.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.detailed;
+
+/*
+ * @test
+ * @requires vm.gc == "null" | vm.gc == "Parallel"
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UseParallelGC -Xmx256m jdk.jfr.event.gc.detailed.TestStressBigAllocationGCEventsWithParallel 1048576
+ */
+public class TestStressBigAllocationGCEventsWithParallel {
+
+    public static void main(String[] args) throws Exception {
+        new StressAllocationGCEvents().run(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/TestTenuringDistributionEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.detailed;
+
+import java.nio.file.Paths;
+import java.time.Duration;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @bug 8009538
+ * @requires vm.gc == "G1" | vm.gc == null
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:NewSize=2m -XX:MaxNewSize=2m -Xmx32m -XX:+UseG1GC -XX:+NeverTenure jdk.jfr.event.gc.detailed.TestTenuringDistributionEvent
+ */
+
+public class TestTenuringDistributionEvent {
+    private final static String EVENT_NAME = EventNames.TenuringDistribution;
+
+    public static void main(String[] args) throws Exception {
+        Recording recording = null;
+        try {
+            recording = new Recording();
+            // activate the event we are interested in and start recording
+            recording.enable(EVENT_NAME).withThreshold(Duration.ofMillis(0));
+            recording.start();
+
+            // Setting NewSize and MaxNewSize will limit eden, so
+            // allocating 1024 20k byte arrays should trigger at
+            // least a few Young GCs.
+            byte[][] array = new byte[1024][];
+            for (int i = 0; i < array.length; i++) {
+                array[i] = new byte[20 * 1024];
+            }
+            recording.stop();
+
+            // Verify recording
+            List<RecordedEvent> events = Events.fromRecording(recording);
+            Asserts.assertFalse(events.isEmpty(), "No events found");
+            for (RecordedEvent event : events) {
+                Events.assertField(event, "gcId").notEqual(-1);
+                Events.assertField(event, "age").notEqual(0);
+                Events.assertField(event, "size").atLeast(0L);
+            }
+
+        } catch (Throwable t) {
+            if (recording != null) {
+                recording.dump(Paths.get("TestTenuringDistribution.jfr"));
+            }
+            throw t;
+        } finally {
+            if (recording != null) {
+                recording.close();
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/concurrentmodefailure-testsettings.jfc	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+-->
+<configuration version="2.0" label="TestSettings" description="Configuration for testing promotion failed event" provider="Oracle">
+
+    <event name="jdk.ConcurrentModeFailure">
+      <setting name="enabled">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+</configuration>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/evacuationfailed-testsettings.jfc	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+-->
+<configuration version="2.0" label="TestSettings" description="Configuration for testing promotion failed event" provider="Oracle">
+
+    <event name="jdk.EvacuationFailed">
+      <setting name="enabled">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+</configuration>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/promotionfailed-testsettings.jfc	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+-->
+<configuration version="2.0" label="TestSettings" description="Configuration for testing promotion failed event" provider="Oracle">
+
+    <event name="jdk.PromotionFailed">
+      <setting name="enabled">true</setting>
+      <setting name="threshold">0 ms</setting>
+    </event>
+</configuration>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/heapsummary/HeapSummaryEventAllGcs.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.heapsummary;
+
+import java.time.Duration;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.GCHelper;
+
+public class HeapSummaryEventAllGcs {
+
+    public static void test(String expectedYoungCollector, String expectedOldCollector) throws Exception {
+        Recording recording = new Recording();
+        recording.enable(EventNames.GCConfiguration);
+        recording.enable(EventNames.GCHeapSummary);
+        recording.enable(EventNames.PSHeapSummary);
+        recording.enable(EventNames.MetaspaceSummary).withThreshold(Duration.ofMillis(0));
+
+        recording.start();
+        // To eliminate the risk of being in the middle of a GC when the recording starts/stops,
+        // we run 5 System.gc() and ignores the first and last GC.
+        GCHelper.callSystemGc(5, true);
+        recording.stop();
+
+        if (!checkCollectors(recording, expectedYoungCollector, expectedOldCollector)) {
+            return;
+        }
+        List<RecordedEvent> events = GCHelper.removeFirstAndLastGC(Events.fromRecording(recording));
+        for (RecordedEvent event : events) {
+            System.out.println("Event:" + event);
+        }
+
+        Asserts.assertFalse(events.isEmpty(), "Expected at least one event.");
+        Asserts.assertEquals(events.size() % 2, 0, "Events should come in pairs");
+
+        int lastHeapGcId = -1;
+        int lastPSGcId = -1;
+        int lastMetaspaceGcId = -1;
+
+        for (RecordedEvent event : events) {
+            final String eventName = event.getEventType().getName();
+            switch (eventName) {
+                case EventNames.GCHeapSummary:
+                    lastHeapGcId = checkGcId(event, lastHeapGcId);
+                    checkHeapEventContent(event);
+                    break;
+                case EventNames.PSHeapSummary:
+                    lastPSGcId = checkGcId(event, lastPSGcId);
+                    checkPSEventContent(event);
+                    break;
+                case EventNames.MetaspaceSummary:
+                    lastMetaspaceGcId = checkGcId(event, lastMetaspaceGcId);
+                    checkMetaspaceEventContent(event);
+                    break;
+                default:
+                    System.out.println("Failed event: " + event);
+                    Asserts.fail("Unknown event type: " + eventName);
+            }
+        }
+
+        // Sanity check. Not complete.
+        Asserts.assertEquals(lastHeapGcId, lastMetaspaceGcId, "Should have gotten perm gen events for all GCs");
+    }
+
+    private static void checkMetaspaceEventContent(RecordedEvent event) {
+        long totalUsed = Events.assertField(event, "metaspace.used").atLeast(0L).getValue();
+        long totalCommitted = Events.assertField(event, "metaspace.committed").atLeast(totalUsed).getValue();
+        long totalReserved = Events.assertField(event, "metaspace.reserved").atLeast(totalCommitted).getValue();
+
+        long dataUsed = Events.assertField(event, "dataSpace.used").atLeast(0L).getValue();
+        long dataCommitted = Events.assertField(event, "dataSpace.committed").atLeast(dataUsed).getValue();
+        long dataReserved = Events.assertField(event, "dataSpace.reserved").atLeast(dataCommitted).getValue();
+
+        long classUsed = Events.assertField(event, "classSpace.used").atLeast(0L).getValue();
+        long classCommitted = Events.assertField(event, "classSpace.committed").atLeast(classUsed).getValue();
+        long classReserved = Events.assertField(event, "classSpace.reserved").atLeast(classCommitted).getValue();
+
+        Asserts.assertEquals(dataCommitted + classCommitted, totalCommitted, "Wrong committed memory");
+        Asserts.assertEquals(dataUsed + classUsed, totalUsed, "Wrong used memory");
+        Asserts.assertEquals(dataReserved + classReserved, totalReserved, "Wrong reserved memory");
+    }
+
+    private static int checkGcId(RecordedEvent event, int currGcId) {
+        int gcId = Events.assertField(event, "gcId").getValue();
+        String when = Events.assertField(event, "when").notEmpty().getValue();
+        if ("Before GC".equals(when)) {
+            Asserts.assertGreaterThan(gcId, currGcId, "gcId should be increasing");
+        } else {
+            Asserts.assertEquals(gcId, currGcId, "After should have same gcId as last Before event");
+        }
+        return gcId;
+    }
+
+    private static void checkHeapEventContent(RecordedEvent event) {
+        checkVirtualSpace(event, "heapSpace");
+        long heapUsed = Events.assertField(event, "heapUsed").atLeast(0L).getValue();
+        long start = Events.assertField(event, "heapSpace.start").atLeast(0L).getValue();
+        long committedEnd = Events.assertField(event, "heapSpace.committedEnd").above(start).getValue();
+        Asserts.assertLessThanOrEqual(heapUsed, committedEnd- start, "used can not exceed size");
+    }
+
+    private static void checkPSEventContent(RecordedEvent event) {
+        checkVirtualSpace(event, "oldSpace");
+        checkVirtualSpace(event, "youngSpace");
+        checkSpace(event, "oldObjectSpace");
+        checkSpace(event, "edenSpace");
+        checkSpace(event, "fromSpace");
+        checkSpace(event, "toSpace");
+
+        checkPSYoungSizes(event);
+        checkPSYoungStartEnd(event);
+    }
+
+    private static void checkPSYoungSizes(RecordedEvent event) {
+        long youngSize = (long)Events.assertField(event, "youngSpace.committedEnd").getValue() -
+                        (long)Events.assertField(event, "youngSpace.start").getValue();
+        long edenSize = (long)Events.assertField(event, "edenSpace.end").getValue() -
+                        (long)Events.assertField(event, "edenSpace.start").getValue();
+        long fromSize = (long)Events.assertField(event, "fromSpace.end").getValue() -
+                        (long)Events.assertField(event, "fromSpace.start").getValue();
+        long toSize = (long)Events.assertField(event, "toSpace.end").getValue() -
+                        (long)Events.assertField(event, "toSpace.start").getValue();
+        Asserts.assertGreaterThanOrEqual(youngSize, edenSize + fromSize + toSize, "Young sizes don't match");
+    }
+
+    private static void checkPSYoungStartEnd(RecordedEvent event) {
+        long oldEnd = Events.assertField(event, "oldSpace.reservedEnd").getValue();
+        long youngStart = Events.assertField(event, "youngSpace.start").getValue();
+        long youngEnd = Events.assertField(event, "youngSpace.committedEnd").getValue();
+        long edenStart = Events.assertField(event, "edenSpace.start").getValue();
+        long edenEnd = Events.assertField(event, "edenSpace.end").getValue();
+        long fromStart = Events.assertField(event, "fromSpace.start").getValue();
+        long fromEnd = Events.assertField(event, "fromSpace.end").getValue();
+        long toStart = Events.assertField(event, "toSpace.start").getValue();
+        long toEnd = Events.assertField(event, "toSpace.end").getValue();
+        Asserts.assertEquals(oldEnd, youngStart, "Young should start where old ends");
+        Asserts.assertEquals(youngStart, edenStart, "Eden should be placed first in young");
+        if (fromStart < toStart) {
+            // [eden][from][to]
+            Asserts.assertGreaterThanOrEqual(fromStart, edenEnd, "From should start after eden");
+            Asserts.assertLessThanOrEqual(fromEnd, toStart, "To should start after From");
+            Asserts.assertLessThanOrEqual(toEnd, youngEnd, "To should start after From");
+        } else {
+            // [eden][to][from]
+            Asserts.assertGreaterThanOrEqual(toStart, edenEnd, "From should start after eden");
+            Asserts.assertLessThanOrEqual(toEnd, fromStart, "To should start after From");
+            Asserts.assertLessThanOrEqual(fromEnd, youngEnd, "To should start after From");
+        }
+    }
+
+    private static void checkVirtualSpace(RecordedEvent event, String structName) {
+        long start = Events.assertField(event, structName + ".start").atLeast(0L).getValue();
+        long committedEnd = Events.assertField(event, structName + ".committedEnd").above(start).getValue();
+        Events.assertField(event, structName + ".reservedEnd").atLeast(committedEnd);
+        long committedSize = Events.assertField(event, structName + ".committedSize").atLeast(0L).getValue();
+        Events.assertField(event, structName + ".reservedSize").atLeast(committedSize);
+    }
+
+    private static void checkSpace(RecordedEvent event, String structName) {
+        long start = Events.assertField(event, structName + ".start").atLeast(0L).getValue();
+        long end = Events.assertField(event, structName + ".end").above(start).getValue();
+        long used =  Events.assertField(event, structName + ".used").atLeast(0L).getValue();
+        long size = Events.assertField(event, structName + ".size").atLeast(used).getValue();
+        Asserts.assertEquals(size, end - start, "Size mismatch");
+    }
+
+    private static boolean checkCollectors(Recording recording, String expectedYoung, String expectedOld) throws Exception {
+        for (RecordedEvent event : Events.fromRecording(recording)) {
+            if (Events.isEventType(event, EventNames.GCConfiguration)) {
+                final String young = Events.assertField(event, "youngCollector").notEmpty().getValue();
+                final String old = Events.assertField(event, "oldCollector").notEmpty().getValue();
+                if (young.equals(expectedYoung) && old.equals(expectedOld)) {
+                    return true;
+                }
+                // TODO: We treat wrong collector types as an error. Old test only warned. Not sure what is correct.
+                Asserts.fail(String.format("Wrong collector types: got('%s','%s'), expected('%s','%s')",
+                young, old, expectedYoung, expectedOld));
+            }
+        }
+        Asserts.fail("Missing event type " + EventNames.GCConfiguration);
+        return false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/heapsummary/TestHeapSummaryCommittedSize.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.heapsummary;
+
+import java.time.Duration;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.EventVerifier;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.GCHelper;
+import sun.hotspot.WhiteBox;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "Parallel" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @build sun.hotspot.WhiteBox
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions
+                     -XX:-UseFastUnorderedTimeStamps -Xmx16m -XX:+UseParallelGC
+                     -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+                     jdk.jfr.event.gc.heapsummary.TestHeapSummaryCommittedSize
+ */
+public class TestHeapSummaryCommittedSize {
+    private final static String EVENT_NAME = EventNames.GCHeapSummary;
+
+    public static void main(String[] args) throws Exception {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME).withThreshold(Duration.ofMillis(0));
+
+        recording.start();
+        System.gc();
+        recording.stop();
+
+        boolean isAnyFound = false;
+        for (RecordedEvent event : Events.fromRecording(recording)) {
+            System.out.println("Event: " + event);
+            if (!Events.isEventType(event, EVENT_NAME)) {
+                continue;
+            }
+            isAnyFound = true;
+            CommittedHeapSizeVerifier verifier = new CommittedHeapSizeVerifier(event);
+            verifier.verify();
+        }
+        Asserts.assertTrue(isAnyFound, "No matching event");
+    }
+}
+
+class CommittedHeapSizeVerifier extends EventVerifier {
+    private final static long  MAX_UNALIGNED_COMMITTED_SIZE  = 16 * 1024 * 1024;
+    private final long  MAX_ALIGNED_COMMITTED_SIZE;
+
+    public CommittedHeapSizeVerifier(RecordedEvent event) {
+        super(event);
+        WhiteBox wb = WhiteBox.getWhiteBox();
+        long heapAlignment = wb.getHeapAlignment();
+        MAX_ALIGNED_COMMITTED_SIZE = GCHelper.alignUp(
+                MAX_UNALIGNED_COMMITTED_SIZE,heapAlignment);
+    }
+
+    public void verify() throws Exception {
+        Events.assertField(event, "heapSpace.committedSize").atLeast(0L).atMost(MAX_ALIGNED_COMMITTED_SIZE);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/heapsummary/TestHeapSummaryEventConcurrentCMS.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.heapsummary;
+
+import java.time.Duration;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @requires (vm.gc == "ConcMarkSweep" | vm.gc == null)
+ *           & vm.opt.ExplicitGCInvokesConcurrent != false
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:+UseConcMarkSweepGC -XX:+ExplicitGCInvokesConcurrent jdk.jfr.event.gc.heapsummary.TestHeapSummaryEventConcurrentCMS
+ */
+public class TestHeapSummaryEventConcurrentCMS {
+
+    public static void main(String[] args) throws Exception {
+        Recording recording = new Recording();
+        recording.enable(EventNames.GarbageCollection).withThreshold(Duration.ofMillis(0));
+        recording.enable(EventNames.GCHeapSummary).withThreshold(Duration.ofMillis(0));
+
+        recording.start();
+        // Need several GCs to ensure at least one heap summary event from concurrent CMS
+        GCHelper.callSystemGc(6, true);
+        recording.stop();
+
+        // Remove first and last GCs which can be incomplete
+        List<RecordedEvent> events = GCHelper.removeFirstAndLastGC(Events.fromRecording(recording));
+        Asserts.assertFalse(events.isEmpty(), "No events found");
+        for (RecordedEvent event : events) {
+            System.out.println("Event: " + event);
+            if (!isCmsGcEvent(event)) {
+                continue;
+            }
+            int gcId = Events.assertField(event, "gcId").getValue();
+            verifyHeapSummary(events, gcId, "Before GC");
+            verifyHeapSummary(events, gcId, "After GC");
+        }
+    }
+
+    private static boolean isCmsGcEvent(RecordedEvent event) {
+        if (!Events.isEventType(event, EventNames.GarbageCollection)) {
+            return false;
+        }
+        final String gcName = Events.assertField(event, "name").notEmpty().getValue();
+        return "ConcurrentMarkSweep".equals(gcName);
+    }
+
+    private static void verifyHeapSummary(List<RecordedEvent> events, int gcId, String when) {
+        for (RecordedEvent event : events) {
+            if (!Events.isEventType(event, EventNames.GCHeapSummary)) {
+                continue;
+            }
+            if (gcId == (int)Events.assertField(event, "gcId").getValue() &&
+                    when.equals(Events.assertField(event, "when").getValue())) {
+                System.out.printf("Found " + EventNames.GCHeapSummary + " for id=%d, when=%s%n", gcId, when);
+                return;
+            }
+        }
+        Asserts.fail(String.format("No " + EventNames.GCHeapSummary + " for id=%d, when=%s", gcId, when));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/heapsummary/TestHeapSummaryEventDefNewSerial.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.heapsummary;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "Serial" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UseSerialGC jdk.jfr.event.gc.heapsummary.TestHeapSummaryEventDefNewSerial
+ */
+public class TestHeapSummaryEventDefNewSerial {
+    public static void main(String[] args) throws Exception {
+        HeapSummaryEventAllGcs.test(GCHelper.gcDefNew, GCHelper.gcSerialOld);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/heapsummary/TestHeapSummaryEventG1.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.heapsummary;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @requires (vm.gc == "G1" | vm.gc == null)
+ *           & vm.opt.ExplicitGCInvokesConcurrent != true
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:+UseG1GC jdk.jfr.event.gc.heapsummary.TestHeapSummaryEventG1
+ */
+public class TestHeapSummaryEventG1 {
+    public static void main(String[] args) throws Exception {
+        HeapSummaryEventAllGcs.test(GCHelper.gcG1New, GCHelper.gcG1Old);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/heapsummary/TestHeapSummaryEventPSParOld.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.heapsummary;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "Parallel" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:+UseParallelGC jdk.jfr.event.gc.heapsummary.TestHeapSummaryEventPSParOld
+ */
+public class TestHeapSummaryEventPSParOld {
+    public static void main(String[] args) throws Exception {
+        HeapSummaryEventAllGcs.test(GCHelper.gcParallelScavenge, GCHelper.gcParallelOld);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/heapsummary/TestHeapSummaryEventPSSerial.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.heapsummary;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "Parallel" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:-UseParallelOldGC -XX:+UseParallelGC jdk.jfr.event.gc.heapsummary.TestHeapSummaryEventPSSerial
+ */
+public class TestHeapSummaryEventPSSerial {
+    public static void main(String[] args) throws Exception {
+        HeapSummaryEventAllGcs.test(GCHelper.gcParallelScavenge, GCHelper.gcSerialOld);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/heapsummary/TestHeapSummaryEventParNewCMS.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.heapsummary;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @requires (vm.gc == "ConcMarkSweep" | vm.gc == null)
+ *           & vm.opt.ExplicitGCInvokesConcurrent != true
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:+UseConcMarkSweepGC jdk.jfr.event.gc.heapsummary.TestHeapSummaryEventParNewCMS
+ */
+public class TestHeapSummaryEventParNewCMS {
+    public static void main(String[] args) throws Exception {
+        HeapSummaryEventAllGcs.test(GCHelper.gcParNew, GCHelper.gcConcurrentMarkSweep);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountAfterGCEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.objectcount;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+
+public class ObjectCountAfterGCEvent {
+
+    private static final String objectCountEventPath = EventNames.ObjectCountAfterGC;
+    private static final String gcEventPath = EventNames.GarbageCollection;
+    private static final String heapSummaryEventPath = EventNames.GCHeapSummary;
+
+    public static void test(String gcName) throws Exception {
+        Recording recording = new Recording();
+        recording.enable(objectCountEventPath);
+        recording.enable(gcEventPath);
+        recording.enable(heapSummaryEventPath);
+
+        ObjectCountEventVerifier.createTestData();
+        recording.start();
+        System.gc();
+        System.gc();
+        recording.stop();
+
+        System.out.println("gcName=" + gcName);
+        for (RecordedEvent event : Events.fromRecording(recording)) {
+            System.out.println("Event: " + event);
+        }
+
+        List<RecordedEvent> events= Events.fromRecording(recording);
+        Optional<RecordedEvent> gcEvent = events.stream()
+                                .filter(e -> isMySystemGc(e, gcName))
+                                .findFirst();
+        Asserts.assertTrue(gcEvent.isPresent(), "No event System.gc event of type " + gcEventPath);
+        System.out.println("Found System.gc event: " + gcEvent.get());
+        int gcId = Events.assertField(gcEvent.get(), "gcId").getValue();
+
+        List<RecordedEvent> objCountEvents = events.stream()
+                                .filter(e -> Events.isEventType(e, objectCountEventPath))
+                                .filter(e -> isGcId(e, gcId))
+                                .collect(Collectors.toList());
+        Asserts.assertFalse(objCountEvents.isEmpty(), "No objCountEvents for gcId=" + gcId);
+
+        Optional<RecordedEvent> heapSummaryEvent = events.stream()
+                                .filter(e -> Events.isEventType(e, heapSummaryEventPath))
+                                .filter(e -> isGcId(e, gcId))
+                                .filter(e -> "After GC".equals(Events.assertField(e, "when").getValue()))
+                                .findFirst();
+        Asserts.assertTrue(heapSummaryEvent.isPresent(), "No heapSummary for gcId=" + gcId);
+        System.out.println("Found heapSummaryEvent: " + heapSummaryEvent.get());
+
+        Events.assertField(heapSummaryEvent.get(), "heapUsed").atLeast(0L).getValue();
+        ObjectCountEventVerifier.verify(objCountEvents);
+    }
+
+    private static boolean isGcId(RecordedEvent event, int gcId) {
+        return gcId == (int)Events.assertField(event, "gcId").getValue();
+    }
+
+    private static boolean isMySystemGc(RecordedEvent event, String gcName) {
+        return Events.isEventType(event, gcEventPath) &&
+            gcName.equals(Events.assertField(event, "name").getValue()) &&
+            "System.gc()".equals(Events.assertField(event, "cause").getValue());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEventVerifier.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.objectcount;
+
+import java.util.List;
+import java.util.HashMap;
+
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+class Foo {
+}
+
+class Constants {
+    public static final int oneMB = 1048576;
+}
+
+public class ObjectCountEventVerifier {
+    public static Foo[] foos;
+
+    public static void createTestData() {
+        foos = new Foo[Constants.oneMB];
+    }
+
+    public static void verify(List<RecordedEvent> objectCountEvents) throws Exception {
+        Asserts.assertFalse(objectCountEvents.isEmpty(), "Expected at least one object count event");
+        // Object count events should be sent only for those classes which instances occupy over 0.5%
+        // of the heap. Therefore there can't be more than 200 events
+        Asserts.assertLessThanOrEqual(objectCountEvents.size(), 200, "Expected at most 200 object count events");
+
+        HashMap<String, Long> numInstancesOfClass = new HashMap<String, Long>();
+        HashMap<String, Long> sizeOfInstances = new HashMap<String, Long>();
+
+        for (RecordedEvent event : objectCountEvents) {
+            String className = Events.assertField(event, "objectClass.name").notEmpty().getValue();
+            long count = Events.assertField(event, "count").atLeast(0L).getValue();
+            long totalSize = Events.assertField(event, "totalSize").atLeast(1L).getValue();
+            System.out.println(className);
+            numInstancesOfClass.put(className, count);
+            sizeOfInstances.put(className, totalSize);
+        }
+        System.out.println(numInstancesOfClass);
+        final String fooArrayName = "[Ljdk/jfr/event/gc/objectcount/Foo;";
+        Asserts.assertTrue(numInstancesOfClass.containsKey(fooArrayName), "Expected an event for the Foo array");
+        Asserts.assertEquals(sizeOfInstances.get(fooArrayName), expectedFooArraySize(Constants.oneMB), "Wrong size of the Foo array");
+    }
+
+    private static long expectedFooArraySize(long count) {
+        boolean runsOn32Bit = System.getProperty("sun.arch.data.model").equals("32");
+        int bytesPerWord = runsOn32Bit ? 4 : 8;
+        int objectHeaderSize = bytesPerWord * 3; // length will be aligned on 64 bits
+        int alignmentInOopArray = runsOn32Bit ? 4 : 0;
+        int ptrSize = bytesPerWord;
+        return objectHeaderSize + alignmentInOopArray + count * ptrSize;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithCMSConcurrent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.objectcount;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @requires (vm.gc == "ConcMarkSweep" | vm.gc == null)
+ *           & vm.opt.ExplicitGCInvokesConcurrent != false
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:+UseConcMarkSweepGC -XX:+ExplicitGCInvokesConcurrent -XX:MarkSweepDeadRatio=0 -XX:-UseCompressedOops -XX:+IgnoreUnrecognizedVMOptions jdk.jfr.event.gc.objectcount.TestObjectCountAfterGCEventWithCMSConcurrent
+ */
+public class TestObjectCountAfterGCEventWithCMSConcurrent {
+    public static void main(String[] args) throws Exception {
+        ObjectCountAfterGCEvent.test(GCHelper.gcConcurrentMarkSweep);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithCMSMarkSweep.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.objectcount;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @requires (vm.gc == "ConcMarkSweep" | vm.gc == null)
+ *           & vm.opt.ExplicitGCInvokesConcurrent != true
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:+UseConcMarkSweepGC -XX:MarkSweepDeadRatio=0 -XX:-UseCompressedOops -XX:+IgnoreUnrecognizedVMOptions jdk.jfr.event.gc.objectcount.TestObjectCountAfterGCEventWithCMSMarkSweep
+ */
+public class TestObjectCountAfterGCEventWithCMSMarkSweep {
+    public static void main(String[] args) throws Exception {
+        ObjectCountAfterGCEvent.test(GCHelper.gcSerialOld);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithG1ConcurrentMark.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.objectcount;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @requires (vm.gc == "G1" | vm.gc == null)
+ *           & vm.opt.ExplicitGCInvokesConcurrent != false
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC -XX:+ExplicitGCInvokesConcurrent -XX:MarkSweepDeadRatio=0 -XX:-UseCompressedOops -XX:+IgnoreUnrecognizedVMOptions jdk.jfr.event.gc.objectcount.TestObjectCountAfterGCEventWithG1ConcurrentMark
+ */
+public class TestObjectCountAfterGCEventWithG1ConcurrentMark {
+    public static void main(String[] args) throws Exception {
+        ObjectCountAfterGCEvent.test(GCHelper.gcG1Old);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithG1FullCollection.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.objectcount;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @requires (vm.gc == "G1" | vm.gc == null)
+ *           & vm.opt.ExplicitGCInvokesConcurrent != true
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:+UseG1GC -XX:MarkSweepDeadRatio=0 -XX:-UseCompressedOops -XX:+IgnoreUnrecognizedVMOptions jdk.jfr.event.gc.objectcount.TestObjectCountAfterGCEventWithG1FullCollection
+ */
+public class TestObjectCountAfterGCEventWithG1FullCollection {
+    public static void main(String[] args) throws Exception {
+        ObjectCountAfterGCEvent.test(GCHelper.gcG1Full);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithPSMarkSweep.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.objectcount;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "Parallel" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UseParallelGC -XX:-UseParallelOldGC -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:MarkSweepDeadRatio=0 -XX:-UseCompressedOops -XX:+IgnoreUnrecognizedVMOptions jdk.jfr.event.gc.objectcount.TestObjectCountAfterGCEventWithPSMarkSweep
+ */
+public class TestObjectCountAfterGCEventWithPSMarkSweep {
+    public static void main(String[] args) throws Exception {
+        ObjectCountAfterGCEvent.test(GCHelper.gcSerialOld);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithParallelOld.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.objectcount;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "Parallel" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:+UseParallelGC -XX:+UseParallelOldGC -XX:MarkSweepDeadRatio=0 -XX:-UseCompressedOops -XX:+IgnoreUnrecognizedVMOptions jdk.jfr.event.gc.objectcount.TestObjectCountAfterGCEventWithParallelOld
+ */
+public class TestObjectCountAfterGCEventWithParallelOld {
+    public static void main(String[] args) throws Exception {
+        ObjectCountAfterGCEvent.test(GCHelper.gcParallelOld);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithSerial.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.objectcount;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "Serial" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:+UseSerialGC -XX:MarkSweepDeadRatio=0 -XX:-UseCompressedOops -XX:+IgnoreUnrecognizedVMOptions jdk.jfr.event.gc.objectcount.TestObjectCountAfterGCEventWithSerial
+ */
+public class TestObjectCountAfterGCEventWithSerial {
+    public static void main(String[] args) throws Exception {
+        ObjectCountAfterGCEvent.test(GCHelper.gcSerialOld);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.objectcount;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "Serial" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:+UseSerialGC -XX:-UseCompressedOops -XX:MarkSweepDeadRatio=0 -XX:+IgnoreUnrecognizedVMOptions jdk.jfr.event.gc.objectcount.TestObjectCountEvent
+ */
+public class TestObjectCountEvent {
+    private static final String objectCountEventPath = EventNames.ObjectCount;
+    private static final String heapSummaryEventPath = EventNames.GCHeapSummary;
+
+    public static void main(String[] args) throws Exception {
+        Recording recording = new Recording();
+        recording.enable(objectCountEventPath);
+        recording.enable(heapSummaryEventPath);
+
+        ObjectCountEventVerifier.createTestData();
+        System.gc();
+        recording.start();
+        recording.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        for (RecordedEvent event : events) {
+            System.out.println("Event: " + event);
+        }
+
+        Optional<RecordedEvent> heapSummaryEvent = events.stream()
+                                .filter(e -> Events.isEventType(e, heapSummaryEventPath))
+                                .filter(e -> "After GC".equals(Events.assertField(e, "when").getValue()))
+                                .findFirst();
+        Asserts.assertTrue(heapSummaryEvent.isPresent(), "No heapSummary with cause='After GC'");
+        System.out.println("Found heapSummaryEvent: " + heapSummaryEvent.get());
+        Events.assertField(heapSummaryEvent.get(), "heapUsed").atLeast(0L).getValue();
+        int gcId = Events.assertField(heapSummaryEvent.get(), "gcId").getValue();
+
+        List<RecordedEvent> objCountEvents = events.stream()
+                                .filter(e -> Events.isEventType(e, objectCountEventPath))
+                                .filter(e -> isGcId(e, gcId))
+                                .collect(Collectors.toList());
+        Asserts.assertFalse(objCountEvents.isEmpty(), "No objCountEvents for gcId=" + gcId);
+        ObjectCountEventVerifier.verify(objCountEvents);
+    }
+
+    private static boolean isGcId(RecordedEvent event, int gcId) {
+        return gcId == (int)Events.assertField(event, "gcId").getValue();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/refstat/RefStatEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.refstat;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.GCHelper;
+
+
+public class RefStatEvent {
+
+    private static final String gcEventPath = EventNames.GarbageCollection;
+    private static final String refStatsEventPath = EventNames.GCReferenceStatistics;
+    public static byte[] garbage;
+
+    public static void test(String gcName) throws Exception {
+        Recording recording = new Recording();
+        recording.enable(refStatsEventPath).withThreshold(Duration.ofMillis(0));
+        recording.enable(gcEventPath).withThreshold(Duration.ofMillis(0));
+
+        recording.start();
+        GCHelper.callSystemGc(6, true);
+        recording.stop();
+
+        System.out.println("gcName=" + gcName);
+        List<RecordedEvent> events = GCHelper.removeFirstAndLastGC(Events.fromRecording(recording));
+        Events.hasEvents(events);
+        for (RecordedEvent event : events) {
+            System.out.println("Event: " + event);
+        }
+
+        for (RecordedEvent event : events) {
+            if (!Events.isEventType(event, gcEventPath)) {
+                continue;
+            }
+            System.out.println("Event: " + event);
+            final int gcId = Events.assertField(event, "gcId").getValue();
+            final String name = Events.assertField(event, "name").notEmpty().getValue();
+            if (gcName.equals(name)) {
+                verifyRefStatEvents(events, gcId);
+            }
+        }
+    }
+
+    // Check that we have a refStat event for each type for this GC.
+    private static void verifyRefStatEvents(List<RecordedEvent> events, int gcId) {
+        List<String> expectedTypes = Arrays.asList("Soft reference", "Weak reference", "Final reference", "Phantom reference");
+        List<String> actualTypes = new ArrayList<>();
+        try {
+            for (RecordedEvent event : events) {
+                if (!Events.isEventType(event, refStatsEventPath)) {
+                    continue;
+                }
+                Events.assertField(event, "count").atLeast(0L);
+                if (Events.assertField(event, "gcId").isEqual(gcId)) {
+                    actualTypes.add(Events.assertField(event, "type").notEmpty().getValue());
+                }
+            }
+
+            Asserts.assertEquals(actualTypes.size(), expectedTypes.size(), "Wrong number of refStat events");
+            Asserts.assertTrue(expectedTypes.containsAll(actualTypes), "Found unknown refStat types");
+            Asserts.assertTrue(actualTypes.containsAll(expectedTypes), "Missning refStat types");
+        } catch (Exception e) {
+            System.out.println("Expected refStatTypes: " + expectedTypes.stream().collect(Collectors.joining(", ")));
+            System.out.println("Got refStatTypes: " + actualTypes.stream().collect(Collectors.joining(", ")));
+            throw e;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/refstat/TestRefStatEventWithCMSConcurrent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.refstat;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @requires (vm.gc == "ConcMarkSweep" | vm.gc == null)
+ *           & vm.opt.ExplicitGCInvokesConcurrent != false
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -Xlog:gc+heap=trace,gc*=debug -XX:+UseConcMarkSweepGC -XX:+ExplicitGCInvokesConcurrent jdk.jfr.event.gc.refstat.TestRefStatEventWithCMSConcurrent
+ */
+public class TestRefStatEventWithCMSConcurrent {
+    public static void main(String[] args) throws Exception {
+        RefStatEvent.test(GCHelper.gcConcurrentMarkSweep);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/refstat/TestRefStatEventWithCMSMarkSweep.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.refstat;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @requires (vm.gc == "ConcMarkSweep" | vm.gc == null)
+ *           & vm.opt.ExplicitGCInvokesConcurrent != true
+ * @library /test/lib /test/jdk
+ * @run main/othervm  -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -Xlog:gc+heap=trace,gc*=debug -XX:+UseConcMarkSweepGC jdk.jfr.event.gc.refstat.TestRefStatEventWithCMSMarkSweep
+ */
+public class TestRefStatEventWithCMSMarkSweep {
+    public static void main(String[] args) throws Exception {
+        RefStatEvent.test(GCHelper.gcSerialOld);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/refstat/TestRefStatEventWithDefNew.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.refstat;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "Serial" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main/othervm  -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -Xlog:gc+heap=trace,gc*=debug -Xmx50m -Xmn2m -XX:+UseSerialGC jdk.jfr.event.gc.refstat.TestRefStatEventWithDefNew
+ */
+public class TestRefStatEventWithDefNew {
+    public static void main(String[] args) throws Exception {
+        RefStatEvent.test(GCHelper.gcDefNew);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/refstat/TestRefStatEventWithG1ConcurrentMark.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.refstat;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @requires (vm.gc == "G1" | vm.gc == null)
+ *           & vm.opt.ExplicitGCInvokesConcurrent != false
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -Xlog:gc+heap=trace,gc*=debug -XX:+UseG1GC -XX:+ExplicitGCInvokesConcurrent jdk.jfr.event.gc.refstat.TestRefStatEventWithG1ConcurrentMark
+ */
+public class TestRefStatEventWithG1ConcurrentMark {
+    public static void main(String[] args) throws Exception {
+        RefStatEvent.test(GCHelper.gcG1Old);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/refstat/TestRefStatEventWithG1FullCollection.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.refstat;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @requires (vm.gc == "G1" | vm.gc == null)
+ *           & vm.opt.ExplicitGCInvokesConcurrent != true
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -Xlog:gc+heap=trace,gc*=debug -XX:+UseG1GC jdk.jfr.event.gc.refstat.TestRefStatEventWithG1FullCollection
+ */
+public class TestRefStatEventWithG1FullCollection {
+    public static void main(String[] args) throws Exception {
+        RefStatEvent.test(GCHelper.gcG1Full);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/refstat/TestRefStatEventWithG1New.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.refstat;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "G1" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -Xlog:gc+heap=trace,gc*=debug -Xmx50m -Xmn2m -XX:+UseG1GC jdk.jfr.event.gc.refstat.TestRefStatEventWithG1New
+ */
+public class TestRefStatEventWithG1New {
+    public static void main(String[] args) throws Exception {
+        RefStatEvent.test(GCHelper.gcG1New);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/refstat/TestRefStatEventWithPSMarkSweep.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.refstat;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "Parallel" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -Xlog:gc+heap=trace,gc*=debug -XX:+UseParallelGC -XX:-UseParallelOldGC jdk.jfr.event.gc.refstat.TestRefStatEventWithPSMarkSweep
+ */
+public class TestRefStatEventWithPSMarkSweep {
+    public static void main(String[] args) throws Exception {
+        RefStatEvent.test(GCHelper.gcSerialOld);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/refstat/TestRefStatEventWithParallelOld.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.refstat;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "Parallel" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -Xlog:gc+heap=trace,gc*=debug -XX:+UseParallelGC -XX:+UseParallelOldGC jdk.jfr.event.gc.refstat.TestRefStatEventWithParallelOld
+ */
+public class TestRefStatEventWithParallelOld {
+    public static void main(String[] args) throws Exception {
+        RefStatEvent.test(GCHelper.gcParallelOld);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/refstat/TestRefStatEventWithParallelScavenge.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.gc.refstat;
+import jdk.test.lib.jfr.GCHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "Parallel" | vm.gc == null
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -Xlog:gc+heap=trace,gc*=debug -Xmx50m -Xmn2m -XX:-UseLargePages -XX:+UseParallelGC -XX:-UseAdaptiveSizePolicy jdk.jfr.event.gc.refstat.TestRefStatEventWithParallelScavenge
+ */
+public class TestRefStatEventWithParallelScavenge {
+    public static void main(String[] args) throws Exception {
+        RefStatEvent.test(GCHelper.gcParallelScavenge);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/stacktrace/AllocationStackTrace.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,497 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.stacktrace;
+
+import javax.management.MBeanServer;
+import java.lang.management.ManagementFactory;
+import com.sun.management.GarbageCollectorMXBean;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedStackTrace;
+import jdk.jfr.consumer.RecordedFrame;
+import jdk.jfr.consumer.RecordedMethod;
+import jdk.jfr.consumer.RecordedThread;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+import java.util.List;
+import java.util.ArrayList;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+abstract class MemoryAllocator {
+
+    public static final int KB = 1024;
+    public static final int MB = 1024 * KB;
+
+    public static Object garbage = null;
+
+    abstract public void allocate();
+    public void clear() {
+        garbage = null;
+    }
+}
+
+class EdenMemoryAllocator extends MemoryAllocator {
+
+    @Override
+    public void allocate() {
+        garbage = new byte[10 * KB];
+    }
+}
+
+class HumongousMemoryAllocator extends MemoryAllocator {
+
+    @Override
+    public void allocate() {
+        garbage = new byte[5 * MB];
+    }
+}
+
+/**
+ * Attempts to fill up young gen and allocate in old gen
+ */
+class OldGenMemoryAllocator extends MemoryAllocator {
+
+    private List<byte[]> list = new ArrayList<byte[]>();
+    private int counter = 6000;
+
+    @Override
+    public void allocate() {
+        if (counter-- > 0) {
+            list.add(new byte[10 * KB]);
+        } else {
+            list = new ArrayList<byte[]>();
+            counter = 6000;
+        }
+
+        garbage = list;
+    }
+
+    @Override
+    public void clear(){
+        list = null;
+        super.clear();
+    }
+}
+
+class MetaspaceMemoryAllocator extends MemoryAllocator {
+
+    private static int counter = 0;
+
+    /**
+     * Imitates class loading. Each invocation of this method causes a new class
+     * loader object is created and a new class is loaded by this class loader.
+     * Method throws OOM when run out of memory.
+     */
+    static protected void loadNewClass() {
+        try {
+            String jarUrl = "file:" + (counter++) + ".jar";
+            URL[] urls = new URL[]{new URL(jarUrl)};
+            URLClassLoader cl = new URLClassLoader(urls);
+            Proxy.newProxyInstance(
+                    cl,
+                    new Class[]{Foo.class},
+                    new FooInvocationHandler(new FooBar()));
+        } catch (java.net.MalformedURLException badThing) {
+            // should never occur
+            System.err.println("Unexpected error: " + badThing);
+            throw new RuntimeException(badThing);
+        }
+    }
+
+    @Override
+    public void allocate() {
+        try {
+            loadNewClass();
+        } catch (OutOfMemoryError e) {
+            /* empty */
+        }
+    }
+
+    public static interface Foo {
+    }
+
+    public static class FooBar implements Foo {
+    }
+
+    static class FooInvocationHandler implements InvocationHandler {
+
+        private final Foo foo;
+
+        FooInvocationHandler(Foo foo) {
+            this.foo = foo;
+        }
+
+        @Override
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+            return method.invoke(foo, args);
+        }
+    }
+}
+
+/**
+ * Utility class to peform JFR recording, GC provocation/detection and
+ * stacktrace verification for related JFR events
+ */
+public class AllocationStackTrace {
+
+    /**
+     * Tests event stacktrace for young GC if -XX:+UseSerialGC is used
+     */
+    public static void testDefNewAllocEvent() throws Exception {
+        GarbageCollectorMXBean bean = garbageCollectorMXBean("Copy");
+        MemoryAllocator memory = new EdenMemoryAllocator();
+
+        String[] expectedStack = new String[]{
+            "jdk.jfr.event.gc.stacktrace.AllocationStackTrace.testAllocEvent",
+            "jdk.jfr.event.gc.stacktrace.AllocationStackTrace.testDefNewAllocEvent"
+        };
+
+        testAllocEvent(bean, memory, expectedStack);
+    }
+
+    /**
+     * Tests event stacktrace for old GC if -XX:+UseSerialGC is used
+     */
+    public static void testMarkSweepCompactAllocEvent() throws Exception {
+        GarbageCollectorMXBean bean = garbageCollectorMXBean("MarkSweepCompact");
+        MemoryAllocator memory = new OldGenMemoryAllocator();
+
+        String[] expectedStack = new String[]{
+            "jdk.jfr.event.gc.stacktrace.AllocationStackTrace.testAllocEvent",
+            "jdk.jfr.event.gc.stacktrace.AllocationStackTrace.testMarkSweepCompactAllocEvent"
+        };
+
+        testAllocEvent(bean, memory, expectedStack);
+    }
+
+    /**
+     * Tests event stacktrace during metaspace GC threshold if -XX:+UseSerialGC
+     * is used
+     */
+    public static void testMetaspaceSerialGCAllocEvent() throws Exception {
+        GarbageCollectorMXBean bean = garbageCollectorMXBean("MarkSweepCompact");
+        MemoryAllocator memory = new MetaspaceMemoryAllocator();
+
+        String[] expectedStack = new String[]{
+            "jdk.jfr.event.gc.stacktrace.AllocationStackTrace.testAllocEvent",
+            "jdk.jfr.event.gc.stacktrace.AllocationStackTrace.testMetaspaceSerialGCAllocEvent"
+        };
+
+        testAllocEvent(bean, memory, expectedStack);
+    }
+
+    /**
+     * Tests event stacktrace for young GC if -XX:+UseConcMarkSweepGC is used
+     */
+    public static void testParNewAllocEvent() throws Exception {
+        GarbageCollectorMXBean bean = garbageCollectorMXBean("ParNew");
+        MemoryAllocator memory = new EdenMemoryAllocator();
+
+        String[] expectedStack = new String[]{
+            "jdk.jfr.event.gc.stacktrace.AllocationStackTrace.testAllocEvent",
+            "jdk.jfr.event.gc.stacktrace.AllocationStackTrace.testParNewAllocEvent"
+        };
+
+        testAllocEvent(bean, memory, expectedStack);
+    }
+
+    /**
+     * Tests event stacktrace for old GC if -XX:+UseConcMarkSweepGC is used
+     */
+    public static void testConcMarkSweepAllocEvent() throws Exception {
+        GarbageCollectorMXBean bean = garbageCollectorMXBean("ConcurrentMarkSweep");
+        MemoryAllocator memory = new OldGenMemoryAllocator();
+
+        String[] expectedStack = new String[]{
+            "jdk.jfr.event.gc.stacktrace.AllocationStackTrace.testAllocEvent",
+            "jdk.jfr.event.gc.stacktrace.AllocationStackTrace.testConcMarkSweepAllocEvent"
+        };
+
+        testAllocEvent(bean, memory, expectedStack);
+    }
+
+    /**
+     * Tests event stacktrace during metaspace GC threshold if
+     * -XX:+UseConcMarkSweepGC is used
+     */
+    public static void testMetaspaceConcMarkSweepGCAllocEvent() throws Exception {
+        GarbageCollectorMXBean bean = garbageCollectorMXBean("ConcurrentMarkSweep");
+        MemoryAllocator memory = new MetaspaceMemoryAllocator();
+
+        String[] expectedStack = new String[]{
+            "jdk.jfr.event.gc.stacktrace.AllocationStackTrace.testAllocEvent",
+            "jdk.jfr.event.gc.stacktrace.AllocationStackTrace.testMetaspaceConcMarkSweepGCAllocEvent"
+        };
+
+        testAllocEvent(bean, memory, expectedStack);
+    }
+
+    /**
+     * Tests event stacktrace for young GC if -XX:+UseParallelGC is used
+     */
+    public static void testParallelScavengeAllocEvent() throws Exception {
+        GarbageCollectorMXBean bean = garbageCollectorMXBean("PS Scavenge");
+        MemoryAllocator memory = new EdenMemoryAllocator();
+
+        String[] expectedStack = new String[]{
+            "jdk.jfr.event.gc.stacktrace.AllocationStackTrace.testAllocEvent",
+            "jdk.jfr.event.gc.stacktrace.AllocationStackTrace.testParallelScavengeAllocEvent"
+        };
+
+        testAllocEvent(bean, memory, expectedStack);
+    }
+
+    /**
+     * Tests event stacktrace for old GC if -XX:+UseParallelGC is used
+     */
+    public static void testParallelMarkSweepAllocEvent() throws Exception {
+        GarbageCollectorMXBean bean = garbageCollectorMXBean("PS MarkSweep");
+        MemoryAllocator memory = new OldGenMemoryAllocator();
+
+        String[] expectedStack = new String[]{
+            "jdk.jfr.event.gc.stacktrace.AllocationStackTrace.testAllocEvent",
+            "jdk.jfr.event.gc.stacktrace.AllocationStackTrace.testParallelMarkSweepAllocEvent"
+        };
+
+        testAllocEvent(bean, memory, expectedStack);
+    }
+
+    /**
+     * Tests event stacktrace during metaspace GC threshold if
+     * -XX:+UseParallelGC is used
+     */
+    public static void testMetaspaceParallelGCAllocEvent() throws Exception {
+        GarbageCollectorMXBean bean = garbageCollectorMXBean("PS MarkSweep");
+        MemoryAllocator memory = new MetaspaceMemoryAllocator();
+
+        String[] expectedStack = new String[]{
+            "jdk.jfr.event.gc.stacktrace.AllocationStackTrace.testAllocEvent",
+            "jdk.jfr.event.gc.stacktrace.AllocationStackTrace.testMetaspaceParallelGCAllocEvent"
+        };
+
+        testAllocEvent(bean, memory, expectedStack);
+    }
+
+    /**
+     * Tests event stacktrace for young GC if -XX:+UseG1GC is used
+     */
+    public static void testG1YoungAllocEvent() throws Exception {
+        GarbageCollectorMXBean bean = garbageCollectorMXBean("G1 Young Generation");
+        MemoryAllocator memory = new EdenMemoryAllocator();
+
+        String[] expectedStack = new String[]{
+            "jdk.jfr.event.gc.stacktrace.AllocationStackTrace.testAllocEvent",
+            "jdk.jfr.event.gc.stacktrace.AllocationStackTrace.testG1YoungAllocEvent"
+        };
+
+        testAllocEvent(bean, memory, expectedStack);
+    }
+
+    /**
+     * Tests event stacktrace for old GC if -XX:+UseG1GC is used
+     */
+    public static void testG1OldAllocEvent() throws Exception {
+        GarbageCollectorMXBean bean = garbageCollectorMXBean("G1 Old Generation");
+        MemoryAllocator memory = new OldGenMemoryAllocator();
+
+        String[] expectedStack = new String[]{
+            "jdk.jfr.event.gc.stacktrace.AllocationStackTrace.testAllocEvent",
+            "jdk.jfr.event.gc.stacktrace.AllocationStackTrace.testG1OldAllocEvent"
+        };
+
+        testAllocEvent(bean, memory, expectedStack);
+    }
+
+    /**
+     * Tests event stacktrace during metaspace GC threshold if -XX:+UseG1GC is
+     * used
+     */
+    public static void testMetaspaceG1GCAllocEvent() throws Exception {
+        GarbageCollectorMXBean bean = garbageCollectorMXBean("G1 Young Generation");
+        MemoryAllocator memory = new MetaspaceMemoryAllocator();
+
+        String[] expectedStack = new String[]{
+            "jdk.jfr.event.gc.stacktrace.AllocationStackTrace.testAllocEvent",
+            "jdk.jfr.event.gc.stacktrace.AllocationStackTrace.testMetaspaceG1GCAllocEvent"
+        };
+
+        testAllocEvent(bean, memory, expectedStack);
+    }
+
+    /**
+     * Tests event stacktrace for GC caused by humongous allocations if
+     * -XX:+UseG1GC is used
+     */
+    public static void testG1HumonAllocEvent() throws Exception {
+        // G1 tries to reclaim humongous objects at every young collection
+        // after doing a conservative estimate of its liveness
+        GarbageCollectorMXBean bean = garbageCollectorMXBean("G1 Young Generation");
+        MemoryAllocator memory = new HumongousMemoryAllocator();
+
+        String[] expectedStack = new String[]{
+            "jdk.jfr.event.gc.stacktrace.AllocationStackTrace.testAllocEvent",
+            "jdk.jfr.event.gc.stacktrace.AllocationStackTrace.testG1HumonAllocEvent"
+        };
+
+        testAllocEvent(bean, memory, expectedStack);
+    }
+
+    private static GarbageCollectorMXBean garbageCollectorMXBean(String name) throws Exception {
+        MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+        GarbageCollectorMXBean bean = ManagementFactory.newPlatformMXBeanProxy(
+                server, "java.lang:type=GarbageCollector,name=" + name, GarbageCollectorMXBean.class);
+        return bean;
+    }
+
+    /**
+     * Performs JFR recording, GC provocation/detection and stacktrace
+     * verification for JFR event. In case of verification failure
+     * repeats several times.
+     *
+     * @param bean MX bean for desired GC
+     * @param memory allocator for desired type of allocations
+     * @param expectedStack array of expected frames
+     */
+    private static void testAllocEvent(GarbageCollectorMXBean bean, MemoryAllocator memory, String[] expectedStack) throws Exception {
+        // The test checks the stacktrace of events and expects all the events are fired
+        // in the current thread. But compilation may also trigger GC.
+        // So to filter out such cases the test performs several iterations and expects
+        // that the memory allocations made by the test will produce the desired JFR event.
+        final int iterations = 5;
+        for (int i = 0; i < iterations; i++) {
+            if (allocAndCheck(bean, memory, expectedStack)) {
+                return;
+            } else {
+                System.out.println("Attempt: " + i + " out of " + iterations+": no matching stack trace found.");
+            }
+            memory.clear();
+        }
+        throw new AssertionError("No matching stack trace found");
+    }
+
+    /**
+     * Performs JFR recording, GC provocation/detection and stacktrace
+     * verification for JFR event.
+     *
+     * @param bean MX bean for desired GC
+     * @param memory allocator for desired type of allocations
+     * @param expectedStack array of expected frames
+     * @throws Exception
+     */
+    private static boolean allocAndCheck(GarbageCollectorMXBean bean, MemoryAllocator memory,
+            String[] expectedStack) throws Exception {
+        String threadName = Thread.currentThread().getName();
+        String event = EventNames.AllocationRequiringGC;
+
+        Recording r = new Recording();
+        r.enable(event).withStackTrace();
+        r.start();
+
+        long prevCollectionCount = bean.getCollectionCount();
+        long collectionCount = -1;
+
+        long iterationCount = 0;
+
+        do {
+            memory.allocate();
+            collectionCount = bean.getCollectionCount();
+            iterationCount++;
+        } while (collectionCount == prevCollectionCount);
+
+        System.out.println("Allocation num: " + iterationCount);
+        System.out.println("GC detected: " + collectionCount);
+
+        r.stop();
+        List<RecordedEvent> events = Events.fromRecording(r);
+
+        System.out.println("JFR GC events found: " + events.size());
+
+        // Find any event that matched the expected stack trace
+        for (RecordedEvent e : events) {
+            System.out.println("Event: " + e);
+            RecordedThread thread = e.getThread();
+            String eventThreadName = thread.getJavaName();
+            if (!threadName.equals(eventThreadName)) {
+                continue;
+            }
+            if (matchingStackTrace(e.getStackTrace(), expectedStack)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static boolean matchingStackTrace(RecordedStackTrace stack, String[] expectedStack) {
+        if (stack == null) {
+            return false;
+        }
+
+        List<RecordedFrame> frames = stack.getFrames();
+        int pos = findFramePos(frames, expectedStack[0]);
+
+        if (pos == -1) {
+            return false;
+        }
+
+        for (String expectedFrame : expectedStack) {
+            RecordedFrame f = frames.get(pos++);
+            String frame = frameToString(f);
+
+            if (!frame.equals(expectedFrame)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    private static int findFramePos(List<RecordedFrame> frames, String frame) {
+        int pos = 0;
+
+        for (RecordedFrame f : frames) {
+            if (frame.equals(frameToString(f))) {
+                return pos;
+            }
+            pos++;
+        }
+
+        return -1;
+    }
+
+    private static String frameToString(RecordedFrame f) {
+        RecordedMethod m = f.getMethod();
+        String methodName = m.getName();
+        String className = m.getType().getName();
+        return className + "." + methodName;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/stacktrace/TEST.properties	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,2 @@
+modules = jdk.management
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/stacktrace/TestConcMarkSweepAllocationPendingStackTrace.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.stacktrace;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @requires vm.gc == "null" | vm.gc == "ConcMarkSweep"
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:MaxNewSize=10M -Xmx64M -XX:+UseConcMarkSweepGC -Xlog:gc* jdk.jfr.event.gc.stacktrace.TestConcMarkSweepAllocationPendingStackTrace
+ */
+public class TestConcMarkSweepAllocationPendingStackTrace {
+
+    public static void main(String[] args) throws Exception {
+        AllocationStackTrace.testConcMarkSweepAllocEvent();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/stacktrace/TestDefNewAllocationPendingStackTrace.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.stacktrace;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @requires vm.gc == "null" | vm.gc == "Serial"
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UseSerialGC -Xlog:gc* jdk.jfr.event.gc.stacktrace.TestDefNewAllocationPendingStackTrace
+ */
+public class TestDefNewAllocationPendingStackTrace {
+
+    public static void main(String[] args) throws Exception {
+        AllocationStackTrace.testDefNewAllocEvent();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/stacktrace/TestG1HumongousAllocationPendingStackTrace.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.stacktrace;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @requires vm.gc == "null" | vm.gc == "G1"
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UseG1GC -Xlog:gc* -Xmx64M -XX:InitiatingHeapOccupancyPercent=100 jdk.jfr.event.gc.stacktrace.TestG1HumongousAllocationPendingStackTrace
+ */
+public class TestG1HumongousAllocationPendingStackTrace {
+
+    public static void main(String[] args) throws Exception {
+        AllocationStackTrace.testG1HumonAllocEvent();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/stacktrace/TestG1OldAllocationPendingStackTrace.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.stacktrace;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @requires vm.gc == "null" | vm.gc == "G1"
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:MaxNewSize=10M -Xmx128M -XX:+UseG1GC -Xlog:gc* jdk.jfr.event.gc.stacktrace.TestG1OldAllocationPendingStackTrace
+ */
+public class TestG1OldAllocationPendingStackTrace {
+
+    public static void main(String[] args) throws Exception {
+        AllocationStackTrace.testG1OldAllocEvent();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/stacktrace/TestG1YoungAllocationPendingStackTrace.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.stacktrace;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @requires vm.gc == "null" | vm.gc == "G1"
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UseG1GC -Xlog:gc* jdk.jfr.event.gc.stacktrace.TestG1YoungAllocationPendingStackTrace
+ */
+public class TestG1YoungAllocationPendingStackTrace {
+
+    public static void main(String[] args) throws Exception {
+        AllocationStackTrace.testG1YoungAllocEvent();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/stacktrace/TestMarkSweepCompactAllocationPendingStackTrace.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.stacktrace;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @requires vm.gc == "null" | vm.gc == "Serial"
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:MaxNewSize=10M -Xmx64M -XX:+UseSerialGC -Xlog:gc* jdk.jfr.event.gc.stacktrace.TestMarkSweepCompactAllocationPendingStackTrace
+ */
+public class TestMarkSweepCompactAllocationPendingStackTrace {
+
+    public static void main(String[] args) throws Exception {
+        AllocationStackTrace.testMarkSweepCompactAllocEvent();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/stacktrace/TestMetaspaceConcMarkSweepGCAllocationPendingStackTrace.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.stacktrace;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @requires vm.gc == "null" | vm.gc == "ConcMarkSweep"
+ * @requires !(vm.compMode == "Xcomp" & os.arch == "aarch64")
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UseConcMarkSweepGC -XX:MaxMetaspaceSize=64M -Xlog:gc* jdk.jfr.event.gc.stacktrace.TestMetaspaceConcMarkSweepGCAllocationPendingStackTrace
+ */
+public class TestMetaspaceConcMarkSweepGCAllocationPendingStackTrace {
+
+    public static void main(String[] args) throws Exception {
+        AllocationStackTrace.testMetaspaceConcMarkSweepGCAllocEvent();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/stacktrace/TestMetaspaceG1GCAllocationPendingStackTrace.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.stacktrace;
+/*
+ * @test
+ * @key jfr
+ *
+ * @requires vm.gc == "null" | vm.gc == "G1"
+ * @requires !(vm.compMode == "Xcomp" & os.arch == "aarch64")
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UseG1GC -Xlog:gc* -XX:MaxMetaspaceSize=64M jdk.jfr.event.gc.stacktrace.TestMetaspaceG1GCAllocationPendingStackTrace
+ */
+
+public class TestMetaspaceG1GCAllocationPendingStackTrace {
+
+    public static void main(String[] args) throws Exception {
+        AllocationStackTrace.testMetaspaceG1GCAllocEvent();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/stacktrace/TestMetaspaceParallelGCAllocationPendingStackTrace.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.stacktrace;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @requires vm.gc == "null" | vm.gc == "Parallel"
+ * @requires !(vm.compMode == "Xcomp" & os.arch == "aarch64")
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UseParallelGC -Xlog:gc* -XX:MaxMetaspaceSize=64M jdk.jfr.event.gc.stacktrace.TestMetaspaceParallelGCAllocationPendingStackTrace
+ */
+public class TestMetaspaceParallelGCAllocationPendingStackTrace {
+
+    public static void main(String[] args) throws Exception {
+        AllocationStackTrace.testMetaspaceParallelGCAllocEvent();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/stacktrace/TestMetaspaceSerialGCAllocationPendingStackTrace.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.stacktrace;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @requires vm.gc == "null" | vm.gc == "Serial"
+ * @requires !(vm.compMode == "Xcomp" & os.arch == "aarch64")
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UseSerialGC -Xlog:gc* -XX:MaxMetaspaceSize=64M -XX:+FlightRecorder jdk.jfr.event.gc.stacktrace.TestMetaspaceSerialGCAllocationPendingStackTrace
+ */
+public class TestMetaspaceSerialGCAllocationPendingStackTrace {
+
+    public static void main(String[] args) throws Exception {
+        AllocationStackTrace.testMetaspaceSerialGCAllocEvent();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/stacktrace/TestParNewAllocationPendingStackTrace.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.stacktrace;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @requires vm.gc == "null" | vm.gc == "ConcMarkSweep"
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UseConcMarkSweepGC -Xlog:gc* -XX:+FlightRecorder jdk.jfr.event.gc.stacktrace.TestParNewAllocationPendingStackTrace
+ */
+public class TestParNewAllocationPendingStackTrace {
+
+    public static void main(String[] args) throws Exception {
+        AllocationStackTrace.testParNewAllocEvent();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/stacktrace/TestParallelMarkSweepAllocationPendingStackTrace.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.stacktrace;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @requires vm.gc == "null" | vm.gc == "Parallel"
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:MaxNewSize=10M -Xmx64M -XX:+UseParallelGC -Xlog:gc* -XX:+FlightRecorder jdk.jfr.event.gc.stacktrace.TestParallelMarkSweepAllocationPendingStackTrace
+ */
+public class TestParallelMarkSweepAllocationPendingStackTrace {
+
+    public static void main(String[] args) throws Exception {
+        AllocationStackTrace.testParallelMarkSweepAllocEvent();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/stacktrace/TestParallelScavengeAllocationPendingStackTrace.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.gc.stacktrace;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @requires vm.gc == "null" | vm.gc == "Parallel"
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UseParallelGC -Xlog:gc* -XX:+FlightRecorder jdk.jfr.event.gc.stacktrace.TestParallelScavengeAllocationPendingStackTrace
+ */
+public class TestParallelScavengeAllocationPendingStackTrace {
+
+    public static void main(String[] args) throws Exception {
+        AllocationStackTrace.testParallelScavengeAllocEvent();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/io/EvilInstrument.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.io;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+import java.lang.instrument.ClassFileTransformer;
+import java.lang.instrument.Instrumentation;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.security.ProtectionDomain;
+import java.util.concurrent.CountDownLatch;
+
+
+/**
+ * @test
+ * @key jfr
+ * @summary This test runs JFR with a javaagent that reads/writes files and
+ * sockets during every class definition. This is to verify that the i/o
+ * instrumentation in JFR does not interfere with javaagents.
+ *
+ * @library /test/lib /test/jdk
+ * @modules java.instrument
+ *
+ * @run shell MakeJAR.sh EvilInstrument 'Can-Redefine-Classes: true'
+ * @run main/othervm -javaagent:EvilInstrument.jar jdk.jfr.event.io.EvilInstrument
+ */
+
+public class EvilInstrument {
+
+    CountDownLatch socketEchoReady = new CountDownLatch(1);
+    ServerSocket ss;
+
+    /**
+     * Thread that echos everything from a socket.
+     */
+    class SocketEcho extends Thread
+    {
+        public SocketEcho() {
+            setDaemon(true);
+        }
+
+        public void run() {
+            try {
+                Socket s = ss.accept();
+                OutputStream os = s.getOutputStream();
+                InputStream is = s.getInputStream();
+                socketEchoReady.countDown();
+                for(;;) {
+                    int b = is.read();
+                    os.write(b);
+                }
+            } catch(Exception ex) {
+                ex.printStackTrace();
+                System.exit(1);
+            }
+        }
+    }
+
+    public static File createScratchFile() throws IOException {
+        return File.createTempFile("EvilTransformer", null, new File(".")).getAbsoluteFile();
+    }
+
+    class EvilTransformer implements ClassFileTransformer {
+        File scratch;
+        Socket s;
+        volatile boolean inited = false;
+
+        public EvilTransformer() throws Exception {
+            scratch = createScratchFile();
+            ss = new ServerSocket(0);
+            new SocketEcho().start();
+            s = new Socket(ss.getInetAddress(), ss.getLocalPort());
+            socketEchoReady.await();
+            inited = true;
+        }
+
+        public byte[] transform(ClassLoader loader, String className,
+                                Class<?> classBeingRedefined,
+                                ProtectionDomain protectionDomain,
+                                byte[] classfileBuffer)
+        {
+            if (!inited) {
+                return null;
+            }
+            // Do i/o operations during every transform call.
+            try {
+                FileOutputStream fos = new FileOutputStream(scratch);
+                fos.write(31);
+                fos.close();
+
+                FileInputStream fis = new FileInputStream(scratch);
+                fis.read();
+                fis.close();
+
+                RandomAccessFile raf = new RandomAccessFile(scratch, "rw");
+                raf.read();
+                raf.write(31);
+                raf.close();
+
+                s.getOutputStream().write(31);
+                s.getInputStream().read();
+
+            } catch(Exception ex) {
+                ex.printStackTrace();
+                System.exit(1);
+            }
+            return null;
+        }
+    }
+
+    public static void premain(String agentArgs, Instrumentation inst) {
+        new EvilInstrument().addTransformer(inst);
+    }
+
+    private void addTransformer(Instrumentation inst) {
+        try {
+            inst.addTransformer(new EvilTransformer());
+        } catch(Exception ex) {
+            ex.printStackTrace();
+            System.exit(1);
+        }
+    }
+
+    public static void main(String... args) throws Exception {
+        System.out.println("Hello");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/io/IOEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.io;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.Socket;
+
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedThread;
+import jdk.test.lib.jfr.EventField;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+// Contains data from a JFR IO event.
+public class IOEvent {
+    public final String thread;
+    public final EventType eventType;
+    public final long size;
+    public final String address;  // Name of file or socket address.
+    public final boolean endOfStream;
+
+    // Constructor is private. Use IOEvent.create...
+    private IOEvent(String thread, EventType eventType, long size, String address, boolean endOfStream) {
+        this.thread = thread;
+        this.eventType = eventType;
+        this.size = size;
+        this.address = address;
+        this.endOfStream = endOfStream;
+    }
+
+    @Override
+    public String toString() {
+        String key = String.format("thread: %s, type: %s, size: %d, address: %s endOfStream: %s", thread, eventType, size, address, endOfStream);
+        return key;
+    }
+
+    @Override
+    public boolean equals(Object object) {
+        if (object == null || !(object instanceof IOEvent)) {
+            return false;
+        }
+        return toString().equals(object.toString());
+    }
+
+    @Override
+    public int hashCode() {
+        return toString().hashCode();
+    }
+
+    public static final String EVENT_UNKNOWN = "unknown-event??";
+    public static final String EVENT_FILE_FORCE = EventNames.FileForce;
+    public static final String EVENT_FILE_READ = EventNames.FileRead;
+    public static final String EVENT_FILE_WRITE = EventNames.FileWrite;
+    public static final String EVENT_SOCKET_READ = EventNames.SocketRead;
+    public static final String EVENT_SOCKET_WRITE = EventNames.SocketWrite;
+
+    public enum EventType { UnknownEvent, FileForce, FileRead, FileWrite, SocketRead, SocketWrite }
+
+    private static final String[] eventPaths = {
+        EVENT_UNKNOWN, EVENT_FILE_FORCE, EVENT_FILE_READ, EVENT_FILE_WRITE, EVENT_SOCKET_READ, EVENT_SOCKET_WRITE
+    };
+
+    public static boolean isWriteEvent(EventType eventType) {
+        return (eventType == EventType.SocketWrite || eventType == EventType.FileWrite);
+    }
+
+    public static boolean isReadEvent(EventType eventType) {
+        return (eventType == EventType.SocketRead || eventType == EventType.FileRead);
+    }
+
+    public static boolean isFileEvent(EventType eventType) {
+        return (eventType == EventType.FileForce || eventType == EventType.FileWrite || eventType == EventType.FileRead);
+    }
+
+    public static IOEvent createSocketWriteEvent(long size, Socket s) {
+        if (size < 0) {
+            size = 0;
+        }
+        return new IOEvent(Thread.currentThread().getName(), EventType.SocketWrite, size, getAddress(s), false);
+    }
+
+    public static IOEvent createSocketReadEvent(long size, Socket s) {
+        boolean endOfStream = false;
+        if (size < 0) {
+            size = 0;
+            endOfStream = true;
+        }
+        return new IOEvent(Thread.currentThread().getName(), EventType.SocketRead, size, getAddress(s), endOfStream);
+    }
+
+    public static IOEvent createFileForceEvent(File file) {
+        String address = null;
+        try {
+            address = file.getCanonicalPath();
+        } catch(IOException ex) {
+            throw new RuntimeException();
+        }
+        return new IOEvent(Thread.currentThread().getName(), EventType.FileForce, 0, address, false);
+    }
+
+    public static IOEvent createFileReadEvent(long size, File file) {
+        boolean endOfStream = false;
+        if (size < 0) {
+            endOfStream = true;
+            size = 0;
+        }
+        String address = null;
+        try {
+            address = file.getCanonicalPath();
+        } catch(IOException ex) {
+                throw new RuntimeException();
+        }
+        return new IOEvent(Thread.currentThread().getName(), EventType.FileRead, size, address, endOfStream);
+    }
+
+    public static IOEvent createFileWriteEvent(long size, File file) {
+        if (size < 0) {
+            size = 0;
+        }
+        String address = null;
+        try {
+            address = file.getCanonicalPath();
+        } catch(IOException ex) {
+                throw new RuntimeException();
+        }
+        return new IOEvent(Thread.currentThread().getName(), EventType.FileWrite, size, address, false);
+    }
+
+    public static EventType getEventType(RecordedEvent event) {
+        final String path = event.getEventType().getName();
+        for (int i = 0; i < eventPaths.length; ++i) {
+            if (path.endsWith(eventPaths[i])) {
+                return EventType.values()[i];
+            }
+        }
+        return EventType.UnknownEvent;
+    }
+
+    public static IOEvent createTestEvent(RecordedEvent event) {
+        EventType eventType = getEventType(event);
+        if (eventType == EventType.UnknownEvent) {
+            return null;
+        }
+        EventField ev = Events.assertField(event, "eventThread");
+        RecordedThread t = ev.getValue();
+        String thread = t.getJavaName();
+        long size = 0L;
+        if (isWriteEvent(eventType)) {
+            size = Events.assertField(event, "bytesWritten").getValue();
+        } else if (isReadEvent(eventType)) {
+            size = Events.assertField(event, "bytesRead").getValue();
+        }
+        String address = getEventAddress(event);
+        boolean endOfStream = false;
+        if (event.hasField("endOfStream")) {
+            endOfStream = event.getValue("endOfStream");
+        }
+        if (event.hasField("endOfFile")) {
+            endOfStream = event.getValue("endOfFile");
+        }
+        return new IOEvent(thread, eventType, size, address, endOfStream);
+    }
+
+    public static String getEventAddress(RecordedEvent event) {
+        if (isFileEvent(getEventType(event))) {
+            String address = Events.assertField(event, "path").getValue();
+            // must ensure canonical format
+            String canonical_path = null;
+            try {
+                canonical_path = new File(address).getCanonicalPath();
+            } catch (IOException ex) {
+                throw new RuntimeException();
+            }
+            return canonical_path;
+        } else {
+            return String.format("%s/%s:%d",
+                                event.getValue("host"),
+                                event.getValue("address"),
+                                event.getValue("port"));
+        }
+    }
+
+    private static String getAddress(Socket s) {
+        return s.getInetAddress().toString() + ":" + s.getPort();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/io/IOHelper.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.io;
+
+import static jdk.test.lib.Asserts.assertEquals;
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import jdk.jfr.event.io.IOEvent.EventType;
+
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.Events;
+
+
+// Helper class to match actual RecordedEvents to expected events.
+public class IOHelper {
+
+    public static void verifyEqualsInOrder(List<RecordedEvent> events, List<IOEvent> expectedEvents) throws Throwable {
+        List<IOEvent> actualEvents = getTestEvents(events, expectedEvents);
+        try {
+            assertEquals(actualEvents.size(), expectedEvents.size(), "Wrong number of events.");
+            for (int i = 0; i < actualEvents.size(); ++i) {
+                assertEquals(actualEvents.get(i), expectedEvents.get(i), "Wrong event at pos " + i);
+            }
+        } catch (Throwable t) {
+            logEvents(actualEvents, expectedEvents);
+            throw t;
+        }
+    }
+
+
+    public static void verifyEquals(List<RecordedEvent> events, List<IOEvent> expectedEvents) throws Throwable {
+        List<IOEvent> actualEvents = getTestEvents(events, expectedEvents);
+        try {
+            assertEquals(actualEvents.size(), expectedEvents.size(), "Wrong number of events");
+            assertTrue(actualEvents.containsAll(expectedEvents), "Not all expected events received");
+            assertTrue(expectedEvents.containsAll(actualEvents), "Received unexpected events");
+        } catch (Throwable t) {
+            logEvents(actualEvents, expectedEvents);
+            throw t;
+        }
+    }
+
+
+    private static List<IOEvent> getTestEvents(List<RecordedEvent> events, List<IOEvent> expectedEvents) throws Throwable {
+        // Log all events
+        for (RecordedEvent event : events) {
+            String msg = event.getEventType().getName();
+            boolean isSocket = IOEvent.EVENT_SOCKET_READ.equals(msg) || IOEvent.EVENT_SOCKET_WRITE.equals(msg);
+            boolean isFile = IOEvent.EVENT_FILE_FORCE.equals(msg) || IOEvent.EVENT_FILE_READ.equals(msg) || IOEvent.EVENT_FILE_WRITE.equals(msg);
+            boolean isFileReadOrWrite = IOEvent.EVENT_FILE_READ.equals(msg) || IOEvent.EVENT_FILE_WRITE.equals(msg);
+            boolean isRead = IOEvent.EVENT_FILE_READ.equals(msg) || IOEvent.EVENT_SOCKET_READ.equals(msg);
+            if (isFile) {
+                msg += " : " + Events.assertField(event, "path").getValue();
+            } else if (isSocket) {
+                msg += " - " + Events.assertField(event, "host").getValue();
+                msg += "." + Events.assertField(event, "address").getValue();
+                msg += "." + Events.assertField(event, "port").getValue();
+            }
+            if (isSocket || isFileReadOrWrite) {
+                String field = isRead ? "bytesRead" : "bytesWritten";
+                msg += " : " + Events.assertField(event, field).getValue();
+            }
+            System.out.println(msg);
+        }
+
+        return events.stream()
+                        .filter(event -> isTestEvent(event, expectedEvents))
+                        .map(event -> IOEvent.createTestEvent(event))
+                        .collect(Collectors.toList());
+    }
+
+    // A recording may contain extra events that are not part of the test.
+    // This function filters out events that not belong to the test.
+    public static boolean isTestEvent(RecordedEvent event, List<IOEvent> testEvents) {
+        EventType eventType = IOEvent.getEventType(event);
+        if (eventType == EventType.UnknownEvent) {
+                return false;
+        }
+
+        // Only care about threads in the expected threads.
+        final String threadName = event.getThread().getJavaName();
+        if (testEvents.stream().noneMatch(te -> te.thread.equals(threadName))) {
+                return false;
+        }
+
+        // Only care about files and sockets in expected events.
+        final String address = IOEvent.getEventAddress(event);
+        if (testEvents.stream().noneMatch(te -> te.address.equals(address))) {
+                return false;
+        }
+        return true;
+    }
+
+    private static void logEvents(List<IOEvent> actualEvents, List<IOEvent> expectedEvents) {
+        for (int i = 0; i < actualEvents.size(); ++i) {
+            System.out.println("actual event[" + i + "] = " + actualEvents.get(i));
+        }
+        for (int i = 0; i < expectedEvents.size(); ++i) {
+            System.out.println("expected event[" + i + "] = " + expectedEvents.get(i));
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/io/InstrumentationCallback.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.io;
+import java.util.Set;
+import java.util.HashSet;
+
+// Will be used by the TestInstrumentation.java as a callback from
+// instrumented classes.
+public class InstrumentationCallback {
+
+    private static Set<String> keys = new HashSet<String>();
+
+    public static synchronized void callback(String key) {
+        if (!keys.contains(key)) {
+            keys.add(key);
+        }
+    }
+
+    public static synchronized void clear() {
+        keys.clear();
+    }
+
+    public static synchronized Set<String> getKeysCopy() {
+        return new HashSet<String>(keys);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/io/MakeJAR.sh	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,45 @@
+#!/bin/sh
+
+AGENT="$1"
+
+if [ "${TESTSRC}" = "" ]
+then
+  echo "TESTSRC not set.  Test cannot execute.  Failed."
+  exit 1
+fi
+echo "TESTSRC=${TESTSRC}"
+
+if [ "${TESTJAVA}" = "" ]
+then
+  echo "TESTJAVA not set.  Test cannot execute.  Failed."
+  exit 1
+fi
+echo "TESTJAVA=${TESTJAVA}"
+
+if [ "${TESTCLASSES}" = "" ]
+then
+  echo "TESTCLASSES not set.  Test cannot execute.  Failed."
+  exit 1
+fi
+
+if [ -z "${COMPILEJAVA}" ]
+then
+  COMPILEJAVA=${TESTJAVA}
+fi
+
+JAVAC="${COMPILEJAVA}/bin/javac -g"
+JAR="${COMPILEJAVA}/bin/jar"
+
+cp ${TESTSRC}/${AGENT}.java .
+${JAVAC} -cp ${TESTCLASSPATH} ${AGENT}.java
+
+echo "Manifest-Version: 1.0"    >  ${AGENT}.mf
+echo Premain-Class: jdk.jfr.event.io.${AGENT} >> ${AGENT}.mf
+shift
+while [ $# != 0 ] ; do
+  echo $1 >> ${AGENT}.mf
+  shift
+done
+
+
+${JAR} cvfm ${AGENT}.jar ${AGENT}.mf ${AGENT}*.class
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/io/TestDisabledEvents.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.io;
+
+import static jdk.test.lib.Asserts.assertEquals;
+import static jdk.test.lib.Asserts.assertNotEquals;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Test with FlightRecorder enabled but with the events disabled.
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.event.io.TestDisabledEvents
+ */
+
+// Verify that IO operations are correct and that no events are generated.
+public class TestDisabledEvents {
+
+    private static final int writeInt = 'A';
+    private static final byte[] writeBuf = { 'B', 'C', 'D' };
+
+    public static void main(String[] args) throws Throwable {
+        File tmp = File.createTempFile("TestDisabledEvents", ".tmp", new File("."));
+        tmp.deleteOnExit();
+        Recording recording = new Recording();
+        recording.disable(IOEvent.EVENT_FILE_READ);
+        recording.disable(IOEvent.EVENT_FILE_WRITE);
+        recording.start();
+
+        useRandomAccessFile(tmp);
+        useFileStreams(tmp);
+        useFileChannel(tmp);
+
+        recording.stop();
+        for (RecordedEvent event : Events.fromRecording(recording)) {
+            final String eventName = event.getEventType().getName();
+            System.out.println("Got eventName:" + eventName);
+            assertNotEquals(eventName, IOEvent.EVENT_FILE_READ, "Got disabled read event");
+            assertNotEquals(eventName, IOEvent.EVENT_FILE_WRITE, "Got disabled write event");
+        }
+    }
+
+    private static void useRandomAccessFile(File tmp) throws Throwable {
+        tmp.delete();
+        try (RandomAccessFile ras = new RandomAccessFile(tmp, "rw")) {
+            ras.write(writeInt);
+            ras.write(writeBuf);
+            ras.seek(0);
+            int readInt = ras.read();
+            assertEquals(readInt, writeInt, "Wrong readInt");
+            byte[] readBuf = new byte[writeBuf.length];
+            int readSize = ras.read(readBuf);
+            assertEquals(readSize, writeBuf.length, "Wrong readSize");
+            // Try to read more which should generate EOF.
+            readInt = ras.read();
+            assertEquals(readInt, -1, "Wrong readInt after EOF");
+        }
+    }
+
+    private static void useFileStreams(File tmp) throws Throwable {
+        tmp.delete();
+        try (FileOutputStream fos = new FileOutputStream(tmp)) {
+            fos.write(writeInt);
+            fos.write(writeBuf);
+        }
+
+        try (FileInputStream fis = new FileInputStream(tmp)) {
+            int readInt = fis.read();
+            assertEquals(readInt, writeInt, "Wrong readInt");
+            byte[] readBuf = new byte[writeBuf.length];
+            int readSize = fis.read(readBuf);
+            assertEquals(readSize, writeBuf.length, "Wrong readSize");
+            // Try to read more which should generate EOF.
+            readInt = fis.read();
+            assertEquals(readInt, -1, "Wrong readInt after EOF");
+        }
+    }
+
+    private static void useFileChannel(File tmp) throws Throwable {
+        tmp.delete();
+        try (RandomAccessFile rf = new RandomAccessFile(tmp, "rw");
+                FileChannel ch = rf.getChannel()) {
+            final String bufContent = "0123456789";
+            final int bufSize = bufContent.length();
+            ByteBuffer writeBuf = ByteBuffer.allocateDirect(bufSize);
+            writeBuf.put(bufContent.getBytes());
+
+            writeBuf.flip();
+            int writeSize = ch.write(writeBuf);
+            assertEquals(writeSize, bufSize, "Wrong writeSize for FileChannel");
+
+            ch.position(0);
+            ByteBuffer readBuf = ByteBuffer.allocateDirect(bufSize);
+            int readSize = ch.read(readBuf);
+            assertEquals(readSize, bufSize, "Wrong readSize full for FileChannel");
+            assertEquals(0, writeBuf.compareTo(readBuf), "Unexpected readBuf content");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/io/TestFileChannelEvents.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.io;
+
+import static jdk.test.lib.Asserts.assertEquals;
+
+import java.io.File;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.event.io.TestFileChannelEvents
+ */
+public class TestFileChannelEvents {
+    public static void main(String[] args) throws Throwable {
+        File tmp = File.createTempFile("TestFileChannelEvents", ".tmp", new File("."));
+        tmp.deleteOnExit();
+        Recording recording = new Recording();
+        List<IOEvent> expectedEvents = new ArrayList<>();
+
+        try (RandomAccessFile rf = new RandomAccessFile(tmp, "rw"); FileChannel ch = rf.getChannel();) {
+            recording.enable(IOEvent.EVENT_FILE_FORCE).withThreshold(Duration.ofMillis(0));
+            recording.enable(IOEvent.EVENT_FILE_READ).withThreshold(Duration.ofMillis(0));
+            recording.enable(IOEvent.EVENT_FILE_WRITE).withThreshold(Duration.ofMillis(0));
+            recording.start();
+
+            ByteBuffer bufA = ByteBuffer.allocateDirect(10);
+            ByteBuffer bufB = ByteBuffer.allocateDirect(20);
+            bufA.put("1234567890".getBytes());
+            bufB.put("1234567890".getBytes());
+
+            // test write(ByteBuffer)
+            bufA.flip();
+            long size = ch.write(bufA);
+            expectedEvents.add(IOEvent.createFileWriteEvent(size, tmp));
+
+            // test write(ByteBuffer, long)
+            bufA.flip();
+            size = ch.write(bufA, bufA.capacity() / 2);
+            expectedEvents.add(IOEvent.createFileWriteEvent(size, tmp));
+
+            // test write(ByteBuffer[])
+            bufA.flip();
+            bufA.limit(5);
+            bufB.flip();
+            bufB.limit(5);
+            size = ch.write(new ByteBuffer[] { bufA, bufB });
+            expectedEvents.add(IOEvent.createFileWriteEvent(size, tmp));
+
+            // test force(boolean)
+            ch.force(true);
+            expectedEvents.add(IOEvent.createFileForceEvent(tmp));
+
+            // reset file
+            ch.position(0);
+
+            // test read(ByteBuffer)
+            bufA.clear();
+            size = ch.read(bufA);
+            expectedEvents.add(IOEvent.createFileReadEvent(size, tmp));
+
+            // test read(ByteBuffer, long)
+            bufA.clear();
+            size = ch.read(bufA, bufA.capacity() / 2);
+            expectedEvents.add(IOEvent.createFileReadEvent(size, tmp));
+
+            // test read(ByteBuffer[])
+            bufA.clear();
+            bufA.limit(5);
+            bufB.clear();
+            bufB.limit(5);
+            size = ch.read(new ByteBuffer[] { bufA, bufB });
+            expectedEvents.add(IOEvent.createFileReadEvent(size, tmp));
+
+            // Read at EOF. Should get size -1 in event.
+            ch.position(ch.size());
+            bufA.clear();
+            size = ch.read(bufA);
+            assertEquals(size, -1L, "Expected size -1 when read at EOF");
+            expectedEvents.add(IOEvent.createFileReadEvent(size, tmp));
+
+            ch.close();
+            recording.stop();
+            List<RecordedEvent> events = Events.fromRecording(recording);
+            IOHelper.verifyEqualsInOrder(events, expectedEvents);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/io/TestFileReadOnly.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.io;
+
+import static jdk.test.lib.Asserts.fail;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.event.io.TestFileReadOnly
+ */
+public class TestFileReadOnly {
+
+    public static void main(String[] args) throws Throwable {
+        File tmp = File.createTempFile("TestFileReadOnly", ".tmp", new File("."));
+        tmp.deleteOnExit();
+        Recording recording = new Recording();
+        List<IOEvent> expectedEvents = new ArrayList<>();
+
+        recording.enable(IOEvent.EVENT_FILE_READ).withThreshold(Duration.ofMillis(0));
+        recording.enable(IOEvent.EVENT_FILE_WRITE).withThreshold(Duration.ofMillis(0));
+        recording.start();
+
+        final byte[] buf = { 1, 2, 3 };
+
+        // Create the file.
+        try (RandomAccessFile f = new RandomAccessFile(tmp, "rw")) {
+            f.write(buf);
+            expectedEvents.add(IOEvent.createFileWriteEvent(buf.length, tmp));
+        }
+
+        // Reopen the file as ReadOnly and try to write to it.
+        // Should generate an event with bytesWritten = -1.
+        try (RandomAccessFile f = new RandomAccessFile(tmp, "r")) {
+            try {
+                f.write(buf);
+                fail("No exception for ReadOnly File");
+            } catch (IOException e) {
+                // Expected exception
+                expectedEvents.add(IOEvent.createFileWriteEvent(-1, tmp));
+            }
+        }
+
+        // Try to write to read-only FileChannel.
+        try (RandomAccessFile f = new RandomAccessFile(tmp, "r"); FileChannel ch = f.getChannel()) {
+            ByteBuffer writeBuf = ByteBuffer.allocateDirect(buf.length);
+            writeBuf.put(buf);
+            writeBuf.flip();
+            ch.position(0);
+            try {
+                ch.write(writeBuf);
+                fail("No exception for ReadOnly FileChannel");
+            } catch (java.nio.channels.NonWritableChannelException e) {
+                // Expected exception
+                expectedEvents.add(IOEvent.createFileWriteEvent(-1, tmp));
+            }
+        }
+
+        recording.stop();
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        IOHelper.verifyEqualsInOrder(events, expectedEvents);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/io/TestFileStreamEvents.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.io;
+
+import static jdk.test.lib.Asserts.assertEquals;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test TestFileStreamEvents
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.event.io.TestFileStreamEvents
+ */
+
+public class TestFileStreamEvents {
+    public static void main(String[] args) throws Throwable {
+        File tmp = File.createTempFile("TestFileStreamEvents", ".tmp", new File("."));
+        tmp.deleteOnExit();
+        Recording recording = new Recording();
+        List<IOEvent> expectedEvents = new ArrayList<>();
+
+        try(FileOutputStream fos = new FileOutputStream(tmp); FileInputStream fis = new FileInputStream(tmp);) {
+            recording.enable(IOEvent.EVENT_FILE_READ).withThreshold(Duration.ofMillis(0));
+            recording.enable(IOEvent.EVENT_FILE_WRITE).withThreshold(Duration.ofMillis(0));
+            recording.start();
+
+            int writeByte = 47;
+            byte[] writeBuf = {11, 12, 13, 14};
+
+            // Write
+            fos.write(writeByte);
+            expectedEvents.add(IOEvent.createFileWriteEvent(1, tmp));
+            fos.write(writeBuf);
+            expectedEvents.add(IOEvent.createFileWriteEvent(writeBuf.length, tmp));
+            fos.write(writeBuf, 0, 2);
+            expectedEvents.add(IOEvent.createFileWriteEvent(2, tmp));
+
+            // Read
+            int readByte = fis.read();
+            assertEquals(readByte, writeByte, "Wrong byte read");
+            expectedEvents.add(IOEvent.createFileReadEvent(1, tmp));
+
+            byte[] readBuf = new byte[writeBuf.length];
+            long size = fis.read(readBuf);
+            assertEquals(size, (long)writeBuf.length, "Wrong size when reading byte[]");
+            expectedEvents.add(IOEvent.createFileReadEvent(size, tmp));
+
+            size = fis.read(readBuf, 0, 2);
+            assertEquals(size, 2L, "Wrong size when reading 2 bytes");
+            expectedEvents.add(IOEvent.createFileReadEvent(size, tmp));
+
+            // We are at EOF. Read more and verify we get size -1.
+            size = fis.read(readBuf);
+            assertEquals(size, -1L, "Size should be -1 at EOF");
+            expectedEvents.add(IOEvent.createFileReadEvent(size, tmp));
+
+            recording.stop();
+            List<RecordedEvent> events = Events.fromRecording(recording);
+            IOHelper.verifyEqualsInOrder(events, expectedEvents);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/io/TestInstrumentation.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,374 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.io;
+
+import java.util.Arrays;
+import java.util.Set;
+import java.util.HashSet;
+import java.io.File;
+import java.security.ProtectionDomain;
+import java.lang.instrument.ClassFileTransformer;
+import java.lang.instrument.Instrumentation;
+import java.lang.instrument.IllegalClassFormatException;
+
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassVisitor;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.internal.org.objectweb.asm.Type;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+/*
+ * @test
+ * @summary Test that will instrument the same classes that JFR will also instrument.
+ * @key jfr
+ *
+ * @library /test/lib /test/jdk
+ * @modules java.base/jdk.internal.org.objectweb.asm
+ *          java.instrument
+ *          jdk.jartool/sun.tools.jar
+ *          jdk.jfr
+ *
+ * @run main/othervm jdk.jfr.event.io.TestInstrumentation
+ */
+
+// Test that will instrument the same classes that JFR will also instrument.
+//
+// The methods that will be instrumented, for example java.io.RandomAccessFile.write,
+// will add the following code at the start of the method:
+// InstrumentationCallback.callback("<classname>::<methodname>");
+//
+// The class InstrumentationCallback will log all keys added by the callback() function.
+//
+// With this instrumentation in place, we will run some existing jfr.io tests
+// to verify that our instrumentation has not broken the JFR instrumentation.
+//
+// After the tests have been run, we verify that the callback() function have been
+// called from all instrumented classes and methods. This will verify that JFR has not
+// broken our instrumentation.
+//
+// To use instrumentation, the test must be run in a new java process with
+// the -javaagent option.
+// We must also create two jars:
+// TestInstrumentation.jar: The javaagent for the instrumentation.
+// InstrumentationCallback.jar: This is a separate jar with the instrumentation
+// callback() function. It is in a separate jar because it must be added to
+// the bootclasspath to be called from java.io classes.
+//
+// The test contains 3 parts:
+// Setup part that will create jars and launch the new test instance.
+// Agent part that contains the instrumentation code.
+// The actual test part is in the TestMain class.
+//
+public class TestInstrumentation implements ClassFileTransformer {
+
+    private static Instrumentation instrumentation = null;
+    private static TestInstrumentation testTransformer = null;
+
+    // All methods that will be instrumented.
+    private static final String[] instrMethodKeys = {
+        "java/io/RandomAccessFile::seek::(J)V",
+        "java/io/RandomAccessFile::read::()I",
+        "java/io/RandomAccessFile::read::([B)I",
+        "java/io/RandomAccessFile::write::([B)V",
+        "java/io/RandomAccessFile::write::(I)V",
+        "java/io/RandomAccessFile::close::()V",
+        "java/io/FileInputStream::read::([BII)I",
+        "java/io/FileInputStream::read::([B)I",
+        "java/io/FileInputStream::read::()I",
+        "java/io/FileOutputStream::write::(I)V",
+        "java/io/FileOutputStream::write::([B)V",
+        "java/io/FileOutputStream::write::([BII)V",
+        "java/net/SocketInputStream::read::()I",
+        "java/net/SocketInputStream::read::([B)I",
+        "java/net/SocketInputStream::read::([BII)I",
+        "java/net/SocketInputStream::close::()V",
+        "java/net/SocketOutputStream::write::(I)V",
+        "java/net/SocketOutputStream::write::([B)V",
+        "java/net/SocketOutputStream::write::([BII)V",
+        "java/net/SocketOutputStream::close::()V",
+        "java/nio/channels/FileChannel::read::([Ljava/nio/ByteBuffer;)J",
+        "java/nio/channels/FileChannel::write::([Ljava/nio/ByteBuffer;)J",
+        "java/nio/channels/SocketChannel::open::()Ljava/nio/channels/SocketChannel;",
+        "java/nio/channels/SocketChannel::open::(Ljava/net/SocketAddress;)Ljava/nio/channels/SocketChannel;",
+        "java/nio/channels/SocketChannel::read::([Ljava/nio/ByteBuffer;)J",
+        "java/nio/channels/SocketChannel::write::([Ljava/nio/ByteBuffer;)J",
+        "sun/nio/ch/FileChannelImpl::read::(Ljava/nio/ByteBuffer;)I",
+        "sun/nio/ch/FileChannelImpl::write::(Ljava/nio/ByteBuffer;)I",
+    };
+
+    private static String getInstrMethodKey(String className, String methodName, String signature) {
+        // This key is used to identify a class and method. It is sent to callback(key)
+        return className + "::" + methodName + "::" + signature;
+    }
+
+    private static String getClassFromMethodKey(String methodKey) {
+        return methodKey.split("::")[0];
+    }
+
+    // Set of all classes targeted for instrumentation.
+    private static Set<String> instrClassesTarget = null;
+
+    // Set of all classes where instrumentation has been completed.
+    private static Set<String> instrClassesDone = null;
+
+    static {
+        // Split class names from InstrMethodKeys.
+        instrClassesTarget = new HashSet<String>();
+        instrClassesDone = new HashSet<String>();
+        for (String s : instrMethodKeys) {
+            String className = getClassFromMethodKey(s);
+            instrClassesTarget.add(className);
+        }
+    }
+
+    private static void log(String msg) {
+        System.out.println("TestTransformation: " + msg);
+    }
+
+
+    ////////////////////////////////////////////////////////////////////
+    // This is the actual test part.
+    // A batch of jfr io tests will be run twice with a
+    // retransfromClasses() in between. After each test batch we verify
+    // that all callbacks have been called.
+    ////////////////////////////////////////////////////////////////////
+
+    public static class TestMain {
+
+        private enum TransformStatus { Transformed, Retransformed, Removed }
+
+        public static void main(String[] args) throws Throwable {
+            runAllTests(TransformStatus.Transformed);
+
+            // Retransform all classes and then repeat tests
+            Set<Class<?>> classes = new HashSet<Class<?>>();
+            for (String className : instrClassesTarget) {
+                Class<?> clazz = Class.forName(className.replaceAll("/", "."));
+                classes.add(clazz);
+                log("Will retransform " + clazz.getName());
+            }
+            instrumentation.retransformClasses(classes.toArray(new Class<?>[0]));
+
+            // Clear all callback keys so we don't read keys from the previous test run.
+            InstrumentationCallback.clear();
+            runAllTests(TransformStatus.Retransformed);
+
+            // Remove my test transformer and run tests again. Should not get any callbacks.
+            instrumentation.removeTransformer(testTransformer);
+            instrumentation.retransformClasses(classes.toArray(new Class<?>[0]));
+            InstrumentationCallback.clear();
+            runAllTests(TransformStatus.Removed);
+        }
+
+        // This is not all available jfr io tests, but a reasonable selection.
+        public static void runAllTests(TransformStatus status) throws Throwable {
+            log("runAllTests, TransformStatus: " + status);
+            try {
+                String[] noArgs = new String[0];
+                TestRandomAccessFileEvents.main(noArgs);
+                TestSocketEvents.main(noArgs);
+                TestSocketChannelEvents.main(noArgs);
+                TestFileChannelEvents.main(noArgs);
+                TestFileStreamEvents.main(noArgs);
+                TestDisabledEvents.main(noArgs);
+
+                // Verify that all expected callbacks have been called.
+                Set<String> callbackKeys = InstrumentationCallback.getKeysCopy();
+                for (String key : instrMethodKeys) {
+                    boolean gotCallback = callbackKeys.contains(key);
+                    boolean expectsCallback = isClassInstrumented(status, key);
+                    String msg = String.format("key:%s, expects:%b", key, expectsCallback);
+                    if (gotCallback != expectsCallback) {
+                        throw new Exception("Wrong callback() for " + msg);
+                    } else {
+                        log("Correct callback() for " + msg);
+                    }
+                }
+            } catch (Throwable t) {
+                log("Test failed in phase " + status);
+                t.printStackTrace();
+                throw t;
+            }
+        }
+
+        private static boolean isClassInstrumented(TransformStatus status, String key) throws Throwable {
+            switch (status) {
+            case Retransformed:
+                return true;
+            case Removed:
+                return false;
+            case Transformed:
+                String className = getClassFromMethodKey(key);
+                return instrClassesDone.contains(className);
+            }
+            throw new Exception("Test error: Unknown TransformStatus: " + status);
+        }
+    }
+
+
+    ////////////////////////////////////////////////////////////////////
+    // This is the setup part. It will create needed jars and
+    // launch a new java instance that will run the internal class TestMain.
+    // This setup step is needed because we must use a javaagent jar to
+    // transform classes.
+    ////////////////////////////////////////////////////////////////////
+
+    public static void main(String[] args) throws Throwable {
+        buildJar("TestInstrumentation", true);
+        buildJar("InstrumentationCallback", false);
+        launchTest();
+    }
+
+    private static void buildJar(String jarName, boolean withManifest) throws Throwable {
+        final String slash = File.separator;
+        final String packageName = "jdk/jfr/event/io".replace("/", slash);
+        System.out.println("buildJar packageName: " + packageName);
+
+        String testClasses = System.getProperty("test.classes", "?");
+        String testSrc = System.getProperty("test.src", "?");
+        String jarPath = testClasses + slash + jarName + ".jar";
+        String manifestPath = testSrc + slash + jarName + ".mf";
+        String className = packageName + slash + jarName + ".class";
+
+        String[] args = null;
+        if (withManifest) {
+            args = new String[] {"-cfm", jarPath, manifestPath, "-C", testClasses, className};
+        } else {
+            args = new String[] {"-cf", jarPath, "-C", testClasses, className};
+        }
+
+        log("Running jar " + Arrays.toString(args));
+        sun.tools.jar.Main jarTool = new sun.tools.jar.Main(System.out, System.err, "jar");
+        if (!jarTool.run(args)) {
+            throw new Exception("jar failed: args=" + Arrays.toString(args));
+        }
+    }
+
+    // Launch the test instance. Will run the internal class TestMain.
+    private static void launchTest() throws Throwable {
+        final String slash = File.separator;
+
+        // Need to add jdk/lib/tools.jar to classpath.
+        String classpath =
+            System.getProperty("test.class.path", "") + File.pathSeparator +
+            System.getProperty("test.jdk", ".") + slash + "lib" + slash + "tools.jar";
+        String testClassDir = System.getProperty("test.classes", "") + slash;
+
+        String[] args = {
+            "-Xbootclasspath/a:" + testClassDir + "InstrumentationCallback.jar",
+            "--add-exports", "java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED",
+            "-classpath", classpath,
+            "-javaagent:" + testClassDir + "TestInstrumentation.jar",
+            "jdk.jfr.event.io.TestInstrumentation$TestMain" };
+        OutputAnalyzer output = ProcessTools.executeTestJvm(args);
+        output.shouldHaveExitValue(0);
+    }
+
+
+    ////////////////////////////////////////////////////////////////////
+    // This is the java agent part. Used to transform classes.
+    //
+    // Each transformed method will add this call:
+    // InstrumentationCallback.callback("<classname>::<methodname>");
+    ////////////////////////////////////////////////////////////////////
+
+    public static void premain(String args, Instrumentation inst) throws Exception {
+        instrumentation = inst;
+        testTransformer = new TestInstrumentation();
+        inst.addTransformer(testTransformer, true);
+    }
+
+    public byte[] transform(
+            ClassLoader classLoader, String className, Class<?> classBeingRedefined,
+            ProtectionDomain pd, byte[] bytes) throws IllegalClassFormatException {
+        // Check if this class should be instrumented.
+        if (!instrClassesTarget.contains(className)) {
+            return null;
+        }
+
+        boolean isRedefinition = classBeingRedefined != null;
+        log("instrument class(" + className + ") " + (isRedefinition ? "redef" : "load"));
+
+        ClassReader reader = new ClassReader(bytes);
+        ClassWriter writer = new ClassWriter(
+                reader, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
+        CallbackClassVisitor classVisitor = new CallbackClassVisitor(writer);
+        reader.accept(classVisitor, 0);
+        instrClassesDone.add(className);
+        return writer.toByteArray();
+    }
+
+    private static class CallbackClassVisitor extends ClassVisitor {
+        private String className;
+
+        public CallbackClassVisitor(ClassVisitor cv) {
+            super(Opcodes.ASM5, cv);
+        }
+
+        @Override
+        public void visit(
+                int version, int access, String name, String signature,
+                String superName, String[] interfaces) {
+            cv.visit(version, access, name, signature, superName, interfaces);
+            className = name;
+        }
+
+        @Override
+        public MethodVisitor visitMethod(
+                int access, String methodName, String desc, String signature, String[] exceptions) {
+            String methodKey = getInstrMethodKey(className, methodName, desc);
+            boolean isInstrumentedMethod = Arrays.asList(instrMethodKeys).contains(methodKey);
+            MethodVisitor mv = cv.visitMethod(access, methodName, desc, signature, exceptions);
+            if (isInstrumentedMethod && mv != null) {
+                mv = new CallbackMethodVisitor(mv, methodKey);
+                log("instrumented " + methodKey);
+            }
+            return mv;
+        }
+    }
+
+    public static class CallbackMethodVisitor extends MethodVisitor {
+        private String logMessage;
+
+        public CallbackMethodVisitor(MethodVisitor mv, String logMessage) {
+            super(Opcodes.ASM5, mv);
+            this.logMessage = logMessage;
+        }
+
+        @Override
+        public void visitCode() {
+            mv.visitCode();
+            String methodDescr = Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(String.class));
+            String className = InstrumentationCallback.class.getName().replace('.', '/');
+            mv.visitLdcInsn(logMessage);
+            mv.visitMethodInsn(Opcodes.INVOKESTATIC, className, "callback", methodDescr);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/io/TestInstrumentation.mf	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,4 @@
+Manifest-Version: 1.0
+Premain-Class: jdk.jfr.event.io.TestInstrumentation
+Can-Redefine-Classes: true
+Can-Retransform-Classes: true
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/io/TestRandomAccessFileEvents.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.io;
+
+import static jdk.test.lib.Asserts.assertEquals;
+
+import java.io.File;
+import java.io.RandomAccessFile;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.event.io.TestRandomAccessFileEvents
+ */
+public class TestRandomAccessFileEvents {
+
+    public static void main(String[] args) throws Throwable {
+        File tmp = File.createTempFile("TestRandomAccessFileEvents", ".tmp", new File("."));
+        tmp.deleteOnExit();
+        Recording recording = new Recording();
+        List<IOEvent> expectedEvents = new ArrayList<>();
+
+        recording.enable(IOEvent.EVENT_FILE_WRITE).withThreshold(Duration.ofMillis(0));
+        recording.enable(IOEvent.EVENT_FILE_READ).withThreshold(Duration.ofMillis(0));
+        recording.start();
+
+        RandomAccessFile ras = new RandomAccessFile(tmp, "rw");
+        int writeInt = 47;
+        byte[] writeBuffer = {10,11,12,13};
+
+        // Write an int and a buffer.
+        ras.write(writeInt);
+        expectedEvents.add(IOEvent.createFileWriteEvent(1, tmp));
+        ras.write(writeBuffer);
+        expectedEvents.add(IOEvent.createFileWriteEvent(writeBuffer.length, tmp));
+
+        ras.seek(0);
+
+        // Read int and buffer
+        int readInt = ras.read();
+        assertEquals(readInt, writeInt, "wrong int read");
+        expectedEvents.add(IOEvent.createFileReadEvent(1, tmp));
+        byte[] readBuffer = new byte [writeBuffer.length];
+        int size = ras.read(readBuffer);
+        verifyBufferEquals(readBuffer, writeBuffer);
+        expectedEvents.add(IOEvent.createFileReadEvent(readBuffer.length, tmp));
+
+        // Read beyond EOF
+        readInt = ras.read();
+        assertEquals(-1, readInt, "wrong read after EOF");
+        expectedEvents.add(IOEvent.createFileReadEvent(-1, tmp));
+
+        // Seek to beginning and verify we can read after EOF.
+        ras.seek(0);
+        readInt = ras.read();
+        assertEquals(readInt, writeInt, "wrong int read after seek(0)");
+        expectedEvents.add(IOEvent.createFileReadEvent(1, tmp));
+
+        // seek beyond EOF and verify we get EOF when reading.
+        ras.seek(10);
+        readInt = ras.read();
+        assertEquals(-1, readInt, "wrong read after seek beyond EOF");
+        expectedEvents.add(IOEvent.createFileReadEvent(-1, tmp));
+
+        // Read partial buffer.
+        int partialSize = writeBuffer.length - 2;
+        ras.seek(ras.length()-partialSize);
+        size = ras.read(readBuffer);
+        assertEquals(size, partialSize, "Wrong size partial buffer read");
+        expectedEvents.add(IOEvent.createFileReadEvent(size, tmp));
+
+        ras.close();
+        recording.stop();
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        IOHelper.verifyEqualsInOrder(events, expectedEvents);
+    }
+
+    private static void verifyBufferEquals(byte[] a, byte[] b) {
+        assertEquals(a.length, b.length, "Wrong buffer size");
+        for (int i = 0; i < a.length; ++i) {
+            assertEquals(a[i], b[i], "Wrong buffer content at pos " + i);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/io/TestRandomAccessFileThread.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.io;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.thread.TestThread;
+import jdk.test.lib.thread.XRun;
+
+
+/*
+ * @test
+ * @summary Verify the event time stamp and thread name
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps jdk.jfr.event.io.TestRandomAccessFileThread
+ */
+
+// TODO: This test should work without -XX:-UseFastUnorderedTimeStamps
+
+// The test uses 2 threads to read and write to a file.
+// The number of bytes in each read/write operation is increased by 1.
+// By looking at the number of bytes in each event, we know in what order
+// the events should arrive. This is used to verify the event time stamps.
+public class TestRandomAccessFileThread {
+    private static final int OP_COUNT = 100;    // Total number of read/write operations.
+    private static volatile int writeCount = 0; // Number of writes executed.
+
+    public static void main(String[] args) throws Throwable {
+        File tmp = File.createTempFile("TestRandomAccessFileThread", ".tmp", new File("."));
+        tmp.deleteOnExit();
+
+        Recording recording = new Recording();
+        recording.enable(IOEvent.EVENT_FILE_READ).withThreshold(Duration.ofMillis(0));
+        recording.enable(IOEvent.EVENT_FILE_WRITE).withThreshold(Duration.ofMillis(0));
+        recording.start();
+
+        TestThread writerThread = new TestThread(new XRun() {
+            @Override
+            public void xrun() throws IOException {
+                final byte[] buf = new byte[OP_COUNT];
+                for (int i = 0; i < buf.length; ++i) {
+                    buf[i] = (byte)((i + 'a') % 255);
+                }
+                try (RandomAccessFile raf = new RandomAccessFile(tmp, "rwd")) {
+                    for(int i = 0; i < OP_COUNT; ++i) {
+                        raf.write(buf, 0, i + 1);
+                        writeCount++;
+                    }
+                }
+            }}, "TestWriterThread");
+
+            TestThread readerThread = new TestThread(new XRun() {
+            @Override
+            public void xrun() throws IOException {
+                try (RandomAccessFile raf = new RandomAccessFile(tmp, "r")) {
+                    byte[] buf = new byte[OP_COUNT];
+                    for(int i = 0; i < OP_COUNT; ++i) {
+                        while (writeCount <= i) {
+                            // No more data to read. Wait for writer thread.
+                            Thread.yield();
+                        }
+                        int expectedSize = i + 1;
+                        int actualSize = raf.read(buf, 0, expectedSize);
+                        Asserts.assertEquals(actualSize, expectedSize, "Wrong read size. Probably test error.");
+                    }
+                }
+            }}, "TestReaderThread");
+
+            readerThread.start();
+            writerThread.start();
+            writerThread.joinAndThrow();
+            readerThread.joinAndThrow();
+            recording.stop();
+
+            List<RecordedEvent> events = Events.fromRecording(recording);
+            events.sort(new EventComparator());
+
+            List<RecordedEvent> readEvents = new ArrayList<>();
+            List<RecordedEvent> writeEvents = new ArrayList<>();
+            for (RecordedEvent event : events) {
+                if (!isOurEvent(event, tmp)) {
+                    continue;
+                }
+                logEventSummary(event);
+                if (Events.isEventType(event,IOEvent.EVENT_FILE_READ)) {
+                    readEvents.add(event);
+                } else {
+                    writeEvents.add(event);
+                }
+            }
+
+            verifyThread(readEvents, readerThread);
+            verifyThread(writeEvents, writerThread);
+            verifyBytes(readEvents, "bytesRead");
+            verifyBytes(writeEvents, "bytesWritten");
+            verifyTimes(readEvents);
+            verifyTimes(writeEvents);
+            verifyReadWriteTimes(readEvents, writeEvents);
+
+            Asserts.assertEquals(readEvents.size(), OP_COUNT, "Wrong number of read events");
+            Asserts.assertEquals(writeEvents.size(), OP_COUNT, "Wrong number of write events");
+        }
+
+        private static void logEventSummary(RecordedEvent event) {
+            boolean isRead = Events.isEventType(event, IOEvent.EVENT_FILE_READ);
+            String name = isRead ? "read " : "write";
+            String bytesField = isRead ? "bytesRead" : "bytesWritten";
+            long bytes = Events.assertField(event, bytesField).getValue();
+            long commit = Events.assertField(event, "startTime").getValue();
+            Instant start = event.getStartTime();
+            Instant end = event.getEndTime();
+            System.out.printf("%s: bytes=%d, commit=%d, start=%s, end=%s%n", name, bytes, commit, start, end);
+        }
+
+        private static void verifyThread(List<RecordedEvent> events, Thread thread) {
+            events.stream().forEach(e -> Events.assertEventThread(e, thread));
+        }
+
+        private static void verifyBytes(List<RecordedEvent> events, String fieldName) {
+            long expectedBytes = 0;
+            for (RecordedEvent event : events) {
+                Events.assertField(event, fieldName).equal(++expectedBytes);
+            }
+        }
+
+        // Verify that all times are increasing
+        private static void verifyTimes(List<RecordedEvent> events) {
+            RecordedEvent prev = null;
+            for (RecordedEvent curr : events) {
+                if (prev != null) {
+                    try {
+                        Asserts.assertGreaterThanOrEqual(curr.getStartTime(), prev.getStartTime(), "Wrong startTime");
+                        Asserts.assertGreaterThanOrEqual(curr.getEndTime(), prev.getEndTime(), "Wrong endTime");
+                        long commitPrev = Events.assertField(prev, "startTime").getValue();
+                        long commitCurr = Events.assertField(curr, "startTime").getValue();
+                        Asserts.assertGreaterThanOrEqual(commitCurr, commitPrev, "Wrong commitTime");
+                    } catch (Exception e) {
+                        System.out.println("Error: " + e.getMessage());
+                        System.out.println("Prev Event: " + prev);
+                        System.out.println("Curr Event: " + curr);
+                        throw e;
+                    }
+                }
+                prev = curr;
+            }
+        }
+
+        // Verify that all times are increasing
+        private static void verifyReadWriteTimes(List<RecordedEvent> readEvents, List<RecordedEvent> writeEvents) {
+            List<RecordedEvent> events = new ArrayList<>();
+            events.addAll(readEvents);
+            events.addAll(writeEvents);
+            events.sort(new EventComparator());
+
+            int countRead = 0;
+            int countWrite = 0;
+            for (RecordedEvent event : events) {
+                if (Events.isEventType(event, IOEvent.EVENT_FILE_READ)) {
+                    ++countRead;
+                } else {
+                    ++countWrite;
+                }
+                // We can not read from the file before it has been written.
+                // This check verifies that times of different threads are correct.
+                // Since the read and write are from different threads, it is possible that the read
+                // is committed before the same write.
+                // But read operation may only be 1 step ahead of the write operation.
+                Asserts.assertLessThanOrEqual(countRead, countWrite + 1, "read must be after write");
+            }
+        }
+
+        private static boolean isOurEvent(RecordedEvent event, File file) {
+            if (!Events.isEventType(event, IOEvent.EVENT_FILE_READ) &&
+                !Events.isEventType(event, IOEvent.EVENT_FILE_WRITE)) {
+                return false;
+            }
+            String path = Events.assertField(event, "path").getValue();
+            return file.getPath().equals(path);
+        }
+
+        private static class EventComparator implements Comparator<RecordedEvent> {
+            @Override
+            public int compare(RecordedEvent a, RecordedEvent b) {
+                long commitA = Events.assertField(a, "startTime").getValue();
+                long commitB = Events.assertField(b, "startTime").getValue();
+                return Long.compare(commitA, commitB);
+            }
+        }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/io/TestSocketChannelEvents.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.io;
+
+import static jdk.test.lib.Asserts.assertEquals;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.thread.TestThread;
+import jdk.test.lib.thread.XRun;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.event.io.TestSocketChannelEvents
+ */
+public class TestSocketChannelEvents {
+    private static final int bufSizeA = 10;
+    private static final int bufSizeB = 20;
+
+    private List<IOEvent> expectedEvents = new ArrayList<>();
+    private synchronized void addExpectedEvent(IOEvent event) {
+        expectedEvents.add(event);
+    }
+
+    public static void main(String[] args) throws Throwable {
+        new TestSocketChannelEvents().test();
+    }
+
+    public void test() throws Throwable {
+        Recording recording = new Recording();
+
+        try (ServerSocketChannel ss = ServerSocketChannel.open()) {
+            recording.enable(IOEvent.EVENT_SOCKET_READ).withThreshold(Duration.ofMillis(0));
+            recording.enable(IOEvent.EVENT_SOCKET_WRITE).withThreshold(Duration.ofMillis(0));
+            recording.start();
+
+            ss.socket().setReuseAddress(true);
+            ss.socket().bind(null);
+
+            TestThread readerThread = new TestThread(new XRun() {
+                @Override
+                public void xrun() throws IOException {
+                    ByteBuffer bufA = ByteBuffer.allocate(bufSizeA);
+                    ByteBuffer bufB = ByteBuffer.allocate(bufSizeB);
+                    try (SocketChannel sc = ss.accept()) {
+                        int readSize = sc.read(bufA);
+                        assertEquals(readSize, bufSizeA, "Wrong readSize bufA");
+                        addExpectedEvent(IOEvent.createSocketReadEvent(bufSizeA, sc.socket()));
+
+                        bufA.clear();
+                        bufA.limit(1);
+                        readSize = (int)sc.read(new ByteBuffer[] { bufA, bufB });
+                        assertEquals(readSize, 1 + bufSizeB, "Wrong readSize 1+bufB");
+                        addExpectedEvent(IOEvent.createSocketReadEvent(readSize, sc.socket()));
+
+                        // We try to read, but client have closed. Should get EOF.
+                        bufA.clear();
+                        bufA.limit(1);
+                        readSize = sc.read(bufA);
+                        assertEquals(readSize, -1, "Wrong readSize at EOF");
+                        addExpectedEvent(IOEvent.createSocketReadEvent(-1, sc.socket()));
+                    }
+                }
+            });
+            readerThread.start();
+
+            try (SocketChannel sc = SocketChannel.open(ss.socket().getLocalSocketAddress())) {
+                ByteBuffer bufA = ByteBuffer.allocateDirect(bufSizeA);
+                ByteBuffer bufB = ByteBuffer.allocateDirect(bufSizeB);
+                for (int i = 0; i < bufSizeA; ++i) {
+                    bufA.put((byte)('a' + (i % 20)));
+                }
+                for (int i = 0; i < bufSizeB; ++i) {
+                    bufB.put((byte)('A' + (i % 20)));
+                }
+                bufA.flip();
+                bufB.flip();
+
+                sc.write(bufA);
+                addExpectedEvent(IOEvent.createSocketWriteEvent(bufSizeA, sc.socket()));
+
+                bufA.clear();
+                bufA.limit(1);
+                int bytesWritten = (int)sc.write(new ByteBuffer[] { bufA, bufB });
+                assertEquals(bytesWritten, 1 + bufSizeB, "Wrong bytesWritten 1+bufB");
+                addExpectedEvent(IOEvent.createSocketWriteEvent(bytesWritten, sc.socket()));
+            }
+
+            readerThread.joinAndThrow();
+            recording.stop();
+            List<RecordedEvent> events= Events.fromRecording(recording);
+            IOHelper.verifyEquals(events, expectedEvents);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/io/TestSocketEvents.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.io;
+
+import static jdk.test.lib.Asserts.assertEquals;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.thread.TestThread;
+import jdk.test.lib.thread.XRun;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.event.io.TestSocketEvents
+ */
+public class TestSocketEvents {
+
+    private static final int writeInt = 'A';
+    private static final byte[] writeBuf = { 'B', 'C', 'D', 'E' };
+
+    private List<IOEvent> expectedEvents = new ArrayList<>();
+    private synchronized void addExpectedEvent(IOEvent event) {
+        expectedEvents.add(event);
+    }
+
+    public static void main(String[] args) throws Throwable {
+        new TestSocketEvents().test();
+    }
+
+    private void test() throws Throwable {
+        Recording recording = new Recording();
+
+        try (ServerSocket ss = new ServerSocket()) {
+            recording.enable(IOEvent.EVENT_SOCKET_READ).withThreshold(Duration.ofMillis(0));
+            recording.enable(IOEvent.EVENT_SOCKET_WRITE).withThreshold(Duration.ofMillis(0));
+            recording.start();
+
+            ss.setReuseAddress(true);
+            ss.bind(null);
+
+            TestThread readerThread = new TestThread(new XRun() {
+                @Override
+                public void xrun() throws IOException {
+                    byte[] bs = new byte[4];
+                    try (Socket s = ss.accept(); InputStream is = s.getInputStream()) {
+                        int readInt = is.read();
+                        assertEquals(readInt, writeInt, "Wrong readInt");
+                        addExpectedEvent(IOEvent.createSocketReadEvent(1, s));
+
+                        int bytesRead = is.read(bs, 0, 3);
+                        assertEquals(bytesRead, 3, "Wrong bytesRead partial buffer");
+                        addExpectedEvent(IOEvent.createSocketReadEvent(bytesRead, s));
+
+                        bytesRead = is.read(bs);
+                        assertEquals(bytesRead, writeBuf.length, "Wrong bytesRead full buffer");
+                        addExpectedEvent(IOEvent.createSocketReadEvent(bytesRead, s));
+
+                        // Try to read more, but writer have closed. Should get EOF.
+                        readInt = is.read();
+                        assertEquals(readInt, -1, "Wrong readInt at EOF");
+                        addExpectedEvent(IOEvent.createSocketReadEvent(-1, s));
+                   }
+                }
+            });
+            readerThread.start();
+
+            try (Socket s = new Socket()) {
+                s.connect(ss.getLocalSocketAddress());
+                try (OutputStream os = s.getOutputStream()) {
+                    os.write(writeInt);
+                    addExpectedEvent(IOEvent.createSocketWriteEvent(1, s));
+                    os.write(writeBuf, 0, 3);
+                    addExpectedEvent(IOEvent.createSocketWriteEvent(3, s));
+                    os.write(writeBuf);
+                    addExpectedEvent(IOEvent.createSocketWriteEvent(writeBuf.length, s));
+                }
+            }
+
+            readerThread.joinAndThrow();
+            recording.stop();
+            List<RecordedEvent> events = Events.fromRecording(recording);
+            IOHelper.verifyEquals(events, expectedEvents);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/metadata/TestDefaultConfigurations.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.metadata;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import jdk.jfr.Configuration;
+import jdk.jfr.EventType;
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.SettingDescriptor;
+import jdk.test.lib.jfr.EventNames;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @library /test/lib
+ * @modules java.xml
+ *          jdk.jfr
+ *
+ * @run main/othervm jdk.jfr.event.metadata.TestDefaultConfigurations
+ */
+public class TestDefaultConfigurations {
+
+    private static final String LINE_SEPARATOR = System.getProperty("line.separator");
+
+    public static void main(String[] args) throws Exception {
+        List<String> errors = new ArrayList<>();
+
+        errors.addAll(testConfiguration(Configuration.getConfiguration("default")));
+        errors.addAll(testConfiguration(Configuration.getConfiguration("profile")));
+
+        if (!errors.isEmpty()) {
+            throwExceptionWithErrors(errors);
+        }
+    }
+
+    private static List<String> testConfiguration(Configuration config) throws ParserConfigurationException, SAXException, IOException {
+        List<String> errors = new ArrayList<>();
+
+        Map<String, EventType> eventTypeLookup = new HashMap<>();
+        for (EventType t : FlightRecorder.getFlightRecorder().getEventTypes()) {
+            eventTypeLookup.put(t.getName(), t);
+        }
+        String content = config.getContents();
+        Document doc = createDocument(content);
+        Element configuration = doc.getDocumentElement();
+        errors.addAll(checkConfiguration(configuration));
+        for (Element event : getChildElements(configuration, "event")) {
+            String name = event.getAttribute("name");
+
+            EventType cd = eventTypeLookup.get(name);
+            if (cd != null) {
+                errors.addAll(checkSettings(config, cd, event));
+            } else {
+                errors.add("Preset '" + config.getName() + "' reference unknown event '" + name + "'");
+            }
+            eventTypeLookup.remove(name);
+        }
+        for (String name : eventTypeLookup.keySet()) {
+            errors.add("Preset '" + config.getName() + "' doesn't configure event '" + name + "'");
+        }
+
+        return errors;
+    }
+
+    private static void throwExceptionWithErrors(List<String> errors) throws Exception {
+        StringBuilder sb = new StringBuilder();
+        for (String error : errors) {
+            sb.append(error);
+            sb.append(LINE_SEPARATOR);
+        }
+        throw new Exception(sb.toString());
+    }
+
+    private static List<String> checkConfiguration(Element configuration) {
+        List<String> errors = new ArrayList<>();
+        if (configuration.getAttribute("description").length() < 2) {
+            errors.add("Configuration should have a valid description!");
+        }
+        if (configuration.getAttribute("label").length() < 2) {
+            errors.add("Configuration should have a label!");
+        }
+        if (!configuration.getAttribute("provider").equals("Oracle")) {
+            errors.add("Configuration should set provider to 'Oracle'!");
+        }
+        return errors;
+    }
+
+    private static List<String> checkSettings(Configuration config, EventType eventType, Element event) {
+        List<String> errors = new ArrayList<>();
+
+        Set<String> requiredSettings = createRequiredSettingNameSet(eventType);
+        for (Element setting : getChildElements(event, "setting")) {
+            String settingName = setting.getAttribute("name");
+            if (requiredSettings.contains(settingName)) {
+                requiredSettings.remove(settingName);
+            } else {
+                errors.add("Setting '" + settingName + "' for event '" + eventType.getName() + "' should not be part of confirguaration '" + config.getName()
+                        + "' since it won't have an impact on the event.");
+            }
+        }
+        for (String required : requiredSettings) {
+            errors.add("Setting '" + required + "' in event '" + eventType.getName() + "' was not configured in the configuration '" + config.getName() + "'");
+        }
+
+        return errors;
+    }
+
+    private static Set<String> createRequiredSettingNameSet(EventType cd) {
+        Set<String> requiredSettings = new HashSet<>();
+        for (SettingDescriptor s : cd.getSettingDescriptors()) {
+            requiredSettings.add(s.getName());
+        }
+        return requiredSettings;
+    }
+
+    private static Document createDocument(String content) throws ParserConfigurationException, SAXException, IOException {
+        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
+        DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
+        Document doc = dBuilder.parse(new InputSource(new StringReader(content)));
+        doc.getDocumentElement().normalize();
+        // Don't want to add these settings to the jfc-files we ship since they
+        // are not useful to configure. They are however needed to make the test
+        // pass.
+        insertSetting(doc, EventNames.ActiveSetting, "stackTrace", "false");
+        insertSetting(doc, EventNames.ActiveSetting, "threshold", "0 ns");
+        insertSetting(doc, EventNames.ActiveRecording, "stackTrace", "false");
+        insertSetting(doc, EventNames.ActiveRecording, "threshold", "0 ns");
+        insertSetting(doc, EventNames.JavaExceptionThrow, "threshold", "0 ns");
+        insertSetting(doc, EventNames.JavaErrorThrow, "threshold", "0 ns");
+        return doc;
+    }
+
+    private static void insertSetting(Document doc, String eventName, String settingName, String settingValue) {
+        for (Element event : getChildElements(doc.getDocumentElement(), "event")) {
+            Attr attribute = event.getAttributeNode("name");
+            if (attribute != null) {
+                if (eventName.equals(attribute.getValue())) {
+                    Element setting = doc.createElement("setting");
+                    setting.setAttribute("name", settingName);
+                    setting.setTextContent(settingValue);
+                    event.appendChild(setting);
+                }
+            }
+        }
+    }
+
+    private static Collection<Element> getChildElements(Element parent, String name) {
+        NodeList elementsByTagName = parent.getElementsByTagName(name);
+        List<Element> elements = new ArrayList<>();
+        for (int i = 0; i < elementsByTagName.getLength(); i++) {
+            Node node = elementsByTagName.item(i);
+            if (node.getNodeType() == Node.ELEMENT_NODE) {
+                elements.add((Element) node);
+            }
+        }
+        return elements;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/metadata/TestEventMetadata.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.metadata;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import jdk.jfr.EventType;
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.ValueDescriptor;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.event.metadata.TestEventMetadata
+ */
+
+public class TestEventMetadata {
+
+    /*
+     * Short guide to writing event metadata
+     * =====================================
+
+     * Name
+     * ----
+     *
+     * Symbolic name that is used to identify an event, or a field. Referred to
+     * as "id" and "field" in trace.xml-files and @Name in the Java API. If it is
+     * the name of an event, the name should be prefixed "jdk.", which
+     * happens automatically for native events.
+     *
+     * The name should be short, but not so brief that collision is likely with
+     * future events or fields. It should only consist of letters and numbers.
+     * Use Java naming convention , i.e. "FileRead" for an event and
+     * "allocationRate" for a field. Do not use "_" and don't add the word
+     * "Event" to the event name.
+     *
+     * Abbreviations should be avoided, but may be acceptable if the name
+     * becomes long, or if it is a well established acronym. Write whole words,
+     * i.e. "allocation" instead of "alloc". The name should not be a reserved
+     * Java keyword, i.e "void" or "class".
+     *
+     * Label
+     * -----
+     *
+     * Describes a human-readable name, typically 1-3 words. Use headline-style
+     * capitalization, capitalize the first and last words, and all nouns,
+     * pronouns, adjectives, verbs and adverbs. Do not include ending
+     * punctuation.
+     *
+     * Description
+     * -----------
+     *
+     * Describes an event with a sentence or two. It's better to omit the
+     * description then copying the label. Use sentence-style
+     * capitalization, capitalize the first letter of the first word, and any
+     * proper names such as the word Java. If the description is one sentence,
+     * period should not be included.
+     *
+     *
+     * Do not forget to set proper units for fields, i.e "NANOS", "MILLS",
+     * "TICKSPAN" ,"BYETS", "PECENTAGE" etc. in native and @Timespan, @Timespan
+     * etc. in Java.
+     */
+    public static void main(String[] args) throws Exception {
+        Set<String> types = new HashSet<>();
+        List<EventType> eventTypes = FlightRecorder.getFlightRecorder().getEventTypes();
+        Set<String> eventNames= new HashSet<>();
+        for (EventType eventType : eventTypes) {
+            verifyEventType(eventType);
+            verifyValueDesscriptors(eventType.getFields(), types);
+            System.out.println();
+            String eventName = eventType.getName();
+            if (eventNames.contains(eventName)) {
+                throw new Exception("Event with name " +eventName+ " already exists");
+            }
+            eventNames.add(eventName);
+            Set<String> fieldNames = new HashSet<>();
+            for (ValueDescriptor v : eventType.getFields()) {
+                String fieldName = v.getName();
+                if (fieldNames.contains(fieldName)) {
+                    throw new Exception("Field with name " + fieldName +" is already in use in event name " +eventName);
+                }
+                fieldNames.add(fieldName);
+            }
+        }
+    }
+
+    private static void verifyValueDesscriptors(List<ValueDescriptor> fields, Set<String> visitedTypes) {
+        for (ValueDescriptor v : fields) {
+            if (!visitedTypes.contains(v.getTypeName())) {
+                visitedTypes.add(v.getTypeName());
+                verifyValueDesscriptors(v.getFields(), visitedTypes);
+            }
+            verifyValueDescriptor(v);
+        }
+    }
+
+    private static void verifyValueDescriptor(ValueDescriptor v) {
+        verifyName(v.getName());
+        verifyLabel(v.getLabel());
+        verifyDescription(v.getDescription());
+    }
+
+    private static void verifyDescription(String description) {
+        if (description == null) {
+            return;
+        }
+        Asserts.assertTrue(description.length() > 10, "Description must be at least ten characters");
+        Asserts.assertTrue(description.length() < 300, "Description should not exceed 300 characters. Found " + description);
+        Asserts.assertTrue(description.length() == description.trim().length(), "Description should not have trim character at start or end");
+        Asserts.assertFalse(description.endsWith(".") && description.indexOf(".") == description.length() - 1, "Single sentence descriptions should not use end punctuation");
+    }
+
+    private static void verifyName(String name) {
+        System.out.println("Verifying name: " + name);
+        Asserts.assertNotEquals(name, null, "Name not allowed to be null");
+        Asserts.assertTrue(name.length() > 1, "Name must be at least two characters");
+        Asserts.assertTrue(name.length() < 32, "Name should not exceed 32 characters");
+        Asserts.assertFalse(isReservedKeyword(name),"Name must not be reserved keyword in the Java language (" + name + ")");
+        char firstChar = name.charAt(0);
+        Asserts.assertTrue(Character.isAlphabetic(firstChar), "Name must start with a character");
+        Asserts.assertTrue(Character.isLowerCase(firstChar), "Name must start with lower case letter");
+        Asserts.assertTrue(Character.isJavaIdentifierStart(firstChar), "Not valid first character for Java identifier");
+        for (int i = 1; i < name.length(); i++) {
+            Asserts.assertTrue(Character.isJavaIdentifierPart(name.charAt(i)), "Not valid character for a Java identifier");
+            Asserts.assertTrue(Character.isAlphabetic(name.charAt(i)), "Name must consists of characters, found '" + name.charAt(i) + "'");
+        }
+        Asserts.assertFalse(name.contains("ID"), "'ID' should not be used in name, consider using 'Id'");
+        checkCommonAbbreviations(name);
+    }
+
+    private static void verifyLabel(String label) {
+        Asserts.assertNotEquals(label, null, "Label not allowed to be null");
+        Asserts.assertTrue(label.length() > 1, "Name must be at least two characters");
+        Asserts.assertTrue(label.length() < 45, "Label should not exceed 45 characters, use description to explain " + label);
+        Asserts.assertTrue(label.length() == label.trim().length(), "Label should not have trim character at start and end");
+        Asserts.assertTrue(Character.isUpperCase(label.charAt(0)), "Label should start with upper case letter");
+        for (int i = 0; i < label.length(); i++) {
+            char c = label.charAt(i);
+            Asserts.assertTrue(Character.isDigit(c) || Character.isAlphabetic(label.charAt(i)) || c == ' ' || c == '(' || c == ')' || c == '-', "Label should only consist of letters or space, found '" + label.charAt(i)
+                    + "'");
+        }
+    }
+
+    private static void verifyEventType(EventType eventType) {
+        System.out.println("Verifying event: " + eventType.getName());
+        verifyDescription(eventType.getDescription());
+        verifyLabel(eventType.getLabel());
+        Asserts.assertNotEquals(eventType.getName(), null, "Name not allowed to be null");
+        Asserts.assertTrue(eventType.getName().startsWith(EventNames.PREFIX), "OpenJDK events must start with " + EventNames.PREFIX);
+        String name = eventType.getName().substring(EventNames.PREFIX.length());
+        Asserts.assertFalse(isReservedKeyword(name),"Name must not be reserved keyword in the Java language (" + name + ")");
+        checkCommonAbbreviations(name);
+          char firstChar = name.charAt(0);
+        Asserts.assertFalse(name.contains("ID"), "'ID' should not be used in name, consider using 'Id'");
+        Asserts.assertTrue(Character.isAlphabetic(firstChar), "Name " + name + " must start with a character");
+        Asserts.assertTrue(Character.isUpperCase(firstChar), "Name " + name + " must start with upper case letter");
+        for (int i = 0; i < name.length(); i++) {
+            char c = name.charAt(i);
+            Asserts.assertTrue(Character.isAlphabetic(c) || Character.isDigit(c), "Name " + name + " must consists of characters or numbers, found '" + name.charAt(i) + "'");
+        }
+    }
+
+    static boolean isReservedKeyword(String s) {
+        String[] keywords = new String[] {
+                // "module", "requires", "exports", "to", "uses", "provides", "with", module-info.java
+                "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue", "default", "do", "double", "else", "enum",
+                "extends", "false", "final", "finally", "float", "for", "goto", "if", "implements", "import", "instanceof", "int", "interface", "long", "native", "new", "null", "package", "private",
+                "protected", "public", "return", "short", "static", "strictfp", "super", "switch", "synchronized", "this", "throw", "throws", "transient", "true", "try", "void", "volatile", "while" };
+        for (int i = 0; i < keywords.length; i++) {
+            if (s.equals(keywords[i])) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static void checkCommonAbbreviations(String name) {
+        String lowerCased = name.toLowerCase();
+        Asserts.assertFalse(lowerCased.contains("info") && !lowerCased.contains("information"), "Use 'information' instead 'info' in name");
+        Asserts.assertFalse(lowerCased.contains("alloc") && !lowerCased.contains("alloca"), "Use 'allocation' instead 'alloc' in name");
+        Asserts.assertFalse(lowerCased.contains("config") && !lowerCased.contains("configuration"), "Use 'configuration' instead of 'config' in name");
+        Asserts.assertFalse(lowerCased.contains("evac") && !lowerCased.contains("evacu"), "Use 'evacuation' instead of 'evac' in name");
+        Asserts.assertFalse(lowerCased.contains("stat") && !(lowerCased.contains("state") ||lowerCased.contains("statistic")) , "Use 'statistics' instead of 'stat' in name");
+        Asserts.assertFalse(name.contains("ID") , "Use 'id' or 'Id' instead of 'ID' in name");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/oldobject/OldObjects.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.oldobject;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.function.Predicate;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedClass;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedFrame;
+import jdk.jfr.consumer.RecordedMethod;
+import jdk.jfr.consumer.RecordedObject;
+import jdk.jfr.consumer.RecordedStackTrace;
+import jdk.test.lib.jfr.Events;
+
+/**
+ * Utility class to perform Old Object provocation/detection and
+ * stack trace/object verification for the Old Object Sample JFR event
+ */
+final public class OldObjects {
+
+    public static final int MIN_SIZE = 99901; // prime number
+    public final static int LEAK_CONTEXT = 100; // length of chain assiociated with the object sample
+    public final static int ROOT_CONTEXT = 100; // length of chain assoicated with the root
+    public final static int MAX_CHAIN_LENGTH = LEAK_CONTEXT + ROOT_CONTEXT; // the VM should not construct chains longer than this
+
+    private static String[] getFrames(String expectedFrame) {
+        if (expectedFrame != null) {
+            return new String[] { expectedFrame };
+        } else {
+            return null;
+        }
+    }
+
+    /**
+    *
+    * @param r
+    *            A recording
+    * @param expectedFrame
+    *            A frame that must be found on the stack. Null if no check is required.
+    * @param fieldType
+    *            The object type (of the field). Null if no check is required.
+    * @param fieldName
+    *            The field name. Null if no check is required.
+    * @param referrerType
+    *            The class name. Null if no check is required.
+    * @param minDuration
+    *            The minimum duration of the event, -1 if not applicable.
+    * @return The count of matching events
+    * @throws IOException
+    */
+   public static long countMatchingEvents(Recording r, String expectedFrame, Class<?> fieldType, String fieldName, Class<?> referrerType, long minDuration) throws IOException {
+       return countMatchingEvents(r, getFrames(expectedFrame), fieldType, fieldName, referrerType, minDuration);
+   }
+
+    /**
+     * Gets the OldObjectSample events from the provided recording through a dump
+     * and counts how many events matches the provided parameters.
+     *
+     * @param r
+     *            A recording
+     * @param expectedStack
+     *            Some frames that must be found on the stack. Null if no check is required.
+     * @param fieldType
+     *            The object type (of the field). Null if no check is required.
+     * @param fieldName
+     *            The field name. Null if no check is required.
+     * @param referrerType
+     *            The class name. Null if no check is required.
+     * @param minDuration
+     *            The minimum duration of the event, -1 if not applicable.
+     * @return The count of matching events
+     * @throws IOException
+     */
+    public static long countMatchingEvents(Recording r, String[] expectedStack, Class<?> fieldType, String fieldName, Class<?> referrerType, long minDuration) throws IOException {
+        return countMatchingEvents(Events.fromRecording(r), fieldType, fieldName, referrerType, minDuration, expectedStack);
+    }
+
+    /**
+    *
+    * @param events
+    *            A list of RecordedEvent.
+    * @param expectedFrame
+    *             A frame that must be found on the stack. Null if no check is required.
+    * @param fieldType
+    *            The object type (of the field). Null if no check is required.
+    * @param fieldName
+    *            The field name. Null if no check is required.
+    * @param referrerType
+    *            The class name. Null if no check is required.
+    * @param minDuration
+    *            The minimum duration of the event, -1 if not applicable.
+    * @return The count of matching events
+    * @throws IOException
+    */
+   public static long countMatchingEvents(List<RecordedEvent> events, String expectedFrame, Class<?> fieldType, String fieldName, Class<?> referrerType, long minDuration) throws IOException {
+       return countMatchingEvents(events, fieldType, fieldName, referrerType, minDuration, getFrames(expectedFrame));
+   }
+
+    /**
+     *
+     * @param events
+     *            The list of events to find matching events in
+     * @param expectedStack
+     *            Some frames that must be found on the stack. Null if no check is required.
+     * @param fieldType
+     *            The object type (of the field). Null if no check is required.
+     * @param fieldName
+     *            The field name. Null if no check is required.
+     * @param referrerType
+     *            The class name. Null if no check is required.
+     * @param minDuration
+     *            The minimum duration of the event, -1 if not applicable.
+     * @return The count of matching events
+     * @throws IOException
+     */
+    public static long countMatchingEvents(List<RecordedEvent> events, Class<?> fieldType, String fieldName, Class<?> referrerType, long minDuration, String... expectedStack) throws IOException {
+        String currentThread = Thread.currentThread().getName();
+        return events.stream()
+                .filter(hasJavaThread(currentThread))
+                .filter(fieldIsType(fieldType))
+                .filter(hasFieldName(fieldName))
+                .filter(isReferrerType(referrerType))
+                .filter(durationAtLeast(minDuration))
+                .filter(hasStackTrace(expectedStack))
+                .count();
+    }
+
+    private static Predicate<RecordedEvent> hasJavaThread(String expectedThread) {
+        if (expectedThread != null) {
+            return e -> e.getThread() != null && expectedThread.equals(e.getThread().getJavaName());
+        } else {
+            return e -> true;
+        }
+    }
+
+    private static Predicate<RecordedEvent> hasStackTrace(String[] expectedStack) {
+        if (expectedStack != null) {
+            return e -> matchingStackTrace(e.getStackTrace(), expectedStack);
+        } else {
+            return e -> true;
+        }
+    }
+
+    private static Predicate<RecordedEvent> fieldIsType(Class<?> fieldType) {
+        if (fieldType != null) {
+            return e -> e.hasField("object.type") && ((RecordedClass) e.getValue("object.type")).getName().equals(fieldType.getName());
+        } else {
+            return e -> true;
+        }
+    }
+
+    private static Predicate<RecordedEvent> hasFieldName(String fieldName) {
+        if (fieldName != null) {
+            return e -> {
+                RecordedObject referrer = e.getValue("object.referrer");
+                return referrer != null ? referrer.hasField("field.name") && referrer.getValue("field.name").equals(fieldName) : false;
+            };
+        } else {
+            return e -> true;
+        }
+    }
+
+    private static Predicate<RecordedEvent> isReferrerType(Class<?> referrerType) {
+        if (referrerType != null) {
+            return e -> {
+                RecordedObject referrer = e.getValue("object.referrer");
+                return referrer != null ? referrer.hasField("object.type") &&
+                                            ((RecordedClass) referrer.getValue("object.type")).getName().equals(referrerType.getName()) : false;
+            };
+        } else {
+            return e -> true;
+        }
+    }
+
+    private static Predicate<RecordedEvent> durationAtLeast(long minDurationMs) {
+        if (minDurationMs > 0) {
+            return e -> e.getDuration().toMillis() >= minDurationMs;
+        } else {
+            return e -> true;
+        }
+    }
+
+    public static boolean matchingReferrerClass(RecordedEvent event, String className) {
+        RecordedObject referrer = event.getValue("object.referrer");
+        if (referrer != null) {
+            if (!referrer.hasField("object.type")) {
+                return false;
+            }
+
+            String reportedClass = ((RecordedClass) referrer.getValue("object.type")).getName();
+            if (reportedClass.equals(className)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static String getReferrerFieldName(RecordedEvent event) {
+        RecordedObject referrer = event.getValue("object.referrer");
+        return referrer != null && referrer.hasField("field.name") ? referrer.getValue("field.name") : null;
+    }
+
+    public static boolean matchingStackTrace(RecordedStackTrace stack, String[] expectedStack) {
+        if (stack == null) {
+            return false;
+        }
+
+        List<RecordedFrame> frames = stack.getFrames();
+        int pos = findFramePos(frames, expectedStack[0]);
+
+        if (pos == -1) {
+            return false;
+        }
+
+        for (String expectedFrame : expectedStack) {
+            RecordedFrame f = frames.get(pos++);
+            String frame = frameToString(f);
+
+            if (!frame.contains(expectedFrame)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static int findFramePos(List<RecordedFrame> frames, String frame) {
+        int pos = 0;
+        for (RecordedFrame f : frames) {
+            if (frameToString(f).contains(frame)) {
+                return pos;
+            }
+            pos++;
+        }
+        return -1;
+    }
+
+    private static String frameToString(RecordedFrame f) {
+        RecordedMethod m = f.getMethod();
+        String methodName = m.getName();
+        String className = m.getType().getName();
+        return className + "." + methodName;
+    }
+
+    public static void validateReferenceChainLimit(RecordedEvent e, int maxLength) {
+        int length = 0;
+        RecordedObject object = e.getValue("object");
+        while (object != null) {
+            ++length;
+            RecordedObject referrer = object.getValue("referrer");
+            object = referrer != null ? referrer.getValue("object") : null;
+        }
+        if (length > maxLength) {
+            throw new RuntimeException("Reference chain max length not respected. Found a chain of length " + length);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/oldobject/TestAllocationTime.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.oldobject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Event;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedClass;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedObject;
+import jdk.jfr.internal.test.WhiteBox;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "null"
+ * @library /test/lib /test/jdk
+ * @modules jdk.jfr/jdk.jfr.internal.test
+ * @run main/othervm  -XX:TLABSize=2k -XX:-FastTLABRefill jdk.jfr.event.oldobject.TestAllocationTime
+ */
+public class TestAllocationTime {
+
+    private static class BeforeLeakEvent extends Event {
+    }
+    private static class AfterLeakEvent extends Event {
+    }
+    private static class Leak {
+    }
+
+    public static List<Leak[]> leak = new ArrayList<>(OldObjects.MIN_SIZE);
+
+    public static void main(String[] args) throws Exception {
+        WhiteBox.setWriteAllObjectSamples(true);
+
+        while(true) {
+            try (Recording recording = new Recording()) {
+                leak.clear();
+                recording.enable(EventNames.OldObjectSample).withStackTrace().with("cutoff", "1 h");
+                recording.start();
+
+                BeforeLeakEvent be = new BeforeLeakEvent();
+                be.commit();
+
+                // Allocate array to trigger sampling code path for interpreter / c1
+                for (int i = 0; i < OldObjects.MIN_SIZE; i++) {
+                    leak.add(new Leak[0]);
+                }
+
+                AfterLeakEvent ae = new AfterLeakEvent();
+                ae.commit();
+
+                recording.stop();
+
+                List<RecordedEvent> events = Events.fromRecording(recording);
+                Events.hasEvents(events);
+                RecordedObject sample = findLeak(events, BeforeLeakEvent.class.getName());
+                if (sample != null)  {
+                    long beforeTime = find(events, BeforeLeakEvent.class.getName()).getValue("startTime");
+                    long allocationTime = sample.getValue("allocationTime");
+                    long afterTime = find(events, AfterLeakEvent.class.getName()).getValue("startTime");
+                    System.out.println("Before time     : " + beforeTime);
+                    System.out.println("Allocation time : " + allocationTime);
+                    System.out.println("After time      : " + afterTime);
+
+                    if (allocationTime < beforeTime) {
+                        throw new Exception("Allocation should not happen this early");
+                    }
+                    if (allocationTime > afterTime) {
+                        throw new Exception("Allocation should not happen this late");
+                    }
+                    return; // sample ok
+                }
+            }
+        }
+    }
+
+    private static RecordedObject findLeak(List<RecordedEvent> events, String name) throws Exception {
+        for (RecordedEvent e : events) {
+            if (e.getEventType().getName().equals(EventNames.OldObjectSample)) {
+                RecordedObject object = e.getValue("object");
+                RecordedClass rc = object.getValue("type");
+                if (rc.getName().equals(Leak[].class.getName())) {
+                    return e;
+                }
+            }
+        }
+        return null;
+    }
+
+    private static RecordedEvent find(List<RecordedEvent> events, String name) throws Exception {
+        for (RecordedEvent e : events) {
+            if (e.getEventType().getName().equals(name)) {
+                return e;
+            }
+        }
+        throw new Exception("Could not find event with name " + name);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/oldobject/TestArrayInformation.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.oldobject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedClass;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedObject;
+import jdk.jfr.internal.test.WhiteBox;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "null"
+ * @library /test/lib /test/jdk
+ * @modules jdk.jfr/jdk.jfr.internal.test
+ * @run main/othervm -XX:TLABSize=2k jdk.jfr.event.oldobject.TestArrayInformation
+ */
+public class TestArrayInformation {
+
+    private static class ArrayLeak {
+    }
+
+    private static final int CHAIN_DEPTH = 50;
+    private static final int ARRAY_SIZE = 52;
+    private static final int ARRAY_INDEX = 26;
+
+    public static List<Object> leak = new ArrayList<>(25);
+
+    public static void main(String[] args) throws Exception {
+        WhiteBox.setWriteAllObjectSamples(true);
+
+        try (Recording recording = new Recording()) {
+            recording.enable(EventNames.OldObjectSample).withoutStackTrace().with("cutoff", "infinity");
+            recording.start();
+            for(int i = 0; i < 25; i++) {
+              leak.add( buildNestedArray(CHAIN_DEPTH));
+            }
+            recording.stop();
+            List<RecordedEvent> events = Events.fromRecording(recording);
+            Events.hasEvents(events);
+            verifyObjectArray(events);
+        }
+    }
+
+    private static void verifyObjectArray(List<RecordedEvent> events) throws Exception {
+        for (RecordedEvent e : events) {
+            RecordedObject object = e.getValue("object");
+            RecordedClass objectType = object.getValue("type");
+            RecordedObject referrer = object.getValue("referrer");
+            System.out.println(objectType.getName());
+            if (objectType.getName().equals(ArrayLeak[].class.getName())) {
+                for (int i = 0; i < CHAIN_DEPTH; i++) {
+                    object = referrer.getValue("object");
+                    if (object == null) {
+                        throw new Exception("Expected referrer object");
+                    }
+                    objectType = object.getValue("type");
+                    if (!objectType.getName().equals(Object[].class.getName())) {
+                        throw new Exception("Expect array class to be named " + Object[].class + " but found " + objectType.getName());
+                    }
+                    RecordedObject field = referrer.getValue("field");
+                    if (field != null) {
+                        throw new Exception("Didn't expect to find field");
+                    }
+                    RecordedObject array = referrer.getValue("array");
+                    if (array == null) {
+                        throw new Exception("Expected array object, but got null");
+                    }
+                    int index = referrer.getValue("array.index");
+                    if (index != ARRAY_INDEX) {
+                        throw new Exception("Expected array index: " + ARRAY_INDEX + ", but got " + index);
+                    }
+                    int size = referrer.getValue("array.size");
+                    if (size != ARRAY_SIZE) {
+                        throw new Exception("Expected array size: " + ARRAY_SIZE + ", but got " + size);
+                    }
+                    referrer = object.getValue("referrer");
+                }
+                return;
+            }
+        }
+        throw new Exception("Could not find event with " + ArrayLeak[].class + " as (leak) object");
+    }
+
+    private static Object buildNestedArray(int depth) {
+        if (depth > 0) {
+            Object[] array = new Object[ARRAY_SIZE];
+            array[ARRAY_INDEX] = buildNestedArray(depth - 1);
+            return array;
+        } else {
+            return new ArrayLeak[OldObjects.MIN_SIZE];
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/oldobject/TestCMS.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.oldobject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.internal.test.WhiteBox;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "null"
+ * @summary Test leak profiler with CMS GC
+ * @library /test/lib /test/jdk
+ * @modules jdk.jfr/jdk.jfr.internal.test
+ * @run main/othervm  -XX:TLABSize=2k -XX:+UseConcMarkSweepGC jdk.jfr.event.oldobject.TestCMS
+ */
+public class TestCMS {
+
+    static private class FindMe {
+    }
+
+    public static List<FindMe[]> list = new ArrayList<>(OldObjects.MIN_SIZE);
+
+    public static void main(String[] args) throws Exception {
+        WhiteBox.setWriteAllObjectSamples(true);
+
+        try (Recording r = new Recording()) {
+            r.enable(EventNames.OldObjectSample).withStackTrace().with("cutoff", "infinity");
+            r.start();
+            allocateFindMe();
+            System.gc();
+            r.stop();
+            List<RecordedEvent> events = Events.fromRecording(r);
+            System.out.println(events);
+            if (OldObjects.countMatchingEvents(events, FindMe[].class, null, null, -1, "allocateFindMe") == 0) {
+                throw new Exception("Could not find leak with " + FindMe[].class);
+            }
+        }
+    }
+
+    public static void allocateFindMe() {
+        for (int i = 0; i < OldObjects.MIN_SIZE; i++) {
+            // Allocate array to trigger sampling code path for interpreter / c1
+            list.add(new FindMe[0]);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/oldobject/TestCircularReference.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.oldobject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.internal.test.WhiteBox;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "null"
+ * @library /test/lib /test/jdk
+ * @modules jdk.jfr/jdk.jfr.internal.test
+ * @run main/othervm -XX:TLABSize=2k jdk.jfr.event.oldobject.TestCircularReference
+ */
+public class TestCircularReference {
+
+    static class TestCircularReferrer {
+        // Allocate array to trigger sampling code path for interpreter / c1
+        final byte[] leak = new byte[1_0000_000];
+        TestCircularReferrer reference;
+
+        public void setReference(TestCircularReferrer reference) {
+            this.reference = reference;
+        }
+    }
+
+    public final static List<Object> referenceHolder = new ArrayList<>(OldObjects.MIN_SIZE);
+
+    public static void main(String[] args) throws Exception {
+        WhiteBox.setWriteAllObjectSamples(true);
+
+        try (Recording r = new Recording()) {
+            r.enable(EventNames.OldObjectSample).with("cutoff", "infinity").withStackTrace();
+            r.start();
+
+            TestCircularReferrer a = new TestCircularReferrer();
+            TestCircularReferrer b = new TestCircularReferrer();
+            TestCircularReferrer c = new TestCircularReferrer();
+            a.setReference(b);
+            b.setReference(c);
+            c.setReference(a);
+            referenceHolder.add(a);
+
+            TestCircularReferrer selfReflector = new TestCircularReferrer();
+            selfReflector.setReference(selfReflector);
+            referenceHolder.add(selfReflector);
+
+            r.stop();
+
+            List<RecordedEvent> events = Events.fromRecording(r);
+            if (events.isEmpty()) {
+                throw new AssertionError("Expected Old Object Sample events!");
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/oldobject/TestClassLoader.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.oldobject;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+/*
+ * A special class loader that will, for our test class, make sure that each
+ * load will become a unique class
+ */
+public final class TestClassLoader extends ClassLoader {
+
+    public static final class TestClass0000000 {
+        public static final byte[] oneByte = new byte[1];
+    }
+
+    static byte[] classByteCode = readTestClassBytes();
+    private static int classIdCounter;
+
+    TestClassLoader() {
+        super(TestClassLoader.class.getClassLoader());
+    }
+
+    public List<Class<?>> loadClasses(int count) throws Exception {
+        List<Class<?>> classes = new ArrayList<>();
+        for (int i = 0; i < count; i++) {
+            String className = "jdk.jfr.event.oldobject.TestClassLoader$";
+            className += "TestClass" + String.format("%07d", classIdCounter++);
+            Class<?> clazz = Class.forName(className, true, this);
+            classes.add(clazz);
+        }
+        return classes;
+    }
+
+    @Override
+    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+        // If not loading the test class, just go on with the normal class loader
+        if (!name.contains("TestClass")) {
+            return super.loadClass(name, resolve);
+        }
+        String[] classNameParts = name.split("\\$");
+        String newName = classNameParts[1];
+        String oldName = "TestClass0000000";
+        if (oldName.length() != newName.length()) {
+            throw new AssertionError("String lengths don't match. Unable to replace class name");
+        }
+        byte[] newBytes = classByteCode.clone();
+        replaceBytes(newBytes, oldName.getBytes(), newName.getBytes());
+        Class<?> c = defineClass(name, newBytes, 0, newBytes.length);
+        if (resolve) {
+            resolveClass(c);
+        }
+        return c;
+    }
+
+    static void replaceBytes(byte[] bytes, byte[] find, byte[] replacement) {
+        for (int index = 0; index < bytes.length - find.length; index++) {
+            if (matches(bytes, index, find)) {
+                replace(bytes, index, replacement);
+            }
+        }
+    }
+
+    private static void replace(byte[] bytes, int startIndex, byte[] replacement) {
+        for (int index = 0; index < replacement.length; index++) {
+            bytes[startIndex + index] = replacement[index];
+        }
+    }
+
+    private static boolean matches(byte[] bytes, int startIndex, byte[] matching) {
+        for (int i = 0; i < matching.length; i++) {
+            if (bytes[startIndex + i] != matching[i]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static byte[] readTestClassBytes() {
+        try {
+            String classFileName = "jdk/jfr/event/oldobject/TestClassLoader$TestClass0000000.class";
+            InputStream is = TestClassLoader.class.getClassLoader().getResourceAsStream(classFileName);
+            if (is == null) {
+                throw new RuntimeException("Culd not find class file " + classFileName);
+            }
+            byte[] b = is.readAllBytes();
+            is.close();
+            return b;
+        } catch (IOException ioe) {
+            ioe.printStackTrace();
+            throw new RuntimeException(ioe);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/oldobject/TestClassLoaderLeak.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.oldobject;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedClass;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedObject;
+import jdk.jfr.internal.test.WhiteBox;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "null"
+ * @library /test/lib /test/jdk
+ * @modules jdk.jfr/jdk.jfr.internal.test
+ * @run main/othervm -XX:TLABSize=2k jdk.jfr.event.oldobject.TestClassLoaderLeak
+ */
+public class TestClassLoaderLeak {
+
+    public static List<Object> classObjects = new ArrayList<>(OldObjects.MIN_SIZE);
+
+    public static void main(String[] args) throws Exception {
+        WhiteBox.setWriteAllObjectSamples(true);
+
+        try (Recording r = new Recording()) {
+            r.enable(EventNames.OldObjectSample).withStackTrace().with("cutoff", "infinity");
+            r.start();
+            TestClassLoader testClassLoader = new TestClassLoader();
+            for (Class<?> clazz : testClassLoader.loadClasses(OldObjects.MIN_SIZE / 20)) {
+                // Allocate array to trigger sampling code path for interpreter / c1
+                for (int i = 0; i < 20; i++) {
+                    Object classArray = Array.newInstance(clazz, 20);
+                    Array.set(classArray, i, clazz.newInstance());
+                    classObjects.add(classArray);
+                }
+            }
+            r.stop();
+            List<RecordedEvent> events = Events.fromRecording(r);
+            Events.hasEvents(events);
+            for (RecordedEvent e : events) {
+                RecordedObject object = e.getValue("object");
+                RecordedClass rc = object.getValue("type");
+                if (rc.getName().contains("TestClass")) {
+                    return;
+                }
+            }
+            Asserts.fail("Could not find class leak");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/oldobject/TestFieldInformation.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.oldobject;
+
+import java.lang.reflect.Modifier;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedObject;
+import jdk.jfr.internal.test.WhiteBox;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "null"
+ * @library /test/lib /test/jdk
+ * @modules jdk.jfr/jdk.jfr.internal.test
+ * @run main/othervm -XX:TLABSize=2k -Xlog:gc+tlab=trace jdk.jfr.event.oldobject.TestFieldInformation
+ */
+public class TestFieldInformation {
+
+    public static final Object[] testField = new Object[50];
+
+    public static void main(String[] args) throws Exception {
+        WhiteBox.setWriteAllObjectSamples(true);
+
+        try (Recording recording = new Recording()) {
+            recording.enable(EventNames.OldObjectSample).withoutStackTrace().with("cutoff", "infinity");
+            recording.start();
+
+            addToTestField();
+
+            recording.stop();
+
+            List<RecordedEvent> events = Events.fromRecording(recording);
+            Events.hasEvents(events);
+            for (RecordedEvent e : events) {
+                if (hasValidField(e)) {
+                    return;
+                }
+            }
+            System.out.println(events);
+            Asserts.fail("Could not find old object with field 'testField'");
+        }
+    }
+
+    private static boolean hasValidField(RecordedEvent e) throws Exception {
+        RecordedObject object = e.getValue("object");
+        Set<Long> visited = new HashSet<>();
+        while (object != null) {
+            Long address = object.getValue("address");
+            if (visited.contains(address)) {
+                return false;
+            }
+            visited.add(address);
+            RecordedObject referrer = object.getValue("referrer");
+            RecordedObject fieldObject = referrer != null ? referrer.getValue("field") : null;
+            if (fieldObject != null) {
+                String name = fieldObject.getValue("name");
+                if (name != null && name.equals("testField")) {
+                    int modifiers = (short) fieldObject.getValue("modifiers");
+                    if (!Modifier.isStatic(modifiers)) {
+                        throw new Exception("Field should be static");
+                    }
+                    if (!Modifier.isPublic(modifiers)) {
+                        throw new Exception("Field should be private");
+                    }
+                    if (!Modifier.isFinal(modifiers)) {
+                        throw new Exception("Field should be final");
+                    }
+                    if (Modifier.isTransient(modifiers)) {
+                        throw new Exception("Field should not be transient");
+                    }
+                    if (Modifier.isVolatile(modifiers)) {
+                        throw new Exception("Field should not be volatile");
+                    }
+                    return true;
+                }
+            }
+            object = referrer != null ? referrer.getValue("object") : null;
+        }
+        return false;
+    }
+
+    private static void addToTestField() {
+        for (int i = 0; i < testField.length; i++) {
+            // Allocate array to trigger sampling code path for interpreter / c1
+            testField[i] = new Object[1_000_000];
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/oldobject/TestG1.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.oldobject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.internal.test.WhiteBox;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "null"
+ * @summary Test leak profiler with G1 GC
+ * @library /test/lib /test/jdk
+ * @modules jdk.jfr/jdk.jfr.internal.test
+ * @run main/othervm  -XX:TLABSize=2k -XX:+UseG1GC jdk.jfr.event.oldobject.TestG1
+ */
+public class TestG1 {
+
+    static private class FindMe {
+    }
+
+    public static List<FindMe[]> list = new ArrayList<>(OldObjects.MIN_SIZE);
+
+    public static void main(String[] args) throws Exception {
+        WhiteBox.setWriteAllObjectSamples(true);
+
+        try (Recording r = new Recording()) {
+            r.enable(EventNames.OldObjectSample).withStackTrace().with("cutoff", "infinity");
+            r.start();
+            allocateFindMe();
+            System.gc();
+            r.stop();
+            List<RecordedEvent> events = Events.fromRecording(r);
+            System.out.println(events);
+            if (OldObjects.countMatchingEvents(events, FindMe[].class, null, null, -1, "allocateFindMe") == 0) {
+                throw new Exception("Could not find leak with " + FindMe[].class);
+            }
+        }
+    }
+
+    public static void allocateFindMe() {
+        for (int i = 0; i < OldObjects.MIN_SIZE; i++) {
+            // Allocate array to trigger sampling code path for interpreter / c1
+            list.add(new FindMe[0]);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/oldobject/TestHeapDeep.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.oldobject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.internal.test.WhiteBox;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "null"
+ * @library /test/lib /test/jdk
+ * @modules jdk.jfr/jdk.jfr.internal.test
+ * @run main/othervm -XX:TLABSize=2k jdk.jfr.event.oldobject.TestHeapDeep
+ */
+public class TestHeapDeep {
+
+    final static class ChainNode {
+        final ChainNode next;
+        List<byte[]> leaks;
+
+        public ChainNode(ChainNode node) {
+            next = node;
+        }
+    }
+
+    public static ChainNode leak;
+
+    public static void main(String[] args) throws Exception {
+        WhiteBox.setWriteAllObjectSamples(true);
+
+        try (Recording r = new Recording()) {
+            r.enable(EventNames.OldObjectSample).withStackTrace().with("cutoff", "infinity");
+            r.start();
+            leak = createChain();
+            List<RecordedEvent> events = Events.fromRecording(r);
+            if (OldObjects.countMatchingEvents(events, byte[].class, null, null, -1, "createChain") == 0) {
+                throw new Exception("Could not find ChainNode");
+            }
+            for (RecordedEvent e : events) {
+                OldObjects.validateReferenceChainLimit(e, OldObjects.MAX_CHAIN_LENGTH);
+            }
+        }
+    }
+
+    private static ChainNode createChain() {
+        ChainNode node = new ChainNode(null);
+        node.leaks = new ArrayList<>();
+        for (int i = 0; i < 100; i++) {
+            // Allocate arrays to trigger sampling code path for interpreter / c1
+            node.leaks.add(new byte[10_000]);
+        }
+        for (int i = 0; i < OldObjects.MIN_SIZE; i++) {
+            node = new ChainNode(node);
+        }
+        return node;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/oldobject/TestHeapShallow.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.oldobject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.internal.test.WhiteBox;
+import jdk.test.lib.jfr.EventNames;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "null"
+ * @library /test/lib /test/jdk
+ * @modules jdk.jfr/jdk.jfr.internal.test
+ * @run main/othervm -XX:TLABSize=2k jdk.jfr.event.oldobject.TestHeapShallow
+ */
+public class TestHeapShallow {
+    private final static long LARGE_OBJECT_FACTOR = 509; // prime number
+
+    static class LeakObject {
+        Object object = null;
+
+        public LeakObject(Object object) {
+            this.object = object;
+        }
+    }
+
+    public static ArrayList<LeakObject> leak =  new ArrayList<>(OldObjects.MIN_SIZE);
+
+    public static void main(String[] args) throws Exception {
+        WhiteBox.setWriteAllObjectSamples(true);
+
+        try (Recording recording = new Recording()) {
+            recording.enable(EventNames.OldObjectSample).withStackTrace().with("cutoff", "infinity");
+            recording.start();
+
+            addObjectsToShallowArray(leak);
+            recording.stop();
+            if (OldObjects.countMatchingEvents(recording, "addObjectsToShallowArray", byte[].class, "object", LeakObject.class, -1) < 1) {
+                throw new Exception("Could not find shallow leak object");
+            }
+        }
+    }
+
+    private static void addObjectsToShallowArray(List<LeakObject> list) {
+        for (int i = 0; i < OldObjects.MIN_SIZE; i++) {
+            if (i % LARGE_OBJECT_FACTOR == 0) {
+                // Triggers allocation outside TLAB path
+                list.add(new LeakObject(new byte[16384]));
+            } else {
+                // Triggers allocation in TLAB path
+                list.add(new LeakObject(new byte[10]));
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/oldobject/TestLargeRootSet.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.oldobject;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.CyclicBarrier;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedClass;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedObject;
+import jdk.jfr.internal.test.WhiteBox;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "null"
+ * @library /test/lib /test/jdk
+ * @modules jdk.jfr/jdk.jfr.internal.test
+ * @run main/othervm -XX:TLABSize=2k -XX:-FastTLABRefill jdk.jfr.event.oldobject.TestLargeRootSet
+ */
+public class TestLargeRootSet {
+
+    private static final int THREAD_COUNT = 50;
+
+    private static class RootThread extends Thread {
+        private final CyclicBarrier barrier;
+        private int maxDepth = OldObjects.MIN_SIZE / THREAD_COUNT;
+
+        public List<StackObject[]> temporaries = new ArrayList<>(maxDepth);
+
+        RootThread(CyclicBarrier cb) {
+            this.barrier = cb;
+        }
+
+        public void run() {
+            buildRootObjects();
+        }
+
+        private void buildRootObjects() {
+            if (maxDepth-- > 0) {
+                // Allocate array to trigger sampling code path for interpreter / c1
+                StackObject[] stackObject = new StackObject[0];
+                temporaries.add(stackObject); // make sure object escapes
+                buildRootObjects();
+            } else {
+                temporaries.clear();
+                try {
+                    barrier.await(); // wait for gc
+                    barrier.await(); // wait for recording to be stopped
+                } catch (InterruptedException e) {
+                    System.err.println("Thread was unexpected interrupted: " + e.getMessage());
+                } catch (BrokenBarrierException e) {
+                    System.err.println("Unexpected barrier exception: " + e.getMessage());
+                }
+                return;
+            }
+        }
+    }
+
+    private static class StackObject {
+    }
+
+    public static void main(String[] args) throws Exception {
+        WhiteBox.setWriteAllObjectSamples(true);
+
+        List<RootThread> threads = new ArrayList<>();
+        try (Recording r = new Recording()) {
+            r.enable(EventNames.OldObjectSample).withStackTrace().with("cutoff", "infinity");
+            r.start();
+            CyclicBarrier cb = new CyclicBarrier(THREAD_COUNT + 1);
+            for (int i = 0; i < THREAD_COUNT; i++) {
+                RootThread t = new RootThread(cb);
+                t.start();
+                if (i % 10 == 0) {
+                    // Give threads some breathing room before starting next batch
+                    Thread.sleep(100);
+                }
+                threads.add(t);
+            }
+            cb.await();
+            System.gc();
+            r.stop();
+            cb.await();
+            List<RecordedEvent> events = Events.fromRecording(r);
+            Events.hasEvents(events);
+            for (RecordedEvent e : events) {
+                RecordedObject ro = e.getValue("object");
+                RecordedClass rc = ro.getValue("type");
+                System.out.println(rc.getName());
+                if (rc.getName().equals(StackObject[].class.getName())) {
+                    return; // ok
+                }
+            }
+            Asserts.fail("Could not find root object");
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/oldobject/TestListenerLeak.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.oldobject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.internal.test.WhiteBox;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "null"
+ * @library /test/lib /test/jdk
+ * @modules jdk.jfr/jdk.jfr.internal.test
+ * @run main/othervm -XX:TLABSize=2k jdk.jfr.event.oldobject.TestListenerLeak
+ */
+public class TestListenerLeak {
+
+    private interface TestListener {
+        void onListen();
+    }
+
+    static class Stuff {
+    }
+
+    static class ListenerThread extends Thread {
+
+        private List<Stuff[]> stuff;
+
+        public ListenerThread(List<Stuff[]> stuff) {
+            this.stuff = stuff;
+        }
+
+        public void run() {
+            listener.add(new TestListener() {
+                @Override
+                public void onListen() {
+                    System.out.println(stuff);
+                }
+            });
+        }
+    }
+
+    private static List<TestListener> listener = new ArrayList<>();
+
+    public static void main(String[] args) throws Exception {
+        WhiteBox.setWriteAllObjectSamples(true);
+
+        try (Recording r = new Recording()) {
+            r.enable(EventNames.OldObjectSample).withStackTrace().with("cutoff", "infinity");
+            r.start();
+            listenerLeak();
+            r.stop();
+            List<RecordedEvent> events = Events.fromRecording(r);
+            if (OldObjects.countMatchingEvents(events, Stuff[].class, null, null, -1, "listenerLeak") == 0) {
+                throw new Exception("Could not find leak with " + Stuff[].class);
+            }
+        }
+    }
+
+    private static void listenerLeak() throws InterruptedException {
+        List<Stuff[]> stuff = new ArrayList<>(OldObjects.MIN_SIZE);
+        for (int i = 0; i < OldObjects.MIN_SIZE; i++) {
+            // Allocate array to trigger sampling code path for interpreter / c1
+            stuff.add(new Stuff[0]);
+        }
+
+        ListenerThread t = new ListenerThread(stuff);
+        t.start();
+        t.join();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/oldobject/TestMetadataObject.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.oldobject;
+
+/**
+ * Purpose of this class is to generate a stack trace
+ * that can be used in a different class loader
+ * to test metadata retention
+ *
+ */
+public final class TestMetadataObject {
+    public static Object startRecurse() {
+        return recurse(50);
+    }
+
+    public static Object recurse(int depth) {
+        if (depth > 0) {
+            return recurse(depth - 1);
+        } else {
+            return makeMemoryLeak();
+        }
+    }
+
+    public static byte[] makeMemoryLeak() {
+        return new byte[OldObjects.MIN_SIZE];
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/oldobject/TestMetadataRetention.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.oldobject;
+
+import java.time.Instant;
+import java.util.List;
+
+import jdk.jfr.Event;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedClass;
+import jdk.jfr.consumer.RecordedClassLoader;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedFrame;
+import jdk.jfr.consumer.RecordedStackTrace;
+import jdk.jfr.consumer.RecordedThread;
+import jdk.jfr.internal.test.WhiteBox;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.TestClassLoader;
+
+/*
+ * @test
+ * @summary The test verifies that an old object sample maintains references to "stale" metadata
+ * @requires vm.gc == "null"
+ * @key jfr
+ * @modules jdk.jfr/jdk.jfr.internal.test
+ * @library /test/lib /test/jdk
+ * @build jdk.jfr.event.oldobject.TestMetadataObject
+ * @run main/othervm -XX:TLABSize=2k -Xmx16m jdk.jfr.event.oldobject.TestMetadataRetention
+ */
+public final class TestMetadataRetention {
+    private final static String TEST_PACKAGE = TestMetadataRetention.class.getPackage().getName();
+    private final static String TEST_CLASS_LOADER_NAME = "JFR TestClassLoader";
+    private final static String TEST_CLASS_NAME = TEST_PACKAGE + ".TestMetadataObject";
+    private final static String ALLOCATOR_THREAD_NAME = "TestAllocationThread";
+
+    public static ClassLoader testClassLoader;
+    public static Object leakObject;
+    public static Thread allocatorThread;
+    public static Class<?> testClass;
+
+    static class ChunkRotation extends Event {
+    }
+
+    public static void main(String[] args) throws Throwable {
+        WhiteBox.setWriteAllObjectSamples(true);
+        while (true) {
+            int failedAttempts = 0;
+            try (Recording recording = new Recording()) {
+                recording.enable(EventNames.OldObjectSample).withStackTrace();
+                recording.enable(EventNames.ClassUnload);
+                recording.start();
+
+                // Setup metadata on the Java heap (class, stack trace and thread)
+                testClassLoader = new TestClassLoader();
+                testClass = testClassLoader.loadClass(TEST_CLASS_NAME);
+                allocatorThread = new Thread(TestMetadataRetention::allocateLeak, ALLOCATOR_THREAD_NAME);
+                allocatorThread.start();
+                allocatorThread.join();
+
+                // Clear out metadata on the heap
+                testClassLoader = null;
+                testClass = null;
+                allocatorThread = null;
+
+                // System.gc() will trigger class unloading if -XX:+ExplicitGCInvokesConcurrent
+                // is NOT set. If this flag is set G1 will never unload classes on System.gc()
+                // and CMS will not guarantee that all semantically dead classes will be
+                // unloaded. As far as the "jfr" key guarantees no VM flags are set from the
+                // outside it should be enough with System.gc().
+                System.gc();
+
+                // Provoke a chunk rotation, which will flush out ordinary metadata.
+                provokeChunkRotation();
+                ChunkRotation cr = new ChunkRotation();
+                cr.commit();
+                recording.stop();
+
+                List<RecordedEvent> events = Events.fromRecording(recording);
+                RecordedEvent chunkRotation = findChunkRotationEvent(events);
+                try {
+                    // Sanity check that class was unloaded
+                    Events.hasEvent(recording, EventNames.ClassUnload);
+                    validateClassUnloadEvent(events);
+                    // Validate that metadata for old object event has survived chunk rotation
+                    Events.hasEvent(recording, EventNames.OldObjectSample);
+                    validateOldObjectEvent(events, chunkRotation.getStartTime());
+                } catch (Throwable t) {
+                    t.printStackTrace();
+                    System.out.println("Number of failed attempts " + ++failedAttempts);
+                    continue;
+                }
+                break;
+            }
+        }
+    }
+
+    private static RecordedEvent findChunkRotationEvent(List<RecordedEvent> events) {
+        for (RecordedEvent e : events)  {
+            if (e.getEventType().getName().equals(ChunkRotation.class.getName())) {
+                return e;
+            }
+        }
+        Asserts.fail("Could not find chunk rotation event");
+        return null; // Can't happen;
+    }
+
+    private static void allocateLeak() {
+        try {
+            leakObject = testClass.getMethod("startRecurse").invoke(null);
+        } catch (Exception e) {
+            System.out.println("Could not allocate memory leak!");
+            e.printStackTrace();
+        }
+    }
+
+    private static void provokeChunkRotation() {
+        try (Recording r = new Recording()) {
+            r.start();
+            r.stop();
+        }
+    }
+
+    private static void validateClassUnloadEvent(List<RecordedEvent> events) throws Throwable {
+        for (RecordedEvent event : events) {
+            if (event.getEventType().getName().equals(EventNames.ClassUnload)) {
+                RecordedClass unloadedClass = event.getValue("unloadedClass");
+                if (TEST_CLASS_NAME.equals(unloadedClass.getName())) {
+                    RecordedClassLoader definingClassLoader = unloadedClass.getClassLoader();
+                    Asserts.assertEquals(TEST_CLASS_LOADER_NAME, definingClassLoader.getName(), "Expected " + TEST_CLASS_LOADER_NAME + ", got " + definingClassLoader.getType().getName());
+                    return;
+                }
+            }
+        }
+    }
+
+    private static void validateOldObjectEvent(List<RecordedEvent> events, Instant chunkRotation) throws Throwable {
+        for (RecordedEvent event : events) {
+            if (event.getEventType().getName().equals(EventNames.OldObjectSample)) {
+                // Only check event after the rotation
+                if (!event.getStartTime().isBefore(chunkRotation)) {
+                    System.out.println(event);
+                    RecordedThread rt = event.getThread();
+                    if (rt.getJavaName().equals(ALLOCATOR_THREAD_NAME)) {
+                        RecordedStackTrace s = event.getStackTrace();
+                        assertStackTrace(s, "startRecurse");
+                        assertStackTrace(s, "recurse");
+                        return;
+                    }
+                }
+            }
+        }
+
+        Asserts.fail("Did not find an old object event with thread " + ALLOCATOR_THREAD_NAME);
+    }
+
+    private static void assertStackTrace(RecordedStackTrace stacktrace, final String methodName) {
+        for (RecordedFrame f : stacktrace.getFrames()) {
+            if (f.getMethod().getName().equals(methodName)) {
+                return;
+            }
+        }
+        Asserts.fail("Could not find class " + methodName + " in stack trace " + stacktrace);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/oldobject/TestObjectDescription.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.oldobject;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.Callable;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedObject;
+import jdk.jfr.internal.test.WhiteBox;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "null"
+ * @library /test/lib /test/jdk
+ * @modules jdk.jfr/jdk.jfr.internal.test
+ * @run main/othervm -XX:TLABSize=2k jdk.jfr.event.oldobject.TestObjectDescription
+ */
+public class TestObjectDescription {
+
+    private static final int OBJECT_DESCRIPTION_MAX_SIZE = 100;
+    private static final String CLASS_NAME = TestClassLoader.class.getName() + "$TestClass";
+    public static List<?> leaks;
+
+    public final static class MyThreadGroup extends ThreadGroup {
+        public final static String NAME = "My Thread Group";
+
+        public MyThreadGroup(String name) {
+            super(name);
+        }
+
+        // Allocate array to trigger sampling code path for interpreter / c1
+        byte[] bytes = new byte[10];
+    }
+
+    public final static class MyThread extends Thread {
+        public final static String NAME = "My Thread";
+
+        public MyThread() {
+            super(NAME);
+        }
+
+        // Allocate array to trigger sampling code path for interpreter / c1
+        byte[] bytes = new byte[10];
+    }
+
+    public static void main(String[] args) throws Exception {
+        WhiteBox.setWriteAllObjectSamples(true);
+
+        testThreadGroupName();
+        testThreadName();
+        testClassName();
+        testSize();
+        testEllipsis();
+    }
+
+    private static void testThreadName() throws Exception {
+        asseertObjectDescription(() -> {
+            List<MyThread> threads = new ArrayList<>(OldObjects.MIN_SIZE);
+            for (int i = 0; i < OldObjects.MIN_SIZE; i++) {
+                threads.add(new MyThread());
+            }
+            return threads;
+        }, "Thread Name: " + MyThread.NAME);
+    }
+
+    private static void testThreadGroupName() throws Exception {
+        asseertObjectDescription(() -> {
+            List<MyThreadGroup> groups = new ArrayList<>(OldObjects.MIN_SIZE);
+            for (int i = 0; i < OldObjects.MIN_SIZE; i++) {
+                groups.add(new MyThreadGroup("My Thread Group"));
+            }
+            return groups;
+        }, "Thread Group: " + "My Thread Group");
+    }
+
+    private static void testClassName() throws Exception {
+        asseertObjectDescription(() -> {
+            TestClassLoader testClassLoader = new TestClassLoader();
+            List<Object> classObjects = new ArrayList<>(OldObjects.MIN_SIZE);
+            for (Class<?> clazz : testClassLoader.loadClasses(OldObjects.MIN_SIZE / 20)) {
+                // Allocate array to trigger sampling code path for interpreter / c1
+                for (int i = 0; i < 20; i++) {
+                    Object classArray = Array.newInstance(clazz, 20);
+                    Array.set(classArray, i, clazz.newInstance());
+                    classObjects.add(classArray);
+                }
+            }
+            return classObjects;
+        }, "Class Name: " + CLASS_NAME);
+    }
+
+    private static void testSize() throws Exception {
+        asseertObjectDescription(() -> {
+            List<Object> arrayLists = new ArrayList<>(OldObjects.MIN_SIZE);
+            for (int i = 0; i < OldObjects.MIN_SIZE; i++) {
+                List<Object> arrayList = new ArrayList<>();
+                arrayList.add(new Object());
+                arrayList.add(new Object());
+                arrayList.add(new Object());
+                arrayLists.add(arrayList);
+            }
+            return arrayLists;
+        }, "Size: 3");
+    }
+
+    private static void testEllipsis() throws Exception {
+        asseertObjectDescription(() -> {
+            StringBuilder sb = new StringBuilder();
+            for (int i = 0; i < 2 * OBJECT_DESCRIPTION_MAX_SIZE; i++) {
+                sb.append("x");
+            }
+            String threadName = sb.toString();
+            List<Thread> threads = new ArrayList<>();
+            for (int i = 0; i < OldObjects.MIN_SIZE; i++) {
+                threads.add(new Thread(threadName));
+            }
+            return threads;
+        }, "xxx...");
+    }
+
+    private static void asseertObjectDescription(Callable<List<?>> callable, String text) throws Exception {
+        int iteration = 1;
+        while (true) {
+            try (Recording recording = new Recording()) {
+                System.out.println("Iteration: " + iteration);
+                recording.enable(EventNames.OldObjectSample).withoutStackTrace().with("cutoff", "infinity");
+                recording.start();
+                leaks = null;
+                System.gc();
+                leaks = callable.call();
+
+                recording.stop();
+
+                List<RecordedEvent> events = Events.fromRecording(recording);
+                Set<String> objectDescriptions = extractObjectDecriptions(events);
+                for (String s : objectDescriptions) {
+                    if (s.contains(text)) {
+                        printDescriptions(objectDescriptions);
+                        return;
+                    }
+                }
+                System.out.println("Could not find object description containing text \"" + text + "\"");
+                printDescriptions(objectDescriptions);
+                System.out.println();
+                iteration++;
+            }
+        }
+    }
+
+    private static void printDescriptions(Set<String> objectDescriptions) {
+        System.out.println("Found descriptions:");
+        for (String t : objectDescriptions) {
+            System.out.println(t);
+        }
+    }
+
+    private static Set<String> extractObjectDecriptions(List<RecordedEvent> events) {
+        Set<String> objectDescriptions = new HashSet<>();
+        for (RecordedEvent e : events) {
+            objectDescriptions.addAll(extractObjectDescriptions(e.getValue("object")));
+        }
+        return objectDescriptions;
+    }
+
+    private static Set<String> extractObjectDescriptions(RecordedObject o) {
+        Set<Long> visited = new HashSet<>();
+        Set<String> descriptions = new HashSet<>();
+        while (o != null) {
+            Long memoryAddress = o.getValue("address");
+            if (visited.contains(memoryAddress)) {
+                return descriptions;
+            }
+            visited.add(memoryAddress);
+            String od = o.getValue("description");
+            if (od != null) {
+                descriptions.add(od);
+            }
+            RecordedObject referrer = o.getValue("referrer");
+            o = referrer != null ? referrer.getValue("object") : null;
+        }
+        return descriptions;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/oldobject/TestParallel.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.oldobject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.internal.test.WhiteBox;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "null"
+ * @summary Test leak profiler with Parallel GC
+ * @library /test/lib /test/jdk
+ * @modules jdk.jfr/jdk.jfr.internal.test
+ * @run main/othervm  -XX:TLABSize=2k -XX:+UseParallelGC jdk.jfr.event.oldobject.TestParallel
+ */
+public class TestParallel {
+
+    static private class FindMe {
+    }
+
+    public static List<FindMe[]> list = new ArrayList<>(OldObjects.MIN_SIZE);
+
+    public static void main(String[] args) throws Exception {
+        WhiteBox.setWriteAllObjectSamples(true);
+
+        try (Recording r = new Recording()) {
+            r.enable(EventNames.OldObjectSample).withStackTrace().with("cutoff", "infinity");
+            r.start();
+            allocateFindMe();
+            System.gc();
+            r.stop();
+            List<RecordedEvent> events = Events.fromRecording(r);
+            System.out.println(events);
+            if (OldObjects.countMatchingEvents(events, FindMe[].class, null, null, -1, "allocateFindMe") == 0) {
+                throw new Exception("Could not find leak with " + FindMe[].class);
+            }
+        }
+    }
+
+    public static void allocateFindMe() {
+        for (int i = 0; i < OldObjects.MIN_SIZE; i++) {
+            // Allocate array to trigger sampling code path for interpreter / c1
+            list.add(new FindMe[0]);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/oldobject/TestParallelOld.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.oldobject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.internal.test.WhiteBox;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "null"
+ * @summary Test leak profiler with Parallel Old GC
+ * @library /test/lib /test/jdk
+ * @modules jdk.jfr/jdk.jfr.internal.test
+ * @run main/othervm  -XX:TLABSize=2k -XX:+UseParallelOldGC jdk.jfr.event.oldobject.TestParallelOld
+ */
+public class TestParallelOld {
+
+    static private class FindMe {
+    }
+
+    public static List<FindMe[]> list = new ArrayList<>(OldObjects.MIN_SIZE);
+
+    public static void main(String[] args) throws Exception {
+        WhiteBox.setWriteAllObjectSamples(true);
+
+        try (Recording r = new Recording()) {
+            r.enable(EventNames.OldObjectSample).withStackTrace().with("cutoff", "infinity");
+            r.start();
+            allocateFindMe();
+            System.gc();
+            r.stop();
+            List<RecordedEvent> events = Events.fromRecording(r);
+            System.out.println(events);
+            if (OldObjects.countMatchingEvents(events, FindMe[].class, null, null, -1, "allocateFindMe") == 0) {
+                throw new Exception("Could not find leak with " + FindMe[].class);
+            }
+        }
+    }
+
+    public static void allocateFindMe() {
+        for (int i = 0; i < OldObjects.MIN_SIZE; i++) {
+            // Allocate array to trigger sampling code path for interpreter / c1
+            list.add(new FindMe[0]);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/oldobject/TestReferenceChainLimit.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.oldobject;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.internal.test.WhiteBox;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "null"
+ * @library /test/lib /test/jdk
+ * @modules jdk.jfr/jdk.jfr.internal.test
+ * @run main/othervm -XX:TLABSize=2k jdk.jfr.event.oldobject.TestReferenceChainLimit
+ */
+public class TestReferenceChainLimit {
+    private final static int TEST_CHAIN_LENGTH_FACTOR = 10; // scaling factor for the how long chain to be used in the test
+
+    final static class ChainNode {
+        final ChainNode next;
+        byte[] leak;
+
+        public ChainNode(ChainNode node) {
+            next = node;
+            leak = new byte[10_000];
+        }
+    }
+
+    private static ChainNode createChain() {
+        ChainNode node = null;
+        final int testChainLength = OldObjects.MAX_CHAIN_LENGTH * TEST_CHAIN_LENGTH_FACTOR;
+        for (int i = 0; i < testChainLength; i++) {
+            node = new ChainNode(node);
+        }
+        return node;
+    }
+
+    public static ChainNode leak;
+
+    public static void main(String[] args) throws Exception {
+        WhiteBox.setWriteAllObjectSamples(true);
+
+        try (Recording r = new Recording()) {
+            r.enable(EventNames.OldObjectSample).withStackTrace().with("cutoff", "infinity");
+            r.start();
+            leak = createChain();
+            List<RecordedEvent> events = Events.fromRecording(r);
+            if (OldObjects.countMatchingEvents(events, byte[].class, null, null, -1, "createChain") == 0) {
+                throw new Exception("Could not find ChainNode");
+            }
+            for (RecordedEvent e : events) {
+                OldObjects.validateReferenceChainLimit(e, OldObjects.MAX_CHAIN_LENGTH);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/oldobject/TestSanityDefault.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.oldobject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "null"
+ * @library /test/lib /test/jdk
+ * @summary Purpose of this test is to run leak profiler without command line tweaks or WhiteBox hacks until we succeed
+ * @run main/othervm jdk.jfr.event.oldobject.TestSanityDefault
+ */
+public class TestSanityDefault {
+
+    static private class FindMe {
+    }
+
+    public static List<FindMe> list = new ArrayList<>(OldObjects.MIN_SIZE);
+
+    public static void main(String[] args) throws Exception {
+        // Should not use WhiteBox API, we want to execute actual code paths
+
+        // Trigger c2 compilation, so we get sample
+        for (long i = 0; i < 100_000_000; i++) {
+            allocateFindMe(true);
+        }
+
+
+        // It's hard to get samples with interpreter / C1 so loop until we do
+        while (true) {
+            try (Recording r = new Recording()) {
+                r.enable(EventNames.OldObjectSample).withStackTrace().with("cutoff", "infinity");
+                r.start();
+                allocateFindMe(false);
+                System.gc();
+                r.stop();
+                List<RecordedEvent> events = Events.fromRecording(r);
+                if (OldObjects.countMatchingEvents(events, FindMe.class, null, null, -1, "allocateFindMe") > 0) {
+                    return;
+                }
+                // no events found, retry
+            }
+        }
+    }
+
+    public static void allocateFindMe(boolean doNothing) {
+        if (doNothing) {
+            return;
+        }
+        for (int i = 0; i < OldObjects.MIN_SIZE; i++) {
+            // Purposely don't allocate array, so we at least
+            // in one old-object test check an ordinary object.
+            list.add(new FindMe());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/oldobject/TestSerial.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.oldobject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.internal.test.WhiteBox;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @requires vm.gc == "null"
+ * @summary Test leak profiler with Serial GC
+ * @library /test/lib /test/jdk
+ * @modules jdk.jfr/jdk.jfr.internal.test
+ * @run main/othervm  -XX:TLABSize=2k -XX:+UseSerialGC jdk.jfr.event.oldobject.TestSerial
+ */
+public class TestSerial {
+
+    static private class FindMe {
+    }
+
+    public static List<FindMe[]> list = new ArrayList<>(OldObjects.MIN_SIZE);
+
+    public static void main(String[] args) throws Exception {
+        WhiteBox.setWriteAllObjectSamples(true);
+
+        try (Recording r = new Recording()) {
+            r.enable(EventNames.OldObjectSample).withStackTrace().with("cutoff", "infinity");
+            r.start();
+            allocateFindMe();
+            System.gc();
+            r.stop();
+            List<RecordedEvent> events = Events.fromRecording(r);
+            System.out.println(events);
+            if (OldObjects.countMatchingEvents(events, FindMe[].class, null, null, -1, "allocateFindMe") == 0) {
+                throw new Exception("Could not find leak with " + FindMe[].class);
+            }
+        }
+    }
+
+    public static void allocateFindMe() {
+        for (int i = 0; i < OldObjects.MIN_SIZE; i++) {
+            // Allocate array to trigger sampling code path for interpreter / c1
+            list.add(new FindMe[0]);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/oldobject/TestThreadLocalLeak.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.oldobject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.internal.test.WhiteBox;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @modules jdk.jfr/jdk.jfr.internal.test
+ * @run main/othervm -XX:TLABSize=2k jdk.jfr.event.oldobject.TestThreadLocalLeak
+ */
+public class TestThreadLocalLeak {
+
+    private static ThreadLocal<List<ThreadLocalObject[]>> threadLocal = new ThreadLocal<List<ThreadLocalObject[]>>() {
+        @Override
+        public List<ThreadLocalObject[]> initialValue() {
+            return new ArrayList<ThreadLocalObject[]>(OldObjects.MIN_SIZE);
+        }
+    };
+
+    static class ThreadLocalObject {
+    }
+
+    public static void main(String[] args) throws Exception {
+        WhiteBox.setWriteAllObjectSamples(true);
+
+        try (Recording r = new Recording()) {
+            r.enable(EventNames.OldObjectSample).withStackTrace().with("cutoff", "infinity");
+            r.start();
+            allocateThreadLocal();
+            r.stop();
+            List<RecordedEvent> events = Events.fromRecording(r);
+            if (OldObjects.countMatchingEvents(events, ThreadLocalObject[].class, null, null, -1, "allocateThreadLocal") == 0) {
+                throw new Exception("Could not find thread local object " + ThreadLocalObject.class);
+            }
+        }
+    }
+
+    private static void allocateThreadLocal() {
+        for (int i = 0; i < OldObjects.MIN_SIZE; i++) {
+            // Allocate array to trigger sampling code path for interpreter / c1
+            threadLocal.get().add(new ThreadLocalObject[0]);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/os/TestCPUInformation.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.os;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.event.os.TestCPUInformation
+ */
+public class TestCPUInformation {
+    private final static String EVENT_NAME = EventNames.CPUInformation;
+
+    public static void main(String[] args) throws Throwable {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME);
+        recording.start();
+        recording.stop();
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        Events.hasEvents(events);
+        for (RecordedEvent event : events) {
+            System.out.println("Event: " + event);
+            Events.assertField(event, "hwThreads").atLeast(1);
+            Events.assertField(event, "cores").atLeast(1);
+            Events.assertField(event, "sockets").atLeast(1);
+            Events.assertField(event, "cpu").containsAny("Intel", "AMD", "Unknown x86", "sparc", "ARM", "PPC", "PowerPC", "AArch64");
+            Events.assertField(event, "description").containsAny("Intel", "AMD", "Unknown x86", "SPARC", "ARM", "PPC", "PowerPC", "AArch64");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/os/TestCPULoad.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.os;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.event.os.TestCPULoad
+ */
+public class TestCPULoad {
+    private final static String EVENT_NAME = EventNames.CPULoad;
+
+    public static void main(String[] args) throws Throwable {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME);
+        recording.start();
+        // Need to sleep so a time delta can be calculated
+        Thread.sleep(100);
+        recording.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        if (events.isEmpty()) {
+            // CPU Load events are unreliable on Windows because
+            // the way processes are identified with perf. counters.
+            // See BUG 8010378.
+            // Workaround is to detect Windows and allow
+            // test to pass if events are missing.
+            if (isWindows()) {
+                return;
+            }
+            throw new AssertionError("Expected at least one event");
+        }
+        for (RecordedEvent event : events) {
+            System.out.println("Event: " + event);
+            for (String loadName : loadNames) {
+                Events.assertField(event, loadName).atLeast(0.0f).atMost(1.0f);
+            }
+        }
+    }
+
+    private static final String[] loadNames = {"jvmUser", "jvmSystem", "machineTotal"};
+
+    private static boolean isWindows() {
+        return System.getProperty("os.name").startsWith("Windows");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/os/TestCPUTimeStampCounter.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.os;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.event.os.TestCPUTimeStampCounter
+ */
+public class TestCPUTimeStampCounter {
+    private final static String EVENT_NAME = EventNames.CPUTimeStampCounter;
+
+    public static void main(String[] args) throws Throwable {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME);
+        recording.start();
+        recording.stop();
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        Events.hasEvents(events);
+        for (RecordedEvent event : events) {
+            System.out.println("Event: " + event);
+            Events.assertField(event, "fastTimeEnabled");
+            Events.assertField(event, "fastTimeAutoEnabled");
+            Events.assertField(event, "osFrequency").atLeast(0L);
+            Events.assertField(event, "fastTimeFrequency").atLeast(0L);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/os/TestInitialEnvironmentVariable.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.os;
+
+import static jdk.test.lib.Asserts.assertEquals;
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+public class TestInitialEnvironmentVariable {
+    private final static String EVENT_NAME = EventNames.InitialEnvironmentVariable;
+
+    public static void main(String[] args) throws Exception {
+        Map<String, String> env = new HashMap<>();
+        env.put("keytest1", "value1");
+        env.put("keytest2", "value 2");
+
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME);
+        recording.start();
+        recording.stop();
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        Events.hasEvents(events);
+        for (RecordedEvent event : events) {
+            System.out.println("Event: " + event);
+            String key = Events.assertField(event, "key").notNull().getValue();
+            String value = Events.assertField(event, "value").notNull().getValue();
+            if (env.containsKey(key)) {
+                assertEquals(value, env.get(key), "Wrong value for key: " + key);
+                env.remove(key);
+            }
+        }
+        assertTrue(env.isEmpty(), "Missing env keys " + env.keySet());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/os/TestInitialEnvironmentVariable.sh	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# 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.
+#
+# @test
+# @key jfr
+# @library /test/lib
+# @build jdk.jfr.event.os.TestInitialEnvironmentVariable
+# @run shell TestInitialEnvironmentVariable.sh
+echo -------------------------------------------------------------
+echo "TESTCLASSES='$TESTCLASSES'"
+echo "TESTSRC='$TESTSRC'"
+echo Launching test for `basename $0 .sh`
+echo -------------------------------------------------------------
+keytest1="value1";export keytest1
+keytest2="value 2";export keytest2
+${TESTJAVA}/bin/java -cp ${TESTCLASSPATH} jdk.jfr.event.os.TestInitialEnvironmentVariable
+exit $?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/os/TestOSInfo.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.os;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.event.os.TestOSInfo
+ */
+public class TestOSInfo {
+    private final static String EVENT_NAME = EventNames.OSInformation;
+
+    public static void main(String[] args) throws Throwable {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME);
+        recording.start();
+        recording.stop();
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        Events.hasEvents(events);
+        for (RecordedEvent event : events) {
+            System.out.println("Event: " + event);
+            Events.assertField(event, "osVersion").notEmpty();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/os/TestPhysicalMemoryEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.os;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.event.os.TestPhysicalMemoryEvent
+ */
+public class TestPhysicalMemoryEvent {
+    private final static String EVENT_NAME = EventNames.PhysicalMemory;
+
+    public static void main(String[] args) throws Throwable {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME);
+        recording.start();
+        recording.stop();
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        Events.hasEvents(events);
+        for (RecordedEvent event : events) {
+            System.out.println("Event: " + event);
+            long totalSize = Events.assertField(event, "totalSize").atLeast(0L).getValue();
+            Events.assertField(event, "usedSize").atLeast(0L).atMost(totalSize);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/os/TestSystemProcess.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.os;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.event.os.TestSystemProcess
+ */
+public class TestSystemProcess {
+    private final static String EVENT_NAME = EventNames.SystemProcess;
+
+    public static void main(String[] args) throws Throwable {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME);
+        recording.start();
+        recording.stop();
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        Events.hasEvents(events);
+        for (RecordedEvent event : events) {
+            System.out.println("Event: " + event);
+            Events.assertField(event, "pid").notEmpty();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/os/TestThreadContextSwitches.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.os;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.event.os.TestThreadContextSwitches
+ */
+public class TestThreadContextSwitches {
+    private final static String EVENT_NAME = EventNames.ThreadContextSwitchRate;
+
+    public static void main(String[] args) throws Throwable {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME);
+        recording.start();
+        recording.stop();
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        Events.hasEvents(events);
+        for (RecordedEvent event : events) {
+            System.out.println("Event: " + event);
+            Events.assertField(event, "switchRate").atLeast(0.0f);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/profiling/TestFullStackTrace.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.profiling;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedFrame;
+import jdk.jfr.consumer.RecordedStackTrace;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.RecurseThread;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.event.profiling.TestFullStackTrace
+ */
+public class TestFullStackTrace {
+    private final static String EVENT_NAME = EventNames.ExecutionSample;
+    private final static int MAX_DEPTH = 64; // currently hardcoded in jvm
+
+    public static void main(String[] args) throws Throwable {
+        RecurseThread[] threads = new RecurseThread[3];
+        for (int i = 0; i < threads.length; ++i) {
+            int depth = MAX_DEPTH - 1 + i;
+            threads[i] = new RecurseThread(depth);
+            threads[i].setName("recursethread-" + depth);
+            threads[i].start();
+        }
+
+        for (RecurseThread thread : threads) {
+            while (!thread.isInRunLoop()) {
+                Thread.sleep(20);
+            }
+        }
+
+        assertStackTraces(threads);
+
+        for (RecurseThread thread : threads) {
+            thread.quit();
+            thread.join();
+        }
+    }
+
+    private static void assertStackTraces( RecurseThread[] threads) throws Throwable {
+        Recording recording= null;
+        do {
+            recording = new Recording();
+            recording.enable(EVENT_NAME).withPeriod(Duration.ofMillis(50));
+            recording.start();
+            Thread.sleep(500);
+            recording.stop();
+        } while (!hasValidStackTraces(recording, threads));
+    }
+
+    private static boolean hasValidStackTraces(Recording recording, RecurseThread[] threads) throws Throwable {
+        boolean[] isEventFound = new boolean[threads.length];
+
+        for (RecordedEvent event : Events.fromRecording(recording)) {
+            //System.out.println("Event: " + event);
+            String threadName = Events.assertField(event, "sampledThread.javaName").getValue();
+            long threadId = Events.assertField(event, "sampledThread.javaThreadId").getValue();
+
+            for (int threadIndex = 0; threadIndex < threads.length; ++threadIndex) {
+                RecurseThread currThread = threads[threadIndex];
+                if (threadId == currThread.getId()) {
+                    System.out.println("ThreadName=" + currThread.getName() + ", depth=" + currThread.totalDepth);
+                    Asserts.assertEquals(threadName, currThread.getName(), "Wrong thread name");
+                    if ("recurseEnd".equals(getTopMethodName(event))) {
+                        isEventFound[threadIndex] = true;
+                        checkEvent(event, currThread.totalDepth);
+                        break;
+                    }
+                }
+            }
+        }
+
+        for (int i = 0; i < threads.length; ++i) {
+            String msg = "threadIndex=%d, recurseDepth=%d, isEventFound=%b%n";
+            System.out.printf(msg, i, threads[i].totalDepth, isEventFound[i]);
+        }
+        for (int i = 0; i < threads.length; ++i) {
+            if(!isEventFound[i]) {
+               // no assertion, let's retry.
+               // Could be race condition, i.e safe point during Thread.sleep
+               System.out.println("Falied to validate all threads, will retry.");
+               return false;
+            }
+        }
+        return true;
+    }
+
+    public static String getTopMethodName(RecordedEvent event) {
+        List<RecordedFrame> frames = event.getStackTrace().getFrames();
+        Asserts.assertFalse(frames.isEmpty(), "JavaFrames was empty");
+        return frames.get(0).getMethod().getName();
+    }
+
+    private static void checkEvent(RecordedEvent event, int expectedDepth) throws Throwable {
+        RecordedStackTrace stacktrace = null;
+        try {
+            stacktrace = event.getStackTrace();
+            List<RecordedFrame> frames = stacktrace.getFrames();
+            Asserts.assertEquals(Math.min(MAX_DEPTH, expectedDepth), frames.size(), "Wrong stacktrace depth. Expected:" + expectedDepth);
+            List<String> expectedMethods = getExpectedMethods(expectedDepth);
+            Asserts.assertEquals(expectedMethods.size(), frames.size(), "Wrong expectedMethods depth. Test error.");
+
+            for (int i = 0; i < frames.size(); ++i) {
+                String name = frames.get(i).getMethod().getName();
+                String expectedName = expectedMethods.get(i);
+                System.out.printf("method[%d]=%s, expected=%s%n", i, name, expectedName);
+                Asserts.assertEquals(name, expectedName, "Wrong method name");
+            }
+
+            boolean isTruncated = stacktrace.isTruncated();
+            boolean isTruncateExpected = expectedDepth > MAX_DEPTH;
+            Asserts.assertEquals(isTruncated, isTruncateExpected, "Wrong value for isTruncated. Expected:" + isTruncateExpected);
+
+            String firstMethod = frames.get(frames.size() - 1).getMethod().getName();
+            boolean isFullTrace = "run".equals(firstMethod);
+            String msg = String.format("Wrong values for isTruncated=%b, isFullTrace=%b", isTruncated, isFullTrace);
+            Asserts.assertTrue(isTruncated != isFullTrace, msg);
+        } catch (Throwable t) {
+            System.out.println(String.format("stacktrace:%n%s", stacktrace));
+            throw t;
+        }
+    }
+
+    private static List<String> getExpectedMethods(int depth) {
+        List<String> methods = new ArrayList<>();
+        methods.add("recurseEnd");
+        for (int i = 0; i < depth - 2; ++i) {
+            methods.add((i % 2) == 0 ? "recurseA" : "recurseB");
+        }
+        methods.add("run");
+        if (depth > MAX_DEPTH) {
+            methods = methods.subList(0, MAX_DEPTH);
+        }
+        return methods;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestActiveRecordingEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.runtime;
+
+import static jdk.test.lib.Asserts.assertEquals;
+import static jdk.test.lib.Asserts.assertNull;
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.List;
+
+import jdk.jfr.EventType;
+import jdk.jfr.Recording;
+import jdk.jfr.Timespan;
+import jdk.jfr.Timestamp;
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Tests that the recording properties are properly reflected in the ActiveRecording event
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.event.runtime.TestActiveRecordingEvent
+ */
+public final class TestActiveRecordingEvent {
+
+    private static final String ACTIVE_RECORDING_EVENT_NAME = EventNames.ActiveRecording;
+
+    private static final Path MY_JFR_FILEPATH = Paths.get("", "my.jfr");
+
+    private static final long MAX_SIZE = 1000000L;
+
+    private static final Duration MAX_AGE = Duration.ofDays(1);
+
+    private static final Duration REC_DURATION = Duration.ofMinutes(10);
+
+    private static final String REC_NAME = "MYNAME";
+
+    public static void main(String[] args) throws Throwable {
+        testWithPath(null);
+        testWithPath(MY_JFR_FILEPATH);
+    }
+
+    private static void testWithPath(Path path) throws Throwable {
+        Recording recording = new Recording();
+        recording.enable(ACTIVE_RECORDING_EVENT_NAME);
+
+        recording.setDuration(REC_DURATION);
+        recording.setMaxSize(MAX_SIZE);
+        recording.setMaxAge(MAX_AGE);
+        recording.setName(REC_NAME);
+        if (path != null) {
+            recording.setToDisk(true);
+            recording.setDestination(path);
+        }
+
+        long tsBeforeStart = Instant.now().toEpochMilli();
+        recording.start();
+        recording.stop();
+        long tsAfterStop = Instant.now().toEpochMilli();
+
+        List<RecordedEvent> events = Events.fromRecording(recording);
+
+        Events.hasEvents(events);
+        RecordedEvent ev = events.get(0);
+
+        // Duration must be kept in milliseconds
+        assertEquals(REC_DURATION.toMillis(), ev.getValue("recordingDuration"));
+
+        assertEquals(MAX_SIZE, ev.getValue("maxSize"));
+
+        // maxAge must be kept in milliseconds
+        assertEquals(MAX_AGE.toMillis(), ev.getValue("maxAge"));
+
+        EventType evType = ev.getEventType();
+        ValueDescriptor durationField = evType.getField("recordingDuration");
+        assertEquals(durationField.getAnnotation(Timespan.class).value(), Timespan.MILLISECONDS);
+
+        if (path == null) {
+            assertNull(ev.getValue("destination"));
+        } else {
+            assertEquals(path.toAbsolutePath().toString(), ev.getValue("destination").toString());
+        }
+
+        ValueDescriptor recordingStartField = evType.getField("recordingStart");
+        assertEquals(recordingStartField.getAnnotation(Timestamp.class).value(), Timestamp.MILLISECONDS_SINCE_EPOCH);
+
+        long tsRecordingStart = ev.getValue("recordingStart");
+        assertTrue(tsBeforeStart <= tsRecordingStart);
+        assertTrue(tsAfterStop >= tsRecordingStart);
+
+        assertEquals(recording.getId(), ev.getValue("id"));
+
+        ValueDescriptor maxAgeField = evType.getField("maxAge");
+        assertEquals(maxAgeField.getAnnotation(Timespan.class).value(), Timespan.MILLISECONDS);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestActiveSettingEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.runtime;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jdk.jfr.Configuration;
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Recording;
+import jdk.jfr.Registered;
+import jdk.jfr.SettingDescriptor;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Tests that active setting are available in the ActiveSettingevent
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.event.runtime.TestActiveSettingEvent
+ */
+public final class TestActiveSettingEvent {
+
+    private static class MyEvent extends Event {
+    }
+
+    @Registered(false)
+    private static class MyRegistrationEvent extends Event {
+    }
+
+    private static final String ACTIVE_SETTING_EVENT_NAME = EventNames.ActiveSetting;
+
+    public static void main(String[] args) throws Throwable {
+        testDefaultSettings();;
+        testProfileSettings();;
+        testNewSettings();
+        testChangedSetting();
+        testUnregistered();
+        testRegistration();
+    }
+
+    private static void testProfileSettings() throws Exception {
+        testSettingConfiguration("profile");
+    }
+
+    private static void testDefaultSettings() throws Exception {
+        testSettingConfiguration("default");
+    }
+
+    private static void testRegistration() throws Exception {
+        // Register new
+        try (Recording recording = new Recording()) {
+            recording.enable(ACTIVE_SETTING_EVENT_NAME);
+            recording.start();
+            FlightRecorder.register(MyRegistrationEvent.class);
+            recording.stop();
+            List<RecordedEvent> events = Events.fromRecording(recording);
+            Events.hasEvents(events);
+            EventType type = EventType.getEventType(MyRegistrationEvent.class);
+            assertSetting(events, type, "threshold", "0 ns");
+            assertSetting(events, type, "enabled", "true");
+            assertSetting(events, type, "stackTrace", "true");
+        }
+        // Register unregistered
+        FlightRecorder.unregister(MyEvent.class);
+        try (Recording recording = new Recording()) {
+            recording.enable(ACTIVE_SETTING_EVENT_NAME);
+            recording.start();
+            FlightRecorder.register(MyRegistrationEvent.class);
+            recording.stop();
+            EventType type = EventType.getEventType(MyRegistrationEvent.class);
+            List<RecordedEvent> events = Events.fromRecording(recording);
+            Events.hasEvents(events);
+            type = EventType.getEventType(MyRegistrationEvent.class);
+            assertSetting(events, type, "threshold", "0 ns");
+            assertSetting(events, type, "enabled", "true");
+            assertSetting(events, type, "stackTrace", "true");
+        }
+    }
+
+    private static void testUnregistered() throws Exception {
+        FlightRecorder.register(MyEvent.class);
+        EventType type = EventType.getEventType(MyEvent.class);
+        FlightRecorder.unregister(MyEvent.class);
+        try (Recording recording = new Recording()) {
+            recording.enable(ACTIVE_SETTING_EVENT_NAME);
+            recording.start();
+            MyEvent m = new MyEvent();
+            m.commit();
+            recording.stop();
+            List<RecordedEvent> events = Events.fromRecording(recording);
+            Events.hasEvents(events);
+            assertNotSetting(events, type, "threshold", "0 ns");
+            assertNotSetting(events, type, "enabled", "true");
+            assertNotSetting(events, type, "stackTrace", "true");
+        }
+    }
+
+    private static void testNewSettings() throws Exception {
+        try (Recording recording = new Recording()) {
+            recording.enable(ACTIVE_SETTING_EVENT_NAME);
+            recording.start();
+            MyEvent m = new MyEvent();
+            m.commit();
+            recording.stop();
+            List<RecordedEvent> events = Events.fromRecording(recording);
+            Events.hasEvents(events);
+            EventType type = EventType.getEventType(MyEvent.class);
+            assertSetting(events, type, "threshold", "0 ns");
+            assertSetting(events, type, "enabled", "true");
+            assertSetting(events, type, "stackTrace", "true");
+            assertNotSetting(events, type, "period", "everyChunk");
+        }
+    }
+
+    private static void testChangedSetting() throws Exception {
+        EventType type = EventType.getEventType(MyEvent.class);
+        Map<String, String> base = new HashMap<>();
+        base.put(ACTIVE_SETTING_EVENT_NAME + "#enabled", "true");
+        try (Recording recording = new Recording()) {
+            recording.setSettings(base);
+            recording.start();
+            Map<String, String> newS = new HashMap<>(base);
+            newS.put(type.getName() + "#enabled", "true");
+            newS.put(type.getName() + "#threshold", "11 ns");
+            recording.setSettings(newS);
+            recording.stop();
+            List<RecordedEvent> events = Events.fromRecording(recording);
+            Events.hasEvents(events);
+            assertSetting(events, type, "threshold", "0 ns"); // initial value
+            assertSetting(events, type, "enabled", "true");
+            assertSetting(events, type, "threshold", "11 ns"); // changed value
+        }
+    }
+
+    private static void assertSetting(List<RecordedEvent> events, EventType evenType, String settingName, String settingValue) throws Exception {
+        if (!hasSetting(events, evenType, settingName, settingValue)) {
+            throw new Exception("Could not find setting " + settingName + " with value " + settingValue + " for event type " + evenType.getName());
+        }
+    }
+
+    private static void assertNotSetting(List<RecordedEvent> events, EventType evenType, String settingName, String settingValue) throws Exception {
+        if (hasSetting(events, evenType, settingName, settingValue)) {
+            throw new Exception("Found unexpected setting " + settingName + " with value " + settingValue + " for event type " + evenType.getName());
+        }
+    }
+
+    private static boolean hasSetting(List<RecordedEvent> events, EventType evenType, String settingName, String settingValue) throws Exception {
+        for (RecordedEvent e : events) {
+            if (e.getEventType().getName().equals(ACTIVE_SETTING_EVENT_NAME)) {
+                String name = e.getValue("name");
+                String value = e.getValue("value");
+                Long id = e.getValue("id");
+                if (evenType.getId() == id && name.equals(settingName) && settingValue.equals(value)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private static void testSettingConfiguration(String configurationName) throws Exception {
+        System.out.println("Testing configuration " + configurationName);
+        Configuration c = Configuration.getConfiguration(configurationName);
+        Map<String, String> settingValues = c.getSettings();
+        // Don't want to add these settings to the jfc-files we ship since they
+        // are not useful to configure. They are however needed to make the test
+        // pass.
+        settingValues.put(EventNames.ActiveSetting + "#stackTrace", "false");
+        settingValues.put(EventNames.ActiveSetting + "#threshold", "0 ns");
+        settingValues.put(EventNames.ActiveRecording + "#stackTrace", "false");
+        settingValues.put(EventNames.ActiveRecording + "#threshold", "0 ns");
+        settingValues.put(EventNames.JavaExceptionThrow + "#threshold", "0 ns");
+        settingValues.put(EventNames.JavaErrorThrow + "#threshold", "0 ns");
+
+        try (Recording recording = new Recording(c)) {
+            Map<Long, EventType> eventTypes = new HashMap<>();
+            for (EventType et : FlightRecorder.getFlightRecorder().getEventTypes()) {
+                eventTypes.put(et.getId(), et);
+            }
+            recording.start();
+            Map<String, String> expectedSettings = new HashMap<>();
+            for (EventType type : FlightRecorder.getFlightRecorder().getEventTypes()) {
+                for (SettingDescriptor s : type.getSettingDescriptors()) {
+                    String settingName = type.getName() + "#" + s.getName();
+                    String value = settingValues.get(settingName);
+                    if (value == null) {
+                        throw new Exception("Could not find setting with name " + settingName);
+                    }
+                    // Prefer to have ms unit in jfc file
+                    if (value.equals("0 ms")) {
+                        value = "0 ns";
+                    }
+                    expectedSettings.put(settingName, value);
+                }
+            }
+            recording.stop();
+
+            for (RecordedEvent e : Events.fromRecording(recording)) {
+                if (e.getEventType().getName().equals(ACTIVE_SETTING_EVENT_NAME)) {
+                    Long id = e.getValue("id");
+                    EventType et = eventTypes.get(id);
+                    if (et == null) {
+                        throw new Exception("Could not find event type with id " + id);
+                    }
+                    String name = e.getValue("name");
+                    String settingName = et.getName() + "#" + name;
+                    String value = e.getValue("value");
+                    String expectedValue = expectedSettings.get(settingName);
+                    if (expectedValue != null) {
+                        if (value.equals("0 ms")) {
+                            value = "0 ns";
+                        }
+                        Asserts.assertEquals(expectedValue, value, "Incorrect settings value for " + settingName + " was " + value + ", expected " + expectedValue);
+                        expectedSettings.remove(settingName);
+                    }
+                }
+            }
+            if (!expectedSettings.isEmpty()) {
+                throw new Exception("Not all setting in event. Missing " + expectedSettings.keySet());
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestBiasedLockRevocationEvents.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.runtime;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.*;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.dcmd.PidJcmdExecutor;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.process.OutputAnalyzer;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.FutureTask;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ *
+ * @run main/othervm jdk.jfr.event.runtime.TestBiasedLockRevocationEvents
+ */
+public class TestBiasedLockRevocationEvents {
+
+    public static void main(String[] args) throws Throwable {
+        testSingleRevocation();
+        testBulkRevocation();
+        testSelfRevocation();
+        testExitedThreadRevocation();
+        testBulkRevocationNoRebias();
+        testRevocationSafepointIdCorrelation();
+    }
+
+    // Default value of BiasedLockingBulkRebiasThreshold is 20, and BiasedLockingBulkRevokeTreshold is 40.
+    // Using a value that will hit the first threshold once, and the second one the next time.
+    private static final int BULK_REVOKE_THRESHOLD = 25;
+
+    static void touch(Object lock) {
+        synchronized(lock) {
+        }
+    }
+
+    static Thread triggerRevocation(int numRevokes, Class<?> lockClass) throws Throwable {
+        Object[] locks = new Object[numRevokes];
+        for (int i = 0; i < locks.length; ++i) {
+            locks[i] = lockClass.getDeclaredConstructor().newInstance();
+            touch(locks[i]);
+        }
+
+        Thread biasBreaker = new Thread("BiasBreaker") {
+            @Override
+            public void run() {
+                for (Object lock : locks) {
+                    touch(lock);
+                }
+            }
+        };
+
+        biasBreaker.start();
+        biasBreaker.join();
+
+        return biasBreaker;
+    }
+
+    // Basic stack trace validation, checking the name of the leaf method
+    static void validateStackTrace(RecordedStackTrace stackTrace, String leafMethodName) {
+        List<RecordedFrame> frames = stackTrace.getFrames();
+        Asserts.assertFalse(frames.isEmpty());
+        String name = frames.get(0).getMethod().getName();
+        Asserts.assertEquals(name, leafMethodName);
+    }
+
+    // Validates that the given stack trace refers to lock.touch(); in triggerRevocation
+    static void validateStackTrace(RecordedStackTrace stackTrace) {
+        validateStackTrace(stackTrace, "touch");
+    }
+
+    static void testSingleRevocation() throws Throwable {
+        class MyLock {};
+
+        Recording recording = new Recording();
+
+        recording.enable(EventNames.BiasedLockRevocation);
+        recording.start();
+
+        Thread biasBreaker = triggerRevocation(1, MyLock.class);
+
+        recording.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(recording);
+
+        // We may or may not catch a second revocation from the biasBreaker thread exiting
+        Asserts.assertGreaterThanOrEqual(events.size(), 1);
+
+        RecordedEvent event = events.get(0);
+        Events.assertEventThread(event, biasBreaker);
+        Events.assertEventThread(event, "previousOwner", Thread.currentThread());
+
+        RecordedClass lockClass = event.getValue("lockClass");
+        Asserts.assertEquals(lockClass.getName(), MyLock.class.getName());
+
+        validateStackTrace(event.getStackTrace());
+    }
+
+    static void testBulkRevocation() throws Throwable {
+        class MyLock {};
+
+        Recording recording = new Recording();
+
+        recording.enable(EventNames.BiasedLockClassRevocation);
+        recording.start();
+
+        Thread biasBreaker = triggerRevocation(BULK_REVOKE_THRESHOLD, MyLock.class);
+
+        recording.stop();
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        Asserts.assertEQ(events.size(), 1);
+
+        RecordedEvent event = events.get(0);
+        Events.assertEventThread(event, biasBreaker);
+        Events.assertField(event, "disableBiasing").equal(false);
+
+        RecordedClass lockClass = event.getValue("revokedClass");
+        Asserts.assertEquals(lockClass.getName(), MyLock.class.getName());
+
+        validateStackTrace(event.getStackTrace());
+    }
+
+    static void testSelfRevocation() throws Throwable {
+        class MyLock {};
+
+        Recording recording = new Recording();
+
+        recording.enable(EventNames.BiasedLockSelfRevocation);
+        recording.start();
+
+        MyLock l = new MyLock();
+        touch(l);
+        Thread.holdsLock(l);
+
+        recording.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        Asserts.assertEQ(events.size(), 1);
+
+        RecordedEvent event = events.get(0);
+        Events.assertEventThread(event, Thread.currentThread());
+
+        validateStackTrace(event.getStackTrace(), "holdsLock");
+    }
+
+    static void testExitedThreadRevocation() throws Throwable {
+        class MyLock {};
+
+        Recording recording = new Recording();
+
+        recording.enable(EventNames.BiasedLockRevocation);
+        recording.start();
+
+        FutureTask<MyLock> lockerTask = new FutureTask<>(() -> {
+           MyLock l = new MyLock();
+           touch(l);
+           return l;
+        });
+
+        Thread locker = new Thread(lockerTask, "BiasLocker");
+        locker.start();
+        locker.join();
+
+        // Even after joining, the VM has a bit more work to do before the thread is actually removed
+        // from the threads list. Ensure that this has happened before proceeding.
+        while (true) {
+            PidJcmdExecutor jcmd = new PidJcmdExecutor();
+            OutputAnalyzer oa = jcmd.execute("Thread.print", true);
+            String lockerThreadFound = oa.firstMatch("BiasLocker");
+            if (lockerThreadFound == null) {
+                break;
+            }
+        };
+
+        MyLock l = lockerTask.get();
+        touch(l);
+
+        recording.stop();
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        Events.hasEvents(events);
+
+        // Joining the locker thread can cause revocations as well, search for the interesting one
+        for (RecordedEvent event : events) {
+            RecordedClass lockClass = event.getValue("lockClass");
+            if (lockClass.getName().equals(MyLock.class.getName())) {
+                Events.assertEventThread(event, Thread.currentThread());
+                // Previous owner will usually be null, but can also be a thread that
+                // was created after the BiasLocker thread exited due to address reuse.
+                RecordedThread prevOwner = event.getValue("previousOwner");
+                if (prevOwner != null) {
+                    Asserts.assertNE(prevOwner.getJavaName(), "BiasLocker");
+                }
+                validateStackTrace(event.getStackTrace());
+                return;
+            }
+        }
+        Asserts.fail("Did not find any revocation event for MyLock");
+    }
+
+    static void testBulkRevocationNoRebias() throws Throwable {
+        class MyLock {};
+
+        Recording recording = new Recording();
+
+        recording.enable(EventNames.BiasedLockClassRevocation);
+        recording.start();
+
+        Thread biasBreaker0 = triggerRevocation(BULK_REVOKE_THRESHOLD, MyLock.class);
+        Thread biasBreaker1 = triggerRevocation(BULK_REVOKE_THRESHOLD, MyLock.class);
+
+        recording.stop();
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        Asserts.assertEQ(events.size(), 2);
+
+        // The rebias event should occur before the noRebias one
+        RecordedEvent eventRebias = events.get(0).getStartTime().isBefore(events.get(1).getStartTime()) ? events.get(0) : events.get(1);
+        RecordedEvent eventNoRebias = events.get(0).getStartTime().isBefore(events.get(1).getStartTime()) ? events.get(1) : events.get(0);
+
+        Events.assertEventThread(eventRebias, biasBreaker0);
+        Events.assertField(eventRebias, "disableBiasing").equal(false);
+
+        Events.assertEventThread(eventNoRebias, biasBreaker1);
+        Events.assertField(eventNoRebias, "disableBiasing").equal(true);
+
+        RecordedClass lockClassRebias = eventRebias.getValue("revokedClass");
+        Asserts.assertEquals(lockClassRebias.getName(), MyLock.class.getName());
+        RecordedClass lockClassNoRebias = eventNoRebias.getValue("revokedClass");
+        Asserts.assertEquals(lockClassNoRebias.getName(), MyLock.class.getName());
+
+        validateStackTrace(eventRebias.getStackTrace());
+        validateStackTrace(eventNoRebias.getStackTrace());
+    }
+
+    static void testRevocationSafepointIdCorrelation() throws Throwable {
+        class MyLock {};
+
+        Recording recording = new Recording();
+
+        recording.enable(EventNames.BiasedLockRevocation);
+        recording.enable(EventNames.BiasedLockClassRevocation);
+        recording.enable(EventNames.ExecuteVMOperation);
+        recording.start();
+
+        triggerRevocation(BULK_REVOKE_THRESHOLD, MyLock.class);
+
+        recording.stop();
+        List<RecordedEvent> events = Events.fromRecording(recording);
+
+        // Find all biased locking related VMOperation events
+        HashMap<Integer, RecordedEvent> vmOperations = new HashMap<Integer, RecordedEvent>();
+        for (RecordedEvent event : events) {
+            if ((event.getEventType().getName().equals(EventNames.ExecuteVMOperation)) &&
+                    (event.getValue("operation").toString().contains("Bias"))) {
+                vmOperations.put(event.getValue("safepointId"), event);
+            }
+        }
+
+        int revokeCount = 0;
+        int bulkRevokeCount = 0;
+
+        // Match all revoke events to a corresponding VMOperation event
+        for (RecordedEvent event : events) {
+            if (event.getEventType().getName().equals(EventNames.BiasedLockRevocation)) {
+                RecordedEvent vmOpEvent = vmOperations.remove(event.getValue("safepointId"));
+                if (event.getValue("safepointId").toString().equals("-1")) {
+                    Asserts.assertEquals(vmOpEvent, null);
+                } else {
+                    Events.assertField(vmOpEvent, "operation").equal("RevokeBias");
+                    revokeCount++;
+                }
+            } else if (event.getEventType().getName().equals(EventNames.BiasedLockClassRevocation)) {
+                RecordedEvent vmOpEvent = vmOperations.remove(event.getValue("safepointId"));
+                Events.assertField(vmOpEvent, "operation").equal("BulkRevokeBias");
+                bulkRevokeCount++;
+            }
+        }
+
+        // All VMOperations should have had a matching revoke event
+        Asserts.assertEQ(vmOperations.size(), 0);
+
+        Asserts.assertGT(bulkRevokeCount, 0);
+        Asserts.assertGT(revokeCount, bulkRevokeCount);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestClassDefineEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.runtime;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedClass;
+import jdk.jfr.consumer.RecordedClassLoader;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.TestClassLoader;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @build jdk.jfr.event.runtime.TestClasses
+ * @run main/othervm jdk.jfr.event.runtime.TestClassDefineEvent
+ */
+public final class TestClassDefineEvent {
+
+    private final static String TEST_CLASS_NAME = "jdk.jfr.event.runtime.TestClasses";
+    private final static String EVENT_NAME = EventNames.ClassDefine;
+
+    public static void main(String[] args) throws Throwable {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME);
+        TestClassLoader cl = new TestClassLoader();
+        recording.start();
+        cl.loadClass(TEST_CLASS_NAME);
+        recording.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        boolean foundTestClasses = false;
+        for (RecordedEvent event : events) {
+            System.out.println(event);
+            RecordedClass definedClass = event.getValue("definedClass");
+            if (TEST_CLASS_NAME.equals(definedClass.getName())) {
+                RecordedClassLoader definingClassLoader = definedClass.getClassLoader();
+                Asserts.assertNotNull(definingClassLoader, "Defining Class Loader should not be null");
+                RecordedClass definingClassLoaderType = definingClassLoader.getType();
+                Asserts.assertNotNull(definingClassLoaderType, "The defining Class Loader type should not be null");
+                Asserts.assertEquals(cl.getClass().getName(), definingClassLoaderType.getName(),
+                    "Expected type " + cl.getClass().getName() + ", got type " + definingClassLoaderType.getName());
+                Asserts.assertEquals(cl.getName(), definingClassLoader.getName(),
+                    "Defining Class Loader should have the same name as the original class loader");
+                foundTestClasses = true;
+            }
+        }
+        Asserts.assertTrue(foundTestClasses, "No class define event found for " + TEST_CLASS_NAME);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestClassLoadEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.runtime;
+
+import java.time.Duration;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedClass;
+import jdk.jfr.consumer.RecordedClassLoader;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.TestClassLoader;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @build jdk.jfr.event.runtime.TestClasses
+ * @run main/othervm jdk.jfr.event.runtime.TestClassLoadEvent
+ */
+public final class TestClassLoadEvent {
+
+    private final static String TEST_CLASS_NAME = "jdk.jfr.event.runtime.TestClasses";
+    private final static String BOOT_CLASS_LOADER_NAME = "boot";
+    private final static String SEARCH_CLASS_NAME = "java.lang.Object";
+    private final static String SEARCH_PACKAGE_NAME = "java/lang";
+    private final static String SEARCH_MODULE_NAME = "java.base";
+    private final static String EVENT_NAME = EventNames.ClassLoad;
+
+    public static void main(String[] args) throws Throwable {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME).withThreshold(Duration.ofMillis(0));
+        TestClassLoader cl = new TestClassLoader();
+        recording.start();
+        cl.loadClass(TEST_CLASS_NAME);
+        recording.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        boolean isLoaded = false;
+        for (RecordedEvent event : events) {
+            RecordedClass loadedClass = event.getValue("loadedClass");
+            if (SEARCH_CLASS_NAME.equals(loadedClass.getName())) {
+                System.out.println(event);
+                Events.assertClassPackage(loadedClass, SEARCH_PACKAGE_NAME);
+                Events.assertClassModule(loadedClass, SEARCH_MODULE_NAME);
+                RecordedClassLoader initiatingClassLoader = event.getValue("initiatingClassLoader");
+                Asserts.assertEquals(cl.getClass().getName(), initiatingClassLoader.getType().getName(),
+                    "Expected type " + cl.getClass().getName() + ", got type " + initiatingClassLoader.getType().getName());
+                RecordedClassLoader definingClassLoader = loadedClass.getClassLoader();
+                Asserts.assertEquals(BOOT_CLASS_LOADER_NAME, definingClassLoader.getName(),
+                    "Expected boot loader to be the defining class loader");
+                Asserts.assertNull(definingClassLoader.getType(), "boot loader should not have a type");
+                isLoaded = true;
+            }
+        }
+        Asserts.assertTrue(isLoaded, "No class load event found for class " + SEARCH_CLASS_NAME);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestClassLoaderStatsEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.runtime;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedClassLoader;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @build jdk.jfr.event.runtime.TestClasses
+ * @run main/othervm jdk.jfr.event.runtime.TestClassLoaderStatsEvent
+ */
+public class TestClassLoaderStatsEvent {
+    private final static String EVENT_NAME = EventNames.ClassLoaderStatistics;
+    private final static String CLASS_LOADER_NAME = "MyDummyClassLoader";
+    private final static String CLASSLOADER_TYPE_NAME = "jdk.jfr.event.runtime.TestClassLoaderStatsEvent$DummyClassLoader";
+    public static DummyClassLoader dummyloader;
+
+    public static void main(String[] args) throws Throwable {
+        createDummyClassLoader(CLASS_LOADER_NAME);
+
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME);
+        recording.start();
+        recording.stop();
+        List<RecordedEvent> consumer = Events.fromRecording(recording);
+        Events.hasEvents(consumer);
+
+        boolean isAnyFound = false;
+        for (RecordedEvent event : consumer) {
+            System.out.println("Event:" + event);
+            if (Events.assertField(event, "classLoader").getValue() == null) {
+                continue;
+            }
+            RecordedClassLoader recordedClassLoader = event.getValue("classLoader");
+            if (CLASSLOADER_TYPE_NAME.equals(recordedClassLoader.getType().getName())) {
+                Asserts.assertEquals(CLASS_LOADER_NAME, recordedClassLoader.getName(),
+                    "Expected class loader name " + CLASS_LOADER_NAME + ", got name " + recordedClassLoader.getName());
+                Events.assertField(event, "classCount").equal(1L);
+                Events.assertField(event, "chunkSize").above(1L);
+                Events.assertField(event, "blockSize").above(1L);
+                Events.assertField(event, "anonymousClassCount").equal(1L);
+                Events.assertField(event, "anonymousChunkSize").above(1L);
+                Events.assertField(event, "anonymousBlockSize").above(1L);
+                isAnyFound = true;
+            }
+        }
+        Asserts.assertTrue(isAnyFound, "No events found");
+    }
+
+    private static void createDummyClassLoader(String name) throws Throwable {
+        dummyloader = new DummyClassLoader(name);
+        Class<?> c = Class.forName(TestClass.class.getName(), true, dummyloader);
+        if (c.getClassLoader() != dummyloader) {
+            throw new RuntimeException("TestClass defined by wrong classloader: " + c.getClassLoader());
+        }
+    }
+
+    public static class DummyClassLoader extends ClassLoader {
+
+        static ByteBuffer readClassFile(String name) {
+            String testClasses = System.getProperty("test.classes");
+            File f = new File(testClasses, name);
+            try (FileInputStream fin = new FileInputStream(f)) {
+                FileChannel fc = fin.getChannel();
+                return fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
+            } catch (IOException e) {
+                throw new RuntimeException("Can't open file: " + f, e);
+            }
+        }
+
+        protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+            Class<?> c;
+            if (TestClass.class.getName().equals(name)) {
+                c = findClass(name);
+                if (resolve) {
+                    resolveClass(c);
+                }
+            } else {
+                c = super.loadClass(name, resolve);
+            }
+            return c;
+        }
+
+        protected Class<?> findClass(String name) throws ClassNotFoundException {
+            if (!TestClass.class.getName().equals(name)) {
+                throw new ClassNotFoundException("Unexpected class: " + name);
+            }
+            return defineClass(name, readClassFile(TestClass.class.getName().replace(".", File.separator) + ".class"), null);
+        }
+
+        public DummyClassLoader(String name) {
+            super(name, ClassLoader.getSystemClassLoader());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestClassLoadingStatisticsEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.runtime;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.TestClassLoader;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @build jdk.jfr.event.runtime.TestClasses
+ * @run main/othervm jdk.jfr.event.runtime.TestClassLoadingStatisticsEvent
+ */
+/**
+ * This test will load a number of classes. After each load step we verify that
+ * the loadedClassCount and unloadedClassCount attributes are correct.
+ *
+ * System.gc() will trigger class unloading if -XX:+ExplicitGCInvokesConcurrent
+ * is NOT set. If this flag is set G1 will never unload classes on System.gc()
+ * and CMS will not guarantee that all semantically dead classes will be
+ * unloaded. As far as the "jfr" key guarantees no VM flags are set from the
+ * outside it should be enough with System.gc().
+ */
+public class TestClassLoadingStatisticsEvent {
+
+    private final static String EVENT_PATH = EventNames.ClassLoadingStatistics;
+    private final static String TESTCLASS_PUBLIC_STATIC =
+                "jdk.jfr.event.runtime.TestClasses$TestClassPublicStatic";
+    private final static String TESTCLASS_PUBLIC_STATIC_INNER =
+                "jdk.jfr.event.runtime.TestClasses$TestClassPublicStatic$TestClassPublicStaticInner";
+
+    // Declare unloadableClassLoader as "public static"
+    // to prevent the compiler to optimize away all unread writes
+    public static TestClassLoader unloadableClassLoader;
+
+    public static void main(String[] args) throws Throwable {
+        // Load twice to get more stable result.
+        RecordedEvent event = getCurrentEvent();
+        event = getCurrentEvent();
+
+        // Declare class ClassLoadingStatisticsHelper.
+        TestClasses[] helpers = new TestClasses[10];
+        event = verifyCountDelta(event, 1, 0);
+
+        // Should load classes TestClassPrivate and TestClassPrivateStatic.
+        for (int c = 0; c < helpers.length; c++) {
+            helpers[c] = new TestClasses();
+        }
+        event = verifyCountDelta(event, 2, 0);
+
+        // Load classes TestClassProtected and B2.
+        helpers[0].new TestClassProtected();
+        helpers[1].new TestClassProtected(); // This class is already loaded.
+        new TestClasses.TestClassProtectedStatic();
+        event = verifyCountDelta(event, 2, 0);
+
+        // Load classes TestClassProtected1 and TestClassProtectedStatic1.
+        for (int c = 0; c < helpers.length; c++) {
+            helpers[c].loadClasses();
+        }
+        event = verifyCountDelta(event, 2, 0);
+
+        // Load the classes with separate class loader. Will be unloaded later.
+        unloadableClassLoader = new TestClassLoader();
+
+        unloadableClassLoader.loadClass(TESTCLASS_PUBLIC_STATIC_INNER);
+        event = verifyCountDelta(event, 1, 0);
+
+        unloadableClassLoader.loadClass(TESTCLASS_PUBLIC_STATIC);
+        event = verifyCountDelta(event, 1, 0);
+
+        // This System.gc() should not unload classes, since the
+        // unloadableClassLoader object is still active.
+        System.gc();
+        event = verifyCountDelta(event, 0, 0);
+
+        // make classes are unloaded.
+        unloadableClassLoader = null;
+        System.gc();
+        event = verifyCountDelta(event, 0, 2);
+    }
+
+    private static RecordedEvent getCurrentEvent() throws Throwable {
+        Recording recording = new Recording();
+        recording.enable(EVENT_PATH);
+        recording.start();
+        recording.stop();
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        Asserts.assertFalse(events.isEmpty(), "No events in recording");
+        RecordedEvent event = events.get(0);
+        return event;
+    }
+
+    private static RecordedEvent verifyCountDelta(
+        RecordedEvent prevEvent, int loadDelta, int unloadDelta) throws Throwable {
+        RecordedEvent currEvent = null;
+        try {
+            long prevLoad = Events.assertField(prevEvent, "loadedClassCount").getValue();
+            long prevUnload = Events.assertField(prevEvent, "unloadedClassCount").getValue();
+
+            currEvent = getCurrentEvent();
+            Events.assertField(currEvent, "loadedClassCount").atLeast(prevLoad + loadDelta);
+            Events.assertField(currEvent, "unloadedClassCount").atLeast(prevUnload + unloadDelta);
+            return currEvent;
+        } catch (Throwable t) {
+            System.out.println("verifyCountDelta failed. prevEvent=" + prevEvent + ", currEvent=" + currEvent);
+            throw t;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestClassUnloadEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.runtime;
+
+import java.time.Duration;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedClass;
+import jdk.jfr.consumer.RecordedClassLoader;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.TestClassLoader;
+
+/*
+ * @test
+ * @summary The test verifies that a class unload event is created when class is unloaded
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @build jdk.jfr.event.runtime.TestClasses
+ * @run main/othervm -Xlog:class+unload -Xlog:gc -Xmx16m jdk.jfr.event.runtime.TestClassUnloadEvent
+ */
+
+/**
+ * System.gc() will trigger class unloading if -XX:+ExplicitGCInvokesConcurrent is NOT set.
+ * If this flag is set G1 will never unload classes on System.gc() and
+ * CMS will not guarantee that all semantically dead classes will be unloaded.
+ * As far as the "jfr" key guarantees no VM flags are set from the outside
+ * it should be enough with System.gc().
+ */
+public final class TestClassUnloadEvent {
+    private final static String TEST_CLASS_NAME = "jdk.jfr.event.runtime.TestClasses";
+    private final static String EVENT_PATH = EventNames.ClassUnload;
+
+    // Declare unloadableClassLoader as "public static"
+    // to prevent the compiler to optimize away all unread writes
+    public static TestClassLoader unloadableClassLoader;
+
+    public static void main(String[] args) throws Throwable {
+        Recording recording = new Recording();
+        recording.enable(EVENT_PATH).withThreshold(Duration.ofMillis(0));
+        unloadableClassLoader = new TestClassLoader();
+        recording.start();
+        unloadableClassLoader.loadClass(TEST_CLASS_NAME);
+        unloadableClassLoader = null;
+        System.gc();
+        recording.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        Events.hasEvents(events);
+        boolean isAnyFound = false;
+        for (RecordedEvent event : events) {
+            System.out.println("Event:" + event);
+            RecordedClass unloadedClass = event.getValue("unloadedClass");
+            if (TEST_CLASS_NAME.equals(unloadedClass.getName())) {
+                RecordedClassLoader definingClassLoader = unloadedClass.getClassLoader();
+                Asserts.assertEquals(TestClassLoader.class.getName(), definingClassLoader.getType().getName(),
+                    "Expected " + TestClassLoader.class.getName() + ", got " + definingClassLoader.getType().getName());
+                Asserts.assertEquals(TestClassLoader.CLASS_LOADER_NAME, definingClassLoader.getName(),
+                    "Expected " + TestClassLoader.CLASS_LOADER_NAME + ", got " + definingClassLoader.getName());
+                Asserts.assertFalse(isAnyFound, "Found more than 1 event");
+                isAnyFound = true;
+            }
+        }
+        Asserts.assertTrue(isAnyFound, "No events found");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestClasses.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.runtime;
+
+public class TestClasses {
+
+    protected TestClassPrivate testClassPrivate;
+    protected TestClassPrivateStatic testClassPrivateStatic;
+
+    public TestClasses() {
+        testClassPrivate = new TestClassPrivate();
+        testClassPrivateStatic = new TestClassPrivateStatic();
+    }
+
+    // Classes TestClassPrivate and TestClassPrivateStatic should be loaded at
+    // the same time
+    // as the base class TestClasses
+    private class TestClassPrivate {
+    }
+
+    private static class TestClassPrivateStatic {
+    }
+
+    protected class TestClassProtected {
+    }
+
+    protected static class TestClassProtectedStatic {
+    }
+
+    // When loadClasses() is run, 3 new classes should be loaded.
+    public void loadClasses() throws ClassNotFoundException {
+        final ClassLoader cl = getClass().getClassLoader();
+        cl.loadClass("jdk.jfr.event.runtime.TestClasses$TestClassProtected1");
+        cl.loadClass("jdk.jfr.event.runtime.TestClasses$TestClassProtectedStatic1");
+    }
+
+    protected class TestClassProtected1 {
+    }
+
+    protected static class TestClassProtectedStatic1 {
+        protected TestClassProtectedStaticInner testClassProtectedStaticInner = new TestClassProtectedStaticInner();
+
+        protected static class TestClassProtectedStaticInner {
+        }
+    }
+
+    public static class TestClassPublicStatic {
+        public static class TestClassPublicStaticInner {
+        }
+    }
+
+}
+
+class TestClass {
+    static {
+        // force creation of anonymous class (for the lambda form)
+        Runnable r = () -> System.out.println("Hello");
+        r.run();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestExceptionEvents.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.runtime;
+
+import java.time.Duration;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedClass;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedFrame;
+import jdk.jfr.consumer.RecordedStackTrace;
+import jdk.jfr.consumer.RecordedThread;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.event.runtime.TestExceptionEvents
+ */
+public class TestExceptionEvents {
+
+    private static final String EXCEPTION_EVENT_PATH = EventNames.JavaExceptionThrow;
+    private static final String ERROR_EVENT_PATH  = EventNames.JavaErrorThrow;
+    private static final String EXCEPTION_STATISTICS_PATH = EventNames.ExceptionStatistics;
+
+    private static final String EXCEPTION_MESSAGE = "exceptiontest";
+    private static final String ERROR_MESSAGE = "errortest";
+    private static final String THROWABLE_MESSAGE = "throwabletest";
+
+    private static final int ITERATIONS = 10;
+
+    private static int exceptionCount = 0;
+
+    public static void main(String[] args) throws Throwable {
+        Recording recording = createRecording();
+
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        checkStatisticsEvent(events, exceptionCount);
+        checkThrowableEvents(events, EXCEPTION_EVENT_PATH, ITERATIONS, MyException.class, EXCEPTION_MESSAGE);
+        checkThrowableEvents(events, ERROR_EVENT_PATH, ITERATIONS, MyError.class, ERROR_MESSAGE);
+        checkThrowableEvents(events, EXCEPTION_EVENT_PATH, ITERATIONS, MyThrowable.class, THROWABLE_MESSAGE);
+        checkExceptionStackTrace();
+    }
+
+    private static void checkExceptionStackTrace() throws Exception {
+        @SuppressWarnings("serial")
+        class TestError extends Error {
+        }
+        @SuppressWarnings("serial")
+        class TestException extends Exception {
+        }
+
+        try (Recording r = new Recording()) {
+            r.enable(EventNames.JavaErrorThrow).withStackTrace();
+            r.enable(EventNames.JavaExceptionThrow).withStackTrace();
+            r.start();
+            try {
+                throw new TestError();
+            } catch (Error e) {
+                System.out.println(e.getClass() + " thrown!");
+            }
+            try {
+                throw new TestException();
+            } catch (Exception e) {
+                System.out.println(e.getClass() + " thrown!");
+            }
+            try {
+                throw new Exception();
+            } catch (Exception e) {
+                System.out.println(e.getClass() + " thrown!");
+            }
+            r.stop();
+            List<RecordedEvent> events = Events.fromRecording(r);
+            Events.hasEvents(events);
+            for (RecordedEvent e : events) {
+                RecordedStackTrace rs = e.getStackTrace();
+                RecordedClass rc = e.getValue("thrownClass");
+                List<RecordedFrame> frames = rs.getFrames();
+                RecordedFrame topFrame = frames.get(0);
+                System.out.println(rc.getName() + " Top frame: " + topFrame.getMethod().getName());
+                if (!topFrame.getMethod().getName().equals("<init>")) {
+                    throw new Exception("Expected name of top frame to be <init>");
+                }
+            }
+        }
+    }
+
+    private static Recording createRecording() throws Exception {
+        Recording recording = new Recording();
+        recording.enable(EXCEPTION_STATISTICS_PATH);
+        recording.enable(EXCEPTION_EVENT_PATH).withThreshold(Duration.ofMillis(0));
+        recording.enable(ERROR_EVENT_PATH).withThreshold(Duration.ofMillis(0));
+        recording.start();
+
+        for (int i = 0; i < ITERATIONS; i++) {
+            try {
+                throw new MyException(EXCEPTION_MESSAGE);
+            } catch (MyException e) {
+                exceptionCount++;
+            }
+            try {
+                throw new MyError(ERROR_MESSAGE);
+            } catch (MyError e) {
+                exceptionCount++;
+            }
+            try {
+                throw new MyThrowable(THROWABLE_MESSAGE);
+            } catch (MyThrowable t) {
+                exceptionCount++;
+            }
+        }
+        recording.stop();
+        return recording;
+    }
+
+
+    private static void checkStatisticsEvent(List<RecordedEvent> events, long minCount) throws Exception {
+        // Events are not guaranteed to be in chronological order, take highest value.
+        long count = -1;
+        for(RecordedEvent event : events) {
+            if (Events.isEventType(event, EXCEPTION_STATISTICS_PATH)) {
+                System.out.println("Event: " + event);
+                count = Math.max(count, Events.assertField(event, "throwables").getValue());
+                System.out.println("count=" +  count);
+            }
+        }
+        Asserts.assertTrue(count != -1, "No events of type " + EXCEPTION_STATISTICS_PATH);
+        Asserts.assertGreaterThanOrEqual(count, minCount, "Too few exception count in statistics event");
+    }
+
+    private static void checkThrowableEvents(List<RecordedEvent> events, String eventName,
+        int excpectedEvents, Class<?> expectedClass, String expectedMessage) throws Exception {
+        int count = 0;
+        for(RecordedEvent event : events) {
+            if (Events.isEventType(event, eventName)) {
+                String message = Events.assertField(event, "message").getValue();
+                if (expectedMessage.equals(message)) {
+                    RecordedThread t = event.getThread();
+                    String threadName = t.getJavaName();
+                    if (threadName != null && threadName.equals(Thread.currentThread().getName())) {
+                        RecordedClass jc = event.getValue("thrownClass");
+                        if (jc.getName().equals(expectedClass.getName())) {
+                            count++;
+                        }
+                    }
+                }
+            }
+        }
+        Asserts.assertEquals(count, excpectedEvents, "Wrong event count for type " + eventName);
+    }
+
+    private static class MyException extends Exception {
+        private static final long serialVersionUID = -2614309279743448910L;
+        public MyException(String msg) {
+            super(msg);
+        }
+    }
+
+    private static class MyError extends Error {
+        private static final long serialVersionUID = -8519872786387358196L;
+        public MyError(String msg) {
+            super(msg);
+        }
+    }
+
+    private static class MyThrowable extends Throwable {
+        private static final long serialVersionUID = -7929442863511070361L;
+        public MyThrowable(String msg) {
+            super(msg);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestExceptionSubclass.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.runtime;
+
+import java.util.concurrent.TimeUnit;
+
+/*
+ * @test
+ * @key jfr
+ * @bug 8013122
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.event.runtime.TestExceptionSubclass
+ */
+public class TestExceptionSubclass {
+
+    public TestExceptionSubclass() {
+        try {
+            throw new PerfectlyFineException(TimeUnit.MILLISECONDS);
+        } catch (PerfectlyFineException e) {
+            //thats perfectly fine.
+        }
+    }
+
+    public static void main(String[] args) throws Throwable {
+        new TestExceptionSubclass();
+    }
+
+
+    class PerfectlyFineException extends Error {
+        private static final long serialVersionUID = 1L;
+        private final TimeUnit unit;
+
+        PerfectlyFineException(TimeUnit unit) {
+            this.unit = unit;
+        }
+
+        public String getMessage() {
+            return "Failed in " + unit.toNanos(1) + " ns";
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestJavaBlockedEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.runtime;
+
+import static jdk.test.lib.Asserts.assertFalse;
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.time.Duration;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.management.ThreadMXBeanTool;
+import jdk.test.lib.thread.TestThread;
+import jdk.test.lib.thread.XRun;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ *
+ * @run main/othervm jdk.jfr.event.runtime.TestJavaBlockedEvent
+ */
+public class TestJavaBlockedEvent {
+    private static final String EVENT_NAME = EventNames.JavaMonitorEnter;
+    private static final long THRESHOLD_MILLIS = 1;
+
+    static class Lock {
+    }
+
+    public static void main(String[] args) throws Throwable {
+        Recording recording = new Recording();
+
+        recording.enable(EVENT_NAME).withThreshold(Duration.ofMillis(THRESHOLD_MILLIS));
+        recording.start();
+        final Lock lock = new Lock();
+        final CountDownLatch blockerInLock = new CountDownLatch(1);
+        final CountDownLatch blockingFinished = new CountDownLatch(1);
+        final CountDownLatch blockedFinished = new CountDownLatch(1);
+        TestThread blockerThread = new TestThread(new XRun() {
+            @Override
+            public void xrun() throws Throwable {
+                synchronized (lock) {
+                    blockerInLock.countDown();
+                    blockingFinished.await();
+                }
+                blockedFinished.await();
+            }
+        });
+
+        TestThread blockedThread = new TestThread(new XRun() {
+            @Override
+            public void xrun() throws Throwable {
+                blockerInLock.await();
+                synchronized (lock) {
+                    blockedFinished.countDown();
+                }
+            }
+        });
+        blockerThread.start();
+        blockedThread.start();
+
+        blockerInLock.await();
+        ThreadMXBeanTool.waitUntilBlockingOnObject(blockedThread, Thread.State.BLOCKED, lock);
+        Thread.sleep(2 * THRESHOLD_MILLIS);
+        blockingFinished.countDown();
+        blockedFinished.await();
+
+        blockedThread.join();
+        blockerThread.join();
+        recording.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        boolean isAnyFound = false;
+        for (RecordedEvent event : events) {
+            System.out.println("Event:" + event);
+            if (event.getThread().getJavaThreadId() == blockedThread.getId()) {
+                if (isMyLock(Events.assertField(event, "monitorClass.name").getValue())) {
+                    Events.assertEventThread(event, "previousOwner", blockerThread);
+                    Events.assertField(event, "address").above(0L);
+                    assertFalse(isAnyFound, "Found multiple events");
+                    isAnyFound = true;
+                }
+            }
+        }
+        assertTrue(isAnyFound, "No blocking event from " + blockedThread.getName());
+    }
+
+    private static boolean isMyLock(String className) {
+        return Lock.class.getName().replace('.', '/').equals(className);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestJavaMonitorInflateEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.runtime;
+
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.nio.file.Paths;
+import java.time.Duration;
+import java.util.concurrent.CountDownLatch;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.thread.TestThread;
+import jdk.test.lib.thread.XRun;
+
+/*
+ * @test TestJavaMonitorInflateEvent
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.event.runtime.TestJavaMonitorInflateEvent
+ */
+public class TestJavaMonitorInflateEvent {
+
+    private static final String FIELD_KLASS_NAME = "monitorClass.name";
+    private static final String FIELD_ADDRESS    = "address";
+    private static final String FIELD_CAUSE      = "cause";
+
+    private static final String EVENT_NAME = EventNames.JavaMonitorInflate;
+    private static final long WAIT_TIME = 123456;
+
+    static class Lock {
+    }
+
+    public static void main(String[] args) throws Exception {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME).withThreshold(Duration.ofMillis(0));
+        final Lock lock = new Lock();
+        final CountDownLatch latch = new CountDownLatch(1);
+        // create a thread that waits
+        TestThread waitThread = new TestThread(new XRun() {
+            @Override
+            public void xrun() throws Throwable {
+                synchronized (lock) {
+                    latch.countDown();
+                    lock.wait(WAIT_TIME);
+                }
+            }
+        });
+        try {
+            recording.start();
+            waitThread.start();
+            latch.await();
+            synchronized (lock) {
+                lock.notifyAll();
+            }
+        } finally {
+            waitThread.join();
+            recording.stop();
+        }
+        final String thisThreadName = Thread.currentThread().getName();
+        final String waitThreadName = waitThread.getName();
+        final String lockClassName = lock.getClass().getName().replace('.', '/');
+        boolean isAnyFound = false;
+        try {
+            // Find at least one event with the correct monitor class and check the other fields
+            for (RecordedEvent event : Events.fromRecording(recording)) {
+                assertTrue(EVENT_NAME.equals(event.getEventType().getName()), "mismatched event types?");
+                // Check recorded inflation event is associated with the Lock class used in the test
+                final String recordedMonitorClassName = Events.assertField(event, FIELD_KLASS_NAME).getValue();
+                if (!lockClassName.equals(recordedMonitorClassName)) {
+                    continue;
+                }
+                // Check recorded thread matches one of the threads in the test
+                final String recordedThreadName = event.getThread().getJavaName();
+                if (!(recordedThreadName.equals(waitThreadName) || recordedThreadName.equals(thisThreadName))) {
+                    continue;
+                }
+                Events.assertField(event, FIELD_ADDRESS).notEqual(0L);
+                Events.assertField(event, FIELD_CAUSE).notNull();
+                isAnyFound = true;
+                break;
+            }
+            assertTrue(isAnyFound, "Expected an inflation event from test");
+        } catch (Throwable e) {
+            recording.dump(Paths.get("failed.jfr"));
+            throw e;
+        } finally {
+            recording.close();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestJavaMonitorWaitEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.runtime;
+
+import static jdk.test.lib.Asserts.assertFalse;
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.time.Duration;
+import java.util.concurrent.CountDownLatch;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.thread.TestThread;
+import jdk.test.lib.thread.XRun;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.event.runtime.TestJavaMonitorWaitEvent
+ */
+public class TestJavaMonitorWaitEvent {
+
+    private final static String EVENT_NAME = EventNames.JavaMonitorWait;
+    private static final long WAIT_TIME = 123456;
+
+    static class Lock {
+    }
+
+    static boolean silenceFindBugsNakedNotify;
+
+    public static void main(String[] args) throws Throwable {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME).withThreshold(Duration.ofMillis(0));
+
+        final Lock lock = new Lock();
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        TestThread waitThread = new TestThread(new XRun() {
+            @Override
+            public void xrun() throws Throwable {
+                synchronized (lock) {
+                    latch.countDown();
+                    lock.wait(WAIT_TIME);
+                    silenceFindBugsNakedNotify = false;
+                }
+            }
+        });
+
+        try {
+            recording.start();
+            waitThread.start();
+            latch.await();
+            synchronized (lock) {
+                silenceFindBugsNakedNotify = true;
+                lock.notifyAll();
+            }
+        } finally {
+            waitThread.join();
+            recording.stop();
+        }
+
+        boolean isAnyFound = false;
+        for (RecordedEvent event : Events.fromRecording(recording)) {
+            System.out.println("Event:" + event);
+            if ((long)Events.assertField(event, "timeout").getValue() != WAIT_TIME) {
+                continue;
+            }
+
+            assertFalse(isAnyFound, "Found more than 1 event");
+            isAnyFound = true;
+            Events.assertEventThread(event, waitThread);
+            final String lockClassName = lock.getClass().getName().replace('.', '/');
+            Events.assertField(event, "monitorClass.name").equal(lockClassName);
+            Events.assertField(event, "address").notEqual(0L);
+            Events.assertField(event, "timedOut").equal(false);
+            Events.assertEventThread(event, "notifier", Thread.currentThread());
+        }
+        assertTrue(isAnyFound, "Correct event not found");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestJavaMonitorWaitTimeOut.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.runtime;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedClass;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedThread;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.event.runtime.TestJavaMonitorWaitTimeOut
+ */
+public class TestJavaMonitorWaitTimeOut {
+
+    static final class Lock {
+
+    }
+
+    private static final String THREAD_NAME = "Notifier";
+
+    static class Notifierhread extends Thread {
+        private final Object lock;
+
+        Notifierhread(Object lock) {
+            super(THREAD_NAME);
+            this.lock = lock;
+        }
+
+        public void run() {
+            synchronized (lock) {
+                lock.notify();
+            }
+        }
+    }
+
+    public static void main(String[] args) throws Throwable {
+        try (Recording recording = new Recording()) {
+            recording.enable(EventNames.JavaMonitorWait).withoutThreshold().withoutStackTrace();
+            recording.start();
+            Lock lock = new Lock();
+
+            synchronized (lock) {
+                // event without notifier, should be null
+                lock.wait(10);
+            }
+            Notifierhread s = new Notifierhread(lock);
+
+            synchronized (lock) {
+                s.start();
+                // event with a notifier
+                lock.wait(1_000_000);
+                s.join();
+            }
+
+            synchronized (lock) {
+                // event without a notifier, should be null
+                lock.wait(11);
+            }
+            recording.stop();
+            List<RecordedEvent> events = Events.fromRecording(recording);
+            for (RecordedEvent e : events) {
+                if (isWaitEvent(e)) {
+                    System.out.println(e);
+                }
+            }
+            assertTimeOutEvent(events, 10, null);
+            assertTimeOutEvent(events, 1_000_000, THREAD_NAME);
+            assertTimeOutEvent(events, 11, null);
+        }
+    }
+
+    private static boolean isWaitEvent(RecordedEvent event) {
+        RecordedClass t = event.getValue("monitorClass");
+        return t != null && t.getName().equals(Lock.class.getName());
+    }
+
+    private static void assertTimeOutEvent(List<RecordedEvent> events, long timeout, String expectedThreadName) {
+        for (RecordedEvent e : events) {
+            if (isWaitEvent(e)) {
+                Long l = e.getValue("timeout");
+                if (l == timeout) {
+                    RecordedThread notifier = e.getValue("notifier");
+                    String threadName = null;
+                    if (notifier != null) {
+                        threadName = notifier.getJavaName();
+                    }
+                    Asserts.assertEquals(threadName, expectedThreadName, "Invalid thread");
+                    return;
+                }
+            }
+        }
+        Asserts.fail("Could not find event with monitorClass" + Lock.class.getName());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestJavaThreadStatisticsEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.runtime;
+
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.event.runtime.TestJavaThreadStatisticsEvent
+ */
+public class TestJavaThreadStatisticsEvent {
+    private static final String EVENT_NAME = EventNames.JavaThreadStatistics;
+
+    private static final int THREAD_COUNT = 10;
+    private static final Random RAND = new Random(4711);
+
+    // verify thread count: 0 <= daemon <= active <= peak <= accumulated.
+    public static void main(String[] args) throws Throwable {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME).withThreshold(Duration.ofMillis(10));
+        recording.start();
+
+        List<Thread> threads = new ArrayList<>();
+        for (int i = 0; i < THREAD_COUNT; i++) {
+            Thread thread = new Thread(TestJavaThreadStatisticsEvent::sleepRandom);
+            thread.start();
+            threads.add(thread);
+        }
+        for (Thread thread : threads) {
+            thread.join();
+        }
+
+        recording.stop();
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        boolean isAnyFound = false;
+        for (RecordedEvent event : events) {
+            System.out.println("Event:" + event);
+            isAnyFound = true;
+            // verify thread count: 0 <= daemon <= active <= peak <= accumulated.
+            long daemonCount = Events.assertField(event, "daemonCount").atLeast(0L).getValue();
+            long activeCount = Events.assertField(event, "activeCount").atLeast(daemonCount).getValue();
+            long peakCount = Events.assertField(event, "peakCount").atLeast(activeCount).atLeast(1L).getValue();
+            Events.assertField(event, "accumulatedCount").atLeast(peakCount).getValue();
+        }
+        assertTrue(isAnyFound, "Correct event not found");
+    }
+
+    static void sleepRandom() {
+        try {
+            Thread.sleep(RAND.nextInt(10));
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestJavaThreadStatisticsEventBean.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.runtime;
+
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadMXBean;
+import java.time.Duration;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ *
+ * @run main/othervm jdk.jfr.event.runtime.TestJavaThreadStatisticsEventBean
+ */
+public class TestJavaThreadStatisticsEventBean {
+    private final static String EVENT_NAME = EventNames.JavaThreadStatistics;
+
+    // Compare JFR thread counts to ThreadMXBean counts
+    public static void main(String[] args) throws Throwable {
+        long mxDaemonCount = -1;
+        long mxActiveCount = -1;
+
+        // Loop until we are sure no threads were started during the recording.
+        Recording recording = null;
+        ThreadMXBean mxBean = ManagementFactory.getThreadMXBean();
+        long totalCountBefore = -1;
+        while (totalCountBefore != mxBean.getTotalStartedThreadCount()) {
+            recording = new Recording();
+            recording.enable(EVENT_NAME).withThreshold(Duration.ofMillis(10));
+            totalCountBefore = mxBean.getTotalStartedThreadCount();
+            recording.start();
+            mxDaemonCount = mxBean.getDaemonThreadCount();
+            mxActiveCount = mxBean.getThreadCount();
+            recording.stop();
+            final String msg = "testCountByMXBean: threadsBefore=%d, threadsAfter=%d%n";
+            System.out.format(msg, totalCountBefore, mxBean.getTotalStartedThreadCount());
+        }
+
+        List<RecordedEvent> events= Events.fromRecording(recording);
+        boolean isAnyFound = false;
+        for (RecordedEvent event : events) {
+            System.out.println("Event:" + event);
+            isAnyFound = true;
+            Events.assertField(event, "daemonCount").equal(mxDaemonCount);
+            Events.assertField(event, "activeCount").equal(mxActiveCount);
+            Events.assertField(event, "accumulatedCount").atLeast(mxActiveCount);
+            Events.assertField(event, "peakCount").atLeast(mxActiveCount);
+        }
+        assertTrue(isAnyFound, "Correct event not found");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestModuleEvents.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.runtime;
+
+import static jdk.test.lib.Asserts.assertEquals;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedObject;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Tests the JFR events related to modules
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm --limit-modules java.base,jdk.jfr jdk.jfr.event.runtime.TestModuleEvents
+ */
+public final class TestModuleEvents {
+
+    private static final String MODULE_EXPORT_EVENT_NAME = EventNames.ModuleExport;
+    private static final String MODULE_REQUIRE_EVENT_NAME = EventNames.ModuleRequire;
+    private static final String UNNAMED = "<unnamed>";
+
+    public static void main(String[] args) throws Throwable {
+        verifyRequiredModules();
+        verifyExportedModules();
+    }
+
+    private static void verifyRequiredModules() throws Throwable {
+        Recording recording = new Recording();
+        recording.enable(MODULE_REQUIRE_EVENT_NAME);
+
+        recording.start();
+        recording.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        assertDependency(events, "jdk.jfr", "java.base"); // jdk.jfr requires java.base (by edfault)
+        assertDependency(events, "java.base", "jdk.jfr"); // java.base require jdk.jfr for JDK events, i.e. FileRead
+
+        recording.close();
+    }
+
+    private static void assertDependency(List<RecordedEvent> events, String source, String required) throws Exception {
+        for (RecordedEvent e : events) {
+            String sourceModule = e.getValue("source.name");
+            if (source.equals(sourceModule)) {
+                RecordedObject module = e.getValue("requiredModule");
+                if (module != null) {
+                    if (required.equals(module.getValue("name"))) {
+                        return;
+                    }
+                }
+            }
+        }
+        throw new Exception("Could not find module dependency between " + source + " and requires modeule "+ required);
+    }
+
+    private static void verifyExportedModules() throws Throwable {
+        Recording recording = new Recording();
+        recording.enable(MODULE_EXPORT_EVENT_NAME);
+        recording.start();
+        recording.stop();
+
+        Map<String, String> edges = new HashMap<>();
+
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        events.stream().forEach((ev) -> {
+            String exportedPackage = getValue(ev.getValue("exportedPackage"), "name", UNNAMED);
+            String toModule = getValue(ev.getValue("targetModule"), "name", UNNAMED);
+
+            edges.put(exportedPackage, toModule);
+        });
+
+        // We expect
+        // 1) jdk.jfr -> <unnamed> (because we use the package)
+        // 2) java.util -> <unnamed> (because we use the package)
+        // 3) jdk.jfr.events -> java.base (from the jfr design)
+        // 4) jdk.internal -> jdk.jfr (from the jfr design)
+        // Where 'a -> b' means "package 'a' exported to module 'b'"
+        assertEquals(edges.get("jdk/jfr"), UNNAMED);
+        assertEquals(edges.get("java/util"), UNNAMED);
+        assertEquals(edges.get("jdk/jfr/events"), "java.base");
+        assertEquals(edges.get("jdk/internal"), "jdk.jfr");
+
+        recording.close();
+    }
+
+    // Helper function to get field from a RecordedObject
+    private static String getValue(RecordedObject ro, String field, String defVal) {
+        if (ro != null && ro.getValue(field) != null) {
+            return ro.getValue(field);
+        } else {
+            return defVal;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestNativeLibrariesEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.runtime;
+
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Platform;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.event.runtime.TestNativeLibrariesEvent
+ */
+public class TestNativeLibrariesEvent {
+
+    private final static String EVENT_NAME = EventNames.NativeLibrary;
+
+    public static void main(String[] args) throws Throwable {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME);
+        recording.start();
+        recording.stop();
+
+        List<String> expectedLibs = getExpectedLibs();
+        for (RecordedEvent event : Events.fromRecording(recording)) {
+            System.out.println("Event:" + event);
+            long unsignedTopAddress = event.getValue("topAddress");
+            long unsignedBaseAddress = event.getValue("baseAddress");
+            assertValidAddresses(unsignedBaseAddress, unsignedTopAddress);
+            String lib = Events.assertField(event, "name").notEmpty().getValue();
+            for (String expectedLib : new ArrayList<>(expectedLibs)) {
+                if (lib.contains(expectedLib)) {
+                    expectedLibs.remove(expectedLib);
+                }
+            }
+        }
+        assertTrue(expectedLibs.isEmpty(), "Missing libraries:" + expectedLibs.stream().collect(Collectors.joining(", ")));
+    }
+
+    private static List<String> getExpectedLibs() throws Throwable {
+        String libTemplate = null;
+        if (Platform.isSolaris()) {
+            libTemplate = "lib%s.so";
+        } else if (Platform.isWindows()) {
+            libTemplate = "%s.dll";
+        } else if (Platform.isOSX()) {
+            libTemplate = "lib%s.dylib";
+        } else if (Platform.isLinux()) {
+            libTemplate = "lib%s.so";
+        }
+        if (libTemplate == null) {
+            throw new Exception("Unsupported OS");
+        }
+
+        List<String> libs = new ArrayList<String>();
+        String[] names = { "jvm", "java", "zip" };
+        for (String name : names) {
+            libs.add(String.format(libTemplate, name));
+        }
+        return libs;
+    }
+
+    private static void assertValidAddresses(long unsignedBaseAddress, long unsignedTopAddress) throws Exception {
+        if (unsignedTopAddress != 0) { // guard against missing value (0)
+            if (Long.compareUnsigned(unsignedTopAddress, unsignedBaseAddress) < 0) {
+                throw new Exception("Top address " + Long.toHexString(unsignedTopAddress) + " is below base addess " + Long.toHexString(unsignedBaseAddress));
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestSafepointEvents.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.runtime;
+
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.nio.file.Paths;
+import java.time.Duration;
+import java.util.*;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import sun.hotspot.WhiteBox;
+
+/*
+ * @test TestSafepointEvents
+ * @key jfr
+ * @library /test/lib
+ * @build sun.hotspot.WhiteBox
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *     sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:.
+ *                   -XX:+FlightRecorder -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *                   jdk.jfr.event.runtime.TestSafepointEvents
+ */
+public class TestSafepointEvents {
+
+    static final String[] EVENT_NAMES = new String[] {
+        EventNames.SafepointBegin,
+        EventNames.SafepointStateSyncronization,
+        EventNames.SafepointWaitBlocked,
+        EventNames.SafepointCleanup,
+        EventNames.SafepointCleanupTask,
+        EventNames.SafepointEnd
+    };
+
+    public static void main(String[] args) throws Exception {
+        Recording recording = new Recording();
+        for (String name : EVENT_NAMES) {
+            recording.enable(name).withThreshold(Duration.ofMillis(0));
+        }
+        recording.start();
+        WhiteBox.getWhiteBox().forceSafepoint();
+        recording.stop();
+
+        try {
+            // Verify that each event type was seen at least once
+            for (String name : EVENT_NAMES) {
+                boolean found = false;
+                for (RecordedEvent event : Events.fromRecording(recording)) {
+                    found = event.getEventType().getName().equals(name);
+                    if (found) {
+                        break;
+                    }
+                }
+                assertTrue(found, "Expected event from test [" + name + "]");
+            }
+
+            // Collect all events grouped by safepoint id
+            SortedMap<Integer, Set<String>> safepointIds = new TreeMap<>();
+            for (RecordedEvent event : Events.fromRecording(recording)) {
+                Integer safepointId = event.getValue("safepointId");
+                if (!safepointIds.containsKey(safepointId)) {
+                    safepointIds.put(safepointId, new HashSet<>());
+                }
+                safepointIds.get(safepointId).add(event.getEventType().getName());
+            }
+
+            // The last safepoint may be related to stopping the recording and can thus be
+            // incomplete - so if there is more than one, ignore the last one
+            if (safepointIds.size() > 1) {
+                safepointIds.remove(safepointIds.lastKey());
+            }
+            Asserts.assertGreaterThanOrEqual(safepointIds.size(), 1, "At least 1 safepoint must have occured");
+
+            // Verify that each safepoint id has an occurence of every event type,
+            // this ensures that all events related to a given safepoint had the same id
+            for (Set<String> safepointEvents : safepointIds.values()) {
+                for (String name : EVENT_NAMES) {
+                    assertTrue(safepointEvents.contains(name), "Expected event '" + name + "' to be present");
+                }
+            }
+        } catch (Throwable e) {
+            recording.dump(Paths.get("failed.jfr"));
+            throw e;
+        } finally {
+            recording.close();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestSizeTFlags.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.event.runtime;
+
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.nio.file.Paths;
+import java.time.Duration;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @bug 8058552
+ * @requires vm.gc == "G1" | vm.gc == null
+ * @key jfr
+ * @summary Test checks that flags of type size_t are being sent to the jfr
+ * @library /test/lib
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:+UseG1GC -XX:+UseTLAB -XX:MinTLABSize=3k -XX:OldSize=30m -XX:YoungPLABSize=3k -XX:MaxDirectMemorySize=5M  jdk.jfr.event.runtime.TestSizeTFlags
+ */
+public class TestSizeTFlags {
+    private static final String EVENT_NAME = EventNames.UnsignedLongFlag;
+    private static final int NUMBER_OF_FLAGS_TO_CHECK = 4;
+    private static final long MIN_TLAB_SIZE_FLAG_VALUE = 3*1024L;
+    private static final long OLD_SIZE_FLAG_VALUE = 30*1024*1024L;
+    private static final long YOUNG_PLAB_SIZE_FLAG_VALUE = 3*1024L;
+    private static final long MAX_DIRECT_MEMORY_SIZE_FLAG_VALUE = 5*1024*1024L;
+
+    // Test run java with some of the flags of type size_t.
+    // Goals are
+    //  - to check that flags are reported to the jfr;
+    //  - to make sure values are as expected.
+    public static void main(String[] args) throws Exception {
+        final boolean[] flagsFoundWithExpectedValue = new boolean[NUMBER_OF_FLAGS_TO_CHECK];
+        Recording recording = null;
+        try {
+            recording = new Recording();
+            recording.enable(EVENT_NAME).withThreshold(Duration.ofMillis(0));
+            recording.start();
+            recording.stop();
+
+            for (final RecordedEvent event : Events.fromRecording(recording)) {
+                final String recordedFlagName = Events.assertField(event, "name").getValue();
+                final long value = Events.assertField(event, "value").getValue();
+                switch (recordedFlagName) {
+                    case "MinTLABSize": {
+                        flagsFoundWithExpectedValue[0] = MIN_TLAB_SIZE_FLAG_VALUE == value;
+                        continue;
+                    }
+                    case "OldSize": {
+                        flagsFoundWithExpectedValue[1] = OLD_SIZE_FLAG_VALUE == value;
+                        continue;
+                    }
+                    case "YoungPLABSize": {
+                        flagsFoundWithExpectedValue[2] = YOUNG_PLAB_SIZE_FLAG_VALUE == value;
+                        continue;
+                    }
+                    case "MaxDirectMemorySize": {
+                        flagsFoundWithExpectedValue[3] = MAX_DIRECT_MEMORY_SIZE_FLAG_VALUE == value;
+                        continue;
+                    }
+                    default: {
+                        continue;
+                    }
+                }
+            }
+
+            for (int i = 0; i < flagsFoundWithExpectedValue.length; ++i) {
+                assertTrue(flagsFoundWithExpectedValue[i], "Flag not found or value error!");
+            }
+
+        } catch (Throwable e) {
+            if (recording != null) {
+                recording.dump(Paths.get("failed.jfr"));
+            }
+            throw e;
+        } finally {
+            if (recording != null) {
+                recording.close();
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestSystemPropertyEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.runtime;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.event.runtime.TestSystemPropertyEvent
+ */
+public class TestSystemPropertyEvent {
+
+    private final static String EVENT_NAME = EventNames.InitialSystemProperty;
+
+    public static void main(String[] args) throws Throwable {
+        Map<String, String> systemProps = createInitialSystemProperties();
+        // Recording should only contain properties defined at JVM start.
+        // This property should not be included.
+        System.setProperty("party.pooper", "buh!");
+
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME);
+        recording.start();
+        recording.stop();
+
+        Map<String, String> eventProps = new HashMap<>();
+        for (RecordedEvent event : Events.fromRecording(recording)) {
+            String key = Events.assertField(event, "key").notEmpty().getValue();
+            String value = Events.assertField(event, "value").notNull().getValue();
+            if (!eventProps.containsKey(key)) {
+                // Event is received at both start and end of chunk. Only log first.
+                System.out.println("Event:" + event);
+            }
+            eventProps.put(key, value);
+        }
+        Asserts.assertGreaterThan(eventProps.size(), 4, "Should have at least 5 events");
+
+        // Value of System.properties may change. We can not expect all values in
+        // events and System.getProperties() to be equal.
+        // To do some verification of property values we require that at least one
+        // property with non-empty value is equal.
+        int countEqualAndNonEmpty = 0;
+
+        String missingKeys = "";
+        for (String key : eventProps.keySet()) {
+            if (!systemProps.containsKey(key)) {
+                missingKeys += key + " ";
+                continue;
+            }
+            if (isEqualAndNonEmpty(key, eventProps.get(key), systemProps.get(key))) {
+                countEqualAndNonEmpty++;
+            }
+        }
+
+        if (!missingKeys.isEmpty()) {
+            Asserts.fail("Event properties not found in System.properties(): " + missingKeys);
+        }
+        Asserts.assertTrue(countEqualAndNonEmpty > 0, "No property had expected value");
+    }
+
+    private static boolean isEqualAndNonEmpty(String key, String eventValue, String systemValue) {
+        if (eventValue == null || systemValue == null || eventValue.isEmpty() || systemValue.isEmpty()) {
+            return false;
+        }
+        boolean isEquals = eventValue.equals(systemValue);
+        System.out.printf("eq=%b, key='%s', event='%s', system='%s'%n", isEquals, key, eventValue, systemValue);
+        return isEquals;
+    }
+
+    private static Map<String, String> createInitialSystemProperties() {
+        Map<String, String> result = new HashMap<>();
+        for (Object keyObject : System.getProperties().keySet()) {
+            String key = (String) keyObject;
+            result.put(key, System.getProperty(key));
+            System.out.println("initialProp: " + key);
+        }
+        return result;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestThreadAllocationEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.runtime;
+
+import static jdk.test.lib.Asserts.assertGreaterThan;
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.lang.management.ManagementFactory;
+import java.time.Duration;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+
+import com.sun.management.ThreadMXBean;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedThread;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @modules jdk.jfr
+ *          jdk.management
+ *
+ * @run main/othervm -XX:-UseTLAB jdk.jfr.event.runtime.TestThreadAllocationEvent
+ */
+
+/**
+ * The test will create a few threads that will allocate memory for a short time.
+ * During this time a number of thread_allocation events will be generated.
+ * The test will verify:
+ * 1. That number of allocated bytes is not decreasing for a thread.
+ *  - This assumption is only true when not using TLABs. For this reason the
+ *    test is run with -XX:-UseTLAB. When using TLABs, the code calculating the
+ *    allocated bytes is using the current TLAB to do as good of an approximation
+ *    as possible, but this introduces a race which might double count the current
+ *    TLAB when it is full and in the middle of being switched out.
+ * 2. That sum of allocated bytes approximately matches value in ThreadMXBean.
+ */
+public class TestThreadAllocationEvent {
+    private static final String EVENT_NAME = EventNames.ThreadAllocationStatistics;
+    private static final String testThreadName = "testThread-";
+    private static final long eventPeriodMillis = 50;
+
+    // The value in both the JFR event and in the ThreadMXBean is documented as
+    // an "approximation" of number of bytes allocated.
+    // To not give any false errors, we allow an error margin of 5 mb.
+    // The test will typically allocate over 600 mb, so 5 mb is an error of less than 1%.
+    private static final long allowedTotalAllocatedDiff = 5000000;
+
+    public static void main(String[] args) throws Throwable {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME).withPeriod(Duration.ofMillis(eventPeriodMillis));
+        recording.start();
+
+        AllocatorThread[] threads = new AllocatorThread[4];
+        CountDownLatch allocationsDoneLatch = new CountDownLatch(threads.length);
+        for (int i = 0; i < threads.length; i++) {
+            threads[i] = new AllocatorThread(allocationsDoneLatch, 1000 * (i + 1));
+            threads[i].setName(testThreadName + i);
+            threads[i].setDaemon(true);
+            threads[i].start();
+        }
+
+        // Take regular measurements while the threads are allocating memory.
+        // Stop measurement when all threads are ready.
+        try {
+            allocationsDoneLatch.await();
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+        // Verify that number of allocated bytes is not decreasing.
+        recording.stop();
+        verifyAllocationsNotDecreasing(Events.fromRecording(recording), threads);
+
+        // Now allocations are done and threads are waiting to die.
+        // Make a new instant recording to get total number of allocated bytes.
+        // The reason for this extra recording is to make sure we get a JFR event
+        // after all allocations are done so we can compare the JFR value with
+        // the value reported by ThreadMXBean.
+        recording = new Recording();
+        recording.enable(EVENT_NAME);
+        recording.start();
+        recording.stop();
+        verifyTotalAllocated(Events.fromRecording(recording), threads);
+    }
+
+    /**
+     * Verify that the allocated value never decreases.
+     * We only compare our own allocator threads. The reason for that is that other threads
+     * may start/stop at any time, and we do not know if other thread names are unique.
+     */
+     private static void verifyAllocationsNotDecreasing(List<RecordedEvent> events, AllocatorThread[] threads) {
+         Collections.sort(events, (u,v) -> u.getEndTime().compareTo(v.getEndTime()));
+         long[] prevAllocated = new long[threads.length];
+         for (RecordedEvent event : events) {
+             RecordedThread rt = Events.assertField(event, "thread").notNull().getValue(); // Check that we have a thread.
+             String name = rt.getJavaName();
+             for (int i = 0; i < threads.length; i++) {
+                 if (name.equals(threads[i].getName())) {
+                     long curr = Events.assertField(event, "allocated").atLeast(prevAllocated[i]).getValue();
+                     prevAllocated[i] = curr;
+                 }
+             }
+         }
+
+         for (int i = 0; i < threads.length; i++) {
+             assertGreaterThan(prevAllocated[i], 0L, "No allocations for thread " + threads[i].getName());
+         }
+     }
+
+     /**
+      * Verify that total allocated bytes in JFR event approximately matches the value in ThreadMXBean.
+      */
+    private static void verifyTotalAllocated(List<RecordedEvent> events, AllocatorThread[] threads) {
+        boolean[] isEventFound = new boolean[threads.length];
+        for (RecordedEvent event : events) {
+            RecordedThread rt = Events.assertField(event, "thread").notNull().getValue();
+            String name = rt.getJavaName();
+            for (int i = 0; i < threads.length; ++i) {
+                if (name.equals(threads[i].getName())) {
+                    System.out.println("Event:" + event);
+                    long maxAllowed = threads[i].totalAllocated + allowedTotalAllocatedDiff;
+                    long minAllowed = Math.max(0, threads[i].totalAllocated - allowedTotalAllocatedDiff);
+                    Events.assertField(event, "allocated").atLeast(minAllowed).atMost(maxAllowed);
+                    isEventFound[i] = true;
+                }
+            }
+        }
+        for (int i = 0; i < threads.length; ++i) {
+            assertTrue(isEventFound[i], "No event for thread id " + i);
+        }
+    }
+
+    /**
+     * Thread that does a number of allocations and records total number of
+     * bytes allocated as reported by ThreadMXBean.
+     */
+    public static class AllocatorThread extends Thread {
+        private volatile long totalAllocated = -1;
+        private final int averageAllocationSize;
+        public byte[] buffer;
+        private final CountDownLatch allocationsDoneLatch;
+
+        public AllocatorThread(CountDownLatch allocationsDoneLatch, int averageAllocationSize) {
+            this.allocationsDoneLatch = allocationsDoneLatch;
+            this.averageAllocationSize = averageAllocationSize;
+        }
+
+        @Override
+        public void run() {
+            Random rand = new Random();
+            int allocationSizeBase = averageAllocationSize / 2;
+            int allocationSizeRandom = averageAllocationSize;
+            for (int batches=0; batches<100; batches++) {
+                for (int i=0; i<1500; i++) {
+                    buffer = new byte[rand.nextInt(allocationSizeRandom) + allocationSizeBase];
+                }
+                try {
+                    // No need to allocate too much data between JFR events, so do a short sleep.
+                    Thread.sleep(eventPeriodMillis / 5);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+            totalAllocated = getThreadAllocatedBytes();
+            allocationsDoneLatch.countDown();
+
+            // Need to keep thread alive so we can get the final JFR event.
+            // This is a daemon thread, so it will finish when the main thread finishes.
+            while (true) {
+                Thread.yield();
+            }
+        }
+
+        private long getThreadAllocatedBytes() {
+            ThreadMXBean bean = (ThreadMXBean) ManagementFactory.getThreadMXBean();
+            return bean.getThreadAllocatedBytes(Thread.currentThread().getId());
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestThreadCpuTimeEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.runtime;
+
+import com.sun.management.ThreadMXBean;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedThread;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+import java.lang.management.ManagementFactory;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.CyclicBarrier;
+import java.util.stream.Collectors;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @modules jdk.jfr
+ *          jdk.management
+ *
+ * @run main/othervm jdk.jfr.event.runtime.TestThreadCpuTimeEvent
+ */
+
+/**
+ */
+public class TestThreadCpuTimeEvent {
+
+    public static void main(String[] args) throws Throwable {
+        testSimple();
+        testCompareWithMXBean();
+        testEventAtThreadExit();
+    }
+
+    private static final long eventPeriodMillis = 50;
+    private static final String cpuConsumerThreadName = "cpuConsumer";
+
+    // The cpu consumer will run for eventPeriodMillis times this factor to ensure that we see some
+    // events even if the scheduler isn't cooperating.
+    private static final long cpuConsumerRunFactor = 10;
+
+    // The cpu consumer will run at least this number of loops, even if it takes longer than
+    // the requested period of time (in case the thread didn't get scheduled within the allotted time).
+    private static final long cpuConsumerMinCount = 1000000;
+
+    static class CpuConsumingThread extends Thread {
+
+        Duration runTime;
+        CyclicBarrier barrier;
+        volatile long counter;
+
+        CpuConsumingThread(Duration runTime, CyclicBarrier barrier, String threadName) {
+            super(threadName);
+            this.runTime = runTime;
+            this.barrier = barrier;
+        }
+
+        CpuConsumingThread(Duration runTime, CyclicBarrier barrier) {
+            this(runTime, barrier, cpuConsumerThreadName);
+        }
+
+        @Override
+        public void run() {
+            try {
+                while (true) {
+                    barrier.await();
+                    Instant start = Instant.now();
+                    counter = 0;
+                    while ((Duration.between(start, Instant.now()).compareTo(runTime) < 0) ||
+                            (counter < cpuConsumerMinCount)) {
+                        counter++;
+                    }
+                    barrier.await();
+                }
+            } catch (BrokenBarrierException e) {
+                // Another thread has been interrupted - wait for us to be interrupted as well
+                while (!interrupted()) {
+                    yield();
+                }
+            } catch (InterruptedException e) {
+                // Normal way of stopping the thread
+            }
+        }
+    }
+
+    // For a given thread, check that accumulated processTime >= cpuTime >= userTime.
+    // This may not hold for a single event instance due to differences in counter resolution
+    static void verifyPerThreadInvariant(List<RecordedEvent> events, String threadName) {
+        List<RecordedEvent> filteredEvents = events.stream()
+                .filter(e -> e.getThread().getJavaName().equals(threadName))
+                .sorted(Comparator.comparing(RecordedEvent::getStartTime))
+                .collect(Collectors.toList());
+
+        int numCpus = Runtime.getRuntime().availableProcessors();
+        Iterator<RecordedEvent> i = filteredEvents.iterator();
+        while (i.hasNext()) {
+            RecordedEvent event = i.next();
+
+            Float systemLoad = (Float)event.getValue("system");
+            Float userLoad = (Float)event.getValue("user");
+
+            Asserts.assertLessThan(systemLoad + userLoad, 1.01f / numCpus); // 100% + rounding errors
+        }
+    }
+
+    static Duration getAccumulatedTime(List<RecordedEvent> events, String threadName, String fieldName) {
+        List<RecordedEvent> filteredEvents = events.stream()
+                .filter(e -> e.getThread().getJavaName().equals(threadName))
+                .sorted(Comparator.comparing(RecordedEvent::getStartTime))
+                .collect(Collectors.toList());
+
+        int numCpus = Runtime.getRuntime().availableProcessors();
+        Iterator<RecordedEvent> i = filteredEvents.iterator();
+        RecordedEvent cur = i.next();
+        Duration totalTime = Duration.ZERO;
+        while (i.hasNext()) {
+            RecordedEvent prev = cur;
+            cur = i.next();
+
+            Duration sampleTime = Duration.between(prev.getStartTime(), cur.getStartTime());
+            Float load = (Float)cur.getValue(fieldName);
+
+            // Adjust load to be thread-relative (fully loaded thread would give 100%)
+            Float totalLoadForThread = load * numCpus;
+            Duration threadTime = Duration.ofMillis((long) (sampleTime.toMillis() * totalLoadForThread));
+            totalTime = totalTime.plus(threadTime);
+        }
+
+        return totalTime;
+    }
+
+    static void testSimple() throws Throwable {
+        Recording recording = new Recording();
+
+        // Default period is once per chunk
+        recording.enable(EventNames.ThreadCPULoad).withPeriod(Duration.ofMillis(eventPeriodMillis));
+        recording.start();
+
+        Duration testRunTime = Duration.ofMillis(eventPeriodMillis * cpuConsumerRunFactor);
+        CyclicBarrier barrier = new CyclicBarrier(2);
+        CpuConsumingThread thread = new CpuConsumingThread(testRunTime, barrier);
+
+        // Run a single pass
+        thread.start();
+        barrier.await();
+        barrier.await();
+
+        recording.stop();
+        List<RecordedEvent> events = Events.fromRecording(recording);
+
+        Events.hasEvents(events);
+        verifyPerThreadInvariant(events, cpuConsumerThreadName);
+
+        thread.interrupt();
+        thread.join();
+    }
+
+    static void testCompareWithMXBean() throws Throwable {
+        Recording recording = new Recording();
+
+        recording.enable(EventNames.ThreadCPULoad).withPeriod(Duration.ofMillis(eventPeriodMillis));
+        recording.start();
+
+        Duration testRunTime = Duration.ofMillis(eventPeriodMillis * cpuConsumerRunFactor);
+        CyclicBarrier barrier = new CyclicBarrier(2);
+        CpuConsumingThread thread = new CpuConsumingThread(testRunTime, barrier);
+
+        // Run a single pass
+        thread.start();
+        barrier.await();
+        barrier.await();
+
+        recording.stop();
+        List<RecordedEvent> beforeEvents = Events.fromRecording(recording);
+
+        verifyPerThreadInvariant(beforeEvents, cpuConsumerThreadName);
+
+        // Run a second single pass
+        barrier.await();
+        barrier.await();
+
+        ThreadMXBean bean = (ThreadMXBean) ManagementFactory.getThreadMXBean();
+        Duration cpuTime = Duration.ofNanos(bean.getThreadCpuTime(thread.getId()));
+        Duration userTime = Duration.ofNanos(bean.getThreadUserTime(thread.getId()));
+
+        // Check something that should hold even in the presence of unfortunate scheduling
+        Asserts.assertGreaterThanOrEqual(cpuTime.toMillis(), eventPeriodMillis);
+        Asserts.assertGreaterThanOrEqual(userTime.toMillis(), eventPeriodMillis);
+
+        Duration systemTimeBefore = getAccumulatedTime(beforeEvents, cpuConsumerThreadName, "system");
+        Duration userTimeBefore = getAccumulatedTime(beforeEvents, cpuConsumerThreadName, "user");
+        Duration cpuTimeBefore = userTimeBefore.plus(systemTimeBefore);
+
+        Asserts.assertLessThan(cpuTimeBefore, cpuTime);
+        Asserts.assertLessThan(userTimeBefore, userTime);
+        Asserts.assertGreaterThan(cpuTimeBefore, Duration.ZERO);
+
+        thread.interrupt();
+        thread.join();
+    }
+
+    static void testEventAtThreadExit() throws Throwable {
+        Recording recording = new Recording();
+
+        recording.enable(EventNames.ThreadCPULoad).withPeriod(Duration.ofHours(10));
+        recording.start();
+
+        Duration testRunTime = Duration.ofMillis(eventPeriodMillis * cpuConsumerRunFactor);
+        CyclicBarrier barrier = new CyclicBarrier(2);
+        CpuConsumingThread thread = new CpuConsumingThread(testRunTime, barrier);
+
+        // Run a single pass
+        thread.start();
+        barrier.await();
+        barrier.await();
+
+        thread.interrupt();
+        thread.join();
+
+        recording.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        verifyPerThreadInvariant(events, cpuConsumerThreadName);
+
+        int exitingCount = 0;
+        for (RecordedEvent event : events) {
+            RecordedThread eventThread = event.getThread();
+            if (eventThread.getJavaName().equals(cpuConsumerThreadName)) {
+                exitingCount++;
+            }
+        }
+        Asserts.assertEquals(exitingCount, 1);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestThreadDumpEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.runtime;
+
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventField;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.event.runtime.TestThreadDumpEvent
+ */
+public class TestThreadDumpEvent {
+
+    private final static String EVENT_NAME = EventNames.ThreadDump;
+    private static final String RESULT_STRING_MATCH = "Full thread dump";
+
+    public static void main(String[] args) throws Throwable {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME);
+        recording.start();
+        recording.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        boolean isAnyFound = false;
+        for (RecordedEvent event : events) {
+            System.out.println("Event:" + event);
+            isAnyFound = true;
+            EventField dumpField = Events.assertField(event, "result");
+            dumpField.instring(RESULT_STRING_MATCH).instring("TestThreadDumpEvent.main");
+        }
+        assertTrue(isAnyFound, "Correct event not found");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestThreadParkEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.runtime;
+
+import static jdk.test.lib.Asserts.assertFalse;
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.time.Duration;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.locks.LockSupport;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.management.ThreadMXBeanTool;
+import jdk.test.lib.thread.TestThread;
+
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ *
+ * @run main/othervm jdk.jfr.event.runtime.TestThreadParkEvent
+ */
+
+public class TestThreadParkEvent {
+    private static final String EVENT_NAME = EventNames.ThreadPark;
+    private static final long THRESHOLD_MILLIS = 1;
+
+    static class Blocker {
+    }
+
+    public static void main(String[] args) throws Throwable {
+        final CountDownLatch stop = new CountDownLatch(1);
+        final Blocker blocker = new Blocker();
+        TestThread parkThread = new TestThread(new Runnable() {
+            public void run() {
+                while (stop.getCount() > 0) {
+                    LockSupport.park(blocker);
+                }
+            }
+        });
+
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME).withThreshold(Duration.ofMillis(THRESHOLD_MILLIS));
+        try {
+            recording.start();
+            parkThread.start();
+            ThreadMXBeanTool.waitUntilBlockingOnObject(parkThread, Thread.State.WAITING, blocker);
+            // sleep so we know the event is recorded
+            Thread.sleep(2 * THRESHOLD_MILLIS);
+        } finally {
+            stop.countDown();
+            LockSupport.unpark(parkThread);
+            parkThread.join();
+            recording.stop();
+        }
+
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        Events.hasEvents(events);
+        boolean isAnyFound = false;
+        for (RecordedEvent event : events) {
+            System.out.println("Event:" + event);
+            String klassName = Events.assertField(event, "parkedClass.name").notNull().getValue();
+            if (klassName.equals(blocker.getClass().getName().replace('.', '/'))) {
+                assertFalse(isAnyFound, "Found more than 1 event");
+                isAnyFound = true;
+                Events.assertField(event, "timeout").equal(0L);
+                Events.assertField(event, "address").notEqual(0L);
+                Events.assertEventThread(event, parkThread);
+            }
+        }
+        assertTrue(isAnyFound, "Correct event not found");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestThreadSleepEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.runtime;
+
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.time.Duration;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.event.runtime.TestThreadSleepEvent
+ */
+public class TestThreadSleepEvent {
+
+    private final static String EVENT_NAME = EventNames.ThreadSleep;
+    // Need to set the sleep time quite high (47 ms) since the sleep
+    // time on Windows has been proved unreliable.
+    // See bug 6313903
+    private final static Long SLEEP_TIME_MS = new Long(47);
+
+    public static void main(String[] args) throws Throwable {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME).withThreshold(Duration.ofMillis(0));
+        recording.start();
+        Thread.sleep(SLEEP_TIME_MS);
+        recording.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        boolean isAnyFound = false;
+        for (RecordedEvent event : events) {
+            if (event.getThread().getJavaThreadId() == Thread.currentThread().getId()) {
+                System.out.println("Event:" + event);
+                isAnyFound = true;
+                Events.assertField(event, "time").equal(SLEEP_TIME_MS);
+            }
+        }
+        assertTrue(isAnyFound, "No matching events found");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestThreadStartEndEvents.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.runtime;
+
+import java.time.Duration;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.event.runtime.TestThreadStartEndEvents
+ */
+
+/**
+ * Starts and stops a number of threads in order.
+ * Verifies that events are in the same order.
+ */
+public class TestThreadStartEndEvents {
+    private final static String EVENT_NAME_THREAD_START = EventNames.ThreadStart;
+    private final static String EVENT_NAME_THREAD_END = EventNames.ThreadEnd;
+    private static final String THREAD_NAME_PREFIX = "TestThread-";
+
+    public static void main(String[] args) throws Throwable {
+        // Test Java Thread Start event
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME_THREAD_START).withThreshold(Duration.ofMillis(0));
+        recording.enable(EVENT_NAME_THREAD_END).withThreshold(Duration.ofMillis(0));
+        recording.start();
+        LatchedThread[] threads = startThreads();
+        stopThreads(threads);
+        recording.stop();
+
+        int currThreadIndex = 0;
+        long currentThreadId = Thread.currentThread().getId();
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        Events.hasEvents(events);
+        for (RecordedEvent event : events) {
+            System.out.println("Event:" + event);
+            if (event.getThread().getJavaThreadId() != currentThreadId) {
+                continue;
+            }
+            // Threads should be started and stopped in the correct order.
+            Events.assertEventThread(event, threads[currThreadIndex % threads.length]);
+            String eventName = currThreadIndex < threads.length ? EVENT_NAME_THREAD_START : EVENT_NAME_THREAD_END;
+            if (!eventName.equals(event.getEventType().getName())) {
+                throw new Exception("Expected event of tyoe " + eventName + " but got " + event.getEventType().getName());
+            }
+            currThreadIndex++;
+        }
+    }
+
+    private static LatchedThread[] startThreads() {
+        LatchedThread threads[] = new LatchedThread[10];
+        ThreadGroup threadGroup = new ThreadGroup("TestThreadGroup");
+        for (int i = 0; i < threads.length; i++) {
+            threads[i] = new LatchedThread(threadGroup, THREAD_NAME_PREFIX + i);
+            threads[i].startThread();
+            System.out.println("Started thread id=" + threads[i].getId());
+        }
+        return threads;
+    }
+
+    private static void stopThreads(LatchedThread[] threads) {
+        for (LatchedThread thread : threads) {
+            thread.stopThread();
+            while (thread.isAlive()) {
+                try {
+                    Thread.sleep(5);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    private static class LatchedThread extends Thread {
+        private final CountDownLatch start = new CountDownLatch(1);
+        private final CountDownLatch stop = new CountDownLatch(1);
+
+        public LatchedThread(ThreadGroup threadGroup, String name) {
+            super(threadGroup, name);
+        }
+
+        public void run() {
+            start.countDown();
+            try {
+                stop.await();
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+
+        public void startThread() {
+            this.start();
+            try {
+                start.await();
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+
+        public void stopThread() {
+            stop.countDown();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestThrowableInstrumentation.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.runtime;
+
+import sun.hotspot.WhiteBox;
+import java.util.Objects;
+import jdk.test.lib.Platform;
+
+/*
+ * @test
+ * @bug 8153324
+ * @summary Verify instrumented Throwable bytecode by compiling it with C1.
+ * @library /test/lib
+ * @modules java.base/jdk.internal.misc
+ *          java.management
+ * @requires vm.compMode!="Xint"
+ * @build  sun.hotspot.WhiteBox
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *                   -Xbatch -XX:StartFlightRecording=dumponexit=true jdk.jfr.event.runtime.TestThrowableInstrumentation
+ */
+public class TestThrowableInstrumentation {
+    private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
+    private static int COMP_LEVEL_SIMPLE = 1;
+
+    private static boolean isTieredCompilationEnabled() {
+        return Boolean.valueOf(Objects.toString(WHITE_BOX.getVMFlag("TieredCompilation")));
+    }
+
+    public static void main(String[] args) {
+        // Compile Throwable::<clinit> with C1 (if available)
+        if (!WHITE_BOX.enqueueInitializerForCompilation(java.lang.Throwable.class, COMP_LEVEL_SIMPLE)) {
+          if (!Platform.isServer() || isTieredCompilationEnabled() || Platform.isEmulatedClient()) {
+            throw new RuntimeException("Unable to compile Throwable::<clinit> with C1");
+          }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestVMInfoEvent.flags	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,1 @@
++FlightRecorder
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestVMInfoEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.runtime;
+
+
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/**
+ * The test will verify that JVM Information event values are delivered
+ * and compare them with the RuntimeMXBean's values.
+ */
+public class TestVMInfoEvent {
+    private final static String EVENT_NAME = EventNames.JVMInformation;
+
+    public static void main(String[] args) throws Exception {
+        RuntimeMXBean mbean = ManagementFactory.getRuntimeMXBean();
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME);
+        recording.start();
+        recording.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        Events.hasEvents(events);
+        for (RecordedEvent event : events) {
+            System.out.println("Event:" + event);
+            Events.assertField(event, "jvmName").equal(mbean.getVmName());
+            String jvmVersion = Events.assertField(event, "jvmVersion").notEmpty().getValue();
+            if (!jvmVersion.contains(mbean.getVmVersion())) {
+                Asserts.fail(String.format("%s does not contain %s", jvmVersion, mbean.getVmVersion()));
+            }
+
+            String jvmArgs = Events.assertField(event, "jvmArguments").notNull().getValue();
+            String jvmFlags = Events.assertField(event, "jvmFlags").notNull().getValue();
+            String eventArgs = (jvmFlags.trim() + " " + jvmArgs).trim();
+            String beanArgs = mbean.getInputArguments().stream().collect(Collectors.joining(" "));
+            Asserts.assertEquals(eventArgs, beanArgs, "Wrong inputArgs");
+
+            final String javaCommand = mbean.getSystemProperties().get("sun.java.command");
+            Events.assertField(event, "javaArguments").equal(javaCommand);
+            Events.assertField(event, "jvmStartTime").equal(mbean.getStartTime());
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestVMInfoEvent.sh	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,34 @@
+#
+# Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# 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.
+#
+# @test
+# @key jfr
+# @library /test/lib /test/jdk
+# @build jdk.jfr.event.runtime.TestVMInfoEvent
+# @run shell TestVMInfoEvent.sh
+
+echo -------------------------------------------------------------
+echo Launching test for `basename $0 .sh`
+echo -------------------------------------------------------------
+
+${TESTJAVA}/bin/java -cp ${TESTCLASSPATH} -XX:Flags=${TESTSRC}/TestVMInfoEvent.flags jdk.jfr.event.runtime.TestVMInfoEvent arg1 arg2
+exit $?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestVMOperation.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.runtime;
+
+import java.time.Duration;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedThread;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @requires vm.gc == "Parallel" | vm.gc == null
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm -XX:+UseParallelGC jdk.jfr.event.runtime.TestVMOperation
+ */
+public class TestVMOperation {
+
+    private static final String EVENT_NAME = EventNames.ExecuteVMOperation;
+    private static final String VM_OPERATION = "ParallelGCSystemGC";
+
+    public static void main(String[] args) throws Throwable {
+        Recording recording = new Recording();
+        recording.enable(EVENT_NAME).withThreshold(Duration.ofMillis(0));
+        recording.start();
+        System.gc();
+        recording.stop();
+
+        List<RecordedEvent> events = Events.fromRecording(recording);
+        Events.hasEvents(events);
+        for (RecordedEvent event : Events.fromRecording(recording)) {
+            String operation = Events.assertField(event, "operation").notEmpty().getValue();
+            if (operation.equals(VM_OPERATION)) {
+                Events.assertField(event, "safepoint").equal(true);
+                Events.assertField(event, "blocking").equal(true);
+                RecordedThread jt = event.getValue("caller");
+                if (Thread.currentThread().getName().equals(jt.getJavaName())) {
+                    return;
+                }
+            }
+        }
+        throw new AssertionError("No matching event with VM operation name " + VM_OPERATION + " and current threasd as caller");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestVmFlagChangedEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.runtime;
+
+import static jdk.test.lib.Asserts.assertEquals;
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.lang.management.ManagementFactory;
+
+import com.sun.management.HotSpotDiagnosticMXBean;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test TestVmFlagChangedEvent
+ * @key jfr
+ * @library /test/lib
+ * @modules jdk.jfr
+ *          jdk.management
+ *
+ * @run main/othervm jdk.jfr.event.runtime.TestVmFlagChangedEvent
+ */
+public final class TestVmFlagChangedEvent {
+
+    public static void main(String[] args) throws Throwable {
+        EventFlag[] eventFlags = {
+            new EventFlag(EventNames.LongFlagChanged, "CMSWaitDuration", "2500"),
+            new EventFlag(EventNames.StringFlagChanged, "HeapDumpPath", "/a/sample/path"),
+            new EventFlag(EventNames.BooleanFlagChanged, "HeapDumpOnOutOfMemoryError", "true")
+        };
+
+        Recording recording = new Recording();
+        for (EventFlag eventFlag : eventFlags) {
+            recording.enable(eventFlag.eventName);
+        }
+
+        recording.start();
+        HotSpotDiagnosticMXBean mbean = ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class);
+        for (EventFlag eventFlag : eventFlags) {
+            eventFlag.update(mbean);
+        }
+        recording.stop();
+
+        for (RecordedEvent event : Events.fromRecording(recording)) {
+            final String flagName = Events.assertField(event, "name").getValue();
+            System.out.println("flag name=" + flagName);
+            for (EventFlag eventFlag : eventFlags) {
+                if (flagName.equals(eventFlag.eventLabel)) {
+                    System.out.println("Event:" + event);
+                    Object newValue = Events.assertField(event, "newValue").getValue();
+                    Object oldValue = Events.assertField(event, "oldValue").getValue();
+                    System.out.println("newValue:" + asText(newValue));
+                    System.out.println("oldValue:" + asText(oldValue));
+                    assertEquals(eventFlag.newValue, asText(newValue), "Wrong new value: expected" + eventFlag.newValue);
+                    assertEquals(eventFlag.oldValue, asText(oldValue), "Wrong old value: expected" + eventFlag.oldValue);
+                    Events.assertField(event, "origin").equal("Management");
+                    eventFlag.isFound = true;
+                    break;
+                }
+            }
+        }
+        for (EventFlag eventFlag : eventFlags) {
+            assertTrue(eventFlag.isFound, "Missing flag change for: " + eventFlag.eventLabel);
+        }
+    }
+
+    private static String asText(Object value) {
+        if (value == null) {
+            return ""; // HotSpotDiagnosticMXBean interface return "" for unset values
+        }
+        return String.valueOf(value);
+    }
+
+    private static class EventFlag {
+        final String eventName;
+        final String eventLabel;
+        String newValue;
+        String oldValue;
+        boolean isFound = false;
+
+        EventFlag(String eventName, String eventLabel, String newValue) {
+            this.eventName = eventName;
+            this.eventLabel = eventLabel;
+            this.newValue = newValue;
+        }
+
+        void update(HotSpotDiagnosticMXBean mbean) {
+            this.oldValue = mbean.getVMOption(eventLabel).getValue();
+            mbean.setVMOption(eventLabel, newValue);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/exception.security.policy	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,20 @@
+grant {
+  // must allow file reads so that jtreg itself and JFR can run
+  permission java.io.FilePermission "<<ALL FILES>>", "read";
+  // must allow file delete so that JFR can delete repository
+  permission java.io.FilePermission "<<ALL FILES>>", "delete";
+  // must allow file write so that the test can create the recording
+  permission java.io.FilePermission "<<ALL FILES>>", "write";
+
+  // need to be able to create temporary files
+  permission java.util.PropertyPermission "java.io.tmpdir", "read";
+  permission java.util.PropertyPermission "user.dir", "read";
+  
+  // need ManagementPermission to control JFR from the test
+  permission java.lang.management.ManagementPermission "control";
+  permission java.lang.management.ManagementPermission "monitor";
+  
+  // JDK-8019403 - access to sun.security.util, which is needed for creation of temp files, 
+  // is not permitted automatically on solaris
+  permission java.lang.RuntimePermission "accessClassInPackage.sun.security.util";
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/sampling/TestNative.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.sampling;
+
+import java.io.File;
+import java.nio.file.Paths;
+import java.time.Duration;
+
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @modules java.base/jdk.internal.misc
+ * @run main/native jdk.jfr.event.sampling.TestNative
+ */
+public class TestNative {
+
+    public final static String EVENT_SETTINGS_FILE = System.getProperty("test.src", ".") + File.separator + "sampling.jfc";
+    public final static String JFR_DUMP = "samples.jfr";
+    public final static String EXCEPTION = "No native samples found";
+    public final static String NATIVE_EVENT = EventNames.NativeMethodSample;
+    public static Recording recording;
+
+    public static native void longTime();
+
+    public static void main(String[] args) throws Exception {
+        String lib = System.getProperty("test.nativepath");
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, "-Djava.library.path=" + lib, "jdk.jfr.event.sampling.TestNative$Test");
+
+        OutputAnalyzer output = ProcessTools.executeProcess(pb);
+        output.shouldHaveExitValue(0);
+        output.stdoutShouldNotContain("No native samples found");
+    }
+
+    static class Test {
+        public static void main(String[] args) throws Exception {
+            System.loadLibrary("TestNative");
+            FlightRecorder.getFlightRecorder();
+            recording = new Recording();
+            recording.setToDisk(true);
+            recording.setDestination(Paths.get(JFR_DUMP));
+            recording.enable(NATIVE_EVENT).withPeriod(Duration.ofMillis(10));
+            recording.start();
+
+            longTime();
+
+            recording.stop();
+            recording.close();
+
+            try (RecordingFile rf = new RecordingFile(Paths.get(JFR_DUMP))) {
+                while (rf.hasMoreEvents()) {
+                    RecordedEvent re = rf.readEvent();
+                    if (re.getEventType().getName().equals(NATIVE_EVENT)) {
+                        return;
+                    }
+                }
+            }
+
+            throw new Exception("No native samples found");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/sampling/libTestNative.c	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include <jni.h>
+
+#ifdef WINDOWS
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+
+JNIEXPORT void JNICALL Java_com_oracle_jfr_event_sampling_TestNative_longTime
+  (JNIEnv *env, jclass jc)
+{
+#ifdef WINDOWS
+  Sleep(2*1000);
+#else
+  usleep(2*1000*1000);
+#endif
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jcmd/JcmdAsserts.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jcmd;
+
+import java.io.File;
+
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Recording;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.process.OutputAnalyzer;
+
+
+
+public class JcmdAsserts {
+
+    private static final String NEW_LINE = System.getProperty("line.separator");
+
+    public static void assertJfrNotUsed(OutputAnalyzer output) {
+        output.shouldMatch("Flight Recorder has not been used");
+    }
+
+    public static void assertJfrUsed(OutputAnalyzer output) {
+        output.shouldMatch("Flight Recorder has been used");
+    }
+
+    public static void assertRecordingDumpedToFile(OutputAnalyzer output, String name, File recording) {
+        output.shouldContain("Dumped recording");
+        output.shouldContain(recording.getAbsolutePath());
+    }
+
+    public static void assertNotAbleToWriteToFile(OutputAnalyzer output) {
+        output.shouldContain("Could not start recording, not able to write to file");
+    }
+
+    public static void assertFileNotFoundException(OutputAnalyzer output, String name) {
+        output.shouldMatch("Could not write recording \"" + name + "\" to file.*");
+    }
+
+//    public static void assertNotAbleToSetFilename(OutputAnalyzer output) {
+//        output.shouldContain(
+//                "Filename can only be set for a recording with a duration, " +
+//                "or if dumponexit=true");
+//    }
+
+    public static void assertNotAbleToFindSettingsFile(OutputAnalyzer output) {
+        output.shouldContain("Could not parse setting");
+    }
+
+    public static void assertNoRecordingsAvailable(OutputAnalyzer output) {
+        output.shouldContain("No available recordings");
+    }
+
+    public static void assertRecordingNotExist(OutputAnalyzer output, String name) {
+        output.shouldContain("Could not find " + name);
+    }
+
+    public static void assertRecordingNotRunning(OutputAnalyzer output, String name) {
+        output.shouldNotMatch(".*" + name + ".*running");
+    }
+
+    public static void assertRecordingIsRunning(OutputAnalyzer output, String name) {
+        output.shouldMatch(".*" + name + ".*running");
+    }
+
+    public static void assertRecordingHasStarted(OutputAnalyzer output) {
+        output.shouldContain("Started recording");
+    }
+
+    public static void assertCouldNotStartDefaultRecordingWithName(OutputAnalyzer output) {
+        output.shouldContain(
+                "It's not possible to set custom name for the defaultrecording");
+    }
+
+    public static void assertCouldNotStartDefaultRecording(OutputAnalyzer output) {
+        output.shouldContain(
+                "The only option that can be combined with defaultrecording is settings");
+    }
+
+    public static void assertRecordingIsUnstarted(OutputAnalyzer output,
+            String name, String duration) {
+        output.stdoutShouldMatch("^\\s*Recording: recording=\\d+\\s+name=\"" + name
+                + "\"\\s+duration=" + duration + "\\s+.*\\W{1}unstarted\\W{1}");
+    }
+
+    public static void assertRecordingIsStopped(OutputAnalyzer output, String name) {
+        output.stdoutShouldMatch("^\\s*Recording: recording=\\d+\\s+name=\"" + name
+                + "\"\\s+.*\\W{1}stopped\\W{1}");
+    }
+
+    public static void assertRecordingIsStopped(OutputAnalyzer output, String name, String duration) {
+        output.stdoutShouldMatch("^\\s*Recording: recording=\\d+\\s+name=\"" + name
+                + "\"\\s+duration=" + duration + "\\s+.*\\W{1}stopped\\W{1}");
+    }
+
+    public static void assertStartTimeGreaterOrEqualThanMBeanValue(String name,
+            long actualStartTime) throws Exception {
+        Recording recording = findRecording(name);
+        Asserts.assertNotNull(recording.getStartTime(), "Start time is not set");
+        Asserts.assertGreaterThanOrEqual(actualStartTime, recording.getStartTime().toEpochMilli());
+    }
+
+    public static void assertDelayAtLeast1s(OutputAnalyzer output) {
+        output.shouldContain("Could not start recording, delay must be at least 1 second.");
+    }
+
+    public static void assertRecordingIsScheduled(OutputAnalyzer output, String name, String delay) {
+        output.stdoutShouldMatch(
+                "^\\s*Recording\\s+" + name + "\\s+scheduled to start in " + delay);
+    }
+
+    public static void assertMaxSizeEqualsMBeanValue(String name, long maxSize) throws Exception {
+        Recording recording = findRecording(name);
+        Asserts.assertEquals(maxSize, recording.getMaxSize());
+    }
+
+    private static Recording findRecording(String name) {
+                for(Recording r : FlightRecorder.getFlightRecorder().getRecordings()) {
+                        if (r.getName().equals(name)) {
+                                return r;
+                        }
+                }
+                throw new AssertionError("Could not find recording named " + name);
+        }
+
+        public static void assertMaxAgeEqualsMBeanValue(String name, long maxAge)
+            throws Exception {
+        Recording recording = findRecording(name);
+        Asserts.assertNotNull(recording, "No recording found");
+        Asserts.assertEquals(maxAge, recording.getMaxAge().toMillis());
+    }
+
+    public static void assertDurationEqualsMBeanValue(String name,
+            long duration) throws Exception {
+        Recording recording = findRecording(name);
+        Asserts.assertNotNull(recording, "No recording found");
+        Asserts.assertEquals(duration, recording.getDuration().toMillis());
+    }
+
+    public static void assertDurationAtLeast1s(OutputAnalyzer output) {
+        output.shouldContain("Could not start recording, duration must be at least 1 second.");
+    }
+
+    public static void assertStoppedRecording(OutputAnalyzer output, String name) {
+        output.shouldContain("Stopped recording \"" + name + "\"");
+    }
+
+    public static void assertStoppedAndWrittenTo(OutputAnalyzer output, String name, File file) {
+        output.shouldMatch("^Stopped recording \"" + name + "\"" + ".*written to:");
+        output.shouldContain(file.getAbsolutePath());
+    }
+
+    public static void assertStoppedDefaultRecording(OutputAnalyzer output) {
+        output.shouldContain("Stopped recording 0");
+    }
+
+    public static void assertThreadSleepThresholdIsSet(OutputAnalyzer output) throws Exception {
+        output.stdoutShouldMatch("\\s+\\W{1}" + EventNames.ThreadSleep + "\\W{1}" +
+                NEW_LINE + ".*threshold=1 ms.*");
+    }
+
+    public static void assertMonitorWaitThresholdIsSet(OutputAnalyzer output) throws Exception {
+        output.stdoutShouldMatch("\\s+\\W{1}" + EventNames.JavaMonitorWait + "\\W{1}" +
+                NEW_LINE + ".*threshold=1 ms.*");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jcmd/JcmdHelper.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jcmd;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.stream.Collectors;
+
+import jdk.test.lib.Asserts;
+import jdk.test.lib.dcmd.CommandExecutor;
+import jdk.test.lib.dcmd.PidJcmdExecutor;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class JcmdHelper {
+
+    // Wait until recording's state became running
+    public static void waitUntilRunning(String name) throws Exception {
+        long timeoutAt = System.currentTimeMillis() + 10000;
+        while (true) {
+            OutputAnalyzer output = jcmdCheck(name, false);
+            try {
+                // The expected output can look like this:
+                // Recording: recording=1 name="Recording 1" (running)
+                output.shouldMatch("^Recording: recording=\\d+\\s+name=\"" + name
+                        + "\".*\\W{1}running\\W{1}");
+                return;
+            } catch (RuntimeException e) {
+                if (System.currentTimeMillis() > timeoutAt) {
+                    Asserts.fail("Recording not started: " + name);
+                }
+                Thread.sleep(100);
+            }
+        }
+    }
+
+    // Wait until default recording's state became running
+    public static void waitUntilDefaultRecordingRunning() throws Exception {
+        while (true) {
+            OutputAnalyzer output = jcmd("JFR.check", "recording=0");
+            try {
+                output.shouldContain("Recording: recording=0 name=\"HotSpot default\" (running)");
+                return;
+            } catch (RuntimeException e) {
+                Thread.sleep(100);
+            }
+        }
+    }
+
+    public static void stopAndCheck(String name) throws Exception {
+        jcmd("JFR.stop", "name=\"" + name + "\"");
+        assertRecordingNotRunning(name);
+    }
+
+    public static void stopWriteToFileAndCheck(String name, File file) throws Exception {
+        OutputAnalyzer output = jcmd("JFR.stop",
+                "name=\"" + name + "\"",
+                "filename=\"" + file.getAbsolutePath() + "\"");
+        JcmdAsserts.assertStoppedAndWrittenTo(output, name, file);
+        assertRecordingNotRunning(name);
+    }
+
+    public static void stopCompressAndCheck(String name, File file) throws Exception {
+        OutputAnalyzer output = jcmd("JFR.stop",
+                "name=\"" + name + "\"",
+                "compress=true",
+                "filename=\"" + file.getAbsolutePath() + "\"");
+        JcmdAsserts.assertStoppedAndWrittenTo(output, name, file);
+        checkAndAssertNoRecordingsAvailable();
+    }
+
+    public static void stopDefaultRecordingAndCheck() throws Exception {
+        OutputAnalyzer output = jcmd("JFR.stop", "recording=0");
+        JcmdAsserts.assertStoppedDefaultRecording(output);
+        checkAndAssertNoRecordingsAvailable();
+    }
+
+    public static void checkAndAssertNoRecordingsAvailable() throws Exception {
+        OutputAnalyzer output = jcmd("JFR.check");
+        JcmdAsserts.assertNoRecordingsAvailable(output);
+    }
+
+    public static void assertRecordingNotExist(String name) throws Exception {
+        OutputAnalyzer output = jcmdCheck(name, false);
+        JcmdAsserts.assertRecordingNotExist(output, name);
+    }
+
+    public static void assertRecordingNotRunning(String name) throws Exception {
+        OutputAnalyzer output = jcmdCheck(name, false);
+        JcmdAsserts.assertRecordingNotRunning(output, name);
+    }
+
+    public static void assertRecordingIsRunning(String name) throws Exception {
+        OutputAnalyzer output = jcmdCheck(name, false);
+        JcmdAsserts.assertRecordingIsRunning(output, name);
+    }
+
+    public static OutputAnalyzer jcmd(int expectedExitValue, String... args) {
+        String argsString = Arrays.stream(args).collect(Collectors.joining(" "));
+        CommandExecutor executor = new PidJcmdExecutor();
+        OutputAnalyzer oa = executor.execute(argsString);
+        oa.shouldHaveExitValue(expectedExitValue);
+        return oa;
+    }
+
+    public static OutputAnalyzer jcmd(String... args) {
+        return jcmd(0, args);
+    }
+
+
+    public static OutputAnalyzer jcmdCheck(String recordingName, boolean verbose) {
+        return jcmd("JFR.check", "name=" + recordingName, "verbose=" + verbose);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jcmd/TEST.properties	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,2 @@
+modules = jdk.jcmd
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jcmd/TestJcmdChangeLogLevel.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jcmd;
+
+
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.List;
+
+import jdk.test.lib.dcmd.JcmdExecutor;
+import jdk.test.lib.dcmd.PidJcmdExecutor;
+
+/*
+ * @test TestJcmdLogLevelChange
+ * @key jfr
+ * @summary Test changing log level
+ *
+ * @library /test/lib /test/jdk
+ *
+ * @run main/othervm -Xlog:jfr=info jdk.jfr.jcmd.TestJcmdChangeLogLevel
+ */
+public class TestJcmdChangeLogLevel {
+    public static void main(String[] args) throws Exception {
+        final String fileName = "jfr_trace.txt";
+        final String findWhat = "[info][jfr] Flight Recorder initialized";
+        boolean passed = false;
+
+        JcmdExecutor je = new PidJcmdExecutor();
+        je.execute("VM.log output='file=" + fileName + "' what='jfr=info'");
+        je.execute("JFR.start duration=1s");
+        List<String> lines;
+
+        do {
+            try {
+                lines = Files.readAllLines(Paths.get(fileName));
+            } catch (IOException e) {
+                throw new Error(e);
+            }
+            for (String l : lines) {
+                if (l.toString().contains(findWhat)) {
+                    passed = true;
+                    break;
+                }
+            }
+            if (lines.size() > 100) {
+                break; /* did not find it */
+            }
+        } while(!passed);
+
+        if (!passed) {
+            throw new Error("Not found " + findWhat  + " in stream" + lines);
+        }
+
+        System.out.println("PASSED");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jcmd/TestJcmdConfigure.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jcmd;
+
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.internal.Options;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @summary The test verifies JFR.configure command
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @modules jdk.jfr/jdk.jfr.internal
+ * @run main/othervm jdk.jfr.jcmd.TestJcmdConfigure
+ */
+public class TestJcmdConfigure {
+
+    private static final String DUMPPATH = "dumppath";
+    private static final String STACK_DEPTH = "stackdepth";
+    private static final String GLOBAL_BUFFER_COUNT = "globalbuffercount";
+    private static final String GLOBAL_BUFFER_SIZE = "globalbuffersize";
+    private static final String THREAD_BUFFER_SIZE = "thread_buffer_size";
+    private static final String MAX_CHUNK_SIZE = "maxchunksize";
+    private static final String SAMPLE_THREADS = "samplethreads";
+    private static final String UNSUPPORTED_OPTION = "unsupportedoption";
+
+    public static void main(String[] args) throws Exception {
+        //
+        // Simple sanity tests against what is available in Java,
+        // before Flight Recorder is loaded. To do:
+        //
+        // - set values when JFR is running, check for errors.
+        // - validate against output from JFR.configure
+        // - where feasible, check if they are respected
+        //
+
+        String dumpPath = Files.createTempDirectory("dump-path").toAbsolutePath().toString();
+
+        test(DUMPPATH, dumpPath);
+        test(STACK_DEPTH, 15);
+        test(GLOBAL_BUFFER_COUNT, 7);
+        test(GLOBAL_BUFFER_SIZE, 6);
+        test(THREAD_BUFFER_SIZE, 5);
+        test(MAX_CHUNK_SIZE, 14 * 1000 * 1000);
+        test(SAMPLE_THREADS, false);
+        test(SAMPLE_THREADS, true);
+        testNegative(UNSUPPORTED_OPTION, 100000);
+        testNegative(MAX_CHUNK_SIZE, -500);
+
+        if (!testExceptions.isEmpty()) {
+            for (Exception e : testExceptions) {
+                System.out.println("Error: " + e.getMessage());
+            }
+            throw testExceptions.get(0);
+        }
+    }
+
+    private static List<Exception> testExceptions = new ArrayList<>();
+
+    private static void test(String configName, Object value) {
+        JcmdHelper.jcmd("JFR.configure", configName + "=" + value);
+        Object actualValue = getOption(configName);
+        System.out.format("Test param='%s', expected='%s', actual='%s'%n", configName, value, actualValue);
+        try {
+            // Need convert to string to compare Integer and Long
+            Asserts.assertEquals(value.toString(), actualValue.toString(), "Wrong JFR.configure " + configName);
+        } catch (Exception e) {
+            testExceptions.add(e);
+        }
+    }
+
+    private static void testNegative(String configName, Object value) {
+        try {
+            // Syntactically invalid arguments are catched by the JCMD framework where an error code of 1 is returned.
+            // Syntactically valid arguments that are semantically invalid (invalid value ranges for example) are handled by JFR code, it will always return a value of 0.
+            JcmdHelper.jcmd(configName.equals(UNSUPPORTED_OPTION) ? 1 : 0, "JFR.configure", configName + "=" + value);
+        } catch(Exception e) {
+            testExceptions.add(e);
+        }
+    }
+
+    private static Object getOption(String name) {
+        switch (name) {
+            case DUMPPATH: return Options.getDumpPath().toString();
+            case STACK_DEPTH: return Options.getStackDepth();
+            case GLOBAL_BUFFER_COUNT: return Options.getGlobalBufferCount();
+            case GLOBAL_BUFFER_SIZE: return Options.getGlobalBufferSize();
+            case THREAD_BUFFER_SIZE: return Options.getThreadBufferSize();
+            case MAX_CHUNK_SIZE: return Options.getMaxChunkSize();
+            case SAMPLE_THREADS: return Options.getSampleThreads();
+            default: throw new RuntimeException("Unknown option " + name);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jcmd/TestJcmdDump.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jcmd;
+
+import java.io.File;
+
+import jdk.test.lib.jfr.FileHelper;
+import jdk.test.lib.process.OutputAnalyzer;
+
+/*
+ * @test
+ * @summary The test verifies JFR.dump command
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jcmd.TestJcmdDump
+ */
+public class TestJcmdDump {
+
+    public static void main(String[] args) throws Exception {
+        String name = "TestJcmdDump";
+        File recording = new File(name + ".jfr");
+
+
+        OutputAnalyzer output = JcmdHelper.jcmd("JFR.start", "name=" + name);
+        JcmdAsserts.assertRecordingHasStarted(output);
+        JcmdHelper.waitUntilRunning(name);
+
+        output = JcmdHelper.jcmd("JFR.dump",
+                "name=" + name,
+                "filename=" + recording.getAbsolutePath());
+        JcmdAsserts.assertRecordingDumpedToFile(output, name, recording);
+        JcmdHelper.stopAndCheck(name);
+        FileHelper.verifyRecording(recording);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jcmd/TestJcmdDumpPathToGCRoots.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jcmd;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jdk.jfr.Enabled;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedObject;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.jfr.internal.test.WhiteBox;
+import jdk.test.lib.jfr.EventNames;
+
+/*
+ * @test
+ * @summary Start a recording with or without path-to-gc-roots
+ * @modules jdk.jfr/jdk.jfr.internal.test
+ * @library /test/lib /test/jdk
+ * @key jfr
+ *
+ * @run main/othervm -XX:TLABSize=2k jdk.jfr.jcmd.TestJcmdDumpPathToGCRoots
+ */
+public class TestJcmdDumpPathToGCRoots {
+
+    private static final int OBJECT_COUNT = 100_000;
+    public static List<Object[]> leak = new ArrayList<>(OBJECT_COUNT);
+
+    public static void main(String[] args) throws Exception {
+        WhiteBox.setWriteAllObjectSamples(true);
+
+        String settingName = EventNames.OldObjectSample + "#" + "cutoff";
+
+        // dump parameter trumps previous setting
+        testDump("path-to-gc-roots=true", Collections.singletonMap(settingName, "infinity"), true);
+        testDump("path-to-gc-roots=true", Collections.singletonMap(settingName, "0 ns"), true);
+        testDump("path-to-gc-roots=true", Collections.emptyMap(), true);
+
+        testDump("path-to-gc-roots=false", Collections.singletonMap(settingName, "infinity"), false);
+        testDump("path-to-gc-roots=false", Collections.singletonMap(settingName, "0 ns"), false);
+        testDump("path-to-gc-roots=false", Collections.emptyMap(), false);
+
+        testDump("", Collections.singletonMap(settingName, "infinity"), true);
+        testDump("", Collections.singletonMap(settingName, "0 ns"), false);
+        testDump("", Collections.emptyMap(), false);
+    }
+
+    private static void testDump(String pathToGcRoots, Map<String, String> settings, boolean expectedChains) throws Exception {
+        try (Recording r = new Recording()) {
+            Map<String, String> p = new HashMap<>(settings);
+            p.put(EventNames.OldObjectSample + "#" + Enabled.NAME, "true");
+            r.setName("dodo");
+            r.setSettings(p);
+            r.setToDisk(true);
+            r.start();
+            clearLeak();
+            System.out.println("Recording id: " + r.getId());
+            System.out.println("Settings: " + settings.toString());
+            System.out.println("Command: JFR.dump " + pathToGcRoots);
+            System.out.println("Chains expected: " + expectedChains);
+            buildLeak();
+            System.gc();
+            System.gc();
+            File recording = new File("TestJcmdDumpPathToGCRoots" + r.getId() + ".jfr");
+            recording.delete();
+            JcmdHelper.jcmd("JFR.dump", "name=dodo", pathToGcRoots, "filename=" + recording.getAbsolutePath());
+            r.setSettings(Collections.emptyMap());
+            List<RecordedEvent> events = RecordingFile.readAllEvents(recording.toPath());
+            if (events.isEmpty()) {
+                throw new Exception("No events found in recoding");
+            }
+            boolean chains = hasChains(events);
+            if (expectedChains && !chains) {
+                System.out.println(events);
+                throw new Exception("Expected chains but found none");
+            }
+            if (!expectedChains && chains) {
+                System.out.println(events);
+                throw new Exception("Didn't expect chains but found some");
+            }
+        }
+    }
+
+    private static void clearLeak() {
+      leak.clear();
+    }
+
+    private static boolean hasChains(List<RecordedEvent> events) throws IOException {
+        for (RecordedEvent e : events) {
+            RecordedObject ro = e.getValue("object");
+            if (ro.getValue("referrer") != null) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static void buildLeak() {
+        for (int i = 0; i < OBJECT_COUNT;i ++) {
+            leak.add(new Object[0]);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jcmd/TestJcmdLegacy.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jcmd;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.FileHelper;
+import jdk.test.lib.process.OutputAnalyzer;
+
+/*
+ * @test TestClassId
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @modules jdk.jfr/jdk.jfr.internal
+ * @run main/othervm jdk.jfr.jcmd.TestJcmdLegacy
+ */
+public class TestJcmdLegacy {
+
+    private static final String DIR = System.getProperty("test.src", ".");
+    private static final File SETTINGS = new File(DIR, "legacy.jfc");
+
+    private static final String LEGACY_EVENT = "com.oracle.jdk.JVMInformation";
+
+    public static void main(String... args) throws Exception {
+        testAPI();
+        testJcmd();
+    }
+
+    private static void testJcmd() throws Exception {
+        String name = "testLegacy";
+        File p = new File(name + ".jfr");
+        OutputAnalyzer output = JcmdHelper.jcmd("JFR.start", "name=" + name, "settings=" + SETTINGS.getCanonicalPath());
+        JcmdAsserts.assertRecordingHasStarted(output);
+        JcmdHelper.waitUntilRunning(name);
+        JcmdHelper.stopWriteToFileAndCheck(name, p);
+        FileHelper.verifyRecording(p);
+        verify(p.toPath());
+    }
+
+    private static void testAPI() throws IOException, Exception {
+        Path p = Files.createTempFile("recording", ".jfr");
+
+        try (Recording r = new Recording()) {
+            r.enable(LEGACY_EVENT);
+            r.start();
+            r.stop();
+            r.dump(p);
+            verify(p);
+        }
+    }
+
+    private static void verify(Path p) throws IOException, Exception {
+        for (RecordedEvent e : RecordingFile.readAllEvents(p)) {
+            System.out.println(e.getEventType().getName());
+            if (e.getEventType().getName().equals(EventNames.JVMInformation)) {
+                return;
+            }
+        }
+        throw new Exception("Could not find legacy event");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jcmd/TestJcmdSaveToFile.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jcmd;
+
+import java.io.File;
+
+import jdk.test.lib.jfr.FileHelper;
+import jdk.test.lib.process.OutputAnalyzer;
+
+/*
+ * @test
+ * @summary The test verifies that recording can be written to a file both with JFR.start and JFR.stop
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jcmd.TestJcmdSaveToFile
+ */
+public class TestJcmdSaveToFile {
+
+    public static void main(String[] args) throws Exception {
+        testStartAndSave();
+        testStopAndSave();
+    }
+
+    private static void testStartAndSave() throws Exception {
+        String name = "testStartAndSave";
+        File recording = new File(name + ".jfr");
+        OutputAnalyzer output = JcmdHelper.jcmd("JFR.start",
+                "name=" + name,
+                "duration=1h",
+                "filename=" + recording.getAbsolutePath());
+        JcmdAsserts.assertRecordingHasStarted(output);
+        JcmdHelper.waitUntilRunning(name);
+        JcmdHelper.stopAndCheck(name);
+        FileHelper.verifyRecording(recording);
+    }
+
+    private static void testStopAndSave() throws Exception {
+        String name = "testStopAndSave";
+        File recording = new File(name + ".jfr");
+        OutputAnalyzer output = JcmdHelper.jcmd("JFR.start", "name=" + name);
+        JcmdAsserts.assertRecordingHasStarted(output);
+        JcmdHelper.waitUntilRunning(name);
+        JcmdHelper.stopWriteToFileAndCheck(name, recording);
+        FileHelper.verifyRecording(recording);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jcmd/TestJcmdStartDirNotExist.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jcmd;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import jdk.test.lib.process.OutputAnalyzer;
+
+/*
+ * @test
+ * @summary Verify error when starting with a dir that does not exist.
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jcmd.TestJcmdStartDirNotExist
+ */
+public class TestJcmdStartDirNotExist {
+
+    public static void main(String[] args) throws Exception {
+        Path path = Paths.get(".", "dirDoesNotExist", "my.jfr");
+        String name = "testStartWithIllegalFilename";
+        OutputAnalyzer output = JcmdHelper.jcmd("JFR.start",
+                "name=" + name,
+                "duration=10s",
+                "filename=" + path.toString());
+        JcmdAsserts.assertNotAbleToWriteToFile(output);
+        JcmdHelper.assertRecordingNotExist(name);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jcmd/TestJcmdStartInvaldFile.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jcmd;
+
+import jdk.test.lib.process.OutputAnalyzer;
+
+/*
+ * @test
+ * @summary Verify error when starting with invalid file.
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jcmd.TestJcmdStartInvaldFile
+ */
+public class TestJcmdStartInvaldFile {
+
+    private final static String ILLEGAL_FILE_NAME = ":;/\\?";
+
+    public static void main(String[] args) throws Exception {
+        String name = "testStartWithIllegalFilename";
+        OutputAnalyzer output = JcmdHelper.jcmd("JFR.start",
+                "name=" + name,
+                "duration=10s",
+                "filename=" + ILLEGAL_FILE_NAME);
+        JcmdAsserts.assertNotAbleToWriteToFile(output);
+        JcmdHelper.assertRecordingNotExist(name);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jcmd/TestJcmdStartPathToGCRoots.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jcmd;
+
+import java.util.List;
+
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Recording;
+import jdk.test.lib.jfr.EventNames;
+
+
+/*
+ * @test
+ * @summary Start a recording with or without path-to-gc-roots
+ * @library /test/lib /test/jdk
+ * @key jfr
+ *
+ * @run main/othervm jdk.jfr.jcmd.TestJcmdStartPathToGCRoots
+ */
+public class TestJcmdStartPathToGCRoots {
+
+    public static void main(String[] args) throws Exception {
+
+        JcmdHelper.jcmd("JFR.start", "path-to-gc-roots=true");
+        assertCutoff("infinity", "Expected cutoff to be '0 ns' wuth -XX:StartFlightRecording=path-to-gc-roots=true");
+        closeRecording();
+
+        JcmdHelper.jcmd("JFR.start", "path-to-gc-roots=false");
+        assertCutoff("0 ns", "Expected cutoff to be '0 ns' with -XX:StartFlightRecording=path-to-gc-roots=false");
+        closeRecording();
+
+        JcmdHelper.jcmd("JFR.start");
+        assertCutoff("0 ns", "Expected cutoff to be '0 ns' with -XX:StartFlightRecording=");
+        closeRecording();
+    }
+
+    private static void assertCutoff(String expected, String errorMessage) throws Exception {
+        List<Recording> recordings = FlightRecorder.getFlightRecorder().getRecordings();
+        if (recordings.isEmpty()) {
+            throw new Exception("Expected recording to be started");
+        }
+        if (recordings.size() != 1) {
+            throw new Exception("Expected only one recording");
+        }
+
+        String settingName = EventNames.OldObjectSample + "#" + "cutoff";
+        Recording r = recordings.get(0);
+        String cutoff = r.getSettings().get(settingName);
+        System.out.println(settingName + "=" + cutoff);
+        if (!expected.equals(cutoff)) {
+            throw new Exception(errorMessage);
+        }
+        r.close();
+    }
+
+    private static void closeRecording() {
+        for (Recording r : FlightRecorder.getFlightRecorder().getRecordings()) {
+            r.close();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jcmd/TestJcmdStartReadOnlyFile.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jcmd;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import jdk.test.lib.jfr.FileHelper;
+import jdk.test.lib.process.OutputAnalyzer;
+
+/*
+ * @test
+ * @summary Verify error when starting with read-only file.
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jcmd.TestJcmdStartReadOnlyFile
+ */
+public class TestJcmdStartReadOnlyFile {
+
+    public static void main(String[] args) throws Exception {
+        String name = "TestJcmdStartReadOnlyFile";
+        Path readonlyFile = FileHelper.createReadOnlyFile(Paths.get(".", name + ".jfr"));
+        if (!FileHelper.isReadOnlyPath(readonlyFile)) {
+            System.out.println("Could not create read-only file. Ignoring test.");
+            return;
+        }
+
+        OutputAnalyzer output = JcmdHelper.jcmd("JFR.start",
+                "name=" + name,
+                "duration=10s",
+                "filename=" + readonlyFile.toAbsolutePath());
+        JcmdAsserts.assertNotAbleToWriteToFile(output);
+        JcmdHelper.assertRecordingNotExist(name);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jcmd/TestJcmdStartStopDefault.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jcmd;
+
+import java.io.File;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.FileHelper;
+import jdk.test.lib.process.OutputAnalyzer;
+
+/*
+ * @test
+ * @summary Start a recording without name.
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jcmd.TestJcmdStartStopDefault
+ */
+public class TestJcmdStartStopDefault {
+
+    public static void main(String[] args) throws Exception {
+        File recording = new File("TestJcmdStartStopDefault.jfr");
+
+        OutputAnalyzer output = JcmdHelper.jcmd("JFR.start");
+        JcmdAsserts.assertRecordingHasStarted(output);
+
+        String name = parseRecordingName(output);
+        name= "Recording-" + name;
+        JcmdHelper.waitUntilRunning(name);
+
+        output = JcmdHelper.jcmd("JFR.dump",
+                "name=" + name,
+                "filename=" + recording.getAbsolutePath());
+        JcmdAsserts.assertRecordingDumpedToFile(output, name, recording);
+        JcmdHelper.stopAndCheck(name);
+        FileHelper.verifyRecording(recording);
+    }
+
+    private static String parseRecordingName(OutputAnalyzer output) {
+        // Expected output:
+        // Started recording recording-1. No limit (duration/maxsize/maxage) in use.
+        // Use JFR.dump name=recording-1 filename=FILEPATH to copy recording data to file.
+
+        String stdout = output.getStdout();
+        Pattern p = Pattern.compile(".*Use JFR.dump name=(\\S+).*", Pattern.DOTALL);
+        Matcher m = p.matcher(stdout);
+        Asserts.assertTrue(m.matches(), "Could not parse recording name");
+        String name = m.group(1);
+        System.out.println("Recording name=" + name);
+        return name;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jcmd/TestJcmdStartWithOptions.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jcmd;
+
+import java.io.File;
+
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Recording;
+import jdk.jfr.RecordingState;
+import jdk.test.lib.process.OutputAnalyzer;
+
+/*
+ * @test
+ * @summary The test verifies that recording can be started with options delay|duration|maxage|maxsize
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:+FlightRecorder -XX:FlightRecorderOptions=maxchunksize=2097152 jdk.jfr.jcmd.TestJcmdStartWithOptions
+ */
+public class TestJcmdStartWithOptions {
+
+    private static final String DIR = System.getProperty("test.src", ".");
+    private static final File SETTINGS = new File(DIR, "jcmd-testsettings3.jfc");
+
+    public static void main(String[] args) throws Exception {
+        testRecordingNotStartedTooEarly();
+        testDelayLessThan1s();
+        testDuration();
+        testDurationLessThan1s();
+        testMaxAge();
+        testMaxSize();
+    }
+
+    static void testRecordingNotStartedTooEarly() throws Exception {
+        String name = "testRecordingNotStartedTooEarly";
+        long delay = 2 * 1000;
+        OutputAnalyzer output = JcmdHelper.jcmd("JFR.start",
+                "name=" + name,
+                "delay=" + delay + "ms");
+        JcmdAsserts.assertRecordingIsScheduled(output, "1", "2 s");
+        for (Recording r : FlightRecorder.getFlightRecorder().getRecordings()) {
+            if (name.equals(r.getName())) {
+                while(r.getState() != RecordingState.RUNNING) {
+                    Thread.sleep(10);
+                }
+                long currentTime = System.currentTimeMillis();
+                long afterActualStart = currentTime + delay;
+                JcmdAsserts.assertStartTimeGreaterOrEqualThanMBeanValue(name, afterActualStart);
+                JcmdHelper.stopAndCheck(name);
+                return;
+            }
+        }
+        throw new Exception("Could not find recording with name " + name);
+    }
+
+    private static void testDelayLessThan1s() throws Exception {
+        String name = "testDelayLessThan1s";
+        OutputAnalyzer output = JcmdHelper.jcmd("JFR.start",
+                "name=" + name,
+                "delay=10ms");
+        JcmdAsserts.assertDelayAtLeast1s(output);
+        output = JcmdHelper.jcmd("JFR.check");
+        JcmdAsserts.assertNoRecordingsAvailable(output);
+    }
+
+    private static void testDuration() throws Exception {
+        String name = "testDuration";
+        long duration = 3600 * 1000;
+        String durationS = String.valueOf(duration / 1000) + "s" ;
+        OutputAnalyzer output = JcmdHelper.jcmd("JFR.start",
+                "name=" + name,
+                "duration=" + durationS);
+        JcmdAsserts.assertRecordingHasStarted(output);
+        JcmdHelper.waitUntilRunning(name);
+        JcmdAsserts.assertDurationEqualsMBeanValue(name, duration);
+        JcmdHelper.stopAndCheck(name);
+    }
+
+    private static void testDurationLessThan1s() throws Exception {
+        String name = "testDurationLessThan1s";
+        OutputAnalyzer output = JcmdHelper.jcmd("JFR.start",
+                "name=" + name,
+                "duration=10ms");
+        JcmdAsserts.assertDurationAtLeast1s(output);
+        JcmdHelper.checkAndAssertNoRecordingsAvailable();
+    }
+
+    /**
+     * Check the maxage is the same as MBean value
+     */
+    private static void testMaxAge() throws Exception {
+        String name = "testMaxAge";
+        long maxAge = 2 * 1000;
+        OutputAnalyzer output = JcmdHelper.jcmd("JFR.start",
+                "name=" + name,
+                "settings=" + SETTINGS.getAbsolutePath(),
+                "maxage=2s");
+        JcmdAsserts.assertRecordingHasStarted(output);
+        JcmdHelper.waitUntilRunning(name);
+        JcmdAsserts.assertMaxAgeEqualsMBeanValue(name, maxAge);
+        JcmdHelper.stopAndCheck(name);
+    }
+
+    /**
+     * Check the maxsize is the same as MBean value
+     */
+    private static void testMaxSize() throws Exception {
+        String name = "testMaxSize";
+        long maxSize = 2 * 1024 * 1024;
+        OutputAnalyzer output = JcmdHelper.jcmd("JFR.start",
+                "name=" + name,
+                "settings=" + SETTINGS.getAbsolutePath(),
+                "maxsize=" + maxSize);
+        JcmdAsserts.assertRecordingHasStarted(output);
+        JcmdHelper.waitUntilRunning(name);
+        JcmdAsserts.assertMaxSizeEqualsMBeanValue(name, maxSize);
+        JcmdHelper.stopAndCheck(name);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jcmd/TestJcmdStartWithSettings.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jcmd;
+
+import java.io.File;
+
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedThread;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.process.OutputAnalyzer;
+
+/*
+ * @test
+ * @summary The test verifies that recording can be started with setting file(s)
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jcmd.TestJcmdStartWithSettings
+ */
+public class TestJcmdStartWithSettings {
+
+    private static final String DIR = System.getProperty("test.src", ".");
+    private static final File SETTINGS = new File(DIR, "jcmd-testsettings.jfc");
+    private static final File SETTINGS2 = new File(DIR, "jcmd-testsettings.2.jfc");
+
+    public static void main(String[] args) throws Exception {
+        testSingleSettingFile();
+        testManySettingFiles();
+        testPresetSettings();
+        testNonExistingSettingFile();
+    }
+
+    private static void testSingleSettingFile() throws Exception {
+        String name = "testSingleSettingFile";
+        File recording = new File(name + ".jfr");
+
+        OutputAnalyzer output = JcmdHelper.jcmd("JFR.start",
+                "name=" + name,
+                "duration=1h",
+                "settings=" + SETTINGS.getCanonicalPath(),
+                "filename=" + recording.getCanonicalPath());
+        JcmdAsserts.assertRecordingHasStarted(output);
+        JcmdHelper.waitUntilRunning(name);
+        output = JcmdHelper.jcmdCheck(name, true);
+        JcmdAsserts.assertThreadSleepThresholdIsSet(output);
+
+        Thread.sleep(100);
+        JcmdHelper.stopAndCheck(name);
+        assertHasEvent(recording, EventNames.ThreadSleep, Thread.currentThread().getName());
+    }
+
+    /**
+     * Start a recording with two setting files and
+     * verify Java Thread Sleep and Java Monitor Wait events have been recorded.
+     */
+    private static void testManySettingFiles() throws Exception {
+        String name = "testManySettingFiles";
+        File recording = new File(name + ".jfr");
+
+        OutputAnalyzer output = JcmdHelper.jcmd("JFR.start",
+                "name=" + name,
+                "duration=1h",
+                "settings=" + SETTINGS.getCanonicalPath(),
+                "settings=" + SETTINGS2.getCanonicalPath(),
+                "filename=" + recording.getCanonicalPath());
+        JcmdAsserts.assertRecordingHasStarted(output);
+        JcmdHelper.waitUntilRunning(name);
+        output = JcmdHelper.jcmdCheck(name, true);
+        JcmdAsserts.assertThreadSleepThresholdIsSet(output);
+        JcmdAsserts.assertMonitorWaitThresholdIsSet(output);
+
+        // Generate Monitor Wait event
+        ThreadWait threadWait = new ThreadWait();
+        threadWait.start();
+        Thread.sleep(300);
+        threadWait.join();
+
+        JcmdHelper.stopAndCheck(name);
+        assertHasEvent(recording, EventNames.ThreadSleep, Thread.currentThread().getName());
+        assertHasEvent(recording, EventNames.JavaMonitorWait, threadWait.getName());
+    }
+
+    /**
+     * It should be possible to use "profile" as non-path preset,
+     * both with and without '.jfc'
+     */
+    private static void testPresetSettings() throws Exception {
+        String name = "testPresetSettingsJfc";
+        OutputAnalyzer output = JcmdHelper.jcmd("JFR.start",
+                "name=" + name,
+                "settings=profile.jfc");
+        JcmdAsserts.assertRecordingHasStarted(output);
+        JcmdHelper.waitUntilRunning(name);
+        JcmdHelper.stopAndCheck(name);
+
+        name = "testPresetSettingsNoJfc";
+        output = JcmdHelper.jcmd("JFR.start",
+                "name=" + name,
+                "settings=profile");
+        JcmdAsserts.assertRecordingHasStarted(output);
+        JcmdHelper.waitUntilRunning(name);
+        JcmdHelper.stopAndCheck(name);
+    }
+
+    /**
+     * It should not be possible to start a recording
+     * with a non-existing setting file
+     */
+    private static void testNonExistingSettingFile() throws Exception {
+        String name = "testNonExistingSettingFile";
+        OutputAnalyzer output = JcmdHelper.jcmd("JFR.start",
+                "name=" + name,
+                "settings=nonexisting.jfc");
+        JcmdAsserts.assertNotAbleToFindSettingsFile(output);
+        JcmdHelper.assertRecordingNotExist(name);
+    }
+
+    private static void assertHasEvent(File file, String eventType, String threadName) throws Exception {
+        for (RecordedEvent event : RecordingFile.readAllEvents(file.toPath())) {
+            if (Events.isEventType(event, eventType)) {
+                System.out.println(event);
+                RecordedThread t = event.getThread();
+                if (t == null) {
+                    throw new Exception("Thread null for event " + eventType);
+                }
+                if (threadName.equals(t.getJavaName())) {
+                    System.out.println("Found event: " + event);
+                    return;
+                }
+            }
+        }
+        Asserts.fail("No events of type " + eventType);
+    }
+
+    static class ThreadWait extends Thread {
+
+        public ThreadWait() {
+            setName("ThreadWait");
+        }
+
+        @Override
+        public void run() {
+            try {
+                synchronized (this) {
+                    wait(100);
+                }
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jcmd/TestJcmdStopInvalidFile.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jcmd;
+
+import jdk.test.lib.process.OutputAnalyzer;
+
+/*
+ * @test
+ * @summary Verify error when stopping with invalid file.
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jcmd.TestJcmdStopInvalidFile
+ */
+public class TestJcmdStopInvalidFile {
+
+    private final static String ILLEGAL_FILE_NAME = ":;/\\?";
+
+    public static void main(String[] args) throws Exception {
+        String name = "testStopWithIllegalFilename";
+        OutputAnalyzer output = JcmdHelper.jcmd("JFR.start", "name=" + name);
+        JcmdAsserts.assertRecordingHasStarted(output);
+        JcmdHelper.waitUntilRunning(name);
+
+        output = JcmdHelper.jcmd("JFR.stop",
+                "name=" + name,
+                "filename=" + ILLEGAL_FILE_NAME);
+        JcmdAsserts.assertFileNotFoundException(output, name);
+
+        output = JcmdHelper.jcmd("JFR.check");
+        JcmdHelper.assertRecordingIsRunning(name);
+        JcmdHelper.stopAndCheck(name);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jcmd/TestJcmdStopReadOnlyFile.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jcmd;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import jdk.test.lib.jfr.FileHelper;
+import jdk.test.lib.process.OutputAnalyzer;
+
+/*
+ * @test
+ * @summary Verify error when stopping with read-only file.
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jcmd.TestJcmdStopReadOnlyFile
+ */
+public class TestJcmdStopReadOnlyFile {
+
+
+    public static void main(String[] args) throws Exception {
+        String name = "TestJcmdStopReadOnlyFile";
+        Path readonlyFile = FileHelper.createReadOnlyFile(Paths.get(".", name + ".jfr"));
+        if (!FileHelper.isReadOnlyPath(readonlyFile)) {
+            System.out.println("Could not create read-only file. Ignoring test.");
+            return;
+        }
+
+        OutputAnalyzer output = JcmdHelper.jcmd("JFR.start", "name=" + name);
+        JcmdAsserts.assertRecordingHasStarted(output);
+        JcmdHelper.waitUntilRunning(name);
+
+        output = JcmdHelper.jcmd("JFR.stop",
+                "name=" + name,
+                "filename=" + readonlyFile.toAbsolutePath());
+        JcmdAsserts.assertFileNotFoundException(output, name);
+        JcmdHelper.assertRecordingIsRunning(name);
+        JcmdHelper.stopAndCheck(name);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jcmd/jcmd-testsettings.2.jfc	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration version="2.0" label="TestSettings" description="Configuration for testing JCMD" provider="Oracle">
+
+    <event name="jdk.JavaMonitorWait">
+      <setting name="enabled">true</setting>
+      <setting name="stackTrace">true</setting>
+      <setting name="threshold">1 ms</setting>
+    </event>
+
+</configuration>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jcmd/jcmd-testsettings.jfc	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration version="2.0" label="TestSettings" description="Configuration for testing JCMD" provider="Oracle">
+
+   <event name="jdk.ThreadSleep">
+     <setting name="enabled">true</setting>
+     <setting name="stackTrace">true</setting>
+     <setting name="threshold">1 ms</setting>
+   </event>
+
+</configuration>  
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jcmd/jcmd-testsettings3.jfc	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration version="2.0" label="TestSettings" description="Configuration for testing JCMD" provider="Oracle">
+
+   <event name="jcmd.Test">
+     <setting name="enabled">true</setting>
+   </event>
+
+</configuration>  
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jcmd/legacy.jfc	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration version="2.0">
+    <event name="com.oracle.jdk.JVMInformation">
+      <setting name="enabled">true</setting>
+      <setting name="period">everyChunk</setting>
+    </event> 
+</configuration>    
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/JmxHelper.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jdk.jfr.EventType;
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Recording;
+import jdk.jfr.RecordingState;
+import jdk.jfr.SettingDescriptor;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.management.jfr.EventTypeInfo;
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.management.jfr.RecordingInfo;
+import jdk.management.jfr.SettingDescriptorInfo;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.CommonHelper;
+import jdk.test.lib.jfr.Events;
+
+public class JmxHelper {
+
+    public static RecordingInfo getJmxRecording(long recId) {
+        for (RecordingInfo r : getFlighteRecorderMXBean().getRecordings()) {
+            if (r.getId() == recId) {
+                return r;
+            }
+        }
+        Asserts.fail("No RecordingInfo with id " + recId);
+        return null;
+    }
+
+    public static Recording getJavaRecording(long recId) {
+        for (Recording r : FlightRecorder.getFlightRecorder().getRecordings()) {
+            if (r.getId() == recId) {
+                return r;
+            }
+        }
+        Asserts.fail("No Recording with id " + recId);
+        return null;
+    }
+
+    public static void verifyState(long recId, RecordingState state, List<RecordingInfo> recordings) {
+        RecordingInfo r = verifyExists(recId, recordings);
+        verifyState(r, state);
+    }
+
+    public static void verifyState(RecordingInfo recording, RecordingState state) {
+        final String actual = recording.getState().toString();
+        final String expected = state.toString();
+        Asserts.assertEquals(actual, expected, "Wrong state");
+    }
+
+    public static void verifyState(long recId, RecordingState state, FlightRecorderMXBean bean) throws Exception {
+        FlightRecorder jfr = FlightRecorder.getFlightRecorder();
+        Recording recording = CommonHelper.verifyExists(recId, jfr.getRecordings());
+        CommonHelper.verifyRecordingState(recording, state);
+        verifyState(recId, state, bean.getRecordings());
+    }
+
+    public static void verifyNotExists(long recId, List<RecordingInfo> recordings) {
+        for (RecordingInfo r : recordings) {
+            if (recId == r.getId()) {
+                logRecordingInfos(recordings);
+                Asserts.fail("Recording should not exist, id=" + recId);
+            }
+        }
+    }
+
+    public static RecordingInfo verifyExists(long recId, List<RecordingInfo> recordings) {
+        for (RecordingInfo r : recordings) {
+            if (recId == r.getId()) {
+                return r;
+            }
+        }
+        logRecordingInfos(recordings);
+        Asserts.fail("Recording not found, id=" + recId);
+        return null;
+    }
+
+
+    public static void logRecordingInfos(List<RecordingInfo> recordings) {
+        System.out.println("RecordingInfos:");
+        for (RecordingInfo r : recordings) {
+            System.out.println(asString(r));
+        }
+    }
+
+    public static void logRecordings(List<Recording> recordings) {
+        System.out.println("Recordings:");
+        for (Recording r : recordings) {
+            System.out.println(asString(r));
+        }
+    }
+
+    static File dump(long streamId, FlightRecorderMXBean bean) throws IOException {
+        File f = File.createTempFile("stream_" + streamId + "_", ".jfr", new File("."));
+        try (FileOutputStream fos = new FileOutputStream(f); BufferedOutputStream bos = new BufferedOutputStream(fos)) {
+            while (true) {
+                byte[] data = bean.readStream(streamId);
+                if (data == null) {
+                    bos.flush();
+                    return f;
+                }
+                bos.write(data);
+            }
+        }
+    }
+
+    public static List<RecordedEvent> parseStream(long streamId, FlightRecorderMXBean bean) throws Exception {
+        File dumpFile = dump(streamId, bean);
+        System.out.println("data.length=" + dumpFile.length());
+        List<RecordedEvent> events = new ArrayList<>();
+        for (RecordedEvent event : RecordingFile.readAllEvents(dumpFile.toPath())) {
+            System.out.println("EVENT:" + event);
+            events.add(event);
+        }
+        return events;
+    }
+
+    public static void verifyEquals(RecordingInfo ri, Recording r) {
+        String destination = r.getDestination() != null ? r.getDestination().toString() : null;
+        long maxAge = r.getMaxAge() != null ? r.getMaxAge().getSeconds() : 0;
+        long duration = r.getDuration() != null ? r.getDuration().getSeconds() : 0;
+
+        Asserts.assertEquals(destination, ri.getDestination(), "Wrong destination");
+        Asserts.assertEquals(r.getDumpOnExit(), ri.getDumpOnExit(), "Wrong dumpOnExit");
+        Asserts.assertEquals(duration, ri.getDuration(), "Wrong duration");
+        Asserts.assertEquals(r.getId(), ri.getId(), "Wrong id");
+        Asserts.assertEquals(maxAge, ri.getMaxAge(), "Wrong maxAge");
+        Asserts.assertEquals(r.getMaxSize(), ri.getMaxSize(), "Wrong maxSize");
+        Asserts.assertEquals(r.getName(), ri.getName(), "Wrong name");
+        Asserts.assertEquals(r.getSize(), ri.getSize(), "Wrong size");
+        Asserts.assertEquals(toEpochMillis(r.getStartTime()), ri.getStartTime(), "Wrong startTime");
+        Asserts.assertEquals(r.getState().toString(), ri.getState(), "Wrong state");
+        Asserts.assertEquals(toEpochMillis(r.getStopTime()), ri.getStopTime(), "Wrong stopTime");
+
+        verifyMapEquals(r.getSettings(), ri.getSettings());
+    }
+
+    public static String asString(RecordingInfo r) {
+        StringBuffer sb = new StringBuffer();
+        sb.append(String.format("RecordingInfo:%n"));
+        sb.append(String.format("destination=%s%n", r.getDestination()));
+        sb.append(String.format("dumpOnExit=%b%n", r.getDumpOnExit()));
+        sb.append(String.format("duration=%d%n", r.getDuration()));
+        sb.append(String.format("id=%d%n", r.getId()));
+        sb.append(String.format("maxAge=%d%n", r.getMaxAge()));
+        sb.append(String.format("maxSize=%d%n", r.getMaxSize()));
+        sb.append(String.format("getName=%s%n", r.getName()));
+        sb.append(String.format("size=%d%n", r.getSize()));
+        sb.append(String.format("startTime=%d%n", r.getStartTime()));
+        sb.append(String.format("state=%s%n", r.getState()));
+        sb.append(String.format("stopTime=%d%n", r.getStopTime()));
+        return sb.toString();
+    }
+
+    public static String asString(Recording r) {
+        StringBuffer sb = new StringBuffer();
+        sb.append(String.format("Recording:%n"));
+        sb.append(String.format("destination=%s%n", r.getDestination()));
+        sb.append(String.format("dumpOnExit=%b%n", r.getDumpOnExit()));
+        sb.append(String.format("duration=%d%n", r.getDuration().getSeconds()));
+        sb.append(String.format("id=%d%n", r.getId()));
+        sb.append(String.format("maxAge=%d%n", r.getMaxAge().getSeconds()));
+        sb.append(String.format("maxSize=%d%n", r.getMaxSize()));
+        sb.append(String.format("getName=%s%n", r.getName()));
+        sb.append(String.format("size=%d%n", r.getSize()));
+        sb.append(String.format("startTime=%d%n", toEpochMillis(r.getStartTime())));
+        sb.append(String.format("state=%s%n", r.getState()));
+        sb.append(String.format("stopTime=%d%n", toEpochMillis(r.getStopTime())));
+        return sb.toString();
+    }
+
+    public static void verifyMapEquals(Map<String, String> a, Map<String, String> b) {
+        try {
+            Asserts.assertEquals(a.size(), b.size(), "Wrong number of keys");
+            for (String key : a.keySet()) {
+                Asserts.assertTrue(a.containsKey(key), "Missing key " + key);
+                Asserts.assertEquals(a.get(key), b.get(key), "Wrong values for key " + key);
+                //System.out.printf("equal: %s=%s%n", key, a.get(key));
+            }
+        } catch (Exception e) {
+            System.out.println("Error: " + e.getMessage());
+            logMap("a", a);
+            logMap("b", b);
+            throw e;
+        }
+    }
+
+    public static void logMap(String name, Map<String, String> map) {
+        for (String key : map.keySet()) {
+            System.out.printf("map %s: %s=%s%n", name, key, map.get(key));
+        }
+    }
+
+    private static long toEpochMillis(Instant instant) {
+        return instant != null ? instant.toEpochMilli() : 0;
+    }
+
+    public static void verifyEventSettingsEqual(EventType javaType, EventTypeInfo jmxType) {
+        Map<String, SettingDescriptor> javaSettings = new HashMap<>();
+        for (SettingDescriptor settingDescriptor : javaType.getSettingDescriptors()) {
+            javaSettings.put(settingDescriptor.getName(), settingDescriptor);
+        }
+        Asserts.assertFalse(javaSettings.isEmpty(), "No ValueDescriptor for EventType " + javaType.getName());
+
+        for (SettingDescriptorInfo jmxSetting : jmxType.getSettingDescriptors()) {
+            final String name = jmxSetting.getName();
+            System.out.printf("SettingDescriptorInfo: %s#%s=%s%n", jmxType.getName(), name, jmxSetting.getDefaultValue());
+            SettingDescriptor javaSetting = javaSettings.remove(name);
+            Asserts.assertNotNull(javaSetting, "No Setting for name " + name);
+            Asserts.assertEquals(jmxSetting.getDefaultValue(), Events.getSetting(javaType, name).getDefaultValue(), "Wrong default value");
+            Asserts.assertEquals(jmxSetting.getDescription(), javaSetting.getDescription(), "Wrong description");
+            Asserts.assertEquals(jmxSetting.getLabel(), javaSetting.getLabel(), "Wrong label");
+            Asserts.assertEquals(jmxSetting.getName(), javaSetting.getName(), "Wrong name");
+            Asserts.assertEquals(jmxSetting.getTypeName(), javaSetting.getTypeName(), "Wrong type name");
+            Asserts.assertEquals(jmxSetting.getContentType(), javaSetting.getContentType());
+        }
+
+        // Verify that all Settings have been matched.
+        if (!javaSettings.isEmpty()) {
+            for (String name : javaSettings.keySet()) {
+                System.out.println("Missing setting" + name + " in EventTypeInfo for " + javaType.getName());
+            }
+            System.out.println();
+            System.out.println(javaType.getName() + " Java API");
+            System.out.println("===============");
+            for (SettingDescriptor v : javaType.getSettingDescriptors()) {
+                System.out.println(" - " + v.getName());
+            }
+            System.out.println();
+            System.out.println(jmxType.getName() + " JMX API");
+            System.out.println("===============");
+            for (SettingDescriptorInfo v : jmxType.getSettingDescriptors()) {
+                System.out.println(" - " + v.getName());
+            }
+
+            Asserts.fail("Missing setting");
+        }
+    }
+
+
+    public static FlightRecorderMXBean getFlighteRecorderMXBean() {
+        return ManagementFactory.getPlatformMXBean(FlightRecorderMXBean.class);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/TEST.properties	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,2 @@
+modules = jdk.management.jfr
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/TestClone.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Iterator;
+import java.util.List;
+
+import jdk.jfr.RecordingState;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.management.jfr.RecordingInfo;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventField;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.SimpleEventHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.TestClone
+ */
+public class TestClone {
+    public static void main(String[] args) throws Exception {
+        FlightRecorderMXBean bean = JmxHelper.getFlighteRecorderMXBean();
+
+        long orgId = bean.newRecording();
+        bean.startRecording(orgId);
+        SimpleEventHelper.createEvent(1); // Should be in both org and clone
+
+        long cloneId = bean.cloneRecording(orgId, false);
+        Asserts.assertNotEquals(orgId, cloneId, "clone id should not be same as org id");
+
+        List<RecordingInfo> recordings = bean.getRecordings();
+        JmxHelper.verifyState(orgId, RecordingState.RUNNING, recordings);
+        JmxHelper.verifyState(cloneId, RecordingState.RUNNING, recordings);
+
+        bean.stopRecording(orgId);
+        recordings = bean.getRecordings();
+        JmxHelper.verifyState(orgId, RecordingState.STOPPED, recordings);
+        JmxHelper.verifyState(cloneId, RecordingState.RUNNING, recordings);
+
+        SimpleEventHelper.createEvent(2);  // Should only be in clone
+
+        bean.stopRecording(cloneId);
+        recordings = bean.getRecordings();
+        JmxHelper.verifyState(orgId, RecordingState.STOPPED, recordings);
+        JmxHelper.verifyState(cloneId, RecordingState.STOPPED, recordings);
+
+        Path orgPath = Paths.get(".", "org.jfr");
+        Path clonePath = Paths.get(".", "clone.jfr");
+        bean.copyTo(orgId, orgPath.toString());
+        bean.copyTo(cloneId, clonePath.toString());
+
+        verifyEvents(orgPath, 1);
+        verifyEvents(clonePath, 1, 2);
+
+        bean.closeRecording(orgId);
+        bean.closeRecording(cloneId);
+    }
+
+    private static void verifyEvents(Path path, int... ids) throws Exception {
+        List<RecordedEvent> events = RecordingFile.readAllEvents(path);
+        Iterator<RecordedEvent> iterator = events.iterator();
+        for (int i=0; i<ids.length; i++) {
+            Asserts.assertTrue(iterator.hasNext(), "Missing event " + ids[i]);
+            EventField idField = Events.assertField(iterator.next(), "id");
+            System.out.println("Event.id=" + idField.getValue());
+            idField.equal(ids[i]);
+        }
+        if (iterator.hasNext()) {
+            Asserts.fail("Got extra event: " + iterator.next());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/TestCloneRepeat.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventField;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.SimpleEventHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.TestCloneRepeat
+ */
+public class TestCloneRepeat {
+    public static void main(String[] args) throws Exception {
+        FlightRecorderMXBean bean = JmxHelper.getFlighteRecorderMXBean();
+
+        long orgId = bean.newRecording();
+        bean.startRecording(orgId);
+
+        List<Integer> ids = new ArrayList<>();
+        for (int i=0; i<5; i++) {
+            long cloneId = bean.cloneRecording(orgId, false);
+            SimpleEventHelper.createEvent(i);
+            bean.stopRecording(cloneId);
+            Path path = Paths.get(".", i + "-org.jfr");
+            bean.copyTo(cloneId, path.toString());
+            bean.closeRecording(cloneId);
+            ids.add(i);
+            verifyEvents(path, ids);
+        }
+
+        bean.closeRecording(orgId);
+    }
+
+    private static void verifyEvents(Path path, List<Integer> ids) throws Exception {
+        List<RecordedEvent> events = RecordingFile.readAllEvents(path);
+        Iterator<RecordedEvent> iterator = events.iterator();
+        for (int i=0; i<ids.size(); i++) {
+            Asserts.assertTrue(iterator.hasNext(), "Missing event " + ids.get(i));
+            EventField idField = Events.assertField(iterator.next(), "id");
+            System.out.println("Event.id=" + idField.getValue());
+            idField.equal(ids.get(i).intValue());
+        }
+        if (iterator.hasNext()) {
+            Asserts.fail("Got extra event: " + iterator.next());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/TestConfigurationInfo.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import jdk.jfr.Configuration;
+import jdk.management.jfr.ConfigurationInfo;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.TestConfigurationInfo
+ */
+public class TestConfigurationInfo {
+    public static void main(String[] args) throws Exception {
+        Map<String, Configuration> cc = new HashMap<>();
+        for (Configuration c : Configuration.getConfigurations()) {
+            cc.put(c.getName(), c);
+        }
+        Asserts.assertTrue(!cc.isEmpty(), "Mising configurations, can't verify ConfigurationInfo");
+        for (ConfigurationInfo ci : JmxHelper.getFlighteRecorderMXBean().getConfigurations()) {
+            Configuration c = cc.remove(ci.getName());
+            Asserts.assertNotNull(c, "Superfluous configuration " + ci.getName());
+            Asserts.assertEquals(c.getDescription(), ci.getDescription(), "Descriptions don't match");
+            Asserts.assertEquals(c.getLabel(), ci.getLabel(), "Labels don't match");
+            Asserts.assertEquals(c.getProvider(), ci.getProvider(), "Providers don't match");
+            Asserts.assertEquals(c.getContents(), ci.getContents(), "Contents don't match");
+            Asserts.assertEquals(c.getSettings(), ci.getSettings(), "Settings don't match");
+        }
+        Asserts.assertTrue(cc.isEmpty(), "Missing configuration in FlightRecorderMXBean, " + cc.keySet());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/TestCopyTo.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.SimpleEventHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.TestCopyTo
+ */
+public class TestCopyTo {
+    public static void main(String[] args) throws Exception {
+        FlightRecorderMXBean bean = JmxHelper.getFlighteRecorderMXBean();
+
+        long recId = bean.newRecording();
+        bean.startRecording(recId);
+        SimpleEventHelper.createEvent(1);
+        bean.stopRecording(recId);
+
+        Path path = Paths.get(".", "my.jfr");
+        bean.copyTo(recId, path.toString());
+
+        List<RecordedEvent> events = RecordingFile.readAllEvents(path);
+        Asserts.assertTrue(events.iterator().hasNext(), "No events found");
+        for (RecordedEvent event : events) {
+            System.out.println("Event:" + event);
+        }
+
+        bean.closeRecording(recId);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/TestCopyToInvalidPath.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx;
+
+import java.io.IOException;
+import java.nio.file.Paths;
+
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.test.lib.jfr.CommonHelper;
+import jdk.test.lib.jfr.SimpleEventHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.TestCopyToInvalidPath
+ */
+public class TestCopyToInvalidPath {
+    public static void main(String[] args) throws Throwable {
+        FlightRecorderMXBean bean = JmxHelper.getFlighteRecorderMXBean();
+
+        long recId = bean.newRecording();
+        bean.startRecording(recId);
+        SimpleEventHelper.createEvent(1);
+        bean.stopRecording(recId);
+
+        CommonHelper.verifyException(()->{bean.copyTo(recId, null);}, "copyTo(null)", NullPointerException.class);
+        CommonHelper.verifyException(()->{bean.copyTo(recId, "");}, "copyTo('')", IOException.class);
+
+        String p = Paths.get(".", "thisdir", "doesnot", "exists").toString();
+        CommonHelper.verifyException(()->{bean.copyTo(recId, p);}, "copyTo(dirNotExist)", IOException.class);
+
+        bean.closeRecording(recId);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/TestCopyToReadOnlyDir.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx;
+
+import java.nio.file.AccessDeniedException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.FileHelper;
+import jdk.test.lib.jfr.SimpleEventHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.TestCopyToReadOnlyDir
+ */
+public class TestCopyToReadOnlyDir {
+    public static void main(String[] args) throws Throwable {
+        FlightRecorderMXBean bean = JmxHelper.getFlighteRecorderMXBean();
+
+        long recId = bean.newRecording();
+        bean.startRecording(recId);
+        SimpleEventHelper.createEvent(1);
+        bean.stopRecording(recId);
+
+        Path readOnlyDir = FileHelper.createReadOnlyDir(Paths.get(".", "readOnlyDir"));
+        System.out.println("readOnlyDir=" + readOnlyDir.toString());
+        Asserts.assertTrue(readOnlyDir.toFile().isDirectory(), "Could not create directory. Test error");
+        if (!FileHelper.isReadOnlyPath(readOnlyDir)) {
+            System.out.println("Failed to create read-only dir. Maybe running as root? Skipping test");
+            return;
+        }
+
+        Path file = Paths.get(readOnlyDir.toString(), "my.jfr");
+        System.out.println("file=" + file.toString());
+        try {
+            bean.copyTo(recId, file.toString());
+            Asserts.fail("Should be able to dump to read only file");
+        } catch (AccessDeniedException e) {
+            // ok as expected
+        }
+
+        bean.closeRecording(recId);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/TestCopyToRunning.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Recording;
+import jdk.jfr.RecordingState;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.SimpleEventHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @summary Copy a recording to file while it is running.
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.TestCopyToRunning
+ */
+public class TestCopyToRunning {
+    public static void main(String[] args) throws Exception {
+        FlightRecorderMXBean bean = JmxHelper.getFlighteRecorderMXBean();
+
+        long recId = bean.newRecording();
+        bean.startRecording(recId);
+        SimpleEventHelper.createEvent(1);
+
+        Path path = Paths.get(".", "my.jfr");
+        bean.copyTo(recId, path.toString());
+
+        List<RecordedEvent> events = RecordingFile.readAllEvents(path);
+        Asserts.assertTrue(events.iterator().hasNext(), "No events found");
+        for (RecordedEvent event : events) {
+            System.out.println("Event:" + event);
+        }
+
+        Recording recording = getRecording(recId);
+        Asserts.assertEquals(recording.getState(), RecordingState.RUNNING, "Recording not in state running");
+        bean.stopRecording(recId);
+        Asserts.assertEquals(recording.getState(), RecordingState.STOPPED, "Recording not in state stopped");
+        bean.closeRecording(recId);
+        Asserts.assertEquals(recording.getState(), RecordingState.CLOSED, "Recording not in state closed");
+    }
+
+    private static Recording getRecording(long recId) {
+        for (Recording r : FlightRecorder.getFlightRecorder().getRecordings()) {
+            if (r.getId() == recId) {
+                return r;
+            }
+        }
+        Asserts.fail("Could not find recording with id " + recId);
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/TestEventTypes.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Description;
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Label;
+import jdk.jfr.Name;
+import jdk.jfr.Recording;
+import jdk.jfr.SettingDescriptor;
+import jdk.management.jfr.EventTypeInfo;
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.management.jfr.SettingDescriptorInfo;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @key jfr
+ * @summary Verifies that EventTypes from jmx and FlightRecorder are the same.
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.TestEventTypes
+ */
+public class TestEventTypes {
+    public static void main(String[] args) throws Exception {
+        FlightRecorderMXBean bean = JmxHelper.getFlighteRecorderMXBean();
+        FlightRecorder jfr = FlightRecorder.getFlightRecorder();
+
+        Recording r = new Recording();
+        r.enable(MyEvent.class);
+        new MyEvent(); // triggers <clinit>
+        List<EventTypeInfo> infos = bean.getEventTypes();
+        List<EventType> types = jfr.getEventTypes();
+        Asserts.assertFalse(infos.isEmpty(), "No EventTypeInfos found");
+        verifyMyEventType(infos);
+        assertSame(infos, types);
+        r.close();
+    }
+
+    @Name("MyEvent.name")
+    @Label("MyEvent.label")
+    @Description("MyEvent.description")
+    private static class MyEvent extends Event {
+        @Label("MyEvent.message")
+        public String message;
+    }
+
+    private static void verifyMyEventType(List<EventTypeInfo> infos) {
+        for (EventTypeInfo info : infos) {
+            if ("MyEvent.name".equals(info.getName())) {
+                System.out.println("EventTypeInfo for MyEvent: " + info);
+                Asserts.assertEquals("MyEvent.label", info.getLabel());
+                Asserts.assertEquals("MyEvent.description", info.getDescription());
+                for (SettingDescriptorInfo si : info.getSettingDescriptors()) {
+                    System.out.println("si=" + si);
+                }
+                return;
+            }
+        }
+        Asserts.fail("Missing EventTypeInfo for MyEvent");
+    }
+
+    private static void assertSame(List<EventTypeInfo> infos, List<EventType> types) {
+        List<Long> ids = new ArrayList<>();
+        for (EventTypeInfo info : infos) {
+            long id = info.getId();
+            Asserts.assertFalse(ids.contains(id), "EventTypeInfo.id not unique:" + id);
+            ids.add(id);
+            boolean isFound = false;
+            for (EventType type : types) {
+                if (type.getId() == id) {
+                    assertSame(info, type);
+                    isFound = true;
+                    break;
+                }
+            }
+            if (!isFound) {
+                String msg = "No EventType for EventTypeInfo";
+                System.out.println(msg + ": " + info);
+                Asserts.fail(msg);
+            }
+        }
+        Asserts.assertEquals(infos.size(), types.size(), "Number of EventTypeInfos != EventTypes");
+    }
+
+    private static void assertSame(EventTypeInfo ti, EventType t) {
+        try {
+            Asserts.assertEquals(ti.getId(), t.getId(), "Wrong id");
+            Asserts.assertEquals(ti.getName(), t.getName(), "Wrong name");
+            Asserts.assertEquals(ti.getLabel(), t.getLabel(), "Wrong label");
+            Asserts.assertEquals(ti.getDescription(), t.getDescription(), "Wrong description");
+            Asserts.assertEquals(ti.getCategoryNames(), t.getCategoryNames(), "Wrong category names");
+
+            for (SettingDescriptorInfo si : ti.getSettingDescriptors()) {
+                String settingName = si.getName();
+                boolean isFound = false;
+                for (SettingDescriptor d : t.getSettingDescriptors()) {
+                    if (settingName.equals(d.getName())) {
+                        assertSame(si, d, t);
+                        isFound = true;
+                        break;
+                    }
+                }
+                if (!isFound) {
+                    Asserts.fail("No ValueDescriptor for SettingDescriptorInfo: " + si);
+                }
+            }
+        } catch (Exception e) {
+            System.out.printf("EventTypeInfo != EventType%nEventTypeInfo=%s%nEventType=%s%n", ti, t);
+            throw e;
+        }
+    }
+
+    private static void assertSame(SettingDescriptorInfo si, SettingDescriptor d, EventType type) {
+        try {
+            Asserts.assertEquals(si.getName(), d.getName(), "Wrong name");
+            Asserts.assertEquals(si.getLabel(), d.getLabel(), "Wrong label");
+            Asserts.assertEquals(si.getTypeName(), d.getTypeName(), "Wrong typeName");
+            Asserts.assertEquals(si.getDescription(), d.getDescription(), "Wrong description");
+            String typeDefaultValue = Events.getSetting(type, si.getName()).getDefaultValue();
+            Asserts.assertEquals(si.getDefaultValue(), typeDefaultValue, "Wrong defaultValue");
+        } catch (Exception e) {
+            System.out.printf("SettingDescriptorInfo != SettingDescriptor=%s%nValueDescriptor=%s%n", si, d);
+            throw e;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/TestGetRecordings.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx;
+
+import java.util.List;
+
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.management.jfr.RecordingInfo;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.TestGetRecordings
+ */
+public class TestGetRecordings {
+    public static void main(String[] args) throws Throwable {
+        FlightRecorderMXBean bean =JmxHelper.getFlighteRecorderMXBean();
+
+        List<RecordingInfo> preCreateRecordings = bean.getRecordings();
+        long recId = bean.newRecording();
+        JmxHelper.verifyNotExists(recId, preCreateRecordings);
+        bean.closeRecording(recId);
+        JmxHelper.verifyNotExists(recId, bean.getRecordings());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/TestGetRecordingsMultiple.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.management.jfr.RecordingInfo;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.TestGetRecordingsMultiple
+ */
+public class TestGetRecordingsMultiple {
+
+    private static class TestRecording {
+        long id;
+        boolean isClosed;
+        public TestRecording(long id) {
+            this.id = id;
+            isClosed = false;
+        }
+    }
+
+    public static void main(String[] args) throws Throwable {
+        List<TestRecording> testRecordings = new ArrayList<>();
+        for (int i = 0; i < 5; ++i) {
+            verifyExistingRecordings(testRecordings);
+            testRecordings.add(createRecording());
+            if (i >= 1) {
+                startRecording(testRecordings.get(i-1));
+            }
+            if (i >= 2) {
+                stopRecording(testRecordings.get(i-2));
+            }
+            if (i >= 3) {
+                closeRecording(testRecordings.get(i-3));
+            }
+        }
+        verifyExistingRecordings(testRecordings);
+
+        for (TestRecording r : testRecordings) {
+            if (!r.isClosed) {
+                closeRecording(r);
+            }
+        }
+        verifyExistingRecordings(testRecordings);
+    }
+
+    // Verify that all active recordings are found, but no closed recordings.
+    private static void verifyExistingRecordings(List<TestRecording> testRecordings) {
+        for (TestRecording testRecording : testRecordings) {
+            RecordingInfo r = findRecording(testRecording);
+            if (r != null) {
+                Asserts.assertFalse(testRecording.isClosed, "Found closed recording with id " + testRecording.id);
+                System.out.printf("Recording %d: %s%n", r.getId(), r.getState());
+            } else {
+                Asserts.assertTrue(testRecording.isClosed, "Missing recording with id " + testRecording.id);
+                System.out.printf("Recording %d: CLOSED%n", testRecording.id);
+            }
+        }
+    }
+
+    private static RecordingInfo findRecording(TestRecording testRecording) {
+        for (RecordingInfo r : JmxHelper.getFlighteRecorderMXBean().getRecordings()) {
+            if (r.getId() == testRecording.id) {
+                return r;
+            }
+        }
+        return null;
+    }
+
+    private static TestRecording createRecording() {
+        long id = JmxHelper.getFlighteRecorderMXBean().newRecording();
+        System.out.println("created recording " + id);
+        return new TestRecording(id);
+    }
+
+    private static void startRecording(TestRecording rec) {
+        System.out.println("starting recording " + rec.id);
+        JmxHelper.getFlighteRecorderMXBean().startRecording(rec.id);
+    }
+
+    private static void stopRecording(TestRecording rec) {
+        System.out.println("stopping recording " + rec.id);
+        JmxHelper.getFlighteRecorderMXBean().stopRecording(rec.id);
+    }
+
+    private static void closeRecording(TestRecording rec) throws Exception {
+        System.out.println("closing recording " + rec.id);
+        JmxHelper.getFlighteRecorderMXBean().closeRecording(rec.id);
+        rec.isClosed = true;
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/TestMultipleRecordings.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx;
+
+import java.util.List;
+
+import jdk.jfr.RecordingState;
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.management.jfr.RecordingInfo;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.TestMultipleRecordings
+ */
+public class TestMultipleRecordings {
+    public static void main(String[] args) throws Throwable {
+        FlightRecorderMXBean bean = JmxHelper.getFlighteRecorderMXBean();
+        System.out.println("bean.class=" + bean.getClass().getName());
+
+        // Start recA
+        long recIdA = createRecording(bean);
+        startRecording(recIdA, bean);
+
+        // Start recB
+        long recIdB = createRecording(bean);
+        startRecording(recIdB, bean);
+
+        // Stop and destroy recA
+        stopRecording(recIdA, bean);
+        destroyRecording(recIdA, bean);
+
+        // Start, stop and destroy recC
+        long recIdC = createRecording(bean);
+        startRecording(recIdC, bean);
+        stopRecording(recIdC, bean);
+        destroyRecording(recIdC, bean);
+
+        // Stop and destroy recB
+        stopRecording(recIdB, bean);
+        destroyRecording(recIdB, bean);
+    }
+
+    private static long createRecording(FlightRecorderMXBean bean) throws Exception {
+        List<RecordingInfo> preCreateRecordings = bean.getRecordings();
+        long recId = bean.newRecording();
+        JmxHelper.verifyNotExists(recId, preCreateRecordings);
+        JmxHelper.verifyState(recId, RecordingState.NEW, bean);
+        return recId;
+    }
+
+    private static void startRecording(long recId, FlightRecorderMXBean bean) throws Exception {
+        JmxHelper.verifyState(recId, RecordingState.NEW, bean);
+        bean.startRecording(recId);
+        JmxHelper.verifyState(recId, RecordingState.RUNNING, bean);
+    }
+
+    private static void stopRecording(long recId, FlightRecorderMXBean bean) throws Exception {
+        JmxHelper.verifyState(recId, RecordingState.RUNNING, bean);
+        bean.stopRecording(recId);
+        JmxHelper.verifyState(recId, RecordingState.STOPPED, bean);
+    }
+
+    private static void destroyRecording(long recId, FlightRecorderMXBean bean) throws Exception {
+        JmxHelper.verifyState(recId, RecordingState.STOPPED, bean);
+        bean.closeRecording(recId);
+        JmxHelper.verifyNotExists(recId, bean.getRecordings());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/TestNotificationListener.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.jmx;
+
+import java.lang.management.ManagementFactory;
+import java.util.concurrent.CountDownLatch;
+
+import javax.management.Notification;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+
+import jdk.management.jfr.FlightRecorderMXBean;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.TestNotificationListener
+ */
+public class TestNotificationListener {
+
+    private final static CountDownLatch latch = new CountDownLatch(1);
+
+    private final static NotificationListener listener = new NotificationListener() {
+        public void handleNotification(Notification notification, Object handback) {
+            System.out.println("Got notification: " + notification);
+            latch.countDown();
+        }
+    };
+
+    public static void main(String[] args) throws Throwable {
+        ObjectName objectName = new ObjectName(FlightRecorderMXBean.MXBEAN_NAME);
+        ManagementFactory.getPlatformMBeanServer().addNotificationListener(objectName, listener, null, null);
+        FlightRecorderMXBean bean = ManagementFactory.getPlatformMXBean(FlightRecorderMXBean.class);
+
+        long recId = bean.newRecording();
+        bean.startRecording(recId);
+
+        latch.await();
+        System.out.println("Completed successfully");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/TestPredefinedConfiguration.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Configuration;
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.management.jfr.RecordingInfo;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.TestPredefinedConfiguration
+ */
+public class TestPredefinedConfiguration {
+    public static void main(String[] args) throws Exception {
+        FlightRecorderMXBean bean = JmxHelper.getFlighteRecorderMXBean();
+
+        long recId = bean.newRecording();
+        List<String> configNames = new ArrayList<>();
+        for (Configuration config : Configuration.getConfigurations()) {
+            System.out.println("name=" + config.getName());
+            configNames.add(config.getName());
+            bean.setPredefinedConfiguration(recId, config.getName());
+
+            RecordingInfo jmxRecording = JmxHelper.getJmxRecording(recId);
+            JmxHelper.verifyMapEquals(jmxRecording.getSettings(), config.getSettings());
+            JmxHelper.verifyMapEquals(bean.getRecordingSettings(recId), config.getSettings());
+        }
+        Asserts.assertTrue(configNames.contains("default"), "Missing config 'default'");
+        Asserts.assertTrue(configNames.contains("profile"), "Missing config 'profile'");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/TestPredefinedConfigurationInvalid.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx;
+
+import jdk.jfr.Configuration;
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.CommonHelper;
+import jdk.test.lib.jfr.VoidFunction;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.TestPredefinedConfigurationInvalid
+ */
+public class TestPredefinedConfigurationInvalid {
+    public static void main(String[] args) throws Throwable {
+        FlightRecorderMXBean bean = JmxHelper.getFlighteRecorderMXBean();
+
+        long recId = bean.newRecording();
+
+        // Test invalid named configs.
+        verifyNullPointer(()->{ bean.setPredefinedConfiguration(recId, null); }, "setNamedConfig(null)");
+        setInvalidConfigName(recId, "");
+        setInvalidConfigName(recId, "invalidname");
+
+        // Verify we can set named config after failed attempts.
+        Configuration config = Configuration.getConfigurations().get(0);
+        bean.setPredefinedConfiguration(recId, config.getName());
+        JmxHelper.verifyMapEquals(bean.getRecordingSettings(recId), config.getSettings());
+    }
+
+    private static void setInvalidConfigName(long recId, String name) {
+        try {
+            JmxHelper.getFlighteRecorderMXBean().setPredefinedConfiguration(recId, name);
+            Asserts.fail("Missing Exception when setNamedConfig('" + name + "')");
+        } catch (IllegalArgumentException e) {
+            // Expected exception.
+            String msg = e.getMessage().toLowerCase();
+            System.out.println("Got expected exception: " + msg);
+            String expectMsg = "not find configuration";
+            Asserts.assertTrue(msg.contains(expectMsg), String.format("No '%s' in '%s'", expectMsg, msg));
+        }
+    }
+
+    private static void verifyNullPointer(VoidFunction f, String msg) throws Throwable {
+        CommonHelper.verifyException(f, msg, NullPointerException.class);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/TestRecordingOptions.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx;
+
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.TestRecordingOptions
+ */
+public class TestRecordingOptions {
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    public static void main(String[] args) throws Exception {
+        Map<String, String> options = new HashMap<>();
+        options.put("name", "myName");
+        options.put("maxAge", "2 h");
+        options.put("maxSize", "1234567890");
+        options.put("dumpOnExit", "false");
+        options.put("disk", "false");
+        options.put("duration", "1 h"); // don't want recording to stop
+
+        FlightRecorderMXBean bean = JmxHelper.getFlighteRecorderMXBean();
+        long recId = bean.newRecording();
+        Map<String, String> defaults = bean.getRecordingOptions(recId);
+        bean.setRecordingOptions(recId, options);
+
+        // Verify that all options have been set. We only check the option we
+        // have set. Unknown options are ignored.
+        Map<String, String> outOptions = bean.getRecordingOptions(recId);
+        logMap("set options", options);
+        logMap("get options", outOptions);
+        for (String key : options.keySet()) {
+            Asserts.assertTrue(outOptions.containsKey(key), "Missing key " + key);
+            Asserts.assertEquals(options.get(key), outOptions.get(key), "Wrong value for key " + key);
+        }
+
+        // Verify options in RecordingInfo
+        Asserts.assertEquals(outOptions.get("name"), "myName", "Wrong name");
+        Asserts.assertEquals(outOptions.get("maxAge"), "2 h", "Wrong maxAge");
+        Asserts.assertEquals(outOptions.get("maxSize"), "1234567890", "Wrong maxSize");
+        Asserts.assertEquals(outOptions.get("dumpOnExit"), "false", "Wrong dumpOnExit");
+        Asserts.assertEquals(outOptions.get("disk"), "false", "Wrong disk");
+        Asserts.assertEquals(outOptions.get("duration"), "1 h", "Wrong duration");
+
+        // try empty map
+        bean.setRecordingOptions(recId, new HashMap<>());
+
+        // try map that does not have string keys
+        Map<Integer, String> invalidKeys = new HashMap<>();
+        invalidKeys.put(4711, "value");
+        try {
+            bean.setRecordingOptions(recId, (Map) invalidKeys);
+            throw new Error("Expected IllagalStateException for non String key");
+        } catch (IllegalArgumentException iae) {
+            // OK, as expected
+        }
+        // try map that does not have string values
+        Map<String, Integer> invalidValues = new HashMap<>();
+        invalidValues.put("duration", 4711);
+        try {
+            bean.setRecordingOptions(recId, (Map) invalidKeys);
+            throw new Error("Expected IllagalStateException for non String value");
+        } catch (IllegalArgumentException iae) {
+            // OK, as expected
+        }
+
+        // Try one incorrect value, and make sure non
+        // of the other values are set.
+        Map<String, String> lastIncorrect = new LinkedHashMap<>();
+        lastIncorrect.put("duration", "10 h");
+        lastIncorrect.put("whatever", "4711");
+        try {
+            bean.setRecordingOptions(recId, lastIncorrect);
+            throw new Error("Expected IllagalStateException for incorrect key");
+        } catch (IllegalArgumentException iae) {
+            // ok
+            Asserts.assertEquals("1 h", bean.getRecordingOptions(recId).get("duration"));
+        }
+
+        // verify that defaults are set back, if we use null
+        Map<String, String> nullMap = new HashMap<>();
+        nullMap.put("name", null);
+        nullMap.put("maxAge", null);
+        nullMap.put("maxSize", null);
+        nullMap.put("dumpOnExit", null);
+        nullMap.put("disk", null);
+        nullMap.put("duration", null);
+        bean.setRecordingOptions(recId, nullMap);
+        Asserts.assertEquals(bean.getRecordingOptions(recId), defaults);
+
+        bean.closeRecording(recId);
+    }
+
+    private static void logMap(String name, Map<String, String> map) {
+        for (String key : map.keySet()) {
+            System.out.printf("%s: %s=%s%n", name, key, map.get(key));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/TestRecordingSettings.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Recording;
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.TestRecordingSettings
+ */
+public class TestRecordingSettings {
+    public static void main(String[] args) throws Exception {
+        Map<String, String> settings = new HashMap<>();
+        settings.put("java.exception_throw#enabled", "false");
+        settings.put("java.exception_throw#threshold", "2 s");
+        settings.put("java.exception_throw#thread", "true");
+        settings.put("java.exception_throw#stackTrace", "false");
+        settings.put("os.information#enabled", "true");
+        settings.put("os.information#period", "400 ms");
+
+        FlightRecorderMXBean bean = JmxHelper.getFlighteRecorderMXBean();
+        long recId = bean.newRecording();
+        bean.setRecordingSettings(recId, settings);
+
+        // Verify that JMX input and output settings are equal.
+        JmxHelper.verifyMapEquals(settings, JmxHelper.getFlighteRecorderMXBean().getRecordingSettings(recId));
+
+        // Verify that settings from Java API is correct.
+        Recording recording = null;
+        for (Recording r :  FlightRecorder.getFlightRecorder().getRecordings()) {
+            if (r.getId() == recId) {
+                recording = r;
+                break;
+            }
+        }
+        Asserts.assertNotNull(recording, "No Recording with id " + recId);
+        JmxHelper.verifyMapEquals(settings, recording.getSettings());
+
+        bean.startRecording(recId);
+        bean.stopRecording(recId);
+        bean.closeRecording(recId);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/TestRecordingSettingsInvalid.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @key jfr
+ * @summary Verify exception when setting invalid settings.
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.TestRecordingSettingsInvalid
+ */
+public class TestRecordingSettingsInvalid {
+    public static void main(String[] args) throws Exception {
+        Map<String, String> settings = new HashMap<>();
+        settings.put(null, "true");
+        settings.put("java.exception_throw#stackTrace", null);
+        settings.put("java.exception_throw#threshold", "not-a-number");
+        settings.put("os.information#period", "4 x");
+
+        // TODO: No exception for these settings. Not sure how much validation can be done on settings.
+        //settings.put("java.exception_throw#enabled", "maybe");
+        //settings.put("os.information#period", "-4 s");
+        //settings.put("java.exception_throw#thread", "");
+        //settings.put("", "true");
+        //settings.put("os.information#what", "4 ms");
+        //settings.put("#", "4 what");
+        //settings.put("java.exception_throw#", "true");
+        //settings.put("java.exception_throwenabled", "false");
+
+        FlightRecorderMXBean bean = JmxHelper.getFlighteRecorderMXBean();
+
+        for (String key : settings.keySet()) {
+            System.out.printf("settings: %s=%s%n", key, settings.get(key));
+            Map<String, String> temp = new HashMap<String, String>();
+            temp.put(key, settings.get(key));
+            long recId = -1;
+            try {
+                recId = bean.newRecording();
+                bean.setRecordingSettings(recId, temp);
+                bean.startRecording(recId);
+                bean.stopRecording(recId);
+                Asserts.fail("Missing exception");
+            } catch (Exception e) {
+                System.out.println("Got expected exception: " + e.getMessage());
+            } finally {
+                bean.closeRecording(recId);
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/TestRecordingSettingsMultiple.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import jdk.management.jfr.FlightRecorderMXBean;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.TestRecordingSettingsMultiple
+ */
+public class TestRecordingSettingsMultiple {
+    public static void main(String[] args) throws Exception {
+        Map<String, String> settingsA = new HashMap<>();
+        settingsA.put("java.exception_throw#enabled", "false");
+        settingsA.put("java.exception_throw#threshold", "2 s");
+        settingsA.put("java.exception_throw#thread", "true");
+        settingsA.put("java.exception_throw#stackTrace", "false");
+        settingsA.put("os.information#enabled", "true");
+        settingsA.put("os.information#period", "400 ms");
+
+        Map<String, String> settingsB = new HashMap<>();
+        settingsB.put("vm/code_sweeper/config#enabled", "true");
+        settingsB.put("vm/code_sweeper/config#period", "everyChunk");
+        settingsA.put("java.exception_throw#enabled", "true");
+        settingsA.put("java.exception_throw#threshold", "6 m");
+        settingsB.put("os.information#enabled", "true");
+        settingsB.put("os.information#period", "0 ms");
+
+        FlightRecorderMXBean bean = JmxHelper.getFlighteRecorderMXBean();
+        long recIdA = bean.newRecording();
+        long recIdB = bean.newRecording();
+        bean.setRecordingSettings(recIdA, settingsA);
+        bean.setRecordingSettings(recIdB, settingsB);
+
+        JmxHelper.verifyMapEquals(settingsA, bean.getRecordingSettings(recIdA));
+        JmxHelper.verifyMapEquals(settingsB, bean.getRecordingSettings(recIdB));
+        JmxHelper.verifyMapEquals(settingsA, JmxHelper.getJavaRecording(recIdA).getSettings());
+        JmxHelper.verifyMapEquals(settingsB, JmxHelper.getJavaRecording(recIdB).getSettings());
+
+        bean.startRecording(recIdA);
+        bean.startRecording(recIdB);
+        JmxHelper.verifyMapEquals(settingsA, bean.getRecordingSettings(recIdA));
+        JmxHelper.verifyMapEquals(settingsB, bean.getRecordingSettings(recIdB));
+        JmxHelper.verifyMapEquals(settingsA, JmxHelper.getJavaRecording(recIdA).getSettings());
+        JmxHelper.verifyMapEquals(settingsB, JmxHelper.getJavaRecording(recIdB).getSettings());
+
+        bean.stopRecording(recIdA);
+        bean.stopRecording(recIdB);
+        JmxHelper.verifyMapEquals(settingsA, bean.getRecordingSettings(recIdA));
+        JmxHelper.verifyMapEquals(settingsB, bean.getRecordingSettings(recIdB));
+        JmxHelper.verifyMapEquals(settingsA, JmxHelper.getJavaRecording(recIdA).getSettings());
+        JmxHelper.verifyMapEquals(settingsB, JmxHelper.getJavaRecording(recIdB).getSettings());
+
+        bean.closeRecording(recIdA);
+        bean.closeRecording(recIdB);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/TestRecordingState.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx;
+
+import java.util.List;
+
+import jdk.jfr.RecordingState;
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.management.jfr.RecordingInfo;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.TestRecordingState
+ */
+public class TestRecordingState {
+    public static void main(String[] args) throws Throwable {
+        FlightRecorderMXBean bean = JmxHelper.getFlighteRecorderMXBean();
+
+        List<RecordingInfo> preCreateRecordings = bean.getRecordings();
+        long recId = bean.newRecording();
+        JmxHelper.verifyNotExists(recId, preCreateRecordings);
+        JmxHelper.verifyState(recId, RecordingState.NEW, bean);
+
+        bean.startRecording(recId);
+        JmxHelper.verifyState(recId, RecordingState.RUNNING, bean);
+
+        bean.stopRecording(recId);
+        JmxHelper.verifyState(recId, RecordingState.STOPPED, bean);
+
+        bean.closeRecording(recId);
+        JmxHelper.verifyNotExists(recId, bean.getRecordings());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/TestRecordingStateInvalid.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx;
+
+import java.util.List;
+
+import jdk.jfr.RecordingState;
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.management.jfr.RecordingInfo;
+import jdk.test.lib.jfr.CommonHelper;
+import jdk.test.lib.jfr.VoidFunction;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.TestRecordingStateInvalid
+ */
+public class TestRecordingStateInvalid {
+    public static void main(String[] args) throws Throwable {
+        FlightRecorderMXBean bean = JmxHelper.getFlighteRecorderMXBean();
+
+        long recId = createRecording(bean);
+        verifyIllegalState(()->{ bean.stopRecording(recId); }, "Stop not started");
+
+        startRecording(recId, bean);
+        verifyIllegalState(()->{ bean.startRecording(recId); }, "Start already started");
+
+        stopRecording(recId, bean);
+        verifyIllegalState(()->{ bean.startRecording(recId); }, "Start already stopped");
+        verifyIllegalState(()->{ bean.stopRecording(recId); }, "Stop already stopped");
+
+        destroyRecording(recId, bean);
+        verifyIllegalArg(()->{ bean.startRecording(recId); }, "Start already destroyed");
+        verifyIllegalArg(()->{ bean.stopRecording(recId); }, "Stop already destroyed");
+
+    }
+
+    private static long createRecording(FlightRecorderMXBean bean) throws Exception {
+        List<RecordingInfo> preCreateRecordings = bean.getRecordings();
+        long recId = bean.newRecording();
+        JmxHelper.verifyNotExists(recId, preCreateRecordings);
+        JmxHelper.verifyState(recId, RecordingState.NEW, bean);
+        return recId;
+    }
+
+    private static void startRecording(long recId, FlightRecorderMXBean bean) throws Exception {
+        JmxHelper.verifyState(recId, RecordingState.NEW, bean);
+        bean.startRecording(recId);
+        JmxHelper.verifyState(recId, RecordingState.RUNNING, bean);
+    }
+
+    private static void stopRecording(long recId, FlightRecorderMXBean bean) throws Exception {
+        JmxHelper.verifyState(recId, RecordingState.RUNNING, bean);
+        bean.stopRecording(recId);
+        JmxHelper.verifyState(recId, RecordingState.STOPPED, bean);
+    }
+
+    private static void destroyRecording(long recId, FlightRecorderMXBean bean) throws Exception {
+        JmxHelper.verifyState(recId, RecordingState.STOPPED, bean);
+        bean.closeRecording(recId);
+        JmxHelper.verifyNotExists(recId, bean.getRecordings());
+    }
+
+    private static void verifyIllegalState(VoidFunction f, String msg) throws Throwable {
+        CommonHelper.verifyException(f, msg, IllegalStateException.class);
+    }
+
+    private static void verifyIllegalArg(VoidFunction f, String msg) throws Throwable {
+        CommonHelper.verifyException(f, msg, IllegalArgumentException.class);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/TestSetConfiguration.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import jdk.jfr.Recording;
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.management.jfr.RecordingInfo;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.TestSetConfiguration
+ */
+public class TestSetConfiguration {
+    public static void main(String[] args) throws Exception {
+        FlightRecorderMXBean bean = JmxHelper.getFlighteRecorderMXBean();
+        long recId = bean.newRecording();
+
+        final String configContents =
+        "<?xml version=\"1.0\" encoding=\"UTF-8\"?> \n" +
+        "<configuration version=\"2.0\" label=\"TestName\" description='TestDesc' provider='TestProvider'>\n" +
+        "  <event name=\"" + EventNames.ClassLoad +"\">\r" +
+        " \t <setting name=\"enabled\" control='class-loading-enabled'>false</setting>\r\n" +
+        "    <setting name=\"stackTrace\">true</setting>\t\r\n" +
+        "    <setting name=\"threshold\">5 ms</setting> \n" +
+        "  </event>  " +
+        "  <control>  " +
+        "    <flag name=\"class-loading-enabled\" label=\"Class Loading\">false</flag>\n" +
+        "  </control>" +
+        "</configuration>";
+
+        Map<String, String> expectedSetting = new HashMap<>();
+        expectedSetting.put(EventNames.ClassLoad + "#enabled", "false");
+        expectedSetting.put(EventNames.ClassLoad + "#stackTrace", "true");
+        expectedSetting.put(EventNames.ClassLoad + "#threshold", "5 ms");
+
+        bean.setConfiguration(recId, configContents);
+        RecordingInfo jmxRecording = JmxHelper.getJmxRecording(recId);
+        Recording javaRecording = JmxHelper.getJavaRecording(recId);
+        JmxHelper.verifyEquals(jmxRecording, javaRecording);
+
+        Map<String, String> settings = jmxRecording.getSettings();
+        for (String name : expectedSetting.keySet()) {
+            String value = settings.remove(name);
+            Asserts.assertNotNull(value, "No setting with name " + name);
+            Asserts.assertEquals(value, expectedSetting.get(name), "Wrong setting value");
+        }
+        Asserts.assertTrue(settings.isEmpty(), "Extra settings found " + settings.keySet());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/TestSetConfigurationInvalid.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import jdk.jfr.Recording;
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.management.jfr.RecordingInfo;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+
+/*
+ * @test
+ * @key jfr
+ * @summary Verify Exception when setting invalid config.
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.TestSetConfigurationInvalid
+ */
+public class TestSetConfigurationInvalid {
+    public static void main(String[] args) throws Exception {
+        FlightRecorderMXBean bean = JmxHelper.getFlighteRecorderMXBean();
+        long recId = bean.newRecording();
+
+        final String correctConfig =
+        "<?xml version=\"1.0\" encoding=\"UTF-8\"?> \n" +
+        "<configuration version=\"2.0\" label=\"TestName\" description='TestDesc' provider='TestProvider'>\n" +
+        "  <event name=\"" + EventNames.ClassLoad + "\">\r" +
+        " \t <setting name=\"enabled\" control='class-loading-enabled'>false</setting>\r\n" +
+        "    <setting name=\"stackTrace\">true</setting>\t\r\n" +
+        "    <setting name=\"threshold\">5 ms</setting> \n" +
+        "  </event>  " +
+        "  <control>  " +
+        "    <flag name=\"class-loading-enabled\" label=\"Class Loading\">false</flag>\n" +
+        "  </control>" +
+        "</configuration>";
+
+        Map<String, String> expectedSetting = new HashMap<>();
+        expectedSetting.put(EventNames.ClassLoad + "#enabled", "false");
+        expectedSetting.put(EventNames.ClassLoad + "#stackTrace", "true");
+        expectedSetting.put(EventNames.ClassLoad + "#threshold", "5 ms");
+
+        // First set a few invalid configs. Should get Exceptions.
+        try {
+            bean.setConfiguration(recId, null);
+            Asserts.fail("Expected NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected exception
+        }
+
+        setInvalidConfig(recId, "Dummy text");
+        setInvalidConfig(recId, correctConfig.replace("/event", "event"));
+        setInvalidConfig(recId, correctConfig.replace("<control>", ""));
+
+        // Verify that we can set a correct setting after the failed attempts.
+        bean.setConfiguration(recId, correctConfig);
+        RecordingInfo jmxRecording = JmxHelper.getJmxRecording(recId);
+        Recording javaRecording = JmxHelper.getJavaRecording(recId);
+        JmxHelper.verifyEquals(jmxRecording, javaRecording);
+
+        Map<String, String> settings = jmxRecording.getSettings();
+        for (String name : expectedSetting.keySet()) {
+            String value = settings.remove(name);
+            Asserts.assertNotNull(value, "No setting with name " + name);
+            Asserts.assertEquals(value, expectedSetting.get(name), "Wrong setting value");
+        }
+        Asserts.assertTrue(settings.isEmpty(), "Extra settings found " + settings.keySet());
+    }
+
+    private static void setInvalidConfig(long recId, String config) {
+        try {
+            JmxHelper.getFlighteRecorderMXBean().setConfiguration(recId, config);
+            System.out.printf("Invalid config:%n%s", config);
+            Asserts.fail("No exception when setting invalid configuration");
+        } catch (IllegalArgumentException e) {
+            // Expected exception
+            // Simple check if error message is about parse error.
+            String msg = e.getMessage().toLowerCase();
+            Asserts.assertTrue(msg.contains("parse"), String.format("Missing 'parse' in msg '%s'", msg));
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/TestSnapshot.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx;
+
+import java.io.IOException;
+import java.util.List;
+
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Recording;
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.management.jfr.RecordingInfo;
+import jdk.test.lib.jfr.SimpleEvent;
+
+/* @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.TestSnapshot
+ */
+public class TestSnapshot {
+
+    public static void main(String[] args) throws Exception {
+        testEmpty();
+        testStopped();
+    }
+
+    private static void testStopped() throws IOException {
+        try (Recording r = new Recording()) {
+            r.enable(SimpleEvent.class);
+            r.start();
+            SimpleEvent se = new SimpleEvent();
+            se.commit();
+            r.stop();
+
+            try (Recording snapshot = FlightRecorder.getFlightRecorder().takeSnapshot()) {
+                r.close();
+                FlightRecorderMXBean mxBean = JmxHelper.getFlighteRecorderMXBean();
+                List<RecordingInfo> recs = mxBean.getRecordings();
+                JmxHelper.verifyEquals(recs.get(0), snapshot);
+            }
+        }
+    }
+
+    private static void testEmpty() throws IOException {
+        try (Recording snapshot = FlightRecorder.getFlightRecorder().takeSnapshot()) {
+            FlightRecorderMXBean mxBean = JmxHelper.getFlighteRecorderMXBean();
+            List<RecordingInfo> recs = mxBean.getRecordings();
+            JmxHelper.verifyEquals(recs.get(0), snapshot);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/TestStartRecording.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx;
+
+import java.util.List;
+import java.util.Map;
+
+import jdk.management.jfr.ConfigurationInfo;
+import jdk.management.jfr.EventTypeInfo;
+import jdk.management.jfr.FlightRecorderMXBean;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.TestStartRecording
+ */
+public class TestStartRecording {
+    public static void main(String[] args) throws Throwable {
+        FlightRecorderMXBean bean = JmxHelper.getFlighteRecorderMXBean();
+        long recId = bean.newRecording();
+        bean.startRecording(recId);
+
+        // TODO: Remove debug logs
+        List<ConfigurationInfo> configs = bean.getConfigurations();
+        for (ConfigurationInfo config : configs) {
+            System.out.println("config=" + config.toString());
+        }
+        Map<String, String> settings = bean.getRecordingSettings(recId);
+        for (String key : settings.keySet()) {
+            System.out.println("setting: " + key + "=" + settings.get(key));
+        }
+        List<EventTypeInfo> types = bean.getEventTypes();
+        for (EventTypeInfo type : types) {
+            System.out.println("type=" + type.getName());
+        }
+        //////////////////////
+
+        bean.stopRecording(recId);
+        bean.closeRecording(recId);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/TestStream.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx;
+
+import java.io.IOException;
+import java.time.Instant;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.test.lib.jfr.SimpleEventHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.TestStream
+ */
+public class TestStream {
+    public static void main(String[] args) throws Exception {
+        FlightRecorderMXBean bean = JmxHelper.getFlighteRecorderMXBean();
+
+        Instant startTime = Instant.now();
+        SimpleEventHelper.createEvent(0);
+
+        long recId = bean.newRecording();
+        bean.startRecording(recId);
+        SimpleEventHelper.createEvent(1);
+
+        bean.stopRecording(recId);
+        SimpleEventHelper.createEvent(2);
+
+        Instant endTime = Instant.now();
+        // Test with ISO-8601
+        Map<String, String> options = new HashMap<>();
+        options.put("startTime", startTime.toString());
+        options.put("endTime", endTime.toString());
+        options.put("blockSize", String.valueOf(50_000));
+        verifyStream(bean, recId, options);
+        // Test with milliseconds since epoch
+        options.put("startTime", Long.toString(startTime.toEpochMilli()));
+        options.put("endTime", Long.toString(endTime.toEpochMilli()));
+        options.put("blockSize", String.valueOf(150_000));
+        verifyStream(bean, recId, options);
+
+        bean.closeRecording(recId);
+    }
+
+    private static void verifyStream(FlightRecorderMXBean bean, long recId, Map<String, String> options) throws IOException, Exception {
+        long streamId = bean.openStream(recId, options);
+
+        List<RecordedEvent> events = JmxHelper.parseStream(streamId, bean);
+        SimpleEventHelper.verifyContains(events, 1);
+        SimpleEventHelper.verifyNotContains(events, 0, 2);
+        bean.closeStream(streamId);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/TestStreamClosed.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx;
+
+import java.io.IOException;
+
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.SimpleEventHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @summary Call readStream() after closeStream()
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.TestStreamClosed
+ */
+public class TestStreamClosed {
+    public static void main(String[] args) throws Exception {
+        FlightRecorderMXBean bean = JmxHelper.getFlighteRecorderMXBean();
+
+        long recId = bean.newRecording();
+        bean.startRecording(recId);
+        SimpleEventHelper.createEvent(1);
+        bean.stopRecording(recId);
+
+        long streamId = bean.openStream(recId, null);
+        bean.closeStream(streamId);
+        try {
+            bean.readStream(streamId);
+            Asserts.fail("No exception whean reading closed stream");
+        } catch (IOException e) {
+            // Expected exception.
+            String msg = e.getMessage().toLowerCase();
+            Asserts.assertTrue(msg.contains("stream") && msg.contains("closed"), "No 'stream closed' in " + msg);
+        }
+        bean.closeRecording(recId);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/TestStreamMultiple.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx;
+
+import java.util.List;
+
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.SimpleEventHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.TestStreamMultiple
+ */
+public class TestStreamMultiple {
+
+    public static void main(String[] args) throws Exception {
+        FlightRecorderMXBean bean = JmxHelper.getFlighteRecorderMXBean();
+
+        SimpleEventHelper.createEvent(0); // No recordings
+
+        long recIdA = bean.newRecording();
+
+        bean.startRecording(recIdA);
+        SimpleEventHelper.createEvent(1); // recA
+
+        long recIdB = bean.newRecording();
+        Asserts.assertNotEquals(recIdA, recIdB, "Recording Ids should be unique");
+        bean.startRecording(recIdB);
+        SimpleEventHelper.createEvent(2); // recA and recB
+
+        bean.stopRecording(recIdA);
+        SimpleEventHelper.createEvent(3); // recB
+
+        bean.stopRecording(recIdB);
+        SimpleEventHelper.createEvent(4); // No recordings
+
+        // Check recA
+        long streamIdA = bean.openStream(recIdA, null);
+        List<RecordedEvent> events = JmxHelper.parseStream(streamIdA, bean);
+        SimpleEventHelper.verifyContains(events, 1, 2);
+        SimpleEventHelper.verifyNotContains(events, 0, 3, 4);
+        bean.closeStream(streamIdA);
+        // check recB
+        long streamIdB = bean.openStream(recIdB, null);
+        events = JmxHelper.parseStream(streamIdB, bean);
+        SimpleEventHelper.verifyContains(events, 2, 3);
+        SimpleEventHelper.verifyNotContains(events, 0, 1, 4);
+        bean.closeStream(streamIdB);
+
+        bean.closeRecording(recIdA);
+        bean.closeRecording(recIdB);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/TestWrongId.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx;
+
+import java.util.HashMap;
+
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.test.lib.jfr.CommonHelper;
+import jdk.test.lib.jfr.VoidFunction;
+
+
+/*
+ * @test
+ * @key jfr
+ * @summary Call functions with invalid argument id. Verify Exception.
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.TestWrongId
+ */
+public class TestWrongId {
+    public static void main(String[] args) throws Throwable {
+        FlightRecorderMXBean bean = JmxHelper.getFlighteRecorderMXBean();
+        final int id = 123456;
+        verifyIllegalArg(() ->  bean.startRecording(id), "startRecording(invalidId)");
+        verifyIllegalArg(() ->  bean.stopRecording(id), "stopRecording(invalidId)");
+        verifyIllegalArg(() ->  bean.closeRecording(id), "destroyRecording(invalidId)");
+        verifyIllegalArg(() ->  bean.openStream(id, null), "openStream(invalidId)");
+        verifyIllegalArg(() ->  bean.closeStream(id), "closeStream(invalidId)");
+        verifyIllegalArg(() ->  bean.readStream(id), "readStream(invalidId)");
+        verifyIllegalArg(() ->  bean.getRecordingSettings(id), "getRecordingSettings(invalidId)");
+        verifyIllegalArg(() ->  bean.setConfiguration(id, "dummy"), "setConfiguration(invalidId)");
+        verifyIllegalArg(() ->  bean.setPredefinedConfiguration(id, "dummy"), "setNamedConfiguration(invalidId)");
+        verifyIllegalArg(() ->  bean.setRecordingSettings(id, new HashMap<String, String>()), "setRecordingSettings(invalidId)");
+        verifyIllegalArg(() ->  bean.copyTo(id, "./dummy.jfr"), "dumpRecording(invalidId)");
+    }
+
+    private static void verifyIllegalArg(VoidFunction f, String msg) throws Throwable {
+        CommonHelper.verifyException(f, msg, IllegalArgumentException.class);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/info/TestConfigurationInfo.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx.info;
+
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jdk.jfr.jmx.JmxHelper;
+
+import jdk.jfr.Configuration;
+import jdk.management.jfr.ConfigurationInfo;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @key jfr
+ * @summary Test for ConfigurationInfo. Compare infos from java API and jmx API.
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.info.TestConfigurationInfo
+ */
+public class TestConfigurationInfo {
+    public static void main(String[] args) throws Throwable {
+        List<ConfigurationInfo> configInfos = JmxHelper.getFlighteRecorderMXBean().getConfigurations();
+        Asserts.assertFalse(configInfos.isEmpty(), "No ConfigurationInfos found");
+
+        Map<String, Configuration> configs = new HashMap<>();
+        for (Configuration config : Configuration.getConfigurations()) {
+            configs.put(config.getName(), config);
+        }
+        Asserts.assertFalse(configs.isEmpty(), "No Configurations found");
+
+        for (ConfigurationInfo configInfo : configInfos) {
+            final String key = configInfo.getName();
+            Configuration config = configs.remove(key);
+            Asserts.assertNotNull(config, "No Configuration for name " + key);
+
+            System.out.println("getDescription:" + configInfo.getDescription());
+            System.out.println("getLabel:" + configInfo.getLabel());
+            System.out.println("getName:" + configInfo.getName());
+            System.out.println("getProvider:" + configInfo.getProvider());
+
+            Asserts.assertEquals(configInfo.getContents(), config.getContents(), "Wrong contents");
+            Asserts.assertEquals(configInfo.getDescription(), config.getDescription(), "Wrong description");
+            Asserts.assertEquals(configInfo.getLabel(), config.getLabel(), "Wrong label");
+            Asserts.assertEquals(configInfo.getName(), config.getName(), "Wrong name");
+            Asserts.assertEquals(configInfo.getProvider(), config.getProvider(), "Wrong provider");
+
+            verifySettingsEqual(config, configInfo);
+        }
+
+        // Verify that all EventTypes have been matched.
+        if (!configs.isEmpty()) {
+            for (String name : configs.keySet()) {
+                System.out.println("Found extra Configuration with name " + name);
+            }
+            Asserts.fail("Found extra Configuration");
+        }
+    }
+
+    private static void verifySettingsEqual(Configuration config, ConfigurationInfo configInfo) {
+        Map<String, String> javaSettings = config.getSettings();
+        Map<String, String> jmxSettings = configInfo.getSettings();
+
+        Asserts.assertFalse(javaSettings.isEmpty(), "No Settings found in java apa");
+        Asserts.assertFalse(jmxSettings.isEmpty(), "No Settings found in jmx api");
+
+        for (String name : jmxSettings.keySet().toArray(new String[0])) {
+            System.out.printf("%s: jmx=%s, java=%s%n", name, jmxSettings.get(name), javaSettings.get(name));
+            Asserts.assertNotNull(javaSettings.get(name), "No java setting for " + name);
+            Asserts.assertEquals(jmxSettings.get(name), javaSettings.get(name), "Wrong value for setting");
+            javaSettings.remove(name);
+        }
+
+        // Verify that all Settings have been matched.
+        if (!javaSettings.isEmpty()) {
+            for (String name : javaSettings.keySet()) {
+                System.out.println("Found extra Settings name " + name);
+            }
+            Asserts.fail("Found extra Setting in java api");
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/info/TestEventTypeInfo.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx.info;
+
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jdk.jfr.jmx.JmxHelper;
+
+import jdk.jfr.EventType;
+import jdk.jfr.FlightRecorder;
+import jdk.management.jfr.EventTypeInfo;
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @key jfr
+ * @summary Test for EventTypeInfo
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.info.TestEventTypeInfo
+ */
+public class TestEventTypeInfo {
+    public static void main(String[] args) throws Throwable {
+        FlightRecorder jfr = FlightRecorder.getFlightRecorder();
+
+        FlightRecorderMXBean bean = JmxHelper.getFlighteRecorderMXBean();
+        List<EventTypeInfo> typeInfos = bean.getEventTypes();
+
+        Map<String, EventType> types = new HashMap<>();
+        for (EventType type : jfr.getEventTypes()) {
+            types.put(type.getName(), type);
+        }
+
+        Asserts.assertFalse(typeInfos.isEmpty(), "No EventTypeInfos found");
+        Asserts.assertFalse(types.isEmpty(), "No EventTypes found");
+
+        for (EventTypeInfo typeInfo : typeInfos) {
+            final String key = typeInfo.getName();
+            System.out.println("EventType name = " + key);
+            EventType type = types.get(key);
+            Asserts.assertNotNull(type, "No EventType for name " + key);
+            types.remove(key);
+
+            Asserts.assertEquals(typeInfo.getCategoryNames(), type.getCategoryNames(), "Wrong category");
+            Asserts.assertEquals(typeInfo.getDescription(), type.getDescription(), "Wrong description");
+            Asserts.assertEquals(typeInfo.getId(), type.getId(), "Wrong id");
+            Asserts.assertEquals(typeInfo.getLabel(), type.getLabel(), "Wrong label");
+            Asserts.assertEquals(typeInfo.getName(), type.getName(), "Wrong name");
+
+            JmxHelper.verifyEventSettingsEqual(type, typeInfo);
+        }
+
+        // Verify that all EventTypes have been matched.
+        if (!types.isEmpty()) {
+            for (String name : types.keySet()) {
+                System.out.println("Found extra EventType with name " + name);
+            }
+            Asserts.fail("Found extra EventTypes");
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/info/TestRecordingInfo.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx.info;
+
+
+import java.nio.file.Paths;
+import java.time.Duration;
+
+import jdk.jfr.jmx.JmxHelper;
+
+import jdk.jfr.Configuration;
+import jdk.jfr.Recording;
+import jdk.jfr.RecordingState;
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.management.jfr.RecordingInfo;
+import jdk.test.lib.jfr.CommonHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @summary Test for RecordingInfo
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.info.TestRecordingInfo
+ */
+public class TestRecordingInfo {
+    public static void main(String[] args) throws Throwable {
+        Recording recording = new Recording(Configuration.getConfiguration("profile"));
+        recording.setDestination(Paths.get(".", "my.jfr"));
+        recording.setDumpOnExit(true);
+        recording.setDuration(Duration.ofSeconds(60));
+        recording.setMaxAge(Duration.ofHours(1));
+        recording.setMaxSize(123456789);
+        recording.setName("myName");
+        recording.enable("java.exception_throw").with("threashold", "2 s");
+        recording.setToDisk(true);
+
+        recording.start();
+        CommonHelper.verifyRecordingState(recording, RecordingState.RUNNING); // Wait until running
+
+        FlightRecorderMXBean bean = JmxHelper.getFlighteRecorderMXBean();
+        RecordingInfo info = JmxHelper.verifyExists(recording.getId(), bean.getRecordings());
+
+        System.out.println(JmxHelper.asString(recording));
+        System.out.println(JmxHelper.asString(info));
+        JmxHelper.verifyEquals(info, recording);
+
+        recording.stop();
+        recording.close();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/info/TestSettingDescriptorInfo.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx.info;
+
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jdk.jfr.jmx.JmxHelper;
+
+import jdk.jfr.EventType;
+import jdk.jfr.FlightRecorder;
+import jdk.management.jfr.EventTypeInfo;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @key jfr
+ * @summary Test for SettingDescriptorInfo. Compare infos from java API and jmx API.
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jmx.info.TestSettingDescriptorInfo
+ */
+public class TestSettingDescriptorInfo {
+    public static void main(String[] args) throws Throwable {
+
+        Map<String, EventType> javaTypes = new HashMap<String, EventType>();
+        for (EventType t : FlightRecorder.getFlightRecorder().getEventTypes()) {
+            javaTypes.put(t.getName(), t);
+        }
+
+        List<EventTypeInfo> jmxTypes =JmxHelper.getFlighteRecorderMXBean().getEventTypes();
+        Asserts.assertFalse(jmxTypes.isEmpty(), "No EventTypes found in jmx api");
+
+        for (EventTypeInfo jmxType : jmxTypes) {
+            final String name = jmxType.getName();
+            EventType javaType = javaTypes.remove(name);
+            Asserts.assertNotNull(javaType, "No EventType for name " + name);
+            JmxHelper.verifyEventSettingsEqual(javaType, jmxType);
+        }
+
+        // Verify that all EventTypes have been matched.
+        if (!javaTypes.isEmpty()) {
+            for (String name : javaTypes.keySet()) {
+                System.out.println("Found extra EventType that is not available using JMX " + name);
+            }
+            Asserts.fail("Found extra EventType");
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/security/TestEnoughPermission.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx.security;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+
+import jdk.jfr.jmx.JmxHelper;
+
+import jdk.management.jfr.ConfigurationInfo;
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @key jfr
+ * @summary Test with minimal needed permissions. All functions should work.
+ * @library /test/lib /test/jdk
+ * @run main/othervm/secure=java.lang.SecurityManager/java.security.policy=enough.policy jdk.jfr.jmx.security.TestEnoughPermission
+ */
+public class TestEnoughPermission {
+
+    public static void main(String[] args) throws Throwable {
+        try {
+            FlightRecorderMXBean bean = JmxHelper.getFlighteRecorderMXBean();
+
+            System.out.println("AAAAAAAAAAAAAAAAAA");
+            Asserts.assertFalse(bean.getEventTypes().isEmpty(), "No EventTypes");
+            System.out.println("BBBBBBBBBBBBBBB");
+            List<ConfigurationInfo> configs = bean.getConfigurations();
+            System.out.println("CCCCCCCCCCCCCCCCC");
+            for (ConfigurationInfo config : configs) {
+                System.out.println("config.name=" + config.getName() + ": " + config.getContents());
+            }
+
+            long recId = testRecording(bean);
+            testStream(bean, recId);
+            bean.closeRecording(recId);
+
+            //*************** verifySecurityException(() -> bean.getRecordingOptions(dummyId), "getRecordingOptions()");
+            //*************** verifySecurityException(() -> bean.getRecordingSettings(dummyId), "getRecordingSettings()");
+            //*********** verifySecurityException(() -> bean.setConfiguration(dummyId, "<>"), "setConfiguration()");
+            //************* verifySecurityException(() -> bean.setRecordingSettings(dummyId, dummyMap), "setRecordingSettings()");
+            //************* verifySecurityException(() -> bean.setRecordingOptions(dummyId, dummyMap), "setRecordingOptions()");
+        } catch (Throwable t) {
+            t.printStackTrace();
+            throw t;
+        }
+    }
+
+    private static long testRecording(FlightRecorderMXBean bean) throws Exception {
+        System.out.println("A");
+        long recId = bean.newRecording();
+        System.out.println("B");
+        bean.setPredefinedConfiguration(recId, "profile");
+        System.out.println("C");
+        bean.startRecording(recId);
+        System.out.println("D");
+        Asserts.assertTrue(bean.getRecordings().stream().anyMatch(r -> { return r.getId() == recId; }), "recId not found");
+        System.out.println("E");
+        bean.stopRecording(recId);
+
+        final Path path = Paths.get(".", String.format("rec%d.jfr", recId));
+        bean.copyTo(recId, path.toString());
+        //EventSet events = EventSet.fromFile(path);
+        return recId;
+    }
+
+    private static void testStream(FlightRecorderMXBean bean, long recId) throws Exception {
+        long streamId = bean.openStream(recId, null);
+        byte[] buff = bean.readStream(streamId);
+        Asserts.assertNotNull(buff, "Stream data was empty");
+        while (buff != null) {
+            // TODO: write to file and parse.
+            System.out.println("buff.length=" + buff.length);
+            buff = bean.readStream(streamId);
+        }
+        bean.closeStream(streamId);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/security/TestNoControlPermission.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx.security;
+
+import jdk.jfr.jmx.JmxHelper;
+
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.test.lib.jfr.CommonHelper;
+import jdk.test.lib.jfr.VoidFunction;
+
+/*
+ * @test
+ * @key jfr
+ * @summary Verify we get SecurityExceptions when missing management permission "control".
+ * @library /test/lib /test/jdk
+ * @run main/othervm/secure=java.lang.SecurityManager/java.security.policy=nocontrol.policy jdk.jfr.jmx.security.TestNoControlPermission
+ */
+public class TestNoControlPermission {
+
+    public static void main(String[] args) throws Throwable {
+        try {
+            FlightRecorderMXBean bean = JmxHelper.getFlighteRecorderMXBean();
+
+            int dummyId = 1;
+            java.util.Map<String, String> dummyMap = new java.util.HashMap<>();
+
+            verifySecurityException(() -> bean.takeSnapshot(), "takeSnapshot()");
+            verifySecurityException(() -> bean.newRecording(), "newRecording()");
+            verifySecurityException(() -> bean.startRecording(dummyId), "startRecording()");
+            verifySecurityException(() -> bean.stopRecording(dummyId), "stopRecording()");
+            verifySecurityException(() -> bean.closeRecording(dummyId), "closeRecording()");
+            verifySecurityException(() -> bean.openStream(dummyId, null), "openStream()");
+            verifySecurityException(() -> bean.closeStream(dummyId), "closeStream()");
+            verifySecurityException(() -> bean.setConfiguration(dummyId, "dummy"), "setConfiguration()");
+            verifySecurityException(() -> bean.setPredefinedConfiguration(dummyId, "dummy"), "setPredefinedConfiguration()");
+            verifySecurityException(() -> bean.setRecordingSettings(dummyId, dummyMap), "setRecordingSettings()");
+            verifySecurityException(() -> bean.setRecordingOptions(dummyId, dummyMap), "setRecordingOptions()");
+            verifySecurityException(() -> bean.copyTo(dummyId, "."), "dumpRecording()");
+        } catch (Throwable t) {
+            t.printStackTrace();
+            throw t;
+        }
+    }
+
+
+    private static void verifySecurityException(VoidFunction f, String msg) throws Throwable {
+        CommonHelper.verifyException(f, msg, java.lang.SecurityException.class);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/security/TestNoMonitorPermission.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx.security;
+
+import jdk.jfr.jmx.JmxHelper;
+
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.test.lib.jfr.CommonHelper;
+import jdk.test.lib.jfr.VoidFunction;
+
+/*
+ * @test
+ * @key jfr
+ * @summary Verify we get SecurityExceptions when missing management permission "monitor".
+ * @library /test/lib /test/jdk
+ * @run main/othervm/secure=java.lang.SecurityManager/java.security.policy=nomonitor.policy jdk.jfr.jmx.security.TestNoMonitorPermission
+ */
+public class TestNoMonitorPermission {
+
+    public static void main(String[] args) throws Throwable {
+        try {
+            FlightRecorderMXBean bean = JmxHelper.getFlighteRecorderMXBean();
+
+            int dummyId = 1;
+            verifySecurityException(() -> bean.getRecordings(), "getRecordings()");
+            verifySecurityException(() -> bean.getConfigurations(), "getConfigurations()");
+            verifySecurityException(() -> bean.getEventTypes(), "getEventTypes()");
+            verifySecurityException(() -> bean.getRecordingOptions(dummyId), "getRecordingOptions()");
+            verifySecurityException(() -> bean.getRecordingSettings(dummyId), "getRecordingSettings()");
+            verifySecurityException(() -> bean.readStream(dummyId), "readStream()");
+        } catch (Throwable t) {
+            t.printStackTrace();
+            throw t;
+        }
+    }
+
+
+    private static void verifySecurityException(VoidFunction f, String msg) throws Throwable {
+        CommonHelper.verifyException(f, msg, java.lang.SecurityException.class);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/security/TestNotificationListenerPermission.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jmx.security;
+
+import java.lang.management.ManagementFactory;
+import java.util.concurrent.CountDownLatch;
+
+import javax.management.Notification;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.test.lib.Asserts;
+
+import jdk.jfr.jmx.JmxHelper;
+
+/*
+ * @test
+ * @key jfr
+ * @summary Test with minimal needed permissions. All functions should work.
+ * @library /test/lib /test/jdk
+ * @run main/othervm/secure=java.lang.SecurityManager/java.security.policy=listener.policy jdk.jfr.jmx.security.TestNotificationListenerPermission
+ */
+public class TestNotificationListenerPermission {
+    private static boolean gotSecurityException;
+
+    static class TestListener implements NotificationListener {
+        private final CountDownLatch latch = new CountDownLatch(1);
+
+        @Override
+        public void handleNotification(Notification arg0, Object arg1) {
+            try {
+                System.getProperty("user.name");
+            } catch (SecurityException se) {
+                se.printStackTrace();
+                gotSecurityException = true;
+            }
+            latch.countDown();
+        }
+
+        public void awaitNotication() throws InterruptedException {
+            latch.await();
+        }
+    }
+
+    public static void main(String[] args) throws Throwable {
+        try {
+            System.getProperty("user.name");
+            Asserts.fail("Didn't get security exception. Test not configured propertly?");
+        } catch (SecurityException se) {
+            // as expected
+        }
+        FlightRecorderMXBean bean = JmxHelper.getFlighteRecorderMXBean();
+        TestListener testListener = new TestListener();
+        ManagementFactory.getPlatformMBeanServer().addNotificationListener(new ObjectName(FlightRecorderMXBean.MXBEAN_NAME), testListener, null, null);
+        long id = bean.newRecording();
+        bean.startRecording(id);
+        testListener.awaitNotication();
+        Asserts.assertTrue(gotSecurityException, "Should not get elevated privileges in notification handler!");
+        bean.stopRecording(id);
+        bean.closeRecording(id);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/security/enough.policy	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,19 @@
+// Minimum policy for JMX to activate JFR and create a recording.
+
+grant {
+
+permission java.lang.management.ManagementPermission "control";
+permission java.lang.management.ManagementPermission "monitor";
+
+// in order for the test to accomplish dump/copyto on a user defined recording
+permission "java.io.FilePermission" "<<ALL FILES>>", "read,write,delete";
+permission "java.util.PropertyPermission" "user.dir", "read";
+permission "javax.management.MBeanPermission" "jdk.management.jfr.FlightRecorderMXBeanImpl#-[jdk.jfr.management:type=FlightRecorder]", "addNotificationListener";
+
+permission "javax.management.MBeanServerPermission" "createMBeanServer";
+permission "javax.management.MBeanPermission" "jdk.management.jfr.FlightRecorderMXBeanImpl#Recordings[jdk.jfr:type=FlightRecorder]", "getAttribute";
+permission "javax.management.MBeanPermission" "jdk.management.jfr.FlightRecorderMXBeanImpl#EventTypes[jdk.jfr:type=FlightRecorder]", "getAttribute";
+permission "javax.management.MBeanPermission" "jdk.management.jfr.FlightRecorderMXBeanImpl#Configurations[jdk.jfr:type=FlightRecorder]", "getAttribute";
+permission "javax.management.MBeanPermission" "jdk.management.jfr.FlightRecorderMXBeanImpl#newRecording[jdk.jfr:type=FlightRecorder]", "invoke";
+
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/security/listener.policy	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,11 @@
+// Minimum policy for JMX to activate JFR and create a recording.
+
+grant {
+
+permission java.lang.management.ManagementPermission "control";
+permission java.lang.management.ManagementPermission "monitor";
+permission "javax.management.MBeanPermission" "*", "addNotificationListener";
+permission "javax.management.MBeanPermission" "*", "invoke";
+permission "javax.management.MBeanServerPermission" "createMBeanServer";
+
+};
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/security/nocontrol.policy	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,11 @@
+// Removed security "ManagementPermission control". Should cause SecurityExceptions.
+
+grant {
+
+// Removed permission: permission java.lang.management.ManagementPermission "control";
+permission java.lang.management.ManagementPermission "monitor";
+
+permission javax.management.MBeanServerPermission "createMBeanServer";
+permission "javax.management.MBeanPermission" "jdk.management.jfr.FlightRecorderMXBeanImpl#Recordings[jdk.jfr:type=FlightRecorder]", "getAttribute";
+
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jmx/security/nomonitor.policy	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,11 @@
+// Removed security "ManagementPermission monitor". Should cause SecurityExceptions.
+
+grant {
+
+permission java.lang.management.ManagementPermission "control";
+// Removed permission: permission java.lang.management.ManagementPermission "monitor";
+
+permission javax.management.MBeanServerPermission "createMBeanServer";
+permission "javax.management.MBeanPermission" "jdk.management.jfr.FlightRecorderMXBeanImpl#Recordings[jdk.jfr:type=FlightRecorder]", "getAttribute";
+
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jvm/HelloWorldEvent1.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jvm;
+
+import jdk.jfr.Description;
+import jdk.jfr.Enabled;
+import jdk.jfr.Event;
+import jdk.jfr.Label;
+
+@Label("Hello World")
+@Description("My first event")
+@Enabled
+public class HelloWorldEvent1 extends Event {
+
+    @Label("Message")
+    public String message;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jvm/HelloWorldEvent2.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jvm;
+
+import jdk.jfr.Description;
+import jdk.jfr.Enabled;
+import jdk.jfr.Event;
+import jdk.jfr.Label;
+
+@Label("Hello World")
+@Description("My second event")
+@Enabled
+public class HelloWorldEvent2 extends Event {
+
+    @Label("Message")
+    public String message;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jvm/TestBeginAndEnd.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jvm;
+
+import jdk.jfr.internal.JVM;
+
+/*
+ * @test TestBeginAndEnd
+ * @key jfr
+ * @modules jdk.jfr/jdk.jfr.internal
+ * @run main/othervm jdk.jfr.jvm.TestBeginAndEnd
+ */
+public class TestBeginAndEnd {
+
+    private final static long MAX_CHUNK_SIZE = 12 * 1024 * 1024;
+
+    public static void main(String... args) {
+        JVM jvm = JVM.getJVM();
+        jvm.createNativeJFR();
+        jvm.setFileNotification(MAX_CHUNK_SIZE);
+        jvm.beginRecording();
+        jvm.endRecording();
+        jvm.destroyNativeJFR();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jvm/TestClassId.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jvm;
+
+import static jdk.test.lib.Asserts.assertGreaterThan;
+import static jdk.test.lib.Asserts.assertNE;
+
+import jdk.jfr.internal.JVM;
+import jdk.jfr.internal.Type;
+
+/*
+ * @test TestClassId
+ * @key jfr
+ * @library /test/lib
+ * @modules jdk.jfr/jdk.jfr.internal
+ * @run main/othervm jdk.jfr.jvm.TestClassId
+ */
+public class TestClassId {
+
+    public static void main(String... args) {
+        assertClassIds();
+        JVM jvm = JVM.getJVM();
+        jvm.createNativeJFR();
+        assertClassIds();
+        jvm.destroyNativeJFR();
+        assertClassIds();
+    }
+
+    private static void assertClassIds() {
+        long doubleClassId = Type.getTypeId(Double.class);
+        assertGreaterThan(doubleClassId, 0L, "Class id must be greater than 0");
+
+        long floatClassId = Type.getTypeId(Float.class);
+        assertNE(doubleClassId, floatClassId, "Different classes must have different class ids");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jvm/TestCounterTime.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jvm;
+
+import static jdk.test.lib.Asserts.assertGreaterThan;
+
+import jdk.jfr.internal.JVM;
+
+/*
+ * @test TestCounterTime
+ * @key jfr
+ * @library /test/lib
+ * @modules jdk.jfr/jdk.jfr.internal
+ * @run main/othervm jdk.jfr.jvm.TestCounterTime
+ */
+public class TestCounterTime {
+
+    public static void main(String... args) throws InterruptedException {
+        // Not enabled
+        assertCounterTime();
+
+        JVM jvm = JVM.getJVM();
+        jvm.createNativeJFR();
+        assertCounterTime();
+        // Enabled
+        jvm.destroyNativeJFR();
+    }
+
+    private static void assertCounterTime() throws InterruptedException {
+        long time1 = JVM.counterTime();
+        assertGreaterThan(time1, 0L, "Counter time can't be negative.");
+
+        Thread.sleep(1);
+
+        long time2 = JVM.counterTime();
+        assertGreaterThan(time2, time1, "Counter time must be increasing.");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jvm/TestCreateNative.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.jvm;
+
+import java.nio.file.Paths;
+
+import jdk.jfr.Configuration;
+import jdk.jfr.Recording;
+import jdk.jfr.internal.JVM;
+
+/*
+ * @test
+ * @summary Checks that the JVM can rollback on native initialization failures.
+ * @key jfr
+ * @library /test/lib
+ * @modules jdk.jfr/jdk.jfr.internal
+ * @run main/othervm jdk.jfr.jvm.TestCreateNative
+ */
+public class TestCreateNative {
+
+    // This is a white-box test where we fabricate a native initialization
+    // error by calling JMV#createNative(false), which will tear down
+    // all native structures after they are setup, as if something went wrong
+    // at the last step.
+    public static void main(String... args) throws Exception {
+        JVM jvm = JVM.getJVM();
+        // Ensure that repeated failures can be handled
+        for (int i = 1; i < 4; i++) {
+            System.out.println("About to try failed initialization, attempt " + i + " out of 3");
+            assertFailedInitialization(jvm);
+            System.out.println("As expected, initialization failed.");
+        }
+        // Ensure that Flight Recorder can be initialized properly after failures
+        Configuration defConfig = Configuration.getConfiguration("default");
+        Recording r = new Recording(defConfig);
+        r.start();
+        r.stop();
+        r.dump(Paths.get("recording.jfr"));
+        r.close();
+    }
+
+    private static void assertFailedInitialization(JVM jvm) throws Exception {
+        try {
+            jvm.createFailedNativeJFR();
+            throw new Exception("Expected failure when creating native JFR");
+        } catch (IllegalStateException ise) {
+            String message = ise.getMessage();
+            if (!message.equals("Unable to start Jfr")) {
+                throw new Exception("Expected failure on initialization of native JFR");
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jvm/TestDumpOnCrash.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.jvm;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+
+import jdk.internal.misc.Unsafe;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+/*
+ * @test
+ * @key jfr
+ * @summary Verifies that data associated with a running recording can be evacuated to an hs_err_pidXXX.jfr when the VM crashes
+ *
+ * @library /test/lib
+ * @modules java.base/jdk.internal.misc
+ *          java.management
+ *          jdk.jfr
+ *
+ * @run main/othervm --add-exports=java.base/jdk.internal.misc=ALL-UNNAMED jdk.jfr.jvm.TestDumpOnCrash
+ */
+public class TestDumpOnCrash {
+
+    private static final CharSequence LOG_FILE_EXTENSION = ".log";
+    private static final CharSequence JFR_FILE_EXTENSION = ".jfr";
+
+    static class Crasher {
+        public static void main(String[] args) {
+            Unsafe.getUnsafe().putInt(0L, 0);
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        processOutput(runProcess());
+    }
+
+    private static OutputAnalyzer runProcess() throws Exception {
+        return new OutputAnalyzer(
+            ProcessTools.createJavaProcessBuilder(true,
+                "-Xmx64m",
+                "-Xint",
+                "-XX:-TransmitErrorReport",
+                "-XX:-CreateCoredumpOnCrash",
+                "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED",
+                "-XX:StartFlightRecording=dumponexit=true",
+                Crasher.class.getName()).start());
+    }
+
+    private static void processOutput(OutputAnalyzer output) throws Exception {
+        output.shouldContain("CreateCoredumpOnCrash turned off, no core file dumped");
+
+        final Path jfrEmergencyFilePath = getHsErrJfrPath(output);
+        Asserts.assertTrue(Files.exists(jfrEmergencyFilePath), "No emergency jfr recording file " + jfrEmergencyFilePath + " exists");
+        Asserts.assertNotEquals(Files.size(jfrEmergencyFilePath), 0L, "File length 0. Should at least be some bytes");
+        System.out.printf("File size=%d%n", Files.size(jfrEmergencyFilePath));
+
+        List<RecordedEvent> events = RecordingFile.readAllEvents(jfrEmergencyFilePath);
+        Asserts.assertFalse(events.isEmpty(), "No event found");
+        System.out.printf("Found event %s%n", events.get(0).getEventType().getName());
+    }
+
+    private static Path getHsErrJfrPath(OutputAnalyzer output) throws Exception {
+        // extract to find hs-err_pid log file location
+        final String hs_err_pid_log_file = output.firstMatch("# *(\\S*hs_err_pid\\d+\\.log)", 1);
+        if (hs_err_pid_log_file == null) {
+            throw new RuntimeException("Did not find hs_err_pid.log file in output.\n");
+        }
+        // the dumped out jfr file should have the same name and location but with a .jfr extension
+        final String hs_err_pid_jfr_file = hs_err_pid_log_file.replace(LOG_FILE_EXTENSION, JFR_FILE_EXTENSION);
+        return Paths.get(hs_err_pid_jfr_file);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jvm/TestGetAllEventClasses.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jvm;
+
+import jdk.jfr.Event;
+import jdk.jfr.internal.JVM;
+
+import java.util.List;
+
+/*
+ * @test TestGetAllEventClasses
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @modules jdk.jfr/jdk.jfr.internal
+ *
+ * @build jdk.jfr.jvm.HelloWorldEvent1
+ * @build jdk.jfr.jvm.HelloWorldEvent2
+ * @run main/othervm jdk.jfr.jvm.TestGetAllEventClasses
+ */
+public class TestGetAllEventClasses {
+
+    public static void main(String... args) throws ClassNotFoundException {
+        JVM jvm = JVM.getJVM();
+        // before creating  native
+        assertEmptyEventList(jvm);
+        jvm.createNativeJFR();
+        // after creating native
+        assertEmptyEventList(jvm);
+
+        // Test event class load is triggered and only once
+        Class<? extends Event> clazz = initialize("jdk.jfr.jvm.HelloWorldEvent1");
+        // check that the event class is registered
+        assertEventsIncluded(jvm, clazz);
+        // second active use of the same event class should not add another class
+        // to the list - it would already be loaded
+        clazz = initialize(clazz);
+        assertEventsIncluded(jvm, clazz);
+
+        // second event class
+        Class<? extends Event> clazz2 = initialize("jdk.jfr.jvm.HelloWorldEvent2");
+        // the list of event classes should now have two classes registered
+        assertEventsIncluded(jvm, clazz, clazz2);
+
+        // verify that an abstract event class is not included
+        Class<? extends Event> abstractClass = initialize(MyAbstractEvent.class); // to run <clinit>
+        assertEventsExcluded(jvm, abstractClass);
+
+        // verify that a class that is yet to run its <clinit> is not included in the list of event classes
+        assertEventsExcluded(jvm, MyUnInitializedEvent.class);
+
+        // ensure old classes are not lost
+        assertEventsIncluded(jvm, clazz, clazz2);
+
+        jvm.destroyNativeJFR();
+    }
+
+    private static Class<? extends Event> initialize(String name) throws ClassNotFoundException {
+        // Class.forName() will force the class to run its <clinit> method
+        return Class.forName(name).asSubclass(Event.class);
+    }
+
+    private static Class<? extends Event> initialize(Class<? extends Event> event) throws ClassNotFoundException {
+        return initialize(event.getName());
+    }
+
+    private static void assertEmptyEventList(JVM jvm) {
+        if (!jvm.getAllEventClasses().isEmpty()) {
+            throw new AssertionError("should not have any event classes registered!");
+        }
+    }
+
+    @SafeVarargs
+    private static void assertEventsExcluded(JVM jvm, Class<? extends Event>... targetEvents) {
+        assertEvents(jvm, false, targetEvents);
+    }
+
+    @SafeVarargs
+    private static void assertEventsIncluded(JVM jvm, Class<? extends Event>... targetEvents) {
+        assertEvents(jvm, true, targetEvents);
+    }
+
+    @SafeVarargs
+    private static void assertEvents(JVM jvm, boolean inclusion, Class<? extends Event>... targetEvents) {
+        final List<Class<? extends Event>> list = jvm.getAllEventClasses();
+        for (Class<? extends Event> ev : targetEvents) {
+           if (list.contains(ev)) {
+               if (inclusion) {
+                   continue;
+               }
+               throw new AssertionError(ev.getName() + " in list but should not be!");
+           }
+           if (!inclusion) {
+               continue;
+           }
+           throw new AssertionError(ev.getName() + " in not in list but should be!");
+       }
+    }
+
+    private static abstract class MyAbstractEvent extends Event {}
+    private static class MyUnInitializedEvent extends Event {}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jvm/TestGetEventWriter.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jvm;
+
+import static jdk.test.lib.Asserts.assertNotNull;
+
+import jdk.jfr.internal.EventWriter;
+import jdk.jfr.internal.JVM;
+
+/*
+ * @test TestGetEventWriter
+ * @key jfr
+ * @library /test/lib
+ * @modules jdk.jfr/jdk.jfr.internal
+ *
+ * @run main/othervm jdk.jfr.jvm.TestGetEventWriter
+ */
+public class TestGetEventWriter {
+
+    public static void main(String... args) {
+        JVM jvm = JVM.getJVM();
+        jvm.createNativeJFR();
+        EventWriter writer = EventWriter.getEventWriter();
+        assertNotNull(writer, "EventWriter should not be null");
+        jvm.destroyNativeJFR();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jvm/TestGetStackTraceId.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jvm;
+
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.internal.JVM;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test TestGetStackTraceId
+ * @key jfr
+ * @library /test/lib
+ * @modules jdk.jfr/jdk.jfr.internal
+ * @run main/othervm jdk.jfr.jvm.TestGetStackTraceId
+ */
+public class TestGetStackTraceId {
+
+    public static void main(String... args) {
+        FlightRecorder.getFlightRecorder();
+        JVM jvm = JVM.getJVM();
+
+        long id10 = getStackIdOfDepth(10);
+        assertValid(id10);
+
+        long id5 = getStackIdOfDepth(5);
+        assertValid(id5);
+
+        Asserts.assertNotEquals(id5, id10, "Different stack depth must return different stack trace ids");
+
+        assertMaxSkip(jvm);
+    }
+
+    private static void assertMaxSkip(JVM jvm) {
+        assertValid(jvm.getStackTraceId(Integer.MAX_VALUE));
+    }
+
+    private static void assertValid(long value) {
+        Asserts.assertGreaterThan(value, 0L, "Stack trace id must be greater than 0, was " + value);
+    }
+
+    public static long getStackIdOfDepth(int depth) {
+        if (depth > 0) {
+            return getStackIdOfDepth(depth - 1);
+        }
+        return JVM.getJVM().getStackTraceId(0);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jvm/TestJFRIntrinsic.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Intrinsic for JFR
+ * @key jfr
+ * @library /test/lib
+ *
+ * @modules jdk.jfr/jdk.jfr.internal
+ *          java.base/jdk.internal.misc
+ *          java.management
+ *
+ * @build sun.hotspot.WhiteBox
+ * @build ClassFileInstaller
+ *
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox
+ *                                sun.hotspot.WhiteBox$WhiteBoxPermission
+ *
+ * @run main/othervm -Xbootclasspath/a:. -ea -Xmixed -Xbatch -XX:TieredStopAtLevel=4 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *      jdk.jfr.jvm.TestJFRIntrinsic
+ *
+  * @run main/othervm -Xbootclasspath/a:. -ea -Xmixed -Xbatch -XX:TieredStopAtLevel=1 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *      jdk.jfr.jvm.TestJFRIntrinsic
+ */
+
+package jdk.jfr.jvm;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.stream.IntStream;
+import jdk.jfr.internal.JVM;
+import jdk.test.lib.Platform;
+import sun.hotspot.WhiteBox;
+import sun.hotspot.code.NMethod;
+
+public class TestJFRIntrinsic {
+
+    private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
+    public Object eventWriter;
+
+    public static void main(String... args) throws Exception {
+        /*
+        Temporarily excluded until getClassId is reworked to accommodate epoch shift tagging
+        Method classid = TestJFRIntrinsic.class.getDeclaredMethod("getClassIdIntrinsic",  Class.class);
+        ti.runIntrinsicTest(classid);
+        */
+        TestJFRIntrinsic ti = new TestJFRIntrinsic();
+        Method eventWriterMethod = TestJFRIntrinsic.class.getDeclaredMethod("getEventWriterIntrinsic", Class.class);
+        ti.runIntrinsicTest(eventWriterMethod);
+    }
+
+    /*
+    public void getClassIdIntrinsic(Class<?> cls) {
+        long exp = JVM.getClassId(cls);
+        if (exp == 0) {
+            throw new RuntimeException("Class id is zero");
+        }
+    }
+    */
+
+    public void getEventWriterIntrinsic(Class<?> cls) {
+        Object o = JVM.getEventWriter();
+        if (o != null) {
+            eventWriter = o;
+        }
+    }
+
+    void runIntrinsicTest(Method method) throws Exception {
+        if (getMaxCompilationLevel() < 1) {
+            /* no compiler */
+            return;
+        }
+        /* load it */
+        try {
+            method.invoke(this, TestJFRIntrinsic.class);
+        } catch(Exception e) {
+            throw new RuntimeException(e);
+        }
+
+        int[] lvls = getAvailableCompilationLevels();
+        for (int i : lvls) {
+            if (!WHITE_BOX.enqueueMethodForCompilation(method, i)) {
+                throw new RuntimeException("Failed to enqueue method on level: " + i);
+            }
+
+            if (WHITE_BOX.isMethodCompiled(method)) {
+                NMethod nm = NMethod.get(method, false);
+                if (nm.comp_level != i) {
+                    throw new RuntimeException("Failed to compile on correct level: " + i);
+                }
+                System.out.println("Compiled " + method + " on level "  + i);
+            }
+        }
+    }
+
+    /* below is copied from CompilerUtil in hotspot test lib, removed this when it's moved */
+
+    /**
+     * Returns available compilation levels
+     *
+     * @return int array with compilation levels
+     */
+    public static int[] getAvailableCompilationLevels() {
+        if (!WhiteBox.getWhiteBox().getBooleanVMFlag("UseCompiler")) {
+            return new int[0];
+        }
+        if (WhiteBox.getWhiteBox().getBooleanVMFlag("TieredCompilation")) {
+            Long flagValue = WhiteBox.getWhiteBox()
+                    .getIntxVMFlag("TieredStopAtLevel");
+            int maxLevel = flagValue.intValue();
+            return IntStream.rangeClosed(1, maxLevel).toArray();
+        } else {
+            if (Platform.isServer() && !Platform.isEmulatedClient()) {
+                return new int[]{4};
+            }
+            if (Platform.isClient() || Platform.isMinimal() || Platform.isEmulatedClient()) {
+                return new int[]{1};
+            }
+        }
+        return new int[0];
+    }
+
+    /**
+     * Returns maximum compilation level available
+     * @return an int value representing maximum compilation level available
+     */
+    public static int getMaxCompilationLevel() {
+        return Arrays.stream(getAvailableCompilationLevels())
+                .max()
+                .getAsInt();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jvm/TestJavaEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jvm;
+
+import java.io.File;
+import java.io.IOException;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Recording;
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+
+/*
+ * @test TestGetThreadId
+ * @key jfr
+ * @library /test/lib
+ * @modules jdk.jfr/jdk.jfr.internal
+ * @run main/othervm jdk.jfr.jvm.TestJavaEvent
+ */
+public class TestJavaEvent {
+
+    private static final int EVENTS_PER_THREAD = 50;
+    private static final int THREAD_COUNT = 100;
+
+    public static class MyEvent extends Event {
+        float floatValue;
+        double doubleValue;
+        int intValue;
+        long longValue;
+        char charValue;
+        byte byteValue;
+        String stringValue;
+        Thread threadValue;
+        Class<?> classValue;
+
+        public void setFloatValue(float value) {
+            floatValue = value;
+        }
+
+        public void setDoubleValue(double value) {
+            doubleValue = value;
+        }
+
+        public void setIntValue(int value) {
+            intValue = value;
+        }
+
+        public void setLongValue(long value) {
+            longValue = value;
+        }
+
+        public void setCharValue(char value) {
+            charValue = value;
+        }
+
+        public void setByteValue(byte value) {
+            byteValue = value;
+        }
+
+        public void setStringValue(String value) {
+            stringValue = value;
+        }
+
+        public void setThreadValue(Thread value) {
+            threadValue = value;
+        }
+
+        public void setClassValue(Class<?> value) {
+            classValue = value;
+        }
+    }
+
+    public static void main(String... args) throws IOException, InterruptedException {
+        Recording r = new Recording();
+        r.enable(MyEvent.class).withThreshold(Duration.ofNanos(0)).withoutStackTrace();
+        r.start();
+        List<Thread> threads = new ArrayList<>();
+        for (int n = 0; n < THREAD_COUNT; n++) {
+            Thread t = new Thread(TestJavaEvent::emitEvents);
+            threads.add(t);
+            t.start();
+        }
+        for (Thread t : threads) {
+            t.join();
+        }
+
+        r.stop();
+        // prettyPrint();
+        File file = File.createTempFile("test", ".jfr");
+        r.dump(file.toPath());
+        int eventCount = 0;
+        for (RecordedEvent e : RecordingFile.readAllEvents(file.toPath())) {
+            if (e.getEventType().getName().equals(MyEvent.class.getName())) {
+                eventCount++;
+            }
+            System.out.println(e);
+        }
+        System.out.println("Event count was " + eventCount + ", expected " + THREAD_COUNT * EVENTS_PER_THREAD);
+        r.close();
+    }
+
+    private static void emitEvents() {
+        for (int n = 0; n < EVENTS_PER_THREAD; n++) {
+            MyEvent event = new MyEvent();
+            event.begin();
+            event.end();
+            event.setFloatValue(1.12345f);
+            event.setDoubleValue(1.234567890);
+            event.setIntValue(123456);
+            event.setLongValue(1234567890);
+            event.setCharValue('c');
+            event.setByteValue((byte) 12);
+            event.setStringValue("1234567890");
+            event.setThreadValue(Thread.currentThread());
+            event.setClassValue(Class.class);
+            event.commit();
+            try {
+                Thread.sleep(1);
+            } catch (InterruptedException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+        }
+    }
+
+    static void prettyPrint() {
+        for (EventType type : FlightRecorder.getFlightRecorder().getEventTypes()) {
+            for (AnnotationElement a : type.getAnnotationElements()) {
+                printAnnotation("", a);
+            }
+            System.out.print("class " + removePackage(type.getName()));
+            System.out.print(" extends Event");
+
+            System.out.println(" {");
+            List<ValueDescriptor> values = type.getFields();
+            for (int i = 0; i < values.size(); i++) {
+                ValueDescriptor v = values.get(i);
+                for (AnnotationElement a : v.getAnnotationElements()) {
+                    printAnnotation("  ", a);
+                }
+                System.out.println("  " + removePackage(v.getTypeName() + brackets(v.isArray())) + " " + v.getName());
+                if (i != values.size() - 1) {
+                    System.out.println();
+                }
+            }
+            System.out.println("}");
+            System.out.println();
+        }
+    }
+
+    private static String brackets(boolean isArray) {
+        return isArray ? "[]" : "";
+    }
+
+    private static String removePackage(String s) {
+
+        int index = s.lastIndexOf(".");
+        return s.substring(index + 1);
+    }
+
+    private static void printAnnotation(String indent, AnnotationElement a) {
+        String name = removePackage(a.getTypeName());
+        if (a.getValues().isEmpty()) {
+            System.out.println(indent + "@" + name);
+            return;
+        }
+        System.out.print(indent + "@" + name + "(");
+        for (Object o : a.getValues()) {
+            printAnnotationValue(o);
+        }
+        System.out.println(")");
+    }
+
+    private static void printAnnotationValue(Object o) {
+        if (o instanceof String) {
+            System.out.print("\"" + o + "\"");
+        } else {
+            System.out.print(String.valueOf(o));
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jvm/TestJfrJavaBase.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8157032
+ * @key jfr
+ * @summary verify that jfr can not be used when JVM is executed only with java.base
+ * @library /test/lib
+ * @modules java.base/jdk.internal.misc
+ * @run driver jdk.jfr.jvm.TestJfrJavaBase
+ */
+
+package jdk.jfr.jvm;
+
+
+import jdk.test.lib.dcmd.PidJcmdExecutor;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+public class TestJfrJavaBase {
+
+    private static void checkOutput(OutputAnalyzer output) {
+        output.shouldContain("jdk.jfr not found.");
+        output.shouldContain("Flight Recorder can not be enabled.");
+        output.shouldContain("To use Flight Recorder, you might need to add \"--add-modules jdk.jfr\" to the VM command-line options.");
+    }
+
+    public static void main(String[] args) throws Exception {
+        OutputAnalyzer output;
+        if (args.length == 0) {
+            output = ProcessTools.executeProcess(ProcessTools.createJavaProcessBuilder(false,
+                "-Dtest.jdk=" + System.getProperty("test.jdk"),
+                "--limit-modules", "java.base", "-cp", System.getProperty("java.class.path"),
+                TestJfrJavaBase.class.getName(), "runtest"));
+            output.shouldHaveExitValue(0);
+        } else {
+            output = ProcessTools.executeTestJava("-XX:StartFlightRecording=dumponexit=true",
+                "--limit-modules", "java.base", "-version");
+            checkOutput(output);
+            output.shouldHaveExitValue(1);
+
+            // Verify that JFR.start jcmd command reports an error when jdk.jfr module is not available
+            output = new PidJcmdExecutor().execute("JFR.start");
+            checkOutput(output);
+            output.shouldHaveExitValue(0);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jvm/TestLargeJavaEvent512k.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jvm;
+
+import java.io.IOException;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jdk.jfr.Event;
+import jdk.jfr.EventFactory;
+import jdk.jfr.Recording;
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventTypePrototype;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.Stressor;
+
+/*
+ * @test TestLargeJavaEvent512k
+ * @key jfr
+ * @library /test/lib
+ * @modules jdk.jfr/jdk.jfr.internal
+ *    java.base/jdk.internal.org.objectweb.asm
+ * @run main/othervm jdk.jfr.jvm.TestLargeJavaEvent512k
+ */
+public class TestLargeJavaEvent512k {
+    static boolean error;
+    static void setError() {
+        error = true;
+    }
+    static boolean hasError() {
+        return error;
+    }
+
+    public static void main(String... args) throws Exception {
+        final String name = "MyLargeJavaEvent512k"; // name of synthetically generated event
+        final String fieldNamePrefix = "myfield";
+        final int numberOfFields = 64; // 64*8k = 512k event size
+        final Map<String, Object> eventMap = new HashMap<>();
+        final int numberOfThreads = 10; // 10 threads will run the test
+        final int numberOfEventsPerThread = 50; // each thread will generate 50 events
+
+        List<ValueDescriptor> fields = new ArrayList<>();
+        for (int i = 0; i < numberOfFields; ++i) {
+            String fieldName = fieldNamePrefix + i;
+            eventMap.put(fieldName, largeString());
+            fields.add(new ValueDescriptor(String.class, fieldName));
+        }
+
+        EventTypePrototype prototype = new EventTypePrototype(name,Collections.emptyList(),  fields);
+
+        EventFactory ef = EventFactory.create(prototype.getAnnotations(), prototype.getFields());
+
+        Recording r = new Recording();
+        r.enable(prototype.getName()).withThreshold(Duration.ofNanos(0)).withoutStackTrace();
+        r.start();
+
+        Thread.UncaughtExceptionHandler eh = (t, e) -> TestLargeJavaEvent512k.setError();
+
+        Stressor.execute(numberOfThreads, eh, () -> {
+            for (int n = 0; n < numberOfEventsPerThread; ++n) {
+                try {
+                    Event event = ef.newEvent();
+                    setEventValues(event, ef, prototype, eventMap);
+                    event.commit();
+                    Thread.sleep(1);
+                } catch (Exception ex) {
+                    throw new RuntimeException(ex);
+                }
+            }
+        });
+        r.stop();
+        try {
+            if (hasError()) {
+                throw new RuntimeException("One (or several) of the threads had an exception/error, test failed");
+            }
+            verifyEvents(r, numberOfThreads, numberOfEventsPerThread, eventMap);
+        } finally {
+            r.close();
+        }
+    }
+
+    private static void verifyEvents(Recording r, int numberOfThreads, int iterations, Map<String, Object> fields) throws IOException {
+        List<RecordedEvent> recordedEvents = Events.fromRecording(r);
+        Events.hasEvents(recordedEvents);
+        int eventCount = 0;
+        for (RecordedEvent re : recordedEvents) {
+            verify(re, fields);
+            eventCount++;
+        }
+        System.out.println("Number of expected events: " + numberOfThreads * iterations);
+        System.out.println("Number of events found: " + eventCount);
+        Asserts.assertEquals(numberOfThreads * iterations, eventCount, "Unexpected number of events");
+    }
+
+    // each row is 64 chars for 128 rows == 8192 chars
+    private static String largeString() {
+        StringBuilder builder = new StringBuilder();
+        for (int i = 0; i < 128; ++i) {
+            builder.append("cygwinapacygwinapacygwinapacygwinapacygwinapacygwinapacygwinapa ");
+        }
+        return builder.toString();
+    }
+
+    private static void setEventValues(Event event, EventFactory f, EventTypePrototype prototype, Map<String, Object> fields) {
+        for (Map.Entry<String, Object> entry : fields.entrySet()) {
+            int index = prototype.getFieldIndex(entry.getKey());
+            event.set(index, entry.getValue());
+        }
+    }
+
+    private static void verify(RecordedEvent event, Map<String, Object> fields) {
+        for (Map.Entry<String, Object> entry : fields.entrySet()) {
+            String fieldName = entry.getKey();
+            Object value = event.getValue(fieldName);
+            Object expected = fields.get(fieldName);
+            Asserts.assertEQ(value, expected);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jvm/TestLargeJavaEvent64k.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jvm;
+
+import java.io.IOException;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jdk.jfr.Event;
+import jdk.jfr.EventFactory;
+import jdk.jfr.Recording;
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventTypePrototype;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.Stressor;
+
+/*
+ * @test TestLargeJavaEvent64k
+ * @key jfr
+ * @library /test/lib
+ * @modules jdk.jfr/jdk.jfr.internal
+ *    java.base/jdk.internal.org.objectweb.asm
+ * @run main/othervm jdk.jfr.jvm.TestLargeJavaEvent64k
+ */
+public class TestLargeJavaEvent64k {
+    static boolean error;
+    static void setError() {
+        error = true;
+    }
+    static boolean hasError() {
+        return error;
+    }
+
+    public static void main(String... args) throws Exception {
+        final String name = "MyLargeJavaEvent64k"; // name of synthetically generated event
+        final String fieldNamePrefix = "myfield";
+        final int numberOfFields = 8; // 8*8k = ~64k event size
+        final Map<String, Object> eventMap = new HashMap<>();
+        final int numberOfThreads = 100; // 50 threads will run the test
+        final int numberOfEventsPerThread = 50; // each thread will generate 50 events
+
+        List<ValueDescriptor> fields = new ArrayList<>();
+        for (int i = 0; i < numberOfFields; ++i) {
+            String fieldName = fieldNamePrefix + i;
+            eventMap.put(fieldName, largeString());
+            fields.add(new ValueDescriptor(String.class, fieldName));
+        }
+
+        EventTypePrototype prototype = new EventTypePrototype(name,Collections.emptyList(),  fields);
+
+        EventFactory ef = EventFactory.create(prototype.getAnnotations(), prototype.getFields());
+
+        Recording r = new Recording();
+        r.enable(prototype.getName()).withThreshold(Duration.ofNanos(0)).withoutStackTrace();
+        r.start();
+
+        Thread.UncaughtExceptionHandler eh = (t, e) -> TestLargeJavaEvent64k.setError();
+
+        Stressor.execute(numberOfThreads, eh, () -> {
+            for (int n = 0; n < numberOfEventsPerThread; ++n) {
+                try {
+                    Event event = ef.newEvent();
+                    setEventValues(event, ef, prototype, eventMap);
+                    event.commit();
+                    Thread.sleep(1);
+                } catch (Exception ex) {
+                    throw new RuntimeException(ex);
+                }
+            }
+        });
+        r.stop();
+        try {
+            if (hasError()) {
+                throw new RuntimeException("One (or several) of the threads had an exception/error, test failed");
+            }
+            verifyEvents(r, numberOfThreads, numberOfEventsPerThread, eventMap);
+        } finally {
+            r.close();
+        }
+    }
+
+    private static void verifyEvents(Recording r, int numberOfThreads, int iterations, Map<String, Object> fields) throws IOException {
+        List<RecordedEvent> recordedEvents = Events.fromRecording(r);
+        Events.hasEvents(recordedEvents);
+        int eventCount = 0;
+        for (RecordedEvent re : recordedEvents) {
+            verify(re, fields);
+            eventCount++;
+        }
+        System.out.println("Number of expected events: " + numberOfThreads * iterations);
+        System.out.println("Number of events found: " + eventCount);
+        Asserts.assertEquals(numberOfThreads * iterations, eventCount, "Unexpected number of events");
+    }
+
+    // each row is 64 chars for 128 rows == 8192 chars
+    private static String largeString() {
+        StringBuilder builder = new StringBuilder();
+        for (int i = 0; i < 128; ++i) {
+            builder.append("cygwinapacygwinapacygwinapacygwinapacygwinapacygwinapacygwinapa ");
+        }
+        return builder.toString();
+    }
+
+    private static void setEventValues(Event event, EventFactory f, EventTypePrototype prototype, Map<String, Object> fields) {
+        for (Map.Entry<String, Object> entry : fields.entrySet()) {
+            int index = prototype.getFieldIndex(entry.getKey());
+            event.set(index, entry.getValue());
+        }
+    }
+
+    private static void verify(RecordedEvent event, Map<String, Object> fields) {
+        for (Map.Entry<String, Object> entry : fields.entrySet()) {
+            String fieldName = entry.getKey();
+            Object value = event.getValue(fieldName);
+            Object expected = fields.get(fieldName);
+            Asserts.assertEQ(value, expected);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jvm/TestLogImplementation.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jvm;
+
+import jdk.jfr.internal.JVM;
+import jdk.jfr.internal.Logger;
+import jdk.jfr.internal.LogTag;
+import jdk.jfr.internal.LogLevel;
+
+/*
+ * @test TestLogImplementation
+ * @key jfr
+ * @library /test/lib
+ * @modules jdk.jfr/jdk.jfr.internal
+ * @run main/othervm jdk.jfr.jvm.TestLogImplementation
+ */
+public class TestLogImplementation {
+    private static LogLevel DEFAULT_TEST_LOG_LEVEL = LogLevel.ERROR;
+    private static LogTag JFR_LOG_TAG = LogTag.JFR;
+
+    private static void assertAllLevelsForTag(LogTag tag, String message) {
+        for (LogLevel level : LogLevel.values()) {
+            Logger.log(tag, level, message);
+        }
+    }
+
+    private static void assertAllTagsForLevel(LogLevel level, String message) {
+        for (LogTag tag : LogTag.values()) {
+            Logger.log(tag, level, message);
+        }
+    }
+
+    public static void main(String... args) {
+        assertEmptyMessageOK();
+        assertNullMessageOK();
+        assertAllCharsOK();
+        assertLargeMessageOK();
+        assertFormatSpecifierOK();
+        assertAllLevelOK();
+        assertLogLevelUnderflow();
+        assertLogLevelOverflow();
+        assertLogTagUnderflow();
+        assertLogTagOverflow();
+    }
+
+    private static void assertAllLevelOK() {
+        assertAllLevelsForTag(JFR_LOG_TAG, "");
+        assertAllTagsForLevel(DEFAULT_TEST_LOG_LEVEL, "");
+    }
+
+    private static void assertFormatSpecifierOK() {
+        assertAllTagsForLevel(DEFAULT_TEST_LOG_LEVEL, "%s");
+        assertAllTagsForLevel(DEFAULT_TEST_LOG_LEVEL, "%n");
+        assertAllTagsForLevel(DEFAULT_TEST_LOG_LEVEL, "%h");
+    }
+
+    private static void assertLargeMessageOK() {
+        StringBuilder large = new StringBuilder();
+        for (int i = 0; i < 1000 * 1000; i++) {
+            large.append('o');
+        }
+        Logger.log(JFR_LOG_TAG, DEFAULT_TEST_LOG_LEVEL, large.toString());
+    }
+
+    private static void assertAllCharsOK() {
+        char c = Character.MIN_VALUE;
+        StringBuilder large = new StringBuilder();
+        int logSize = 0;
+        for(int i = Character.MIN_VALUE; i< (int)Character.MAX_VALUE; i++, c++) {
+            large.append(c);
+            logSize++;
+            if (logSize == 80) {
+                Logger.log(JFR_LOG_TAG, DEFAULT_TEST_LOG_LEVEL, large.toString());
+                large = new StringBuilder();
+            }
+        }
+    }
+
+    private static void assertEmptyMessageOK() {
+        assertAllLevelsForTag(JFR_LOG_TAG, "");
+    }
+
+    private static void assertNullMessageOK() {
+        assertAllLevelsForTag(JFR_LOG_TAG, (String)null);
+    }
+
+    private static void assertLogLevelUnderflow() {
+        try {
+            JVM.log(JFR_LOG_TAG.ordinal(), 0, (String)null);
+        } catch (IllegalArgumentException ex) {
+            // Expected
+        }
+    }
+
+    private static void assertLogLevelOverflow() {
+        try {
+            JVM.log(JFR_LOG_TAG.ordinal(), LogLevel.ERROR.ordinal() + 1, (String)null);
+        } catch (IllegalArgumentException ex) {
+            // Expected
+        }
+    }
+
+    private static void assertLogTagUnderflow() {
+        try {
+            JVM.log(JFR_LOG_TAG.ordinal() - 1, DEFAULT_TEST_LOG_LEVEL.ordinal(), (String)null);
+        } catch (IllegalArgumentException ex) {
+            // Expected
+        }
+    }
+
+    // since the enum will grow with new entries, provoking an overflow is problematic
+    // is there a built-in "current max" in a Java enum
+    private static void assertLogTagOverflow() {
+        try {
+            JVM.log(10000, DEFAULT_TEST_LOG_LEVEL.ordinal(), (String)null);
+        } catch (IllegalArgumentException ex) {
+            // Expected
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jvm/TestLogOutput.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jvm;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+/*
+ * @test TestLogOutput
+ * @key jfr
+ * @summary Sanity test jfr logging output
+ * @library /test/lib
+ * @run main/othervm -Xlog:disable -Xlog:jfr*=trace:file=jfr_trace.txt -XX:StartFlightRecording=duration=1s,filename=recording.jfr jdk.jfr.jvm.TestLogOutput
+ */
+public class TestLogOutput {
+    public static void main(String[] args) throws Exception {
+        final String fileName = "jfr_trace.txt";
+        final List<String>findWhat = new ArrayList<>();
+        findWhat.add("Starting up Jfr startup recording");
+        findWhat.add("Flight Recorder initialized");
+        boolean passed = false;
+        List<String> matches = new ArrayList<String>(findWhat);
+
+        do {
+            List<String> lines;
+            try {
+                lines = Files.readAllLines(Paths.get(fileName));
+            } catch (IOException e) {
+                throw new Error(e);
+            }
+            for (String l : lines) {
+                for (String m : matches) {
+                    if (l.toString().contains(m)) {
+                        matches.remove(m);
+                        break;
+                    }
+                }
+            }
+            if (matches.size() < 1) {
+                passed = true;
+                break;
+            }
+            if (lines.size() > 100) {
+                break; /* did not find it */
+            }
+        } while(!passed);
+
+        if (!passed) {
+            throw new Error("Not found " + findWhat  + " in stream");
+        }
+
+       System.out.println("PASSED");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jvm/TestPid.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jvm;
+
+import static jdk.test.lib.Asserts.assertEquals;
+
+import jdk.jfr.internal.JVM;
+
+/*
+ * @test TestPid
+ * @key jfr
+ * @library /test/lib
+ * @modules jdk.jfr/jdk.jfr.internal
+ * @run main/othervm jdk.jfr.jvm.TestPid
+ */
+public class TestPid {
+
+    public static void main(String... args) throws InterruptedException {
+
+        JVM jvm = JVM.getJVM();
+        String pid = jvm.getPid();
+
+        try {
+            String managementPid = String.valueOf(ProcessHandle.current().pid());
+            assertEquals(pid, managementPid, "Pid doesn't match value returned by RuntimeMXBean");
+        } catch (NumberFormatException nfe) {
+            throw new AssertionError("Pid must be numeric, but was '" + pid + "'");
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jvm/TestUnloadEventClassCount.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jvm;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+
+import jdk.jfr.Event;
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.internal.JVM;
+
+/*
+ * @test
+ * @key jfr
+ * @summary Unit test for JVM#getUnloadedEventClassCount
+ *
+ * @library /test/lib
+ * @modules jdk.jfr/jdk.jfr.internal
+ *          java.base/jdk.internal.misc
+ *
+ * @run main/othervm -Xlog:class+unload -Xlog:gc -Xmx16m jdk.jfr.jvm.TestUnloadEventClassCount
+ */
+public class TestUnloadEventClassCount {
+
+    private static final String EVENT_NAME = "jdk.jfr.jvm.TestUnloadEventClassCount$ToBeUnloaded";
+
+    public static class ToBeUnloaded extends Event {
+    }
+
+    static public class MyClassLoader extends ClassLoader {
+        public MyClassLoader() {
+            super("MyClassLoader", null);
+        }
+
+        public final Class<?> defineClass(String name, byte[] b) {
+            return super.defineClass(name, b, 0, b.length);
+        }
+    }
+
+    public static MyClassLoader myClassLoader;
+
+    public static void main(String[] args) throws Throwable {
+        FlightRecorder.getFlightRecorder();
+        myClassLoader = createClassLoaderWithEventClass();
+        System.out.println("MyClassLoader instance created");
+        long initialCount = JVM.getJVM().getUnloadedEventClassCount();
+        System.out.println("Initiali unloaded count is " + initialCount);
+        myClassLoader = null;
+        System.out.println("Reference to class loader cleared");
+        long count = 0;
+        do {
+            System.gc();
+            System.out.println("GC triggered");
+            count = JVM.getJVM().getUnloadedEventClassCount();
+            System.out.println("Unloaded count was " + count);
+            Thread.sleep(1000); // sleep to reduce log
+        } while (count != initialCount + 1);
+    }
+
+    private static MyClassLoader createClassLoaderWithEventClass() throws Exception {
+        String resourceName = EVENT_NAME.replace('.', '/') + ".class";
+        try (InputStream is = TestUnloadEventClassCount.class.getClassLoader().getResourceAsStream(resourceName)) {
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            byte[] buffer = new byte[4096];
+            int byteValue = 0;
+            while ((byteValue = is.read(buffer, 0, buffer.length)) != -1) {
+                baos.write(buffer, 0, byteValue);
+            }
+            baos.flush();
+            MyClassLoader myClassLoader = new MyClassLoader();
+            Class<?> eventClass = myClassLoader.defineClass(EVENT_NAME, baos.toByteArray());
+            if (eventClass == null) {
+                throw new Exception("Could not define test class");
+            }
+            if (eventClass.getSuperclass() != Event.class) {
+                throw new Exception("Superclass should be jdk.jfr.Event");
+            }
+            if (eventClass.getSuperclass().getClassLoader() != null) {
+                throw new Exception("Class loader of jdk.jfr.Event should be null");
+            }
+            if (eventClass.getClassLoader() != myClassLoader) {
+                throw new Exception("Incorrect class loader for event class");
+            }
+            eventClass.newInstance(); // force <clinit>
+            return myClassLoader;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/jvm/TestUnsupportedVM.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.jvm;
+
+
+import java.io.FileReader;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.concurrent.Callable;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.Configuration;
+import jdk.jfr.Description;
+import jdk.jfr.Event;
+import jdk.jfr.EventFactory;
+import jdk.jfr.EventSettings;
+import jdk.jfr.EventType;
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.FlightRecorderListener;
+import jdk.jfr.FlightRecorderPermission;
+import jdk.jfr.Label;
+import jdk.jfr.Recording;
+import jdk.jfr.RecordingState;
+import jdk.jfr.SettingControl;
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.consumer.RecordedClass;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedFrame;
+import jdk.jfr.consumer.RecordedMethod;
+import jdk.jfr.consumer.RecordedObject;
+import jdk.jfr.consumer.RecordedStackTrace;
+import jdk.jfr.consumer.RecordedThread;
+import jdk.jfr.consumer.RecordedThreadGroup;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.management.jfr.ConfigurationInfo;
+import jdk.management.jfr.EventTypeInfo;
+import jdk.management.jfr.FlightRecorderMXBean;
+import jdk.management.jfr.RecordingInfo;
+import jdk.management.jfr.SettingDescriptorInfo;
+
+/*
+ * @test TestUnsupportedVM
+ * @key jfr
+ *
+ * @modules jdk.jfr
+ *          jdk.management.jfr
+ *
+ * @run main/othervm -Dprepare-recording=true jdk.jfr.jvm.TestUnsupportedVM
+ * @run main/othervm -Djfr.unsupported.vm=true jdk.jfr.jvm.TestUnsupportedVM
+ */
+public class TestUnsupportedVM {
+
+    private static Path RECORDING_FILE = Paths.get("recording.jfr");
+    private static Class<?> [] APIClasses = {
+            AnnotationElement.class,
+            Configuration.class,
+            ConfigurationInfo.class,
+            Event.class,
+            EventFactory.class,
+            EventSettings.class,
+            EventType.class,
+            EventTypeInfo.class,
+            FlightRecorder.class,
+            FlightRecorderPermission.class,
+            FlightRecorderListener.class,
+            FlightRecorderMXBean.class,
+            RecordedClass.class,
+            RecordedEvent.class,
+            RecordedFrame.class,
+            RecordedMethod.class,
+            RecordedObject.class,
+            RecordedStackTrace.class,
+            RecordedThread.class,
+            RecordedThreadGroup.class,
+            Recording.class,
+            RecordingFile.class,
+            RecordingInfo.class,
+            RecordingState.class,
+            SettingControl.class,
+            SettingDescriptorInfo.class,
+            ValueDescriptor.class
+       };
+    // * @run main/othervm -Dprepare-recording=true jdk.jfr.jvm.TestUnsupportedVM
+    @Label("My Event")
+    @Description("My fine event")
+    static class MyEvent extends Event {
+        int myValue;
+    }
+
+    public static void main(String... args) throws Exception {
+        if (Boolean.getBoolean("prepare-recording")) {
+            Recording r = new Recording(Configuration.getConfiguration("default"));
+            r.start();
+            r.stop();
+            r.dump(RECORDING_FILE);
+            r.close();
+            return;
+        }
+
+        System.out.println("jdk.jfr.unsupportedvm=" + System.getProperty("jdk.jfr.unsupportedvm"));
+        // Class FlightRecorder
+        if (FlightRecorder.isAvailable()) {
+            throw new AssertionError("JFR should not be available on an unsupported VM");
+        }
+
+        if (FlightRecorder.isInitialized()) {
+            throw new AssertionError("JFR should not be initialized on an unsupported VM");
+        }
+
+        assertIllegalStateException(() -> FlightRecorder.getFlightRecorder());
+        assertSwallow(() -> FlightRecorder.addListener(new FlightRecorderListener() {}));
+        assertSwallow(() -> FlightRecorder.removeListener(new FlightRecorderListener() {}));
+        assertSwallow(() -> FlightRecorder.register(MyEvent.class));
+        assertSwallow(() -> FlightRecorder.unregister(MyEvent.class));
+        assertSwallow(() -> FlightRecorder.addPeriodicEvent(MyEvent.class, new Runnable() { public void run() {} }));
+        assertSwallow(() -> FlightRecorder.removePeriodicEvent(new Runnable() { public void run() {} }));
+
+        // Class Configuration
+        if (!Configuration.getConfigurations().isEmpty()) {
+            throw new AssertionError("Configuration files should not exist on an unsupported VM");
+        }
+        Path jfcFile = Files.createTempFile("my", ".jfr");
+        assertIOException(() -> Configuration.getConfiguration("default"));
+        assertIOException(() -> Configuration.create(jfcFile));
+        assertIOException(() -> Configuration.create(new FileReader(jfcFile.toFile())));
+
+        // Class EventType
+        assertInternalError(() -> EventType.getEventType(MyEvent.class));
+
+        // Class EventFactory
+        assertInternalError(() -> EventFactory.create(new ArrayList<>(), new ArrayList<>()));
+
+        // Create a static event
+        MyEvent myEvent = new MyEvent();
+        myEvent.begin();
+        myEvent.end();
+        myEvent.shouldCommit();
+        myEvent.commit();
+
+        // Trigger class initialization failure
+        for (Class<?> c : APIClasses) {
+            assertNoClassInitFailure(c);
+        }
+
+        // jdk.jfr.consumer.*
+        // Only run this part of tests if we are on VM
+        // that can produce a recording file
+        if (Files.exists(RECORDING_FILE)) {
+            for(RecordedEvent re : RecordingFile.readAllEvents(RECORDING_FILE)) {
+                System.out.println(re);
+            }
+        }
+    }
+
+    private static void assertNoClassInitFailure(Class<?> clazz) {
+        try {
+            Class.forName(clazz.getName(), true, clazz.getClassLoader());
+        } catch (ClassNotFoundException e) {
+            throw new AssertionError("Could not find public API class on unsupported VM");
+        }
+    }
+
+    private static void assertInternalError(Runnable r) {
+        try {
+            r.run();
+        } catch (InternalError e) {
+           // OK, as expected
+            return;
+        }
+        throw new AssertionError("Expected InternalError on an unsupported JVM");
+    }
+
+    private static void assertIOException(Callable<?> c) {
+        try {
+            c.call();
+        } catch (Exception e) {
+            if (e.getClass() == IOException.class) {
+                return;
+            }
+        }
+        throw new AssertionError("Expected IOException on an unsupported JVM");
+    }
+
+    private static void assertIllegalStateException(Runnable r) throws Exception {
+        try {
+            r.run();
+        } catch (IllegalStateException ise) {
+            if (!ise.getMessage().equals("Flight Recorder is not supported on this VM")) {
+                throw new AssertionError("Expected 'Flight Recorder is not supported on this VM'");
+            }
+        }
+    }
+
+    private static void assertSwallow(Runnable r) throws Exception {
+        try {
+            r.run();
+        } catch (Exception e) {
+            throw new AssertionError("Unexpected exception '" + e.getMessage() + " on an unspported VM");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/startupargs/StartupHelper.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.startupargs;
+
+import java.io.IOException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Recording;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.dcmd.CommandExecutor;
+import jdk.test.lib.dcmd.PidJcmdExecutor;
+import jdk.test.lib.process.OutputAnalyzer;
+
+
+
+public class StartupHelper {
+
+    public static Recording getRecording(String name) {
+        for (Recording r : FlightRecorder.getFlightRecorder().getRecordings()) {
+            System.out.println("Recording=" + r.getName());
+            if (name.equals(r.getName())) {
+                return r;
+            }
+        }
+        Asserts.fail("No recording with name " + name);
+        return null;
+    }
+
+    public static List<Path> listFilesInDir(Path root) throws IOException {
+        List<Path> paths = new ArrayList<>();
+        List<Path> searchPaths = new ArrayList<>();
+        searchPaths.add(root);
+
+        while (!searchPaths.isEmpty()) {
+            Path currRoot = searchPaths.remove(searchPaths.size() - 1);
+            DirectoryStream<Path> contents = Files.newDirectoryStream(currRoot);
+            for (Path path : contents) {
+                paths.add(path);
+                if (Files.isDirectory(path)) {
+                    searchPaths.add(path);
+                }
+            }
+        }
+
+        System.out.println("Files in '" + root + "':");
+        for (Path path : paths) {
+            System.out.println("  path: " + path);
+        }
+        return paths;
+    }
+
+    public static Path findRecordingFileInRepo(Path baseLocation) throws IOException {
+        // Check that repo contains a file ending in "jfr" or "part"
+        for (Path path : listFilesInDir(baseLocation)) {
+            if (Files.isRegularFile(path)) {
+                String filename = path.toString();
+                if (filename.endsWith("jfr") || filename.endsWith("part")) {
+                    return path;
+                }
+            }
+        }
+        return null;
+    }
+
+    public static OutputAnalyzer jcmd(String... args) {
+        String argsString = Arrays.stream(args).collect(Collectors.joining(" "));
+        CommandExecutor executor = new PidJcmdExecutor();
+        OutputAnalyzer oa = executor.execute(argsString);
+        oa.shouldHaveExitValue(0);
+        return oa;
+    }
+
+    public static OutputAnalyzer jcmdCheck(String recordingName) {
+        return jcmd("JFR.check", "name=" + recordingName, "verbose=true");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/startupargs/TestBadOptionValues.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.startupargs;
+
+import jdk.test.lib.Asserts;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+/*
+ * @test
+ * @key jfr
+ *
+ * @library /test/lib
+ * @modules java.base/jdk.internal.misc
+ *          java.management
+ *          jdk.jfr
+ *
+ * @run main jdk.jfr.startupargs.TestBadOptionValues
+ */
+public class TestBadOptionValues {
+
+    private static final String START_FLIGHT_RECORDING = "-XX:StartFlightRecording=";
+    private static final String FLIGHT_RECORDER_OPTIONS = "-XX:FlightRecorderOptions=";
+
+    private static void test(String prepend, String expectedOutput, String... options) throws Exception {
+        ProcessBuilder pb;
+        OutputAnalyzer output;
+
+        Asserts.assertGreaterThan(options.length, 0);
+
+        for (String option : options) {
+            pb = ProcessTools.createJavaProcessBuilder(prepend + option, "-version");
+            output = new OutputAnalyzer(pb.start());
+            output.shouldContain(expectedOutput);
+        }
+    }
+
+    private static void testBoolean(String prepend, String... options) throws Exception {
+        String[] splitOption;
+
+        Asserts.assertGreaterThan(options.length, 0);
+
+        for (String option : options) {
+            splitOption = option.split("=", 2);
+            test(prepend, String.format("Boolean parsing error in command argument '%s'. Could not parse: %s.", splitOption[0], splitOption[1]), option);
+        }
+    }
+
+    private static void testJlong(String prepend, String... options) throws Exception {
+        String[] splitOption;
+
+        Asserts.assertGreaterThan(options.length, 0);
+
+        for (String option : options) {
+            splitOption = option.split("=", 2);
+            test(prepend, String.format("Integer parsing error in command argument '%s'. Could not parse: %s.",
+                splitOption[0], splitOption.length > 1 ? splitOption[1]: ""), option);
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        // Nanotime options
+        test(START_FLIGHT_RECORDING, "Integer parsing error nanotime value: syntax error",
+            "delay=ms",
+            "duration=",
+            "maxage=q");
+        test(START_FLIGHT_RECORDING, "Integer parsing error nanotime value: syntax error, value is null",
+            "duration");
+        test(START_FLIGHT_RECORDING, "Integer parsing error nanotime value: illegal unit",
+            "delay=1000mq",
+            "duration=2000mss",
+            "maxage=-1000");
+        test(START_FLIGHT_RECORDING, "Integer parsing error nanotime value: unit required",
+            "delay=3037",
+            "maxage=1");
+
+        // Memory size options
+        test(START_FLIGHT_RECORDING, "Parsing error memory size value: negative values not allowed",
+            "maxsize=-1",
+            "maxsize=-10k");
+
+        test(FLIGHT_RECORDER_OPTIONS, "Parsing error memory size value: negative values not allowed",
+            "threadbuffersize=-1M",
+            "memorysize=-1g",
+            "globalbuffersize=-0",
+            "maxchunksize=-");
+
+        test(START_FLIGHT_RECORDING, "Parsing error memory size value: syntax error, value is null",
+            "maxsize");
+
+        test(FLIGHT_RECORDER_OPTIONS, "Parsing error memory size value: syntax error, value is null",
+            "threadbuffersize",
+            "memorysize",
+            "globalbuffersize",
+            "maxchunksize");
+
+        test(START_FLIGHT_RECORDING, "Parsing error memory size value: invalid value",
+            "maxsize=");
+
+        test(FLIGHT_RECORDER_OPTIONS, "Parsing error memory size value: invalid value",
+            "threadbuffersize=a",
+            "globalbuffersize=G",
+            "maxchunksize=M10");
+
+        // Jlong options
+        testJlong(FLIGHT_RECORDER_OPTIONS,
+            "stackdepth=q",
+            "stackdepth=",
+            "numglobalbuffers=10m",
+            "numglobalbuffers",
+            "numglobalbuffers=0x15");
+
+        // Boolean options
+        testBoolean(START_FLIGHT_RECORDING,
+            "disk=on",
+            "dumponexit=truee");
+
+        testBoolean(FLIGHT_RECORDER_OPTIONS,
+            "samplethreads=falseq",
+            "retransform=0");
+
+        // Not existing options
+        test(START_FLIGHT_RECORDING, "Unknown argument 'dumponexitt' in diagnostic command.",
+            "dumponexitt=true");
+        test(FLIGHT_RECORDER_OPTIONS, "Unknown argument 'notexistoption' in diagnostic command.",
+            "notexistoption");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/startupargs/TestDumpOnExit.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.startupargs;
+
+import java.io.IOException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Iterator;
+import java.util.function.Supplier;
+
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+/*
+ * @test
+ * @summary Start a FlightRecording with dumponexit. Verify dump exists.
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.startupargs.TestDumpOnExit
+ */
+public class TestDumpOnExit {
+
+    public static void main(String[] args) throws Exception {
+        Path dumpPath = Paths.get(".", "dumped.jfr");
+
+        // Test without security manager and a file name relative to current directory
+        testDumponExit(() -> dumpPath,
+                "-Xlog:jfr=trace",
+                "-XX:StartFlightRecording=filename=./dumped.jfr,dumponexit=true,settings=profile",
+                "jdk.jfr.startupargs.TestDumpOnExit$TestMain"
+        );
+        // Test with security manager and a file name relative to current directory
+        testDumponExit(() -> dumpPath,
+                "-Xlog:jfr=trace",
+                "-XX:StartFlightRecording=filename=./dumped.jfr,dumponexit=true,settings=profile",
+                "-Djava.security.manager",
+                "jdk.jfr.startupargs.TestDumpOnExit$TestMain"
+        );
+        // Test with security manager but without a name
+        testDumponExit(() -> findJFRFileInCurrentDirectory(),
+                "-Xlog:jfr=trace",
+                "-XX:StartFlightRecording=dumponexit=true,settings=profile",
+                "-Djava.security.manager",
+                "jdk.jfr.startupargs.TestDumpOnExit$TestMain"
+        );
+    }
+
+    private static Path findJFRFileInCurrentDirectory() {
+        try {
+            DirectoryStream<Path> ds = Files.newDirectoryStream(Paths.get("."), "*pid-*.jfr");
+            Iterator<Path> pathIterator = ds.iterator();
+            if (!pathIterator.hasNext()) {
+                throw new RuntimeException("Could not find jfr file in current directory");
+            }
+            return pathIterator.next();
+        } catch (IOException e) {
+            throw new RuntimeException("Could not list jfr file in current directory");
+        }
+    }
+
+    private static void testDumponExit(Supplier<Path> p,String... args) throws Exception, IOException {
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, args);
+        OutputAnalyzer output = ProcessTools.executeProcess(pb);
+        System.out.println(output.getOutput());
+        output.shouldHaveExitValue(0);
+        Path dump = p.get();
+        Asserts.assertTrue(Files.isRegularFile(dump), "No recording dumped " + dump);
+        System.out.println("Dumped recording size=" + Files.size(dump));
+        Asserts.assertFalse(RecordingFile.readAllEvents(dump).isEmpty(), "No events in dump");
+    }
+
+    @SuppressWarnings("unused")
+    private static class TestMain {
+        public static void main(String[] args) throws Exception {
+            System.out.println("Hello from test main");
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/startupargs/TestMemoryOptions.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,652 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.startupargs;
+
+import java.util.List;
+import java.util.ArrayList;
+
+import jdk.jfr.internal.Options;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+import jdk.internal.misc.Unsafe;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @modules jdk.jfr/jdk.jfr.internal
+ *                 java.base/jdk.internal.misc
+ * @run main/timeout=900 jdk.jfr.startupargs.TestMemoryOptions
+ */
+public class TestMemoryOptions {
+
+    public enum Unit {
+        b('b'), k('k'), m('m'), g('g');
+
+        private char unit;
+
+        Unit(char unit) {
+            this.unit = unit;
+        }
+
+        char getUnit() {
+            return unit;
+        }
+    };
+
+    static class Option implements Comparable<Option> {
+        static final long MIN_GLOBAL_BUFFER_COUNT = 2;
+        static final long DEFAULT_GLOBAL_BUFFER_COUNT = 20;
+        static final long MIN_GLOBAL_BUFFER_SIZE = 64 * 1024;
+        static long DEFAULT_GLOBAL_BUFFER_SIZE = 524288;
+        static final long MIN_MEMORY_SIZE = 1024 * 1024;
+        static final long DEFAULT_MEMORY_SIZE = DEFAULT_GLOBAL_BUFFER_COUNT * DEFAULT_GLOBAL_BUFFER_SIZE;
+        static final long MIN_THREAD_BUFFER_SIZE = 4 * 1024;
+        static long DEFAULT_THREAD_BUFFER_SIZE;
+        static final long PAGE_SIZE;
+        static final long UNDEFINED = -1;
+
+        static {
+            PAGE_SIZE = Unsafe.getUnsafe().pageSize();
+            if (PAGE_SIZE == MIN_THREAD_BUFFER_SIZE) {
+                DEFAULT_THREAD_BUFFER_SIZE = PAGE_SIZE * 2;
+            } else {
+                DEFAULT_THREAD_BUFFER_SIZE = PAGE_SIZE;
+            }
+            if (PAGE_SIZE > DEFAULT_GLOBAL_BUFFER_SIZE) {
+                DEFAULT_GLOBAL_BUFFER_SIZE = PAGE_SIZE;
+            }
+        }
+
+        final private long min;
+        final private long max;
+        final private String paramName;
+
+        private long input;
+        private Unit inputUnit;
+        private long result;
+        private Unit resultUnit;
+
+        private long getValueAsUnit(long value, Unit unit) {
+            switch (unit) {
+                case b:
+                    return value;
+                case k:
+                    return value / 1024;
+                case m:
+                    return value / (1024 * 1024);
+                case g:
+                    return value / (1024 * 1024 * 1024);
+            }
+            return value;
+        }
+
+        private long getRawValue(long value, Unit unit) {
+            switch (unit) {
+                case b:
+                    return value;
+                case k:
+                    return value * 1024;
+                case m:
+                    return value * (1024 * 1024);
+                case g:
+                    return value * (1024 * 1024 * 1024);
+            }
+            return value;
+        }
+
+        private long parseValue(String valueString, char unit) {
+            if (Character.isLetter(unit)) {
+                unit = Character.toLowerCase(unit);
+                return getRawValue(Long.parseLong(valueString.substring(0, valueString.length() - 1), 10),
+                                                  Unit.valueOf(String.valueOf(unit)));
+            }
+            // does not have a unit, default is bytes
+            return Long.parseLong(valueString.substring(0, valueString.length()), 10);
+        }
+
+        public Option(String minString, String maxString, String paramName) {
+            if (minString == null) {
+                this.min = UNDEFINED;
+            } else {
+                char unit = minString.charAt(minString.length() - 1);
+                this.min = parseValue(minString, unit);
+            }
+            if (maxString == null) {
+                this.max = UNDEFINED;
+            } else {
+                char unit = maxString.charAt(maxString.length() - 1);
+                this.max = parseValue(maxString, unit);
+            }
+            this.input = UNDEFINED;
+            this.result = UNDEFINED;
+            this.paramName = paramName;
+        }
+
+        private Option(long value, char unit) {
+            this.resultUnit = Unit.valueOf(String.valueOf(unit));
+            this.result = getRawValue(value, this.resultUnit);
+            this.min = UNDEFINED;
+            this.max = UNDEFINED;
+            this.paramName = "";
+        }
+
+        public void setInput(long value, char unit) {
+            this.inputUnit = Unit.valueOf(String.valueOf(unit));
+            this.input = getRawValue(value, this.inputUnit);
+        }
+
+        public long getInput() {
+            return input;
+        }
+
+        public void setResult(long value, char unit) {
+            this.resultUnit = Unit.valueOf(String.valueOf(unit));
+            this.result = getRawValue(value, this.resultUnit);
+        }
+
+        public long getResult() {
+            return result;
+        }
+
+        public long getResultAs(Unit unit) {
+            return getValueAsUnit(this.result, unit);
+        }
+
+        public String getOptionParamName() {
+            return paramName;
+        }
+
+        public String getOptionParamString() {
+            if (input == UNDEFINED) {
+                return null;
+            }
+            char unit = inputUnit.getUnit();
+            String unitString = Character.compare(unit, 'b') == 0 ? "" : String.valueOf(unit);
+            return getOptionParamName() + "=" + Long.toString(getValueAsUnit(input, inputUnit)) + unitString;
+        }
+
+        public boolean predictedToStartVM() {
+            if (input == UNDEFINED) {
+                // option not set
+                return true;
+            }
+            if (input >= 0) {
+                if (min != UNDEFINED) {
+                    if (max != UNDEFINED) {
+                        return input >= min && input <= max;
+                    }
+                    return input >= min;
+                }
+                if (max != UNDEFINED) {
+                    if (min != UNDEFINED) {
+                        return input <= max && input >= min;
+                    }
+                }
+                return true;
+            }
+            return false;
+        }
+
+        public boolean isSet() {
+            return input != UNDEFINED;
+        }
+
+        public boolean validate() throws IllegalArgumentException {
+            // a result memory options should be page aligned
+            if (getResult() > PAGE_SIZE) {
+                if (getResult() % PAGE_SIZE != 0) {
+                    throw new IllegalArgumentException("Result value: "
+                    + getResult() + " for option " + getOptionParamName() + " is not aligned to page size " + PAGE_SIZE);
+                }
+            }
+            // if min is defined, the result value should be gteq
+            if (min != UNDEFINED) {
+                if (getResult() < min) {
+                    throw new IllegalArgumentException("Result value: "
+                    + getResult() + " for option " + getOptionParamName() + " is less than min: " + min);
+                }
+            }
+            // if max is defined, the result values should be lteq
+            if (max != UNDEFINED) {
+                if (getResult() > max) {
+                    throw new IllegalArgumentException("Result value: "
+                    + getResult() + " for option " + getOptionParamName() + " is greater than max: " + max);
+                }
+            }
+            return true;
+        }
+
+        @Override
+        public int compareTo(Option obj) {
+            if (getResult() == obj.getResult()) {
+                return 0;
+            }
+            return getResult() > obj.getResult() ? 1 : -1;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == null) {
+                return false;
+            }
+            if (!Option.class.isAssignableFrom(obj.getClass())) {
+                return false;
+            }
+            final Option other = (Option) obj;
+
+            return getResult() == other.getResult();
+        }
+
+        @Override
+        public int hashCode() {
+            long hash = 3;
+            hash = 53 * hash * getResult();
+            return (int)hash;
+        }
+
+        @Override
+        public String toString() {
+            return Long.toString(getResult());
+        }
+
+        public Option multiply(Option rhsFactor) {
+            return new Option(getResult() * rhsFactor.getResult(), 'b');
+        }
+
+        public Option divide(Option rhsDivisor) {
+            long divisor = rhsDivisor.getResult();
+            if (divisor == 0) {
+                return new Option(0, 'b');
+            }
+            return new Option(getResult() / divisor, 'b');
+        }
+
+        boolean isLessThanOrEqual(Option rhs) {
+            return getResult() <= rhs.getResult();
+        }
+
+        boolean isGreaterThanOrEqual(Option rhs) {
+            return getResult() >= rhs.getResult();
+        }
+    }
+
+    private static class TestCase {
+        private static final int MEMORYSIZE = 0;
+        private static final int GLOBALBUFFERSIZE = 1;
+        private static final int GLOBALBUFFERCOUNT = 2;
+        private static final int THREADBUFFERSIZE = 3;
+
+        final private List<Option> optionList = new ArrayList<Option>();
+        final private String testName;
+
+        public TestCase(String testName, boolean runTest) {
+            this.testName = testName;
+            Option memorySize = new Option(Long.toString(Option.MIN_MEMORY_SIZE), null, "memorysize");
+            optionList.add(memorySize);
+
+            Option globalBufferSize = new Option(Long.toString(Option.MIN_GLOBAL_BUFFER_SIZE),
+                                                 null, "globalbuffersize");
+            optionList.add(globalBufferSize);
+
+            Option globalBufferCount = new Option(Long.toString(Option.MIN_GLOBAL_BUFFER_COUNT), null, "numglobalbuffers");
+            optionList.add(globalBufferCount);
+
+            Option threadBufferSize = new Option(Long.toString(Option.MIN_THREAD_BUFFER_SIZE), null, "threadbuffersize");
+            optionList.add(threadBufferSize);
+
+            if (runTest) {
+                populateResults();
+                validateNodes();
+                validateEdges();
+            }
+        }
+
+        public String getTestString() {
+            String optionString = "-XX:FlightRecorderOptions=";
+            for (Option o : optionList) {
+                String optionParamString = o.getOptionParamString();
+                if (optionParamString == null) {
+                    continue;
+                }
+                optionString = optionString.concat(optionParamString);
+                optionString = optionString.concat(",");
+            }
+            if (optionString.equals("-XX:FlightRecorderOptions=")) {
+                return null;
+            }
+            // strip last ","
+            optionString = optionString.substring(0, optionString.length() - 1);
+            return optionString;
+        }
+
+        public String getTestName() {
+            return this.testName;
+        }
+
+        private void setInputForIndex(int index, long size, char unit) {
+            optionList.get(index).setInput(size, unit);
+        }
+
+        private void setResultForIndex(int index, long size, char unit) {
+            optionList.get(index).setResult(size, unit);
+        }
+
+        public void setMemorySizeTestParam(long size, char unit) {
+            setInputForIndex(MEMORYSIZE, size, unit);
+        }
+
+        public void setMemorySizeTestResult(long size, char unit) {
+            setResultForIndex(MEMORYSIZE, size, unit);
+        }
+
+        public void setGlobalBufferSizeTestParam(long size, char unit) {
+            setInputForIndex(GLOBALBUFFERSIZE, size, unit);
+        }
+
+        public void setGlobalBufferSizeTestResult(long size, char unit) {
+            setResultForIndex(GLOBALBUFFERSIZE, size, unit);
+        }
+
+        public void setGlobalBufferCountTestParam(long size, char unit) {
+            setInputForIndex(GLOBALBUFFERCOUNT, size, unit);
+        }
+
+        public void setGlobalBufferCountTestResult(long size, char unit) {
+            setResultForIndex(GLOBALBUFFERCOUNT, size, unit);
+        }
+
+        public void setThreadBufferSizeTestParam(long size, char unit) {
+            setInputForIndex(THREADBUFFERSIZE, size, unit);
+        }
+
+        public void setThreadBufferSizeTestResult(long size, char unit) {
+            setResultForIndex(THREADBUFFERSIZE, size, unit);
+        }
+
+        public void validateNodes() {
+            for (Option o : optionList) {
+                o.validate();
+            }
+        }
+
+        public void validateEdges() {
+            final Option memorySize = optionList.get(MEMORYSIZE);
+            final Option globalBufferSize = optionList.get(GLOBALBUFFERSIZE);
+            final Option globalBufferCount = optionList.get(GLOBALBUFFERCOUNT);
+            final Option threadBufferSize = optionList.get(THREADBUFFERSIZE);
+
+            if (!memorySize.divide(globalBufferCount).equals(globalBufferSize)) {
+                throw new IllegalArgumentException(getTestName() + " failure: " + memorySize.getOptionParamName() + " (" + memorySize.getResult() + ") / " +
+                                                   globalBufferCount.getOptionParamName() + " (" + globalBufferCount.getResult() +
+                                                   ") (" + memorySize.divide(globalBufferCount).getResult() + ") != " +
+                                                   globalBufferSize.getOptionParamName() + " (" + globalBufferSize.getResult() + ")");
+            }
+
+            if (!globalBufferSize.multiply(globalBufferCount).equals(memorySize)) {
+                throw new IllegalArgumentException(getTestName() + " failure: " + globalBufferSize.getOptionParamName() + ": " +
+                                                   globalBufferSize.getResult() +
+                                                   " * " + globalBufferCount.getOptionParamName() + ": " + globalBufferCount.getResult() +
+                                                   " != " + memorySize.getOptionParamName() + ": " + memorySize.getResult());
+            }
+
+            if (!threadBufferSize.isLessThanOrEqual(globalBufferSize)) {
+                throw new IllegalArgumentException(getTestName() + " failure: " + threadBufferSize.getOptionParamName() + ": " + threadBufferSize.getResult() +
+                                                   " is larger than " + globalBufferSize.getOptionParamName() + ": " + globalBufferSize.getResult());
+            }
+        }
+
+        public void print() {
+            System.out.println("Printing information for testcase : " + getTestName());
+            for (Option o : optionList) {
+                System.out.println("Parameter name: " + o.getOptionParamName());
+                System.out.println("Parameter test value : " + o.getOptionParamString() != null ?  o.getOptionParamString() : "not enabled for input testing");
+                String inputString = o.getInput() == Option.UNDEFINED ? "N/A" : Long.toString(o.getInput());
+                System.out.println("Input value: " + inputString);
+                System.out.println("Predicted to start VM: " + (o.predictedToStartVM() ? "true" : "false"));
+            }
+        }
+
+        private void populateResults() {
+            optionList.get(MEMORYSIZE).setResult(Options.getMemorySize(), 'b');
+            optionList.get(GLOBALBUFFERSIZE).setResult(Options.getGlobalBufferSize(), 'b');
+            optionList.get(GLOBALBUFFERCOUNT).setResult(Options.getGlobalBufferCount(), 'b');
+            optionList.get(THREADBUFFERSIZE).setResult(Options.getThreadBufferSize(), 'b');
+        }
+
+        public boolean predictedToStartVM() {
+            // check each individual option
+            for (Option o : optionList) {
+                if (!o.predictedToStartVM()) {
+                    return false;
+                }
+            }
+
+            // check known invalid combinations that will not allow the VM to start
+
+            // GLOBALBUFFERSIZE * GLOBALBUFFERCOUNT == MEMORYSIZE
+            if (optionList.get(GLOBALBUFFERSIZE).isSet() && optionList.get(GLOBALBUFFERCOUNT).isSet()
+               && optionList.get(MEMORYSIZE).isSet()) {
+               long calculatedMemorySize = optionList.get(GLOBALBUFFERSIZE).getInput() * optionList.get(GLOBALBUFFERCOUNT).getInput();
+               if (optionList.get(MEMORYSIZE).getInput() != calculatedMemorySize) {
+                   return false;
+               }
+            }
+            // GLOBALBUFFERSIZE * GLOBALBUFFERCOUNT >= MIN_MEMORY_SIZE
+            if (optionList.get(GLOBALBUFFERSIZE).isSet() && optionList.get(GLOBALBUFFERCOUNT).isSet()
+                && !optionList.get(MEMORYSIZE).isSet()) {
+                long calculatedMemorySize = optionList.get(GLOBALBUFFERSIZE).getInput() * optionList.get(GLOBALBUFFERCOUNT).getInput();
+                if (Option.MIN_MEMORY_SIZE > calculatedMemorySize) {
+                    return false;
+                }
+            }
+            // GLOBALBUFFERSIZE >= THREADBUFFERSIZE
+            if (optionList.get(GLOBALBUFFERSIZE).isSet() && optionList.get(THREADBUFFERSIZE).isSet()) {
+                if (optionList.get(GLOBALBUFFERSIZE).getInput() < optionList.get(THREADBUFFERSIZE).getInput()) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
+    public static class SUT {
+        public static void main(String[] args) {
+            TestCase tc = new TestCase(args[0], true);
+        }
+    }
+
+    private static class Driver {
+        private static void launchTestVM(TestCase tc) throws Exception {
+            final String flightRecorderOptions = tc.getTestString();
+            ProcessBuilder pb;
+            if (flightRecorderOptions != null) {
+                pb = ProcessTools.createJavaProcessBuilder(true,
+                                                           "--add-exports=jdk.jfr/jdk.jfr.internal=ALL-UNNAMED",
+                                                           "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED",
+                                                           flightRecorderOptions,
+                                                           "-XX:StartFlightRecording",
+                                                           SUT.class.getName(),
+                                                           tc.getTestName());
+            } else {
+                // default, no FlightRecorderOptions passed
+                pb = ProcessTools.createJavaProcessBuilder(true,
+                                                           "--add-exports=jdk.jfr/jdk.jfr.internal=ALL-UNNAMED",
+                                                           "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED",
+                                                           "-XX:StartFlightRecording",
+                                                           SUT.class.getName(),
+                                                           tc.getTestName());
+            }
+
+            System.out.println("Driver launching SUT with string: " + flightRecorderOptions != null ? flightRecorderOptions : "default");
+            System.out.println("SUT VM " + (tc.predictedToStartVM() ? "is" : "is not") + " expected to start");
+            tc.print();
+
+            OutputAnalyzer out = ProcessTools.executeProcess(pb);
+
+            if (tc.predictedToStartVM()) {
+                out.shouldHaveExitValue(0);
+            } else {
+                out.shouldContain("Failure when starting JFR");
+                out.shouldHaveExitValue(1);
+            }
+        }
+
+        public static void runTestCase(TestCase tc) throws Exception {
+            launchTestVM(tc);
+        }
+    }
+
+    static private List<TestCase> testCases = new ArrayList<TestCase>();
+
+    static {
+        // positive example-based tests
+        TestCase tc = new TestCase("DefaultOptionsPositive", false);
+        // defaults, no options explicitly set
+        testCases.add(tc);
+
+        // explicit defaults passed as parameters
+        tc = new TestCase("MemorySizePositive", false);
+        tc.setMemorySizeTestParam(10, 'm');
+        testCases.add(tc);
+
+        tc = new TestCase("GlobalBufferSizePositive", false);
+        tc.setGlobalBufferSizeTestParam(512, 'k');
+        testCases.add(tc);
+
+        tc = new TestCase("BufferCountPositive", false);
+        tc.setGlobalBufferCountTestParam(20, 'b');
+        testCases.add(tc);
+
+        tc = new TestCase("ThreadBufferSizePositive", false);
+        tc.setThreadBufferSizeTestParam(Option.DEFAULT_THREAD_BUFFER_SIZE, 'b');
+        testCases.add(tc);
+
+        // negative example-based tests, each individual option below minimum size
+        tc = new TestCase("MemorySizeBelowMinNegative", false);
+        tc.setMemorySizeTestParam(Option.MIN_MEMORY_SIZE - 1, 'b');
+        testCases.add(tc);
+
+        tc = new TestCase("GlobalBufferSizeBelowMinNegative", false);
+        tc.setGlobalBufferSizeTestParam(Option.MIN_GLOBAL_BUFFER_SIZE - 1, 'b');
+        testCases.add(tc);
+
+        tc = new TestCase("BufferCountBelowMinNegative", false);
+        tc.setGlobalBufferCountTestParam(Option.MIN_GLOBAL_BUFFER_COUNT - 1, 'b');
+        testCases.add(tc);
+
+        tc = new TestCase("ThreadBufferSizeBelowMinNegative", false);
+        tc.setThreadBufferSizeTestParam(Option.MIN_THREAD_BUFFER_SIZE - 1, 'b');
+        testCases.add(tc);
+
+        // Memory size permutations
+        // a few single memorysize option for deduction
+        tc = new TestCase("MemorySizeValue1Positive", false);
+        tc.setMemorySizeTestParam(48128, 'k'); // 47mb
+        testCases.add(tc);
+
+        tc = new TestCase("MemorySizeValue2Positive", false);
+        tc.setMemorySizeTestParam(17391, 'k'); // 17808384 bytes
+        testCases.add(tc);
+
+        tc = new TestCase("MemorySizeValue3Positive", false);
+        tc.setMemorySizeTestParam(Option.MIN_MEMORY_SIZE + 17, 'b');
+        testCases.add(tc);
+
+        // positive example-based-tests, memory size combined with other options
+        tc = new TestCase("MemorySizeGlobalBufferSizePositive", false);
+        tc.setMemorySizeTestParam(14680064, 'b'); // 14mb
+        tc.setGlobalBufferSizeTestParam(720, 'k');
+        testCases.add(tc);
+
+        tc = new TestCase("MemorySizeGlobalBufferCountPositive", false);
+        tc.setMemorySizeTestParam(14674581, 'b'); // 14mb - 5483 bytes
+        tc.setGlobalBufferCountTestParam(17, 'b');
+        testCases.add(tc);
+
+        tc = new TestCase("MemorySizeThreadBufferSizePositive", false);
+        tc.setMemorySizeTestParam(14586853, 'b'); // 14mb - 93211 bytes
+        tc.setThreadBufferSizeTestParam(Option.DEFAULT_THREAD_BUFFER_SIZE, 'b');
+        testCases.add(tc);
+
+        tc = new TestCase("MemorySizeGlobalBufferSizeBufferCountPositive", false);
+        tc.setMemorySizeTestParam(12240, 'k');
+        tc.setGlobalBufferSizeTestParam(720, 'k'); // 720 k * 17 == 12240 k
+        tc.setGlobalBufferCountTestParam(17, 'b');
+        testCases.add(tc);
+
+        tc = new TestCase("MemorySizeGlobalBufferSizeBufferCountThreadBufferSizePositive", false);
+        tc.setMemorySizeTestParam(12240, 'k');
+        tc.setGlobalBufferSizeTestParam(720, 'k'); // 720 k * 17 == 12240 k
+        tc.setGlobalBufferCountTestParam(17, 'b');
+        tc.setThreadBufferSizeTestParam(600, 'k');
+        testCases.add(tc);
+
+        // negative example-based test, create an ambiguous situtation
+        tc = new TestCase("MemorySizeGlobalBufferSizeBufferCountAmbiguousNegative", false);
+        tc.setMemorySizeTestParam(12240, 'k');
+        tc.setGlobalBufferSizeTestParam(720, 'k'); // 720 k * 19 != 12240 k
+        tc.setGlobalBufferCountTestParam(19, 'b');
+        testCases.add(tc);
+
+        // Global buffer size permutations
+        tc = new TestCase("GlobalBufferSizeBufferCountPositive", false);
+        tc.setGlobalBufferSizeTestParam(917, 'k');
+        tc.setGlobalBufferCountTestParam(31, 'b');
+        testCases.add(tc);
+
+        tc = new TestCase("GlobalBufferSizeBufferCountThreadBufferSizePositive", false);
+        tc.setGlobalBufferSizeTestParam(917, 'k');
+        tc.setGlobalBufferCountTestParam(31, 'b');
+        tc.setThreadBufferSizeTestParam(760832, 'b'); // 743 k
+        testCases.add(tc);
+
+        // negative example-based test, let thread buffer size > global buffer size
+        tc = new TestCase("GlobalBufferSizeLessThanThreadBufferSizeNegative", false);
+        tc.setGlobalBufferSizeTestParam(917, 'k');
+        tc.setThreadBufferSizeTestParam(1317, 'k');
+        testCases.add(tc);
+
+        // explicitly specifying global buffer size and global buffer count must be gteq min memorysize
+        tc = new TestCase("GlobalBufferSizeTimesGlobalBufferCountLessThanMinMemorySizeNegative", false);
+        tc.setGlobalBufferSizeTestParam(67857, 'b');
+        tc.setGlobalBufferCountTestParam(3, 'b');
+        testCases.add(tc);
+
+        // absolute minimum size
+        tc = new TestCase("GlobalBufferSizeTimesGlobalBufferCountEqualToMinMemorySizePositive", false);
+        tc.setGlobalBufferSizeTestParam(64, 'k');
+        tc.setGlobalBufferCountTestParam(16, 'b');
+        testCases.add(tc);
+    }
+
+    public static void main(String[] args) throws Exception {
+        System.out.println("Testing " + testCases.size() + " number of testcases");
+        for (TestCase tc : testCases) {
+            Driver.runTestCase(tc);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/startupargs/TestOldObjectQueueSize.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.startupargs;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.internal.test.WhiteBox;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+/*
+ * @test
+ * @summary Test -XX:FlightRecorderOptions=old-object-queue-size
+ * @modules jdk.jfr/jdk.jfr.internal.test
+ * @library /test/lib
+ * @key jfr
+ *
+ * @run main/othervm -XX:TLABSize=2k -XX:-FastTLABRefill -XX:FlightRecorderOptions=old-object-queue-size=0 jdk.jfr.startupargs.TestOldObjectQueueSize off
+ * @run main/othervm -XX:TLABSize=2k -Xlog:gc+tlab=trace -XX:-FastTLABRefill -XX:FlightRecorderOptions=old-object-queue-size=10000 jdk.jfr.startupargs.TestOldObjectQueueSize many
+ * @run main/othervm -XX:TLABSize=2k -Xlog:gc+tlab=trace -XX:-FastTLABRefill -XX:FlightRecorderOptions=old-object-queue-size=1000000 jdk.jfr.startupargs.TestOldObjectQueueSize many
+ */
+public class TestOldObjectQueueSize {
+
+    private static final int OBJECT_COUNT = 10_000;
+    private static final int DEFAULT_OLD_OBJECT_QUEUE_SIZE = 256;
+
+    public final static List<Object> leak = new ArrayList<>(OBJECT_COUNT);
+
+    public static void main(String[] args) throws Exception {
+        WhiteBox.setWriteAllObjectSamples(true);
+        System.out.println("TESTING: " + args[0]);
+
+        String amount = args[0];
+        try (Recording recording = new Recording()) {
+            recording.enable(EventNames.OldObjectSample).withoutStackTrace().with("cutoff", "infinity");
+            recording.start();
+            // It's hard to get a larger number of samples without running into OOM
+            // since the TLAB size increases when there is more allocation.
+            // Allocate 200 MB, which should give at least 400 samples if the TLAB
+            // size manages to stay below 512kb, which logging with -Xlog:gc+tlab=trace indicates.
+            for (int i = 0; i < OBJECT_COUNT; i++) {
+                leak.add(new byte[20_000]);
+            }
+            recording.stop();
+            List<RecordedEvent> events = Events.fromRecording(recording);
+            System.out.println("Found samples: " + events.size());
+            if (amount.equals("off")) {
+                if (!events.isEmpty()) {
+                    throw new Exception("No objects shuld be emitted when queue size 0");
+                }
+            }
+            if (amount.equals("many")) {
+                // Sanity check that we at least have managed to set a value above the default
+                if (events.size() <= DEFAULT_OLD_OBJECT_QUEUE_SIZE) {
+                    throw new Exception("Should be at least be " + DEFAULT_OLD_OBJECT_QUEUE_SIZE + ", but found " + events.size());
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/startupargs/TestRepositoryPath.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.startupargs;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @summary Set repository path. Verify recording created in repo.
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:StartFlightRecording=name=TestStartRecording,settings=profile -XX:FlightRecorderOptions=repository=./repo jdk.jfr.startupargs.TestRepositoryPath
+ */
+public class TestRepositoryPath {
+
+    public static void main(String[] args) throws Exception {
+
+        final Path repo = Paths.get(".", "repo");
+        System.out.println("dot is " + Paths.get(".").toRealPath());
+        Asserts.assertTrue(Files.exists(repo), "Base repo path does not exist: " + repo);
+        Path recordingPath = StartupHelper.findRecordingFileInRepo(repo);
+        System.out.println("recordingPath: " + recordingPath);
+        Asserts.assertNotNull(recordingPath, "Could not find recording file in repository " + repo);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/startupargs/TestRepositoryPathLong.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.startupargs;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @summary Set repository path. Verify recording created in repo.
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:StartFlightRecording=name=myrec,settings=profile -XX:FlightRecorderOptions=repository=./subdirectory/subdirectory1/subdirectory2/subdirectory3/subdirectory4/subdirectory5/subdirectory6/subdirectory7/subdirectory8/subdirectory9/subdirectory10/subdirectory11/subdirectory12/subdirectory13/subdirectory14/subdirectory15 jdk.jfr.startupargs.TestRepositoryPathLong
+ */
+public class TestRepositoryPathLong {
+
+    public static void main(String[] args) throws Exception {
+        final Path repo = Paths.get(
+                        "./subdirectory/subdirectory1/subdirectory2/subdirectory3/subdirectory4/subdirectory5/" +
+                        "subdirectory6/subdirectory7/subdirectory8/subdirectory9/subdirectory10/subdirectory11/" +
+                        "subdirectory12/subdirectory13/subdirectory14/subdirectory15");
+        Asserts.assertTrue(Files.isDirectory(repo), "Repo path does not exist: " + repo);
+
+        Path recordingPath = StartupHelper.findRecordingFileInRepo(repo);
+        System.out.println("recordingPath: " + recordingPath);
+        Asserts.assertNotNull(recordingPath, "Could not find recording file in repository " + repo);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/startupargs/TestRetransform.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.startupargs;
+
+import jdk.jfr.Event;
+import jdk.jfr.EventType;
+import jdk.jfr.Recording;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.SimpleEvent;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm -XX:FlightRecorderOptions=retransform=false jdk.jfr.startupargs.TestRetransform
+ * @run main/othervm -XX:FlightRecorderOptions=retransform=true jdk.jfr.startupargs.TestRetransform
+ */
+public class TestRetransform {
+    private static class TestEvent extends Event {
+    }
+    public static void main(String[] args) throws Exception {
+        EventType type = EventType.getEventType(TestEvent.class);
+        if (type.isEnabled()) {
+            Asserts.fail("Expected event to be disabled before recording start");
+        }
+        Recording r = new Recording();
+        r.start();
+        if (!type.isEnabled()) {
+            Asserts.fail("Expected event to be enabled during recording");
+        }
+        TestEvent testEvent = new TestEvent();
+        testEvent.commit();
+        loadEventClassDuringRecording();
+        r.stop();
+        if (type.isEnabled()) {
+            Asserts.fail("Expected event to be disabled after recording stopped");
+        }
+        Events.hasEvent(r, SimpleEvent.class.getName());
+        Events.hasEvent(r, TestEvent.class.getName());
+    }
+
+    // Classes that are loaded during a recording
+    // should get instrumentation on class load
+    private static void loadEventClassDuringRecording() {
+        SimpleEvent event = new SimpleEvent();
+        event.commit();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/startupargs/TestRetransformUsingLog.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.startupargs;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.SimpleEvent;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.startupargs.TestRetransformUsingLog
+ */
+public class TestRetransformUsingLog {
+
+    private static final String FILE_READ_FORCED_CLASS_LOAD = "Adding forced instrumentation for event type " + EventNames.FileRead + " during initial class load";
+    private static final String SIMPLE_EVENT_FORCED_CLASS_LOAD = "Adding forced instrumentation for event type jdk.test.lib.jfr.SimpleEvent during initial class load";
+    private static final String SIMPLE_EVENT_UNFORCED_CLASS_LOAD = "Adding instrumentation for event type jdk.test.lib.jfr.SimpleEvent during initial class load";
+
+    public static class TestApp {
+        public static void main(String[] args) throws Exception {
+            SimpleEvent event = new SimpleEvent();
+            event.commit();
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        testRecordingRetransFormFalse();
+        testRecordingRetransFormTrue();
+        testNoRecordingRetransFormFalse();
+        testNoRecordingRetransFormTrue();
+    }
+
+    private static void testRecordingRetransFormFalse() throws Exception {
+        startApp(true, false, out -> {
+            out.shouldContain(FILE_READ_FORCED_CLASS_LOAD);
+            out.shouldContain(SIMPLE_EVENT_FORCED_CLASS_LOAD);
+        });
+    }
+
+    private static void testRecordingRetransFormTrue() throws Exception {
+        startApp(true, true, out -> {
+            out.shouldContain(FILE_READ_FORCED_CLASS_LOAD);
+            out.shouldContain(SIMPLE_EVENT_UNFORCED_CLASS_LOAD);
+        });
+    }
+
+    private static void testNoRecordingRetransFormFalse() throws Exception {
+        startApp(false, false, out -> {
+            out.shouldNotContain(FILE_READ_FORCED_CLASS_LOAD);
+            out.shouldContain(SIMPLE_EVENT_FORCED_CLASS_LOAD);
+        });
+    }
+
+    private static void testNoRecordingRetransFormTrue() throws Exception {
+        startApp(false, true, out -> {
+            out.shouldNotContain(FILE_READ_FORCED_CLASS_LOAD);
+            out.shouldNotContain(SIMPLE_EVENT_FORCED_CLASS_LOAD);
+            out.shouldNotContain(SIMPLE_EVENT_UNFORCED_CLASS_LOAD);
+        });
+    }
+
+    private static void startApp(boolean recording, boolean retransform, Consumer<OutputAnalyzer> verifier) throws Exception {
+        List<String> args = new ArrayList<>();
+        args.add("-Xlog:jfr+system");
+        args.add("-XX:FlightRecorderOptions=retransform=" + retransform);
+        if (recording) {
+            args.add("-XX:StartFlightRecording");
+        }
+        args.add(TestApp.class.getName());
+        System.out.println();
+        System.out.println("Starting test app:");
+        System.out.print("java ");
+        for (String arg : args) {
+            System.out.print(arg + " ");
+        }
+        System.out.println();
+        System.out.println();
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, args.toArray(new String[0]));
+        OutputAnalyzer out = ProcessTools.executeProcess(pb);
+        System.out.println(out.getOutput());
+        verifier.accept(out);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/startupargs/TestStartDelay.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.startupargs;
+
+import java.time.Duration;
+import java.time.Instant;
+
+import jdk.jfr.Recording;
+import jdk.jfr.RecordingState;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.CommonHelper;
+
+/*
+ * @test
+ * @summary Start a recording with delay. Verify recording starts later.
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:StartFlightRecording=name=TestStartDelay,delay=5000s jdk.jfr.startupargs.TestStartDelay
+ */
+public class TestStartDelay {
+
+    public static void main(String[] args) throws Exception {
+        Instant testStart = Instant.now();
+        System.out.println("Test started at " + testStart);
+        Recording r = StartupHelper.getRecording("TestStartDelay");
+        CommonHelper.verifyRecordingState(r, RecordingState.DELAYED);
+        Asserts.assertNotNull(r.getStartTime(), "Recording start time should not be null for a delayed recording");
+        Asserts.assertLessThanOrEqual(r.getStartTime(), testStart.plus(Duration.ofSeconds(5000)), "Recording start time should not exceed test start time + delay");
+        Asserts.assertGreaterThanOrEqual(r.getStartTime(), testStart, "Recording start time should not happen before test start time");
+        r.close();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/startupargs/TestStartDelayRunning.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.startupargs;
+
+import java.time.Instant;
+
+import jdk.jfr.Recording;
+import jdk.jfr.RecordingState;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.CommonHelper;
+
+/*
+ * @test
+ * @summary Verify that a recopding with a delay is started.
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:StartFlightRecording=name=TestStartDelay,delay=1s jdk.jfr.startupargs.TestStartDelayRunning
+ */
+public class TestStartDelayRunning {
+
+    public static void main(String[] args) throws Exception {
+        System.out.println("Test started at " + Instant.now());
+        Recording r = StartupHelper.getRecording("TestStartDelay");
+        CommonHelper.waitForRecordingState(r, RecordingState.RUNNING);
+        System.out.println("Recording startTime = " + r.getStartTime());
+        Asserts.assertNotNull(r.getStartTime(), "StartTime was null after delay");
+        Asserts.assertGreaterThan(Instant.now(), r.getStartTime(), "Current time should exceed start time");
+        r.stop();
+        r.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/startupargs/TestStartDuration.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.startupargs;
+
+import java.time.Duration;
+
+import jdk.jfr.Recording;
+import jdk.jfr.RecordingState;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.CommonHelper;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+/*
+ * @test
+ * @summary Start a recording with duration. Verify recording stops.
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main jdk.jfr.startupargs.TestStartDuration
+ */
+public class TestStartDuration {
+
+    public static class TestValues {
+        public static void main(String[] args) throws Exception {
+            Recording r = StartupHelper.getRecording("TestStartDuration");
+            Asserts.assertEquals(r.getDuration(), Duration.parse(args[0]));
+            if (args.length > 1 && args[1].equals("wait")) {
+                CommonHelper.waitForRecordingState(r, RecordingState.STOPPED);
+            }
+        }
+    }
+
+    private static void testDurationInRange(String duration, Duration durationString, boolean wait) throws Exception {
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true,
+            "-XX:StartFlightRecording=name=TestStartDuration,duration=" + duration, TestValues.class.getName(),
+            durationString.toString(), wait ? "wait" : "");
+        OutputAnalyzer out = ProcessTools.executeProcess(pb);
+
+        out.shouldHaveExitValue(0);
+    }
+
+
+    private static void testDurationJavaVersion(String duration, boolean inRange) throws Exception {
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true,
+            "-XX:StartFlightRecording=name=TestStartDuration,duration=" + duration, "-version");
+        OutputAnalyzer out = ProcessTools.executeProcess(pb);
+
+        if (inRange) {
+            out.shouldHaveExitValue(0);
+        } else {
+            out.shouldContain("Could not start recording, duration must be at least 1 second.");
+            out.shouldHaveExitValue(1);
+        }
+    }
+
+    private static void testDurationInRangeAccept(String duration) throws Exception {
+        testDurationJavaVersion(duration, true);
+    }
+
+    private static void testDurationOutOfRange(String duration) throws Exception {
+        testDurationJavaVersion(duration, false);
+    }
+
+    public static void main(String[] args) throws Exception {
+        testDurationInRange("1s", Duration.ofSeconds(1), true);
+        testDurationInRange("1234003005ns", Duration.ofNanos(1234003005L), true);
+        testDurationInRange("1034ms", Duration.ofMillis(1034), false);
+        testDurationInRange("32m", Duration.ofMinutes(32), false);
+        testDurationInRange("65h", Duration.ofHours(65), false);
+        testDurationInRange("354d", Duration.ofDays(354), false);
+
+        // additional test for corner values, verify that JVM accepts following durations
+        testDurationInRangeAccept("1000000000ns");
+        testDurationInRangeAccept("1000ms");
+        testDurationInRangeAccept("1m");
+        testDurationInRangeAccept("1h");
+        testDurationInRangeAccept("1d");
+
+        // out-of-range durations
+        testDurationOutOfRange("0s");
+        testDurationOutOfRange("999ms");
+        testDurationOutOfRange("999999999ns");
+        testDurationOutOfRange("0m");
+        testDurationOutOfRange("0h");
+        testDurationOutOfRange("0d");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/startupargs/TestStartMaxAgeSize.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.startupargs;
+
+import java.time.Duration;
+
+import jdk.jfr.Recording;
+import jdk.jfr.RecordingState;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.CommonHelper;
+
+/*
+ * @test
+ * @summary Start a recording with delay. Verify recording starts later.
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:StartFlightRecording=name=TestStartMaxAgeSize,maxage=10s,maxsize=1000000 jdk.jfr.startupargs.TestStartMaxAgeSize
+ */
+public class TestStartMaxAgeSize {
+
+    public static void main(String[] args) throws Exception {
+        Recording r = StartupHelper.getRecording("TestStartMaxAgeSize");
+        CommonHelper.verifyRecordingState(r, RecordingState.RUNNING);
+        Asserts.assertEquals(r.getMaxAge(), Duration.ofSeconds(10), "Wrong maxAge");
+        Asserts.assertEquals(r.getMaxSize(), 1000000L, "Wrong maxSize");
+        r.stop();
+        r.close();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/startupargs/TestStartName.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.startupargs;
+
+import jdk.jfr.Recording;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main jdk.jfr.startupargs.TestStartName
+ */
+public class TestStartName {
+
+    public static class TestName {
+        public static void main(String[] args) throws Exception {
+            Recording r = StartupHelper.getRecording(args[0]);
+            Asserts.assertNotNull(r);
+        }
+    }
+
+    private static void testName(String recordingName, boolean validName) throws Exception {
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true,
+            "-XX:StartFlightRecording=name=" + recordingName, TestName.class.getName(), recordingName);
+        OutputAnalyzer out = ProcessTools.executeProcess(pb);
+
+        if (validName) {
+            out.shouldHaveExitValue(0);
+        } else {
+            out.shouldHaveExitValue(1);
+            out.shouldContain("Name of recording can't be numeric");
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        testName("12345a", true);
+        testName("--12345", true);
+        testName("[()]", true);
+
+        // numeric names should not be accepted
+        testName("100", false);
+        testName("-327", false);
+        testName("+511", false);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/startupargs/TestStartRecording.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.startupargs;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.process.OutputAnalyzer;
+
+/*
+ * @test
+ * @summary Start a recording with -XX:StartFlightRecording. Dump recording with jcmd.
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm -XX:StartFlightRecording=name=TestStartRecording,settings=profile jdk.jfr.startupargs.TestStartRecording
+ */
+public class TestStartRecording {
+
+    public static void main(String[] args) throws Exception {
+        final String recordingName = "TestStartRecording";
+        OutputAnalyzer output = StartupHelper.jcmd("JFR.check");
+        output.shouldContain(recordingName);
+
+        Path path = Paths.get(".", "my.jfr");
+        output = StartupHelper.jcmd("JFR.dump", "name=" + recordingName, "filename=" + path);
+        Asserts.assertFalse(RecordingFile.readAllEvents(path).isEmpty(), "No events found");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/jfr/AppExecutorHelper.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib.jfr;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+
+/**
+ * Helper class for running applications with enabled JFR recording
+ */
+public class AppExecutorHelper {
+
+    /**
+     * Executes an application with enabled JFR and writes collected events
+     * to the given output file.
+     * Which events to track and other parameters are taken from the setting .jfc file.
+     *
+     * @param setting JFR settings file(optional)
+     * @param jfrFilename JFR resulting recording filename(optional)
+     * @param additionalVMFlags additional VM flags passed to the java(optional)
+     * @param className name of the class to execute
+     * @param classArguments arguments passed to the class(optional)
+     * @return output analyzer for executed application
+     */
+    public static OutputAnalyzer executeAndRecord(String settings, String jfrFilename, String[] additionalVmFlags,
+                                                  String className, String... classArguments) throws Exception {
+        List<String> arguments = new ArrayList<>();
+        String baseStartFlightRecording = "-XX:StartFlightRecording";
+        String additionalStartFlightRecording = "";
+
+        if (additionalVmFlags != null) {
+            Collections.addAll(arguments, additionalVmFlags);
+        }
+
+        if (settings != null & jfrFilename != null) {
+            additionalStartFlightRecording = String.format("=settings=%s,filename=%s", settings, jfrFilename);
+        } else if (settings != null) {
+            additionalStartFlightRecording = String.format("=settings=%s", settings);
+        } else if (jfrFilename != null) {
+            additionalStartFlightRecording = String.format("=filename=%s", jfrFilename);
+        }
+        arguments.add(baseStartFlightRecording + additionalStartFlightRecording);
+
+        arguments.add(className);
+        if (classArguments.length > 0) {
+            Collections.addAll(arguments, classArguments);
+        }
+
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, arguments.toArray(new String[0]));
+        return ProcessTools.executeProcess(pb);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/jfr/CommonHelper.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.test.lib.jfr;
+
+import static jdk.test.lib.Asserts.assertEquals;
+import static jdk.test.lib.Asserts.fail;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.RecordingState;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+
+
+/**
+ * Common helper class.
+ */
+public final class CommonHelper {
+
+    private static RecordedEvent timeStampCounterEvent;
+
+    public static void verifyException(VoidFunction f, String msg, Class<? extends Throwable> expectedException) throws Throwable {
+        try {
+            f.run();
+        } catch (Throwable t) {
+            if (expectedException.isAssignableFrom(t.getClass())) {
+                return;
+            }
+            t.printStackTrace();
+            assertEquals(t.getClass(), expectedException, "Wrong exception class");
+        }
+        fail("Missing Exception for: " + msg);
+    }
+
+    public static Recording verifyExists(long recId, List<Recording> recordings) {
+        for (Recording r : recordings) {
+            if (recId == r.getId()) {
+                return r;
+            }
+        }
+        Asserts.fail("Recording not found, id=" + recId);
+        return null;
+    }
+
+
+    public static void waitForRecordingState(Recording r, RecordingState expectedState) throws Exception {
+        while (r.getState() != expectedState) {
+            Thread.sleep(20);
+        }
+    }
+
+    public static void verifyRecordingState(Recording r, RecordingState expectedState) throws Exception {
+        assertEquals(expectedState, r.getState(), "Wrong state");
+    }
+
+    public static boolean hasFastTimeEnabled() throws Exception {
+        return getTimeStampCounterEvent().getValue("fastTimeEnabled");
+    }
+
+    private synchronized static RecordedEvent getTimeStampCounterEvent() throws IOException, Exception {
+        if (timeStampCounterEvent == null) {
+            try (Recording r = new Recording()) {
+                r.enable(EventNames.CPUTimeStampCounter);
+                r.start();
+                r.stop();
+                Path p = Files.createTempFile("timestamo", ".jfr");
+                r.dump(p);
+                List<RecordedEvent> events = RecordingFile.readAllEvents(p);
+                Files.deleteIfExists(p);
+                if (events.isEmpty()) {
+                    throw new Exception("Could not locate CPUTimeStampCounter event");
+                }
+                timeStampCounterEvent = events.get(0);
+            }
+        }
+        return timeStampCounterEvent;
+    }
+
+    public static void waitForSystemCurrentMillisToChange() {
+        long t = System.currentTimeMillis();
+        while (t != System.currentTimeMillis()) {
+            try {
+                Thread.sleep(2);
+            } catch (InterruptedException e) {
+               throw new Error("Sleep interupted", e);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/jfr/EventField.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.test.lib.jfr;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.consumer.RecordedObject;
+import jdk.test.lib.Asserts;
+
+
+public final class EventField {
+    public final RecordedObject event;
+    public final ValueDescriptor desc;
+
+    public EventField(RecordedObject event, ValueDescriptor valueDescriptor) {
+        this.event = event;
+        this.desc = valueDescriptor;
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Comparable<T>> boolean isEqual(T value) {
+        return value == (T)getValue();
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Comparable<T>> EventField equal(T value) {
+        doAssert(()-> Asserts.assertEquals((T)getValue(), value, getErrMsg("Value not equal to " + value)));
+        return this;
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Comparable<T>> EventField notEqual(T value) {
+        doAssert(()-> Asserts.assertNotEquals((T)getValue(), value, getErrMsg("Value equal to " + value)));
+        return this;
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Comparable<T>> EventField above(T value) {
+        doAssert(()-> Asserts.assertGreaterThan((T)getValue(), value, getErrMsg("Value not above " + value)));
+        return this;
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Comparable<T>> EventField below(T value) {
+        doAssert(()-> Asserts.assertLessThan((T)getValue(), value, getErrMsg("Value not below " + value)));
+        return this;
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Comparable<T>> EventField atLeast(T value) {
+        doAssert(()-> Asserts.assertGreaterThanOrEqual((T)getValue(), value, getErrMsg("Value not atLeast" + value)));
+        return this;
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Comparable<T>> EventField atMost(T value) {
+        doAssert(()-> Asserts.assertLessThanOrEqual((T)getValue(), value, getErrMsg("Value not atMost " + value)));
+        return this;
+    }
+
+    public <T extends Comparable<T>> EventField instring(String part) {
+        final String value = getValue();
+        doAssert(()-> Asserts.assertTrue(value.contains(part), getErrMsg("Value does not contain '" + part +"'")));
+        return this;
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> T getValue() {
+        return (T)event.getValue(desc.getName());
+    }
+
+    public EventField notNull() {
+        doAssert(()-> Asserts.assertNotNull(getValue(), getErrMsg("Field is null")));
+        return this;
+    }
+
+    public EventField isNull() {
+        doAssert(()-> Asserts.assertNull(getValue(), getErrMsg("Field is not null")));
+        return this;
+    }
+
+    public EventField notEmpty() {
+        notNull();
+        final String s = getValue();
+        doAssert(()-> Asserts.assertFalse(s.isEmpty(), getErrMsg("Field is empty")));
+        return this;
+    }
+
+    private void doAssert(AssertFunction f) {
+        try {
+            f.doAssert();
+        } catch (RuntimeException e) {
+            System.out.printf("Error: %s%nFailed event:%n%s%n", e.getMessage(), event.toString());
+            throw e;
+        }
+    }
+
+    public EventField containsAny(String... allowed) {
+        final String value = getValue();
+        final List<String> allowedValues = Arrays.asList(allowed);
+        boolean contains = false;
+        for(String allowedValue : allowed) {
+            if (value.contains(allowedValue))  {
+                contains = true;
+            }
+        }
+        if (!contains) {
+            doAssert(()-> Asserts.fail(getErrMsg(String.format("Value not in (%s)",
+                allowedValues.stream().collect(Collectors.joining(", "))))));
+        }
+        return this;
+    }
+
+    private String getErrMsg(String msg) {
+        final String name = desc.getName();
+        final Object value = event.getValue(name);
+        return String.format("%s, field='%s', value='%s'", msg, name, value);
+    }
+
+    @FunctionalInterface
+    public interface AssertFunction {
+        void doAssert();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/jfr/EventNames.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.test.lib.jfr;
+
+import jdk.jfr.EventType;
+
+/**
+ * Contains id for events that are shipped with the JDK.
+ *
+ */
+public class EventNames {
+
+    public final static String PREFIX = "jdk.";
+    private static final String GC_CATEGORY = "GC";
+
+    // JVM Configuration
+    public final static String JVMInformation = PREFIX + "JVMInformation";
+    public final static String InitialSystemProperty = PREFIX + "InitialSystemProperty";
+    public final static String IntFlag = PREFIX + "IntFlag";
+    public final static String UnsignedIntFlag = PREFIX + "UnsignedIntFlag";
+    public final static String LongFlag = PREFIX + "LongFlag";
+    public final static String UnsignedLongFlag = PREFIX + "UnsignedLongFlag";
+    public final static String DoubleFlag = PREFIX + "DoubleFlag";
+    public final static String BooleanFlag = PREFIX + "BooleanFlag";
+    public final static String StringFlag = PREFIX + "StringFlag";
+    public final static String IntFlagChanged = PREFIX + "IntFlagChanged";
+    public final static String UnsignedIntFlagChanged = PREFIX + "UnsignedIntFlagChanged";
+    public final static String LongFlagChanged = PREFIX + "LongFlagChanged";
+    public final static String UnsignedLongFlagChanged = PREFIX + "UnsignedLongFlagChanged";
+    public final static String DoubleFlagChanged = PREFIX + "DoubleFlagChanged";
+    public final static String BooleanFlagChanged = PREFIX + "BooleanFlagChanged";
+    public final static String StringFlagChanged = PREFIX + "StringFlagChanged";
+
+    // Runtime
+    public final static String VMException = PREFIX + "JavaErrorThrow";
+    public final static String ThreadStart = PREFIX + "ThreadStart";
+    public final static String ThreadEnd = PREFIX + "ThreadEnd";
+    public final static String ThreadSleep = PREFIX + "ThreadSleep";
+    public final static String ThreadPark = PREFIX + "ThreadPark";
+    public final static String JavaMonitorEnter = PREFIX + "JavaMonitorEnter";
+    public final static String JavaMonitorWait = PREFIX + "JavaMonitorWait";
+    public final static String JavaMonitorInflate = PREFIX + "JavaMonitorInflate";
+    public final static String ClassLoad = PREFIX + "ClassLoad";
+    public final static String ClassDefine = PREFIX + "ClassDefine";
+    public final static String ClassUnload = PREFIX + "ClassUnload";
+    public final static String SafepointBegin = PREFIX + "SafepointBegin";
+    public final static String SafepointStateSyncronization = PREFIX + "SafepointStateSynchronization";
+    public final static String SafepointWaitBlocked = PREFIX + "SafepointWaitBlocked";
+    public final static String SafepointCleanup = PREFIX + "SafepointCleanup";
+    public final static String SafepointCleanupTask = PREFIX + "SafepointCleanupTask";
+    public final static String SafepointEnd = PREFIX + "SafepointEnd";
+    public final static String ExecuteVMOperation = PREFIX + "ExecuteVMOperation";
+    public final static String Shutdown = PREFIX + "Shutdown";
+    public final static String VMError = PREFIX + "VMError";
+    public final static String JavaThreadStatistics = PREFIX + "JavaThreadStatistics";
+    public final static String ClassLoadingStatistics = PREFIX + "ClassLoadingStatistics";
+    public final static String ClassLoaderStatistics = PREFIX + "ClassLoaderStatistics";
+    public final static String ThreadAllocationStatistics = PREFIX + "ThreadAllocationStatistics";
+    public final static String ExecutionSample = PREFIX + "ExecutionSample";
+    public final static String NativeMethodSample = PREFIX + "NativeMethodSample";
+    public final static String ExecutionSampling = PREFIX + "ExecutionSampling";
+    public final static String ThreadDump = PREFIX + "ThreadDump";
+    public final static String OldObjectSample = PREFIX + "OldObjectSample";
+    public final static String BiasedLockRevocation = PREFIX + "BiasedLockRevocation";
+    public final static String BiasedLockSelfRevocation = PREFIX + "BiasedLockSelfRevocation";
+    public final static String BiasedLockClassRevocation = PREFIX + "BiasedLockClassRevocation";
+
+    // GC
+    public final static String GCHeapSummary = PREFIX + "GCHeapSummary";
+    public final static String MetaspaceSummary = PREFIX + "MetaspaceSummary";
+    public final static String MetaspaceGCThreshold = PREFIX + "MetaspaceGCThreshold";
+    public final static String MetaspaceAllocationFailure = PREFIX + "MetaspaceAllocationFailure";
+    public final static String MetaspaceOOM = PREFIX + "MetaspaceOOM";
+    public final static String MetaspaceChunkFreeListSummary = PREFIX + "MetaspaceChunkFreeListSummary";
+    public final static String PSHeapSummary = PREFIX + "PSHeapSummary";
+    public final static String G1HeapSummary = PREFIX + "G1HeapSummary";
+    public final static String G1HeapRegionInformation = PREFIX + "G1HeapRegionInformation";
+    public final static String G1HeapRegionTypeChange = PREFIX + "G1HeapRegionTypeChange";
+    public final static String TenuringDistribution = PREFIX + "TenuringDistribution";
+    public final static String GarbageCollection = PREFIX + "GarbageCollection";
+    public final static String ParallelOldCollection = PREFIX + "ParallelOldGarbageCollection";
+    public final static String YoungGarbageCollection = PREFIX + "YoungGarbageCollection";
+    public final static String OldGarbageCollection = PREFIX + "OldGarbageCollection";
+    public final static String G1GarbageCollection = PREFIX + "G1GarbageCollection";
+    public final static String G1MMU = PREFIX + "G1MMU";
+    public final static String EvacuationInfo = PREFIX + "EvacuationInfo";
+    public final static String GCReferenceStatistics = PREFIX + "GCReferenceStatistics";
+    public final static String ObjectCountAfterGC = PREFIX + "ObjectCountAfterGC";
+    public final static String PromoteObjectInNewPLAB = PREFIX + "PromoteObjectInNewPLAB";
+    public final static String PromoteObjectOutsidePLAB = PREFIX + "PromoteObjectOutsidePLAB";
+    public final static String PromotionFailed = PREFIX + "PromotionFailed";
+    public final static String EvacuationFailed = PREFIX + "EvacuationFailed";
+    public final static String ConcurrentModeFailure = PREFIX + "ConcurrentModeFailure";
+    public final static String GCPhasePause = PREFIX + "GCPhasePause";
+    public final static String GCPhasePauseLevel1 = PREFIX + "GCPhasePauseLevel1";
+    public final static String GCPhasePauseLevel2 = PREFIX + "GCPhasePauseLevel2";
+    public final static String GCPhasePauseLevel3 = PREFIX + "GCPhasePauseLevel3";
+    public final static String ObjectCount = PREFIX + "ObjectCount";
+    public final static String GCConfiguration = PREFIX + "GCConfiguration";
+    public final static String GCSurvivorConfiguration = PREFIX + "GCSurvivorConfiguration";
+    public final static String GCTLABConfiguration = PREFIX + "GCTLABConfiguration";
+    public final static String GCHeapConfiguration = PREFIX + "GCHeapConfiguration";
+    public final static String YoungGenerationConfiguration = PREFIX + "YoungGenerationConfiguration";
+    public final static String G1AdaptiveIHOP = PREFIX + "G1AdaptiveIHOP";
+    public final static String G1EvacuationYoungStatistics = PREFIX + "G1EvacuationYoungStatistics";
+    public final static String G1EvacuationOldStatistics = PREFIX + "G1EvacuationOldStatistics";
+    public final static String G1BasicIHOP = PREFIX + "G1BasicIHOP";
+    public final static String AllocationRequiringGC = PREFIX + "AllocationRequiringGC";
+
+    // Compiler
+    public final static String Compilation = PREFIX + "Compilation";
+    public final static String CompilerPhase = PREFIX + "CompilerPhase";
+    public final static String CompilationFailure = PREFIX + "CompilationFailure";
+    public final static String CompilerInlining = PREFIX + "CompilerInlining";
+    public final static String CompilerStatistics = PREFIX + "CompilerStatistics";
+    public final static String CompilerConfig = PREFIX + "CompilerConfiguration";
+    public final static String CodeCacheStatistics = PREFIX + "CodeCacheStatistics";
+    public final static String CodeCacheConfiguration = PREFIX + "CodeCacheConfiguration";
+    public final static String CodeSweeperStatistics = PREFIX + "CodeSweeperStatistics";
+    public final static String CodeSweeperConfiguration = PREFIX + "CodeSweeperConfiguration";
+    public final static String SweepCodeCache = PREFIX + "SweepCodeCache";
+    public final static String CodeCacheFull = PREFIX + "CodeCacheFull";
+    public final static String ObjectAllocationInNewTLAB = PREFIX + "ObjectAllocationInNewTLAB";
+    public final static String ObjectAllocationOutsideTLAB = PREFIX + "ObjectAllocationOutsideTLAB";
+
+    // OS
+    public final static String OSInformation = PREFIX + "OSInformation";
+    public final static String CPUInformation = PREFIX + "CPUInformation";
+    public final static String CPULoad = PREFIX + "CPULoad";
+    public final static String ThreadCPULoad = PREFIX + "ThreadCPULoad";
+    public final static String SystemProcess = PREFIX + "SystemProcess";
+    public final static String ThreadContextSwitchRate = PREFIX + "ThreadContextSwitchRate";
+    public final static String InitialEnvironmentVariable = PREFIX + "InitialEnvironmentVariable";
+    public final static String NativeLibrary = PREFIX + "NativeLibrary";
+    public final static String PhysicalMemory = PREFIX + "PhysicalMemory";
+
+    // JDK
+    public static final String FileForce  = PREFIX + "FileForce";
+    public static final String FileRead = PREFIX + "FileRead";
+    public static final String FileWrite = PREFIX + "FileWrite";
+    public static final String SocketRead = PREFIX + "SocketRead";
+    public static final String SocketWrite = PREFIX + "SocketWrite";
+    public final static String ExceptionStatistics = PREFIX + "ExceptionStatistics";
+    public final static String JavaExceptionThrow = PREFIX + "JavaExceptionThrow";
+    public final static String JavaErrorThrow = PREFIX + "JavaErrorThrow";
+    public final static String ModuleRequire = PREFIX + "ModuleRequire";
+    public final static String ModuleExport = PREFIX + "ModuleExport";
+
+    // Flight Recorder
+    public final static String DumpReason = PREFIX + "DumpReason";
+    public final static String DataLoss = PREFIX + "DataLoss";
+    public final static String CPUTimeStampCounter = PREFIX + "CPUTimeStampCounter";
+    public final static String ActiveRecording = PREFIX + "ActiveRecording";
+    public final static String ActiveSetting = PREFIX + "ActiveSetting";
+
+    public static boolean isGcEvent(EventType et) {
+        return et.getCategoryNames().contains(GC_CATEGORY);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/jfr/EventTypePrototype.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.test.lib.jfr;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.Name;
+import jdk.jfr.ValueDescriptor;
+
+public final class EventTypePrototype {
+    private final List<ValueDescriptor> fields;
+    private final List<AnnotationElement> annotations;
+    private final String name;
+
+    public EventTypePrototype(String name, List<AnnotationElement> as, List<ValueDescriptor> fields) {
+        this.annotations = new ArrayList<>(as);
+        this.annotations.add(new AnnotationElement(Name.class, name));
+        this.fields = fields;
+        this.name = name;
+    }
+
+    public EventTypePrototype(String name) {
+        this(name, new ArrayList<>(), new ArrayList<>());
+    }
+
+    public int getFieldIndex(String key) {
+        int index = 0;
+        for (ValueDescriptor f : fields) {
+            if (f.getName().equals(key)) {
+                return index;
+            }
+            index++;
+        }
+        throw new NoSuchFieldError(key);
+    }
+
+    public void addField(ValueDescriptor fieldDescriptor) {
+        fields.add(fieldDescriptor);
+    }
+
+    public void addAnnotation(AnnotationElement annotation) {
+        annotations.add(annotation);
+    }
+
+    public List<ValueDescriptor> getFields() {
+        return fields;
+    }
+
+    public List<AnnotationElement> getAnnotations() {
+        return annotations;
+    }
+
+    public String getName() {
+        return name;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/jfr/EventVerifier.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.test.lib.jfr;
+
+import jdk.jfr.consumer.RecordedEvent;
+
+public abstract class EventVerifier {
+    protected final RecordedEvent event;
+
+    public EventVerifier(RecordedEvent event) {
+        this.event = event;
+    }
+
+    public <T extends Comparable<T>> void verifyEquals(String name, T value) {
+        Events.assertField(event, name).equal(value);
+    }
+
+    public void verifyContains(String name, String value) {
+        Events.assertField(event, name).containsAny(value);
+    }
+
+    protected long gigabytes(int num) {
+        return num * 1024L * 1024L * 1024L;
+    }
+
+    protected long megabytes(int num) {
+        return num * 1024L * 1024L;
+    }
+
+    public abstract void verify() throws Exception;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/jfr/Events.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.test.lib.jfr;
+
+import static jdk.test.lib.Asserts.assertEquals;
+import static jdk.test.lib.Asserts.assertFalse;
+import static jdk.test.lib.Asserts.assertNotNull;
+import static jdk.test.lib.Asserts.assertTrue;
+import static jdk.test.lib.Asserts.fail;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.List;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.EventType;
+import jdk.jfr.Recording;
+import jdk.jfr.SettingDescriptor;
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+import jdk.jfr.consumer.RecordedClass;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedObject;
+import jdk.jfr.consumer.RecordedThread;
+import jdk.jfr.consumer.RecordedThreadGroup;
+
+
+/**
+ * Helper class to verify RecordedEvent content
+ */
+public class Events {
+
+    public static EventField assertField(RecordedEvent event, String name)  {
+        String[] partNames = name.split("\\.");
+        RecordedObject struct = event;
+        try {
+            for (int i=0; i<partNames.length; ++i) {
+                final String partName =  partNames[i];
+                final boolean isLastPart = i == partNames.length - 1;
+                ValueDescriptor d = getValueDescriptor(struct, partName);
+                if (isLastPart) {
+                    return new EventField(struct, d);
+                } else {
+                    assertTrue(struct.getValue(partName) instanceof RecordedObject, "Expected '" + partName + "' to be a struct");
+                    struct = struct.getValue(partName);
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        System.out.printf("Failed event:%n%s%n", event.toString());
+        fail(String.format("Field %s not in event", name));
+        return null;
+    }
+
+    private static RecordedObject getRecordedPackage(final RecordedClass rc) {
+        if (rc == null) {
+            throw new RuntimeException("RecordedClass must not be null!");
+        }
+        return rc.getValue("package");
+    }
+
+    private static RecordedObject getRecordedModule(final RecordedObject pkg) {
+        if (pkg == null) {
+            // null package is an unnamed module (null)
+            return null;
+        }
+
+        return pkg.getValue("module");
+    }
+    /**
+     * Validates the recored name field
+     *
+     * @param ro should be a Package or a Module
+     * @param targetName name to match
+     */
+    private static boolean isMatchingTargetName(final RecordedObject ro, final String targetName) {
+        if (ro == null) {
+            return targetName == null;
+        }
+
+        final String recordedName = ro.getValue("name");
+
+        if (recordedName == null) {
+            return targetName == null;
+        }
+
+        return recordedName.equals(targetName);
+    }
+
+    public static void assertClassPackage(final RecordedClass rc, final String packageNameTarget) {
+        final RecordedObject recordedPackage = getRecordedPackage(rc);
+
+        if (recordedPackage == null) {
+            if (packageNameTarget != null) {
+                throw new RuntimeException("RecordedClass package is null!");
+            }
+            return;
+        }
+        assertTrue(isMatchingTargetName(recordedPackage, packageNameTarget), "mismatched package name! Target is " + packageNameTarget);
+    }
+
+    public static void assertClassModule(final RecordedClass rc, final String moduleNameTarget) {
+        final RecordedObject recordedPackage = getRecordedPackage(rc);
+        final RecordedObject recordedModule = getRecordedModule(recordedPackage);
+
+        if (recordedModule == null) {
+            if (moduleNameTarget != null) {
+                throw new RuntimeException("RecordedClass module is null!");
+            }
+            return;
+        }
+
+       assertTrue(isMatchingTargetName(recordedModule, moduleNameTarget), "mismatched module name! Target is " + moduleNameTarget);
+    }
+
+    private static ValueDescriptor getValueDescriptor(RecordedObject struct, String name) throws Exception {
+        List<ValueDescriptor> valueDescriptors = struct.getFields();
+        for (ValueDescriptor d : valueDescriptors) {
+            if (name.equals(d.getName())) {
+                return d;
+            }
+        }
+        System.out.printf("Failed struct:%s", struct.toString());
+        fail(String.format("Field %s not in struct", name));
+        return null;
+    }
+
+    public static void hasEvents(List<RecordedEvent> events) {
+        assertFalse(events.isEmpty(), "No events");
+    }
+
+    public static void hasEvents(RecordingFile file) {
+        assertTrue(file.hasMoreEvents(), "No events");
+    }
+
+    public static void assertEventThread(RecordedEvent event) {
+        RecordedThread eventThread = event.getThread();
+        if (eventThread == null) {
+            System.out.printf("Failed event:%n%s%n", event.toString());
+            fail("No thread in event");
+        }
+    }
+
+    public static void assertJavaMethod(RecordedEvent event) {
+        assertField(event, "method.name").notEmpty();
+        assertField(event, "method.descriptor").notEmpty();
+        assertField(event, "method.modifiers").atLeast(0);
+        assertField(event, "method.hidden");
+        assertField(event, "method.type.name").notEmpty();
+        assertField(event, "method.type.modifiers").atLeast(0);
+    }
+
+    public static void assertEventThread(RecordedEvent event, Thread thread) {
+        assertThread(event.getThread(), thread);
+    }
+
+    public static void assertEventThread(RecordedEvent event, String structName, Thread thread) {
+        assertThread(assertField(event, structName).notNull().getValue(), thread);
+    }
+
+    private static void assertThread(RecordedThread eventThread, Thread thread) {
+        assertNotNull(eventThread, "Thread in event was null");
+        assertEquals(eventThread.getJavaThreadId(), thread.getId(), "Wrong thread id");
+        assertEquals(eventThread.getJavaName(), thread.getName(), "Wrong thread name");
+
+        ThreadGroup threadGroup = thread.getThreadGroup();
+        RecordedThreadGroup eventThreadGroup = eventThread.getThreadGroup();
+        assertNotNull(eventThreadGroup, "eventThreadGroup was null");
+
+        // Iterate and check all threadGroups
+        while (eventThreadGroup != null) {
+            final String groupName = eventThreadGroup.getName();
+            if (threadGroup != null) {
+                assertEquals(groupName, threadGroup.getName(), "Wrong threadGroup name");
+                threadGroup = threadGroup.getParent();
+            } else {
+                assertNotNull(groupName, "threadGroup name was null");
+                assertFalse(groupName.isEmpty(), "threadGroup name was empty");
+            }
+            eventThreadGroup = eventThreadGroup.getParent();
+        }
+    }
+
+    public static boolean hasField(RecordedEvent event, String name) {
+        return event.getFields().stream().map(vd -> vd.getName()).anyMatch(s -> s.equals(name));
+    }
+
+    public static boolean isEventType(RecordedEvent event, String typeName) {
+        return typeName.equals(event.getEventType().getName());
+    }
+
+
+    /**
+     * Creates a list of events from a recording.
+     *
+     * @param recording recording, not {@code null}
+     * @return an a list, not null
+     * @throws IOException if an event set could not be created due to I/O
+     *         errors.
+     */
+    public static List<RecordedEvent> fromRecording(Recording recording) throws IOException {
+        return RecordingFile.readAllEvents(makeCopy(recording));
+    }
+
+    public static RecordingFile copyTo(Recording r) throws IOException {
+        return new RecordingFile(makeCopy(r));
+    }
+
+    private static Path makeCopy(Recording recording) throws IOException {
+        Path p = recording.getDestination();
+        if (p == null) {
+            File directory = new File(".");
+            // FIXME: Must come up with a way to give human-readable name
+            // this will at least not clash when running parallel.
+            ProcessHandle h = ProcessHandle.current();
+            p = new File(directory.getAbsolutePath(), "recording-" + recording.getId() + "-pid" + h.pid() + ".jfr").toPath();
+            recording.dump(p);
+        }
+        return p;
+    }
+
+   public static void hasAnnotation(ValueDescriptor field, Class<? extends java.lang.annotation.Annotation> annotationClass) throws Exception {
+       AnnotationElement a = getAnnotation(field, annotationClass);
+       if (a == null) {
+           throw new Exception("Expected " + annotationClass.getSimpleName() + " on field " + field.getName());
+       }
+   }
+
+   public static void assertAnnotation(ValueDescriptor field, Class<? extends java.lang.annotation.Annotation> annotationClass, String value) throws Exception {
+       AnnotationElement a = getAnnotation(field, annotationClass);
+       Object v = a.getValue("value");
+       if (!v.equals(value)) {
+           throw new Exception("Expected " + annotationClass.getSimpleName() + " on field " + field.getName() + " to have value " + value + ", but got " + v);
+       }
+   }
+
+   // candidate for moving into API
+   public static AnnotationElement getAnnotation(ValueDescriptor v, Class<?> clazz) throws Exception {
+      for (AnnotationElement a : v.getAnnotationElements()) {
+          if (a.getTypeName().equals(clazz.getName())) {
+              return a;
+          }
+      }
+
+      throw new Exception("Could not find annotation " + clazz.getName());
+  }
+
+   // candidate for moving into API
+   public static AnnotationElement getAnnotationByName(EventType t, String name) throws Exception {
+       for (AnnotationElement a : t.getAnnotationElements()) {
+           if (a.getTypeName().equals(name)) {
+               return a;
+           }
+       }
+       throw new Exception("Could not find annotation '" + name + " in type " + t.getName());
+   }
+
+    // candidate for moving into API
+    public static SettingDescriptor getSetting(EventType type, String name) {
+        for (SettingDescriptor s : type.getSettingDescriptors()) {
+            if (s.getName().equals(name)) {
+                return s;
+            }
+        }
+        throw new IllegalArgumentException("Could not setting with name " + name);
+    }
+
+    public static void hasEvent(Recording r, String name) throws IOException {
+        List<RecordedEvent> events = fromRecording(r);
+        Events.hasEvents(events);
+        Events.hasEvent(events, name);
+    }
+
+    public static void hasEvent(List<RecordedEvent> events, String name) throws IOException {
+        if (!containsEvent(events, name)) {
+            Asserts.fail("Missing event " + name  + " in recording " + events.toString());
+        }
+    }
+
+    public static void hasNotEvent(List<RecordedEvent> events, String name) throws IOException {
+        if (containsEvent(events, name)) {
+            Asserts.fail("Rercording should not contain event " + name  + " " + events.toString());
+        }
+    }
+
+    private static boolean containsEvent(List<RecordedEvent> events, String name) {
+        for (RecordedEvent event : events) {
+            if (event.getEventType().getName().equals(name)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/jfr/FileHelper.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.test.lib.jfr;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.AccessDeniedException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+
+/**
+ * Common helper class.
+ */
+public class FileHelper {
+
+    public static Path getDest(String subPath) throws IOException {
+        Path path = Paths.get(subPath + "/test.jfr");
+        Path parent = path.getParent();
+        if (parent == null) {
+            throw new IOException("No parent cound be found for path " + subPath);
+        }
+        Files.createDirectories(parent);
+        return path;
+    }
+
+    public static Path createLongDir(Path root) throws IOException {
+        final int minPathLength = 400;
+        StringBuilder buff = new StringBuilder();
+        buff.append(root.toString());
+        while (buff.length() < minPathLength) {
+            buff.append("/veryLongPath012345678901234567890123456789");
+        }
+        Path path = Paths.get(buff.toString());
+        System.out.println("long dir=" + path);
+        Files.createDirectories(path);
+        return path;
+    }
+
+    public static Path getDestReadOnly(String subPath) throws IOException {
+        final Path path = getDest(subPath);
+        Path parent = path.getParent();
+        if (parent == null) {
+            throw new IOException("No parent cound be found for path " + subPath);
+        }
+        parent.toFile().setReadOnly();
+        return path;
+    }
+
+    public static Path createReadOnlyFile(Path path) throws IOException {
+        final Path createdPath = Files.createFile(path);
+        createdPath.toFile().setReadOnly();
+        return createdPath;
+    }
+
+    public static Path createReadOnlyDir(Path path) throws IOException {
+        final Path createdPath = Files.createDirectories(path);
+        createdPath.toFile().setReadOnly();
+        return createdPath;
+    }
+
+    public static Path getDestNotExist() {
+        return Paths.get(".", "thisDirDoesNotExist/test.jfr");
+    }
+
+    public static boolean isReadOnlyPath(Path path) throws IOException {
+        // Files.isWritable(path) can not really be trusted. At least not on Windows.
+        // If path is a directory, we try to create a new file in it.
+        if (Files.isDirectory(path)) {
+            try {
+                Path f = Files.createFile(Paths.get(path.toString(), "dummyFileToCheckReadOnly"));
+                System.out.printf("Dir is not read-only, created %s, exists=%b%n", f, Files.exists(f));
+                return false;
+            } catch (AccessDeniedException e) {
+                System.out.printf("'%s' verified read-only by %s%n", path, e.toString());
+                return true;
+            }
+        } else {
+            boolean isReadOnly = !Files.isWritable(path);
+            System.out.format("isReadOnly '%s': %b%n", path, isReadOnly);
+            return isReadOnly;
+        }
+    }
+
+    public static void verifyRecording(File file) throws Exception {
+        Asserts.assertTrue(file.exists(), file.getAbsolutePath() + " does not exist");
+        Asserts.assertTrue(file.isFile(), file.getAbsolutePath() + " is not a file");
+        Asserts.assertGreaterThan(file.length(), 0L, "Size of recording is 0.");
+        List<RecordedEvent> events = RecordingFile.readAllEvents(file.toPath());
+        for (RecordedEvent event : events) {
+            System.out.printf("First event in recording '%s':%n%s", file.getName(), event);
+            return;
+        }
+        Asserts.fail("No events in file " + file.getName());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/jfr/GCHelper.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,467 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.test.lib.jfr;
+
+import static jdk.test.lib.Asserts.assertEquals;
+import static jdk.test.lib.Asserts.assertNotEquals;
+import static jdk.test.lib.Asserts.assertNotNull;
+import static jdk.test.lib.Asserts.assertNull;
+import static jdk.test.lib.Asserts.fail;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.lang.management.GarbageCollectorMXBean;
+import java.lang.management.ManagementFactory;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Stack;
+
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.consumer.RecordedEvent;
+
+/**
+ * Mixed helper classes to test GC events.
+ */
+public class GCHelper {
+    public static final String event_garbage_collection = EventNames.GarbageCollection;
+    public static final String event_young_garbage_collection = EventNames.YoungGarbageCollection;
+    public static final String event_old_garbage_collection = EventNames.OldGarbageCollection;
+    public static final String event_parold_garbage_collection = EventNames.ParallelOldCollection;
+    public static final String event_g1_garbage_collection = EventNames.G1GarbageCollection;
+    public static final String event_heap_summary = EventNames.GCHeapSummary;
+    public static final String event_heap_ps_summary = EventNames.PSHeapSummary;
+    public static final String event_heap_metaspace_summary = EventNames.MetaspaceSummary;
+    public static final String event_reference_statistics = EventNames.GCReferenceStatistics;
+    public static final String event_phases_pause = EventNames.GCPhasePause;
+    public static final String event_phases_level_1 = EventNames.GCPhasePauseLevel1;
+    public static final String event_phases_level_2 = EventNames.GCPhasePauseLevel2;
+    public static final String event_phases_level_3 = EventNames.GCPhasePauseLevel3;
+
+    public static final String gcG1New = "G1New";
+    public static final String gcParNew = "ParNew";
+    public static final String gcDefNew = "DefNew";
+    public static final String gcParallelScavenge = "ParallelScavenge";
+    public static final String gcG1Old = "G1Old";
+    public static final String gcG1Full = "G1Full";
+    public static final String gcConcurrentMarkSweep = "ConcurrentMarkSweep";
+    public static final String gcSerialOld = "SerialOld";
+    public static final String gcPSMarkSweep = "PSMarkSweep";
+    public static final String gcParallelOld = "ParallelOld";
+    public static final String pauseLevelEvent = "GCPhasePauseLevel";
+
+    private static final List<String> g1HeapRegionTypes;
+    private static PrintStream defaultErrorLog = null;
+
+    public static int getGcId(RecordedEvent event) {
+        return Events.assertField(event, "gcId").getValue();
+    }
+
+    public static boolean isGcEvent(RecordedEvent event) {
+        for (ValueDescriptor v : event.getFields()) {
+            if ("gcId".equals(v.getName())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+//    public static String getEventDesc(RecordedEvent event) {
+//      final String path = event.getEventType().getName();
+//        if (!isGcEvent(event)) {
+//            return path;
+//        }
+//        if (event_garbage_collection.equals(path)) {
+//            String name = Events.assertField(event, "name").getValue();
+//            String cause = Events.assertField(event, "cause").getValue();
+//            return String.format("path=%s, gcId=%d, endTime=%d, name=%s, cause=%s, startTime=%d",
+//                    path, getGcId(event), event.getEndTime(), name, cause, event.getStartTime());
+//        } else {
+//            return String.format("path=%s, gcId=%d, endTime=%d", path, getGcId(event), event.getEndTime());
+//        }
+//    }
+
+    public static RecordedEvent getConfigEvent(List<RecordedEvent> events) throws Exception {
+        for (RecordedEvent event : events) {
+            if (EventNames.GCConfiguration.equals(event.getEventType().getName())) {
+                return event;
+            }
+        }
+        fail("Could not find event " + EventNames.GCConfiguration);
+        return null;
+    }
+
+    public static void callSystemGc(int num, boolean withGarbage) {
+        for (int i = 0; i < num; i++) {
+            if (withGarbage) {
+                makeGarbage();
+            }
+            System.gc();
+        }
+    }
+
+    private static void makeGarbage() {
+        Object[] garbage = new Object[1024];
+        for (int i = 0; i < 1024; i++) {
+            garbage[i] = new Object();
+        }
+    }
+
+    // Removes gcEvents with lowest and highest gcID. This is used to filter out
+    // any incomplete GCs if the recording started/stopped in the middle of a GC.
+    // We also filters out events without gcId. Those events are not needed.
+    public static List<RecordedEvent> removeFirstAndLastGC(List<RecordedEvent> events) {
+        int minGcId = Integer.MAX_VALUE;
+        int maxGcId = Integer.MIN_VALUE;
+        // Find min/max gcId
+        for (RecordedEvent event : events) {
+            if (Events.hasField(event, "gcId")) {
+                int gcId = Events.assertField(event, "gcId").getValue();
+                minGcId = Math.min(gcId, minGcId);
+                maxGcId = Math.max(gcId, maxGcId);
+            }
+        }
+
+        // Add all events except those with gcId = min/max gcId
+        List<RecordedEvent> filteredEvents = new ArrayList<>();
+        for (RecordedEvent event : events) {
+            if (Events.hasField(event, "gcId")) {
+                int gcId = Events.assertField(event, "gcId").getValue();
+                if (gcId != minGcId && gcId != maxGcId) {
+                    filteredEvents.add(event);
+                }
+            }
+        }
+        return filteredEvents;
+    }
+
+    public static Map<String, Boolean> beanCollectorTypes = new HashMap<>();
+    public static Set<String> collectorOverrides = new HashSet<>();
+    public static Map<String, String[]> requiredEvents = new HashMap<>();
+
+    static {
+        // young GarbageCollectionMXBeans.
+        beanCollectorTypes.put("G1 Young Generation", true);
+        beanCollectorTypes.put("Copy", true);
+        beanCollectorTypes.put("PS Scavenge", true);
+        beanCollectorTypes.put("ParNew", true);
+
+        // old GarbageCollectionMXBeans.
+        beanCollectorTypes.put("G1 Old Generation", false);
+        beanCollectorTypes.put("ConcurrentMarkSweep", false);
+        beanCollectorTypes.put("PS MarkSweep", false);
+        beanCollectorTypes.put("MarkSweepCompact", false);
+
+        // List of expected collector overrides. "A.B" means that collector A may use collector B.
+        collectorOverrides.add("G1Old.G1Full");
+        collectorOverrides.add("ConcurrentMarkSweep.SerialOld");
+        collectorOverrides.add("SerialOld.PSMarkSweep");
+
+        requiredEvents.put(gcG1New, new String[] {event_heap_summary, event_young_garbage_collection});
+        requiredEvents.put(gcParNew, new String[] {event_heap_summary, event_heap_metaspace_summary, event_phases_pause, event_phases_level_1, event_young_garbage_collection});
+        requiredEvents.put(gcDefNew, new String[] {event_heap_summary, event_heap_metaspace_summary, event_phases_pause, event_phases_level_1, event_young_garbage_collection});
+        requiredEvents.put(gcParallelScavenge, new String[] {event_heap_summary, event_heap_ps_summary, event_heap_metaspace_summary, event_reference_statistics, event_phases_pause, event_phases_level_1, event_young_garbage_collection});
+        requiredEvents.put(gcG1Old, new String[] {event_heap_summary, event_old_garbage_collection});
+        requiredEvents.put(gcG1Full, new String[] {event_heap_summary, event_heap_metaspace_summary, event_phases_pause, event_phases_level_1, event_old_garbage_collection});
+        requiredEvents.put(gcConcurrentMarkSweep, new String[] {event_phases_pause, event_phases_level_1, event_old_garbage_collection});
+        requiredEvents.put(gcSerialOld, new String[] {event_heap_summary, event_heap_metaspace_summary, event_phases_pause, event_phases_level_1, event_old_garbage_collection});
+        requiredEvents.put(gcParallelOld, new String[] {event_heap_summary, event_heap_ps_summary, event_heap_metaspace_summary, event_reference_statistics, event_phases_pause, event_phases_level_1, event_old_garbage_collection, event_parold_garbage_collection});
+
+        String[] g1HeapRegionTypeLiterals = new String[] {
+                                                           "Free",
+                                                           "Eden",
+                                                           "Survivor",
+                                                           "Starts Humongous",
+                                                           "Continues Humongous",
+                                                           "Old",
+                                                           "Archive"
+                                                         };
+
+        g1HeapRegionTypes = Collections.unmodifiableList(Arrays.asList(g1HeapRegionTypeLiterals));
+    }
+
+    /**
+     * Contains all GC events belonging to the same GC (same gcId).
+     */
+    public static class GcBatch {
+        private List<RecordedEvent> events = new ArrayList<>();
+
+        public int getGcId() {
+            if (events.isEmpty()) {
+                return -1;
+            }
+            return GCHelper.getGcId(events.get(0));
+        }
+
+        public String getName() {
+            RecordedEvent endEvent = getEndEvent();
+            String name = endEvent == null ? null : Events.assertField(endEvent, "name").getValue();
+            return name == null ? "null" : name;
+        }
+
+        public RecordedEvent getEndEvent() {
+            return getEvent(event_garbage_collection);
+        }
+
+        public boolean addEvent(RecordedEvent event) {
+            if (!events.isEmpty()) {
+                assertEquals(getGcId(), GCHelper.getGcId(event), "Wrong gcId in event. Error in test code.");
+            }
+            boolean isEndEvent = event_garbage_collection.equals(event.getEventType().getName());
+            if (isEndEvent) {
+                // Verify that we have not already got a garbage_collection event with this gcId.
+                assertNull(getEndEvent(), String.format("Multiple %s for gcId %d", event_garbage_collection, getGcId()));
+            }
+            events.add(event);
+            return isEndEvent;
+        }
+
+        public boolean isYoungCollection() {
+            boolean isYoung = containsEvent(event_young_garbage_collection);
+            boolean isOld = containsEvent(event_old_garbage_collection);
+            assertNotEquals(isYoung, isOld, "isYoung and isOld was same for batch: " + toString());
+            return isYoung;
+        }
+
+        public int getEventCount() {
+            return events.size();
+        }
+
+        public RecordedEvent getEvent(int index) {
+            return events.get(index);
+        }
+
+        public List<RecordedEvent> getEvents() {
+            return events;
+        }
+
+        public RecordedEvent getEvent(String eventPath) {
+            for (RecordedEvent event : events) {
+                if (eventPath.equals(event.getEventType().getName())) {
+                    return event;
+                }
+            }
+            return null;
+        }
+
+        public boolean containsEvent(String eventPath) {
+            return getEvent(eventPath) != null;
+        }
+
+        public String toString() {
+            RecordedEvent endEvent = getEndEvent();
+            Instant startTime = Instant.EPOCH;
+            String cause = "?";
+            String name = "?";
+            if (endEvent != null) {
+                name = getName();
+                startTime = endEvent.getStartTime();
+                cause = Events.assertField(endEvent, "cause").getValue();
+            }
+            return String.format("GcEvent: gcId=%d, method=%s, cause=%s, startTime=%s",
+                    getGcId(), name, cause, startTime);
+        }
+
+        public String getLog() {
+            StringBuilder sb = new StringBuilder();
+            sb.append(this.toString() + System.getProperty("line.separator"));
+            for (RecordedEvent event : events) {
+                sb.append(String.format("event: %s%n", event));
+            }
+            return sb.toString();
+        }
+
+        // Group all events info batches.
+        public static List<GcBatch> createFromEvents(List<RecordedEvent> events) throws Exception {
+            Stack<Integer> openGcIds = new Stack<>();
+            List<GcBatch> batches = new ArrayList<>();
+            GcBatch currBatch = null;
+
+            for (RecordedEvent event : events) {
+                if (!isGcEvent(event)) {
+                    continue;
+                }
+                int gcId = GCHelper.getGcId(event);
+                if (currBatch == null || currBatch.getGcId() != gcId) {
+                    currBatch = null;
+                    // Search for existing batch
+                    for (GcBatch loopBatch : batches) {
+                        if (gcId == loopBatch.getGcId()) {
+                            currBatch = loopBatch;
+                            break;
+                        }
+                    }
+                    if (currBatch == null) {
+                        // No existing batch. Create new.
+                        currBatch = new GcBatch();
+                        batches.add(currBatch);
+                        openGcIds.push(new Integer(gcId));
+                    }
+                }
+                boolean isEndEvent = currBatch.addEvent(event);
+                if (isEndEvent) {
+                    openGcIds.pop();
+                }
+            }
+            // Verify that all start_garbage_collection events have received a corresponding "garbage_collection" event.
+            for (GcBatch batch : batches) {
+                if (batch.getEndEvent() == null) {
+                    System.out.println(batch.getLog());
+                }
+                assertNotNull(batch.getEndEvent(), "GcBatch has no end event");
+            }
+            return batches;
+        }
+    }
+
+    /**
+     * Contains number of collections and sum pause time for young and old collections.
+     */
+    public static class CollectionSummary {
+        public long collectionCountOld;
+        public long collectionCountYoung;
+        public long collectionTimeOld;
+        public long collectionTimeYoung;
+        private Set<String> names = new HashSet<>();
+
+        public void add(String collectorName, boolean isYoung, long count, long time) {
+            if (isYoung) {
+                collectionCountYoung += count;
+                collectionTimeYoung += time;
+            } else {
+                collectionCountOld += count;
+                collectionTimeOld += time;
+            }
+            if (!names.contains(collectorName)) {
+                names.add(collectorName);
+            }
+        }
+
+        public long sum() {
+            return collectionCountOld + collectionCountYoung;
+        }
+
+        public CollectionSummary calcDelta(CollectionSummary prev) {
+            CollectionSummary delta = new CollectionSummary();
+            delta.collectionCountOld = this.collectionCountOld - prev.collectionCountOld;
+            delta.collectionTimeOld = this.collectionTimeOld - prev.collectionTimeOld;
+            delta.collectionCountYoung = this.collectionCountYoung - prev.collectionCountYoung;
+            delta.collectionTimeYoung = this.collectionTimeYoung - prev.collectionTimeYoung;
+            delta.names.addAll(this.names);
+            delta.names.addAll(prev.names);
+            return delta;
+        }
+
+        public static CollectionSummary createFromMxBeans() {
+            CollectionSummary summary = new CollectionSummary();
+            List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans();
+            for (int c=0; c<gcBeans.size(); c++) {
+                GarbageCollectorMXBean currBean = gcBeans.get(c);
+                Boolean isYoung = beanCollectorTypes.get(currBean.getName());
+                assertNotNull(isYoung, "Unknown MXBean name: " + currBean.getName());
+                long collectionTime = currBean.getCollectionTime() * 1000; // Convert from millis to micros.
+                summary.add(currBean.getName(), isYoung.booleanValue(), currBean.getCollectionCount(), collectionTime);
+            }
+            return summary;
+        }
+
+        public static CollectionSummary createFromEvents(List<GcBatch> batches) {
+            CollectionSummary summary = new CollectionSummary();
+            for (GcBatch batch : batches) {
+                RecordedEvent endEvent = batch.getEndEvent();
+                assertNotNull(endEvent, "No end event in batch with gcId " + batch.getGcId());
+                String name = batch.getName();
+                summary.add(name, batch.isYoungCollection(), 1, Events.assertField(endEvent, "sumOfPauses").getValue());
+            }
+            return summary;
+        }
+
+        public String toString() {
+            StringBuilder collectorNames = new StringBuilder();
+            for (String s : names) {
+                if (collectorNames.length() > 0) {
+                    collectorNames.append(", ");
+                }
+                collectorNames.append(s);
+            }
+            return String.format("CollectionSummary: young.collections=%d, young.time=%d, old.collections=%d, old.time=%d, collectors=(%s)",
+                    collectionCountYoung, collectionTimeYoung, collectionCountOld, collectionTimeOld, collectorNames);
+        }
+    }
+
+    public static PrintStream getDefaultErrorLog() {
+        if (defaultErrorLog == null) {
+            try {
+                defaultErrorLog = new PrintStream(new FileOutputStream("error.log", true));
+            } catch (IOException e) {
+                e.printStackTrace();
+                defaultErrorLog = System.err;
+            }
+        }
+        return defaultErrorLog;
+    }
+
+    public static void log(Object msg) {
+        log(msg, System.err);
+        log(msg, getDefaultErrorLog());
+    }
+
+    public static void log(Object msg, PrintStream ps) {
+        ps.println(msg);
+    }
+
+    public static boolean isValidG1HeapRegionType(final String type) {
+        return g1HeapRegionTypes.contains(type);
+    }
+
+    /**
+     * Helper function to align heap size up.
+     *
+     * @param value
+     * @param alignment
+     * @return aligned value
+     */
+    public static long alignUp(long value, long alignment) {
+        return (value + alignment - 1) & ~(alignment - 1);
+    }
+
+    /**
+     * Helper function to align heap size down.
+     *
+     * @param value
+     * @param alignment
+     * @return aligned value
+     */
+    public static long alignDown(long value, long alignment) {
+        return value & ~(alignment - 1);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/jfr/RecurseThread.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib.jfr;
+
+import jdk.test.lib.Asserts;
+
+public class RecurseThread extends Thread {
+
+    public int totalDepth;
+    public long dummy = 0; // Just to make sure the optimizer does not remove the test code.
+    private volatile boolean timeToQuit = false;
+    private volatile boolean isInRunLoop = false;
+
+    public RecurseThread(int totalDepth) {
+        this.totalDepth = totalDepth;
+    }
+
+    @Override
+    public void run() {
+        // totalDepth includes functions run() and recurse() and runloop().
+        // Remove 3 from totalDepth when recursing.
+        final int minDepth = 3;
+        Asserts.assertGreaterThanOrEqual(totalDepth, minDepth, "totalDepth too small");
+        int recurseDepth = totalDepth - minDepth;
+
+        // We want the last function before runloop() to be recurseA().
+        boolean startWithRecurseA = (totalDepth % 2) != 0;
+        dummy = startWithRecurseA ? recurseA(recurseDepth) : recurseB(recurseDepth);
+    }
+
+    public void quit() {
+        timeToQuit = true;
+    }
+
+    public boolean isInRunLoop() {
+        return isInRunLoop;
+    }
+
+    private long recurseA(int depth) {
+        if (depth == 0) {
+            return recurseEnd();
+        } else {
+            return recurseB(depth - 1);
+        }
+    }
+
+    private long recurseB(int depth) {
+        if (depth == 0) {
+            return recurseEnd();
+        } else {
+            return recurseA(depth - 1);
+        }
+    }
+
+    // Test expects this function to be at the top of the stack.
+    // We should not call other functions from here.
+    private long recurseEnd() {
+        isInRunLoop = true;
+        long[] dummyTable = new long[] { 0, 2, 4, 8, 16 };
+        long dummyTotal = 0;
+        while (!timeToQuit) {
+            dummyTotal = 0;
+            for (int i = 0; i < 5; ++i) {
+                dummyTotal += dummyTable[i];
+            }
+        }
+        return dummyTotal;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/jfr/SimpleEvent.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib.jfr;
+
+import jdk.jfr.Event;
+
+public class SimpleEvent extends Event {
+    public int id;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/jfr/SimpleEventHelper.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib.jfr;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+
+public class SimpleEventHelper {
+
+    public static void enable(Recording r, boolean isEnabled) {
+        if (isEnabled) {
+            r.enable(SimpleEvent.class).withThreshold(Duration.ofMillis(0)).withoutStackTrace();
+        } else {
+            r.disable(SimpleEvent.class);
+        }
+    }
+
+    public static SimpleEvent createEvent(int id) {
+        SimpleEvent event = new SimpleEvent();
+        event.begin();
+        event.id = id;
+        event.end();
+        event.commit();
+        return event;
+    }
+
+    public static void verifyEvents(Recording r, int ... ids) throws Exception {
+        List<Integer> eventIds = new ArrayList<>();
+        for (RecordedEvent event : Events.fromRecording(r)) {
+            if (Events.isEventType(event, SimpleEvent.class.getName())) {
+                int id = Events.assertField(event, "id").getValue();
+                System.out.printf("recording %s: event.id=%d%n", r.getName(), id);
+                eventIds.add(id);
+            }
+        }
+        Asserts.assertEquals(eventIds.size(), ids.length, "Wrong number of events");
+        for (int i = 0; i < ids.length; ++i) {
+            Asserts.assertEquals(eventIds.get(i).intValue(), ids[i], "Wrong id in event");
+        }
+    }
+
+    public static void verifyContains(List<RecordedEvent> events, int ... ids) throws Exception {
+        Set<Integer> missingIds = new HashSet<>();
+        for (int id : ids) {
+            missingIds.add(id);
+        }
+        for (RecordedEvent event : getSimpleEvents(events)) {
+            int id = Events.assertField(event, "id").getValue();
+            System.out.printf("event.id=%d%n", id);
+            missingIds.remove(new Integer(id));
+        }
+        if (!missingIds.isEmpty()) {
+            missingIds.forEach(id -> System.out.println("Missing MyEvent with id " + id));
+            Asserts.fail("Missing some MyEvent events");
+        }
+    }
+
+    public static void verifyNotContains(List<RecordedEvent> events, int ... ids) throws Exception {
+        for (RecordedEvent event : getSimpleEvents(events)) {
+            int eventId = Events.assertField(event, "id").getValue();
+            System.out.printf("event.id=%d%n", eventId);
+            for (int id : ids) {
+                Events.assertField(event, "id").notEqual(id);
+            }
+        }
+    }
+
+    public static List<RecordedEvent> getSimpleEvents(List<RecordedEvent> events) {
+        List<RecordedEvent> myEvents = new ArrayList<>();
+        for (RecordedEvent event : events) {
+            if (Events.isEventType(event, SimpleEvent.class.getName())) {
+                myEvents.add(event);
+            }
+        }
+        return myEvents;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/jfr/SimpleSetting.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib.jfr;
+
+import java.util.Set;
+
+import jdk.jfr.SettingControl;
+
+public class SimpleSetting extends SettingControl {
+
+    @Override
+    public String combine(Set<String> settingValue) {
+        return "none";
+    }
+
+    @Override
+    public void setValue(String value) {
+    }
+
+    @Override
+    public String getValue() {
+        return "none";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/jfr/Stressor.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.test.lib.jfr;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Class to help run multiple threads executing some task
+ *
+ *
+ * @since 1.9
+ */
+public class Stressor {
+    public static void execute(int numberOfThreads, Thread.UncaughtExceptionHandler eh, Runnable task) throws Exception {
+        List<Thread> threads = new ArrayList<>();
+        for (int n = 0; n < numberOfThreads; ++n) {
+            Thread t = new Thread(task);
+            t.setUncaughtExceptionHandler(eh);
+            threads.add(t);
+            t.start();
+        }
+        for (Thread t : threads) {
+            t.join();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/jfr/TestClassLoader.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib.jfr;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Custom class loader which will try to load the class via getResourceAsStream().
+ * If there are any errors, the parent class loader will be used instead.
+ */
+public class TestClassLoader extends ClassLoader {
+    static public final String CLASS_LOADER_NAME = "JFR TestClassLoader";
+
+    public TestClassLoader() {
+        super(CLASS_LOADER_NAME, ClassLoader.getSystemClassLoader());
+    }
+
+    public Class<?> loadClass(String name) throws ClassNotFoundException {
+
+        InputStream is = null;
+        DataInputStream dis = null;
+        try {
+            String resourceName = name.replace('.', '/') + ".class";
+            is = getResourceAsStream(resourceName);
+            if (is != null) {
+                int i = is.available();
+                byte buf[] = new byte[i];
+                dis = new DataInputStream(is);
+                dis.readFully(buf);
+                dis.close();
+                return defineClass(name, buf, 0, buf.length);
+            }
+        } catch (SecurityException e) {
+            // This error will happen quite often (for example when loading
+            // "java.lang...").
+            // Ignore this error and use parent class loader.
+        } catch (IOException e) {
+            // Unexpected error. Use parent class loader.
+            e.printStackTrace();
+        } finally {
+            if (dis != null) {
+                try {
+                    dis.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return super.loadClass(name);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/jfr/VoidFunction.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib.jfr;
+
+@FunctionalInterface
+public interface VoidFunction {
+    void run() throws Throwable;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/thread/TestThread.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2013, 2015, 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 jdk.test.lib.thread;
+
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Thread which catches exceptions thrown during the execution
+ * and stores them for later analysis.
+ *
+ * <pre>
+ * {@code
+ * TestThread thread = new TestThread(new XRun() {
+ *      public void run() {
+ *      // do something
+ *      }
+ * });
+ * thread.start();
+ * // do something
+ * Throwable uncaught = thread.getUncaught();
+ * }
+ * </pre>
+ */
+public class TestThread extends Thread {
+
+    private final Runnable runnable;
+    private volatile Throwable uncaught;
+
+    /**
+     * Returns {@link Runnable} the thread has been created with.
+     *
+     * @return The object whose {@code run} method is called
+     */
+    public Runnable getRunnable() {
+        return runnable;
+    }
+
+    /**
+     * Creates a new {@code TestThread} object.
+     *
+     * @param target The object whose {@code run} method is called
+     * @param name The thread name
+     */
+    public TestThread(Runnable target, String name) {
+        super(target, name);
+        this.runnable = target;
+    }
+
+    /**
+     * Creates a new {@code TestThread} object.
+     *
+     * @param target The object whose {@code run} method is called
+     */
+    public TestThread(Runnable target) {
+        super(target);
+        this.runnable = target;
+    }
+
+    /**
+     * Creates a new {@code TestThread} object.
+     *
+     * @param group The thread group
+     * @param target The object whose {@code run} method is called
+     * @param name The thread name
+     * @param stackSize Stack size
+     */
+    public TestThread(ThreadGroup group, Runnable target, String name,
+            long stackSize) {
+        super(group, target, name, stackSize);
+        this.runnable = target;
+    }
+
+    /**
+     * Creates a new {@code TestThread} object.
+     *
+     * @param group The thread group
+     * @param target The object whose {@code run} method is called
+     * @param name The thread name
+     */
+    public TestThread(ThreadGroup group, Runnable target, String name) {
+        super(group, target, name);
+        this.runnable = target;
+    }
+
+    /**
+     * Creates a new {@code TestThread} object.
+     *
+     * @param group The thread group
+     * @param target The object whose {@code run} method is called
+     */
+    public TestThread(ThreadGroup group, Runnable target) {
+        super(group, target);
+        this.runnable = target;
+    }
+
+    /**
+     * The thread executor.
+     */
+    @Override
+    public void run() {
+        try {
+            super.run();
+        } catch (Throwable t) {
+            uncaught = t;
+        }
+    }
+
+    /**
+     * Returns exception caught during the execution.
+     *
+     * @return {@link Throwable}
+     */
+    public Throwable getUncaught() {
+        return uncaught;
+    }
+
+    /**
+     * Waits for {@link TestThread} to die
+     * and throws exception caught during the execution.
+     *
+     * @throws InterruptedException
+     * @throws Throwable
+     */
+    public void joinAndThrow() throws InterruptedException, Throwable {
+        join();
+        if (uncaught != null) {
+            throw uncaught;
+        }
+    }
+
+    /**
+     * Waits during {@code timeout} for {@link TestThread} to die
+     * and throws exception caught during the execution.
+     *
+     * @param timeout The time to wait in milliseconds
+     * @throws InterruptedException
+     * @throws Throwable
+     */
+    public void joinAndThrow(long timeout) throws InterruptedException,
+            Throwable {
+        join(timeout);
+        if (isAlive()) {
+            throw new TimeoutException();
+        }
+        if (uncaught != null) {
+            throw uncaught;
+        }
+    }
+
+    /**
+     * Waits for {@link TestThread} to die
+     * and returns exception caught during the execution.
+     *
+     * @return Exception caught during the execution
+     * @throws InterruptedException
+     */
+    public Throwable joinAndReturn() throws InterruptedException {
+        join();
+        if (uncaught != null) {
+            return uncaught;
+        }
+        return null;
+    }
+
+    /**
+     * Waits during {@code timeout} for {@link TestThread} to die
+     * and returns exception caught during the execution.
+     *
+     * @param timeout The time to wait in milliseconds
+     * @return Exception caught during the execution
+     * @throws InterruptedException
+     */
+    public Throwable joinAndReturn(long timeout) throws InterruptedException {
+        join(timeout);
+        if (isAlive()) {
+            return new TimeoutException();
+        }
+        if (uncaught != null) {
+            return uncaught;
+        }
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/thread/XRun.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib.thread;
+
+/**
+ * This type serves no other purpose than to simply allow automatically running
+ * something in a thread, and have all exceptions propagated to
+ * RuntimeExceptions, which are thrown up to thread, which in turn should
+ * probably be a {@link TestThread} to they are stored.
+ */
+public abstract class XRun implements Runnable {
+
+    /**
+     * Invokes {@code xrun()} and throws all exceptions caught in it
+     * up to the thread.
+     */
+    public final void run() {
+        try {
+            xrun();
+        } catch (Error e) {
+            throw e;
+        } catch (RuntimeException e) {
+            throw e;
+        } catch (Throwable e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Override this method to implement what to run in the thread.
+     *
+     * @throws Throwable
+     */
+    protected abstract void xrun() throws Throwable;
+}