Skip to content

Commit

Permalink
7798: Make the frame type extensible
Browse files Browse the repository at this point in the history
Reviewed-by: clanger
  • Loading branch information
Jaroslav Bachorik authored and RealCLanger committed May 31, 2022
1 parent 44bbcd0 commit 303031f
Show file tree
Hide file tree
Showing 4 changed files with 193 additions and 43 deletions.
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2018, 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2022 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, Datadog, Inc. All rights reserved.

This comment has been minimized.

Copy link
@thegreystone

thegreystone Dec 2, 2022

Member

We should not add a Datadog copyright in pre-existing files.

*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
Expand Down Expand Up @@ -32,13 +33,17 @@
*/
package org.openjdk.jmc.common;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;

import org.openjdk.jmc.common.messages.internal.Messages;

/**
* A stack trace frame.
* <p>
* It's recommended, but by design not a requirement, that classes that implements IMCFrame also
* implement {@link IMCMethod}. This allow classes in higher layers to treat a frame just like a
* implement {@link IMCMethod}. This allows classes in higher layers to treat a frame just like a
* method, for instance when using Eclipse object contribution mechanism.
* <p>
* This can be implemented simply by letting {@link IMCFrame#getMethod()} return {@code this}.
Expand All @@ -49,45 +54,113 @@ public interface IMCFrame {
/**
* Frame compilation types.
*/
public enum Type {
/**
* The frame was executed as native code compiled by the Java JIT compiler.
*/
JIT_COMPILED,
/**
* The frame was executed as interpreted Java byte code.
*/
INTERPRETED,
/**
* The frame was executed as code that was inlined by the Java JIT compiler.
*/
INLINED,
/**
* The frame was executed as native code, most probably a C function.
*/
NATIVE,
/**
* The frame was executed as native code compiled from C++.
*/
CPP,
/**
* The frame was executed as kernel native code.
*/
KERNEL,
/**
* The frame compilation type is unknown.
*/
UNKNOWN;
final class Type {
/**
* The frame was executed as native code compiled by the Java JIT compiler.
*/
public static final Type JIT_COMPILED = new Type("JIT_COMPILED"); //$NON-NLS-1$

/**
* The frame was executed as interpreted Java byte code.
*/
public static final Type INTERPRETED = new Type("INTERPRETED"); //$NON-NLS-1$

/**
* The frame was executed as code that was inlined by the Java JIT compiler.
*/
public static final Type INLINED = new Type("INLINED"); //$NON-NLS-1$

/**
* The frame was executed as native code, most probably a C function
*/
public static final Type NATIVE = new Type("NATIVE"); //$NON-NLS-1$

private String name;
/**
* The frame was executed as native code compiled from C++
*/
public static final Type CPP = new Type("CPP"); //$NON-NLS-1$

private Type() {
name = Messages.getString("IMCFrame_Type_" + toString()); //$NON-NLS-1$
/**
* The frame was executed as kernel native code
*/
public static final Type KERNEL = new Type("KERNEL"); //$NON-NLS-1$

/**
* The frame compilation type is unknown.
*/
public static final Type UNKNOWN = new Type("UNKNONW"); //$NON-NLS-1$

private static final String MSG_PREFIX = "IMCFrame_Type_";

/*
* Maximum number of items the TYPE_CACHE will hold. The assumption is that the number of
* 'dynamic' frame types will be small, typically in ones rather than tens and as such 100
* items in the type cache should cover the vast majority of use cases.
*/
private static final int TYPE_CACHE_MAX_SIZE = 100;

/*
* A helper cache for the unrecognized frame types to reduce the amount of allocated
* instances. The expectation is that the number of unrecognized frame types will be very
* small, usually zero, so the memory overhead of the cache stays negligible.
*/
private static final Map<String, Type> TYPE_CACHE = new LinkedHashMap<String, Type>() {
private static final long serialVersionUID = 6330800425284157773L;

@Override
protected boolean removeEldestEntry(Map.Entry<String, Type> eldest) {
return size() > TYPE_CACHE_MAX_SIZE;
}
};

private final String id;
private final String name;
private final boolean isUnknown;

private Type(String id) {
this.id = id.toUpperCase();

String key = MSG_PREFIX + this.id;
if (Messages.hasString(key)) {
name = Messages.getString(key);
isUnknown = false;
} else {
name = this.id;
isUnknown = true;
}
}

public static Type cachedType(String type) {
return TYPE_CACHE.computeIfAbsent(type, IMCFrame.Type::new);
}

public String getName() {
return name;
}

public boolean isUnknown() {
return isUnknown;
}

@Override
public String toString() {
return id;
}

@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Type type = (Type) o;
return id.equals(type.id);
}

@Override
public int hashCode() {
return Objects.hash(id);
}
}

/**
Expand Down
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2022 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, Datadog, Inc. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
Expand Down Expand Up @@ -92,4 +93,8 @@ public static String getString(String key, String def) {
return def;
}
}

public static boolean hasString(String key) {
return RESOURCE_BUNDLE.containsKey(key);
}
}
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2018, 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2022 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, Datadog, Inc. All rights reserved.

This comment has been minimized.

Copy link
@thegreystone

thegreystone Dec 2, 2022

Member

We should not add a Datadog copyright in pre-existing files.

*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
Expand Down Expand Up @@ -38,6 +39,15 @@
import org.openjdk.jmc.flightrecorder.internal.InvalidJfrFileException;

public final class ParserToolkit {
// The following type IDs are public only for the sakes of testing
public static final String INTERPRETED_TYPE_ID = "Interpreted"; //$NON-NLS-1$
public static final String JIT_COMPILED_TYPE_ID = "JIT compiled"; //$NON-NLS-1$
public static final String INLINED_TYPE_ID = "Inlined"; //$NON-NLS-1$
public static final String NATIVE_TYPE_ID = "Native"; //$NON-NLS-1$
public static final String CPP_TYPE_ID = "C++"; //$NON-NLS-1$
public static final String KERNEL_TYPE_ID = "Kernel"; //$NON-NLS-1$
public static final String UNKNOWN_TYPE_ID = "Unknown"; //$NON-NLS-1$

private ParserToolkit() {
throw new Error("Don't"); //$NON-NLS-1$
}
Expand Down Expand Up @@ -71,24 +81,27 @@ public static void assertValue(Object value, Object ... accepted) throws Invalid
}

public static IMCFrame.Type parseFrameType(String type) {
if ("Interpreted".equals(type)) { //$NON-NLS-1$
if (INTERPRETED_TYPE_ID.equals(type)) {
return IMCFrame.Type.INTERPRETED;
}
if ("JIT compiled".equals(type)) { //$NON-NLS-1$
if (JIT_COMPILED_TYPE_ID.equals(type)) {
return IMCFrame.Type.JIT_COMPILED;
}
if ("Inlined".equals(type)) { //$NON-NLS-1$
if (INLINED_TYPE_ID.equals(type)) {
return IMCFrame.Type.INLINED;
}
if ("Native".equals(type)) { //$NON-NLS-1$
if (NATIVE_TYPE_ID.equals(type)) {
return IMCFrame.Type.NATIVE;
}
if ("C++".equals(type)) { //$NON-NLS-1$
if (CPP_TYPE_ID.equals(type)) {
return IMCFrame.Type.CPP;
}
if ("Kernel".equals(type)) { //$NON-NLS-1$
if (KERNEL_TYPE_ID.equals(type)) {
return IMCFrame.Type.KERNEL;
}
return IMCFrame.Type.UNKNOWN;
if (UNKNOWN_TYPE_ID.equals(type)) {
return IMCFrame.Type.UNKNOWN;
}
return IMCFrame.Type.cachedType(type);
}
}
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, Datadog, Inc. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The contents of this file are subject to the terms of either the Universal Permissive License
* v 1.0 as shown at http://oss.oracle.com/licenses/upl
*
* or the following license:
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions
* and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided with
* the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.openjdk.jmc.flightrecorder.test.internal.util;

import org.junit.Assert;
import org.junit.Test;
import org.openjdk.jmc.common.IMCFrame;
import org.openjdk.jmc.flightrecorder.internal.util.ParserToolkit;

public class ParserToolkitTest {
@Test
public void testParseBuiltinFrameType() {
Assert.assertTrue(IMCFrame.Type.INTERPRETED == ParserToolkit.parseFrameType(ParserToolkit.INTERPRETED_TYPE_ID));
Assert.assertTrue(
IMCFrame.Type.JIT_COMPILED == ParserToolkit.parseFrameType(ParserToolkit.JIT_COMPILED_TYPE_ID));
Assert.assertTrue(IMCFrame.Type.INLINED == ParserToolkit.parseFrameType(ParserToolkit.INLINED_TYPE_ID));
Assert.assertTrue(IMCFrame.Type.NATIVE == ParserToolkit.parseFrameType(ParserToolkit.NATIVE_TYPE_ID));
Assert.assertTrue(IMCFrame.Type.CPP == ParserToolkit.parseFrameType(ParserToolkit.CPP_TYPE_ID));
Assert.assertTrue(IMCFrame.Type.KERNEL == ParserToolkit.parseFrameType(ParserToolkit.KERNEL_TYPE_ID));
Assert.assertTrue(IMCFrame.Type.UNKNOWN == ParserToolkit.parseFrameType(ParserToolkit.UNKNOWN_TYPE_ID));
}

@Test
public void testCachedFrameType() {
String typeId = "custom type";
Assert.assertTrue(ParserToolkit.parseFrameType(typeId) == ParserToolkit.parseFrameType(typeId));
}
}

0 comments on commit 303031f

Please sign in to comment.