diff --git a/nashorn/bin/runoptdualcatch.sh b/nashorn/bin/runoptdualcatch.sh index 7bde221aed4..dc5d8690bd4 100644 --- a/nashorn/bin/runoptdualcatch.sh +++ b/nashorn/bin/runoptdualcatch.sh @@ -1,6 +1,7 @@ #!/bin/sh #FLAGS="-Djava.lang.invoke.MethodHandle.COMPILE_THRESHOLD=3 -Djava.lang.invoke.MethodHandle.DUMP_CLASS_FILES=true -Djava.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE=true -Djava.lang.invoke.MethodHandle.TRACE_INTERPRETER=true" +#FLAGS="-Djava.security.manager -Djava.security.policy=../build/nashorn.policy -Dnashorn.debug" FILENAME="./optimistic_dual_catch_$(date|sed "s/ /_/g"|sed "s/:/_/g").jfr" diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java index dd947033d34..8c6dc27d101 100644 --- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java @@ -26,7 +26,6 @@ package jdk.nashorn.internal.tools.nasgen; import java.lang.invoke.MethodHandle; -import java.lang.reflect.Method; import java.util.Collection; import java.util.ArrayList; import java.util.Collections; diff --git a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java index e71e400eb92..e6044aea427 100644 --- a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java +++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java @@ -388,7 +388,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C } // Arbitrary user Bindings implementation. Look for NASHORN_GLOBAL in it! - Object scope = bindings.get(NASHORN_GLOBAL); + final Object scope = bindings.get(NASHORN_GLOBAL); if (scope instanceof ScriptObjectMirror) { final Global glob = globalFromMirror((ScriptObjectMirror)scope); if (glob != null) { @@ -405,7 +405,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C // Retrieve nashorn Global object from a given ScriptObjectMirror private Global globalFromMirror(final ScriptObjectMirror mirror) { - ScriptObject sobj = mirror.getScriptObject(); + final ScriptObject sobj = mirror.getScriptObject(); if (sobj instanceof Global && isOfContext((Global)sobj, nashornContext)) { return (Global)sobj; } @@ -643,7 +643,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C continue; } - Object obj = sobj.get(method.getName()); + final Object obj = sobj.get(method.getName()); if (! (obj instanceof ScriptFunction)) { return false; } diff --git a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java index beb0c2a0fef..470502d4448 100644 --- a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java +++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java @@ -220,7 +220,7 @@ public final class NashornScriptEngineFactory implements ScriptEngineFactory { // Revisit: script engine implementation needs the capability to // find the class loader of the context in which the script engine // is running so that classes will be found and loaded properly - ClassLoader ccl = Thread.currentThread().getContextClassLoader(); + final ClassLoader ccl = Thread.currentThread().getContextClassLoader(); return (ccl == null)? NashornScriptEngineFactory.class.getClassLoader() : ccl; } } diff --git a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java index 69825f39ecf..eb433baf97a 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java @@ -172,11 +172,11 @@ final class Attr extends NodeOperatorVisitor { } @Override - public boolean enterAccessNode(AccessNode accessNode) { + public boolean enterAccessNode(final AccessNode accessNode) { tagNeverOptimistic(accessNode.getBase()); tagNeverOptimistic(accessNode.getProperty()); return true; - }; + } @Override public Node leaveAccessNode(final AccessNode accessNode) { @@ -423,7 +423,7 @@ final class Attr extends NodeOperatorVisitor { private Symbol defineSymbol(final Block block, final String name, final int symbolFlags) { int flags = symbolFlags; Symbol symbol = findSymbol(block, name); // Locate symbol. - boolean isGlobal = (flags & KINDMASK) == IS_GLOBAL; + final boolean isGlobal = (flags & KINDMASK) == IS_GLOBAL; if (isGlobal) { flags |= IS_SCOPE; @@ -805,7 +805,7 @@ final class Attr extends NodeOperatorVisitor { } @Override - public boolean enterIndexNode(IndexNode indexNode) { + public boolean enterIndexNode(final IndexNode indexNode) { tagNeverOptimistic(indexNode.getBase()); return true; } diff --git a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java index f0ba75d36ce..2dd46be699a 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -3493,7 +3493,6 @@ final class CodeGenerator extends NodeOperatorVisitor list = osc.getClassHistogram(); + final List list = osc.getClassHistogram(); + final StringBuilder sb = new StringBuilder(); + final long totalSize = osc.calculateObjectSize(functionNode); - final StringBuilder sb = new StringBuilder(); - final long totalSize = osc.calculateObjectSize(functionNode); - sb.append(phaseName).append(" Total size = ").append(totalSize / 1024 / 1024).append("MB"); + sb.append(phaseName). + append(" Total size = "). + append(totalSize / 1024 / 1024). + append("MB"); LOG.info(sb); Collections.sort(list, new Comparator() { @Override - public int compare(ClassHistogramElement o1, ClassHistogramElement o2) { + public int compare(final ClassHistogramElement o1, final ClassHistogramElement o2) { final long diff = o1.getBytes() - o2.getBytes(); if (diff < 0) { return 1; @@ -197,9 +212,9 @@ public final class Compiler { }); for (final ClassHistogramElement e : list) { final String line = String.format(" %-48s %10d bytes (%8d instances)", e.getClazz(), e.getBytes(), e.getInstances()); - LOG.info(line); + info(line); if (e.getBytes() < totalSize / 200) { - LOG.info(" ..."); + info(" ..."); break; // never mind, so little memory anyway } } @@ -507,4 +522,36 @@ public final class Compiler { public static String binaryName(final String name) { return name.replace('/', '.'); } + + /** + * Log hook; level finest + * @param args args + */ + public static void finest(final Object... args) { + LOG.finest(args); + } + + /** + * Log hook; level fine + * @param args args + */ + public static void fine(final Object... args) { + LOG.fine(args); + } + + /** + * Log hook; level info + * @param args args + */ + public static void info(final Object... args) { + LOG.info(args); + } + + /** + * Log hook; level warning + * @param args args + */ + public static void warning(final Object... args) { + LOG.warning(args); + } } diff --git a/nashorn/src/jdk/nashorn/internal/codegen/DumpBytecode.java b/nashorn/src/jdk/nashorn/internal/codegen/DumpBytecode.java index 6c9ed63a2af..c8f2bc0b9f0 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/DumpBytecode.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/DumpBytecode.java @@ -25,6 +25,9 @@ package jdk.nashorn.internal.codegen; +import static jdk.nashorn.internal.codegen.Compiler.info; +import static jdk.nashorn.internal.codegen.Compiler.warning; + import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -98,10 +101,10 @@ final class DumpBytecode { try (final FileOutputStream fos = new FileOutputStream(file)) { fos.write(bytecode); } - Compiler.LOG.info("Wrote class to '" + file.getAbsolutePath() + '\''); + info("Wrote class to '" + file.getAbsolutePath() + '\''); } } catch (final IOException e) { - Compiler.LOG.warning("Skipping class dump for ", + warning("Skipping class dump for ", className, ": ", ECMAErrors.getMessage( @@ -109,5 +112,4 @@ final class DumpBytecode { dir.toString())); } } - } diff --git a/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java b/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java index 71cf33dfad9..65acfd0aa74 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java @@ -89,7 +89,15 @@ public final class ObjectClassGenerator { * Debug field logger * Should we print debugging information for fields when they are generated and getters/setters are called? */ - public static final DebugLogger LOG = new DebugLogger("fields", "nashorn.fields.debug"); + private static final DebugLogger LOG = new DebugLogger("fields", "nashorn.fields.debug"); + + /** + * Get the field logger + * @return logger + */ + public static DebugLogger getLogger() { + return LOG; + } private static final Set FIELDS_TO_INSTRUMENT; static { diff --git a/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java b/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java index b9d56715a88..54021d4cbd7 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java @@ -26,6 +26,7 @@ package jdk.nashorn.internal.codegen; import static jdk.nashorn.internal.codegen.CompilerConstants.SPLIT_PREFIX; +import static jdk.nashorn.internal.codegen.Compiler.finest; import java.util.ArrayList; import java.util.HashMap; @@ -42,7 +43,6 @@ import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.ir.SplitNode; import jdk.nashorn.internal.ir.Statement; import jdk.nashorn.internal.ir.visitor.NodeVisitor; -import jdk.nashorn.internal.runtime.DebugLogger; import jdk.nashorn.internal.runtime.options.Options; /** @@ -64,8 +64,6 @@ final class Splitter extends NodeVisitor { /** Weight threshold for when to start a split. */ public static final long SPLIT_THRESHOLD = Options.getIntProperty("nashorn.compiler.splitter.threshold", 32 * 1024); - private static final DebugLogger LOG = Compiler.LOG; - /** * Constructor. * @@ -85,10 +83,10 @@ final class Splitter extends NodeVisitor { * @param fn the function to split * @param top whether this is the topmost compiled function (it's either a program, or we're doing a recompilation). */ - FunctionNode split(final FunctionNode fn, boolean top) { + FunctionNode split(final FunctionNode fn, final boolean top) { FunctionNode functionNode = fn; - LOG.finest("Initiating split of '", functionNode.getName(), "'"); + finest("Initiating split of '", functionNode.getName(), "'"); long weight = WeighNodes.weigh(functionNode); @@ -97,7 +95,7 @@ final class Splitter extends NodeVisitor { assert lc.isEmpty() : "LexicalContext not empty"; if (weight >= SPLIT_THRESHOLD) { - LOG.finest("Splitting '", functionNode.getName(), "' as its weight ", weight, " exceeds split threshold ", SPLIT_THRESHOLD); + finest("Splitting '", functionNode.getName(), "' as its weight ", weight, " exceeds split threshold ", SPLIT_THRESHOLD); functionNode = (FunctionNode)functionNode.accept(this); if (functionNode.isSplit()) { @@ -134,7 +132,7 @@ final class Splitter extends NodeVisitor { @Override public Node leaveFunctionNode(final FunctionNode nestedFunction) { - FunctionNode split = new Splitter(compiler, nestedFunction, outermostCompileUnit).split(nestedFunction, false); + final FunctionNode split = new Splitter(compiler, nestedFunction, outermostCompileUnit).split(nestedFunction, false); lc.replace(nestedFunction, split); return split; } diff --git a/nashorn/src/jdk/nashorn/internal/ir/IdentNode.java b/nashorn/src/jdk/nashorn/internal/ir/IdentNode.java index 9b550d00aff..b8a341be5a9 100644 --- a/nashorn/src/jdk/nashorn/internal/ir/IdentNode.java +++ b/nashorn/src/jdk/nashorn/internal/ir/IdentNode.java @@ -220,7 +220,7 @@ public final class IdentNode extends Expression implements PropertyKey, Function return this; } if (DEBUG_FIELDS && ObjectClassGenerator.shouldInstrument(getName()) && getSymbol() != null && !Type.areEquivalent(getSymbol().getSymbolType(), callSiteType)) { - ObjectClassGenerator.LOG.info(getClass().getName(), " ", this, " => ", callSiteType, " instead of ", getType()); + ObjectClassGenerator.getLogger().info(getClass().getName(), " ", this, " => ", callSiteType, " instead of ", getType()); } return new IdentNode(this, name, callSiteType, flags, programPoint); } diff --git a/nashorn/src/jdk/nashorn/internal/objects/Global.java b/nashorn/src/jdk/nashorn/internal/objects/Global.java index 75bbe5fb00a..3a3b76401fc 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/Global.java +++ b/nashorn/src/jdk/nashorn/internal/objects/Global.java @@ -38,6 +38,7 @@ import java.util.Arrays; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; + import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.linker.LinkRequest; import jdk.nashorn.internal.lookup.Lookup; @@ -54,7 +55,6 @@ import jdk.nashorn.internal.runtime.PropertyMap; import jdk.nashorn.internal.runtime.Scope; import jdk.nashorn.internal.runtime.ScriptEnvironment; import jdk.nashorn.internal.runtime.ScriptFunction; -import jdk.nashorn.internal.runtime.ScriptFunctionData; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptRuntime; import jdk.nashorn.internal.runtime.ScriptingFunctions; @@ -489,20 +489,6 @@ public final class Global extends ScriptObject implements Scope { init(); } - /** - * Create a new ScriptFunction object - * - * @param name function name - * @param handle invocation handle for function - * @param scope the scope - * @param strict are we in strict mode - * - * @return new script function - */ - public ScriptFunction newScriptFunction(final String name, final MethodHandle handle, final ScriptObject scope, final boolean strict) { - return new ScriptFunctionImpl(name, handle, scope, null, strict ? ScriptFunctionData.IS_STRICT_CONSTRUCTOR : ScriptFunctionData.IS_CONSTRUCTOR); - } - /** * Wrap a Java object as corresponding script object * @@ -538,7 +524,7 @@ public final class Global extends ScriptObject implements Scope { * * @return guarded invocation */ - public GuardedInvocation primitiveLookup(final LinkRequest request, final Object self) { + public static GuardedInvocation primitiveLookup(final LinkRequest request, final Object self) { if (self instanceof String || self instanceof ConsString) { return NativeString.lookupPrimitive(request, self); } else if (self instanceof Number) { @@ -730,6 +716,7 @@ public final class Global extends ScriptObject implements Scope { * @param value of the data property * @param configurable is the property configurable? * @param enumerable is the property enumerable? + * @param writable is the property writable? * @return newly created DataPropertyDescriptor object */ public PropertyDescriptor newDataDescriptor(final Object value, final boolean configurable, final boolean enumerable, final boolean writable) { @@ -1829,7 +1816,6 @@ public final class Global extends ScriptObject implements Scope { this.addOwnProperty("Debug", Attribute.NOT_ENUMERABLE, initConstructor("Debug")); } - @SuppressWarnings("resource") private static Object printImpl(final boolean newLine, final Object... objects) { final PrintWriter out = Global.getEnv().getOut(); final StringBuilder sb = new StringBuilder(); diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java b/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java index f943ee8f7a7..7139cf80d1e 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java @@ -50,19 +50,6 @@ public final class NativeArrayBuffer extends ScriptObject { // initialized by nasgen private static PropertyMap $nasgenmap$; - @Constructor(arity = 1) - public static Object constructor(final boolean newObj, final Object self, final Object... args) { - if (!newObj) { - throw typeError("constructor.requires.new", "ArrayBuffer"); - } - - if (args.length == 0) { - throw new RuntimeException("missing length argument"); - } - - return new NativeArrayBuffer(JSType.toInt32(args[0])); - } - /** * Constructor * @param nb native byte buffer to wrap @@ -100,7 +87,27 @@ public final class NativeArrayBuffer extends ScriptObject { this(cloneBuffer(other.getNioBuffer(), begin, end)); } - private static ByteBuffer cloneBuffer(ByteBuffer original, final int begin, final int end) { + /** + * Constructor + * @param newObj is this invoked with new + * @param self self reference + * @param args arguments to constructor + * @return new NativeArrayBuffer + */ + @Constructor(arity = 1) + public static Object constructor(final boolean newObj, final Object self, final Object... args) { + if (!newObj) { + throw typeError("constructor.requires.new", "ArrayBuffer"); + } + + if (args.length == 0) { + throw new RuntimeException("missing length argument"); + } + + return new NativeArrayBuffer(JSType.toInt32(args[0])); + } + + private static ByteBuffer cloneBuffer(final ByteBuffer original, final int begin, final int end) { final ByteBuffer clone = ByteBuffer.allocateDirect(original.capacity()); original.rewind();//copy from the beginning clone.put(original); diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java b/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java index cfa9fba41fc..16b2484ba0a 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java @@ -28,14 +28,18 @@ package jdk.nashorn.internal.objects; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; import java.io.PrintWriter; +import java.util.LinkedList; import java.util.Objects; + import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Function; import jdk.nashorn.internal.objects.annotations.ScriptClass; import jdk.nashorn.internal.objects.annotations.Where; import jdk.nashorn.internal.runtime.Context; +import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.PropertyListeners; import jdk.nashorn.internal.runtime.PropertyMap; +import jdk.nashorn.internal.runtime.RuntimeEvent; import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.linker.LinkerCallSite; @@ -206,7 +210,6 @@ public final class NativeDebug extends ScriptObject { * @param self self reference * @return undefined */ - @SuppressWarnings("resource") @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object dumpCounters(final Object self) { final PrintWriter out = Context.getCurrentErr(); @@ -233,4 +236,133 @@ public final class NativeDebug extends ScriptObject { return UNDEFINED; } + + /* + * Framework for logging runtime events + */ + + private static final String EVENT_QUEUE = "__eventQueue__"; + private static final String EVENT_QUEUE_CAPACITY = "__eventQueueCapacity__"; + + /** + * Get the capacity of the event queue + * @param self self reference + * @return capacity of event queue as an integer + */ + @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) + public static Object getEventQueueCapacity(final Object self) { + final ScriptObject sobj = (ScriptObject)self; + Integer cap; + if (sobj.has(EVENT_QUEUE_CAPACITY)) { + cap = JSType.toInt32(sobj.get(EVENT_QUEUE_CAPACITY)); + } else { + setEventQueueCapacity(self, cap = RuntimeEvent.RUNTIME_EVENT_QUEUE_SIZE); + } + return cap; + } + + /** + * Set the event queue capacity + * @param self + * @param newCapacity + */ + @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) + public static void setEventQueueCapacity(final Object self, final Object newCapacity) { + ((ScriptObject)self).set(EVENT_QUEUE_CAPACITY, newCapacity, true); + } + + /** + * Add a runtime event to the runtime event queue. The queue has a fixed + * size {@link RuntimeEvent#RUNTIME_EVENT_QUEUE_SIZE} and the oldest + * entry will be thrown out of the queue is about to overflow + * @param self self reference + * @param event event to add + */ + @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) + public static void addRuntimeEvent(final Object self, final Object event) { + final LinkedList> q = getEventQueue(self); + final int cap = (Integer)getEventQueueCapacity(self); + while (q.size() >= cap) { + q.removeFirst(); + } + q.addLast(getEvent(event)); + } + + /** + * Expands the event queue capacity, or truncates if capacity is lower than + * current capacity. Then only the newest entries are kept + * @param self self reference + * @param newCapacity new capacity + */ + @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) + public static void expandEventQueueCapacity(final Object self, final Object newCapacity) { + final LinkedList> q = getEventQueue(self); + final int nc = JSType.toInt32(newCapacity); + while (q.size() > nc) { + q.removeFirst(); + } + setEventQueueCapacity(self, nc); + } + + /** + * Clear the runtime event queue + * @param self self reference + */ + @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) + public static void clearRuntimeEvents(final Object self) { + final LinkedList> q = getEventQueue(self); + q.clear(); + } + + /** + * Remove a specific runtime event from the event queue + * @param self self reference + * @param event event to remove + */ + @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) + public static void removeRuntimeEvent(final Object self, final Object event) { + final LinkedList> q = getEventQueue(self); + final RuntimeEvent re = getEvent(event); + if (!q.remove(re)) { + throw new IllegalStateException("runtime event " + re + " was not in event queue"); + } + } + + /** + * Return all runtime events in the queue as an array + * @param self self reference + * @return array of events + */ + @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) + public static RuntimeEvent[] getRuntimeEvents(final Object self) { + final LinkedList> q = getEventQueue(self); + return q.toArray(new RuntimeEvent[q.size()]); + } + + /** + * Return the last runtime event in the queue + * @param self self reference + * @return the freshest event, null if queue is empty + */ + @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) + public static RuntimeEvent getLastRuntimeEvent(final Object self) { + final LinkedList> q = getEventQueue(self); + return q.isEmpty() ? null : q.getLast(); + } + + @SuppressWarnings("unchecked") + private static LinkedList> getEventQueue(final Object self) { + final ScriptObject sobj = (ScriptObject)self; + LinkedList> q; + if (sobj.has(EVENT_QUEUE)) { + q = (LinkedList>)((ScriptObject)self).get(EVENT_QUEUE); + } else { + ((ScriptObject)self).set(EVENT_QUEUE, q = new LinkedList<>(), true); + } + return q; + } + + private static RuntimeEvent getEvent(final Object event) { + return (RuntimeEvent)event; + } } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java b/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java index e208baf060e..ab936402616 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java @@ -26,7 +26,6 @@ package jdk.nashorn.internal.runtime; import static jdk.nashorn.internal.codegen.ObjectClassGenerator.DEBUG_FIELDS; -import static jdk.nashorn.internal.codegen.ObjectClassGenerator.LOG; import static jdk.nashorn.internal.codegen.ObjectClassGenerator.OBJECT_FIELDS_ONLY; import static jdk.nashorn.internal.codegen.ObjectClassGenerator.PRIMITIVE_FIELD_TYPE; import static jdk.nashorn.internal.codegen.ObjectClassGenerator.createGetter; @@ -58,6 +57,8 @@ public class AccessorProperty extends Property { private static final int NOOF_TYPES = getNumberOfAccessorTypes(); + private static final DebugLogger LOG = ObjectClassGenerator.getLogger(); + /** * Properties in different maps for the same structure class will share their field getters and setters. This could * be further extended to other method handles that are looked up in the AccessorProperty constructor, but right now diff --git a/nashorn/src/jdk/nashorn/internal/runtime/CompiledFunction.java b/nashorn/src/jdk/nashorn/internal/runtime/CompiledFunction.java index f334e440760..f750334d035 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/CompiledFunction.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/CompiledFunction.java @@ -27,7 +27,6 @@ package jdk.nashorn.internal.runtime; import static jdk.nashorn.internal.lookup.Lookup.MH; import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT; import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid; - import java.lang.invoke.CallSite; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -36,6 +35,8 @@ import java.lang.invoke.MutableCallSite; import java.lang.invoke.SwitchPoint; import java.util.Map; import java.util.TreeMap; +import java.util.logging.Level; + import jdk.internal.dynalink.support.CatchExceptionCombinator; import jdk.nashorn.internal.codegen.types.ArrayType; import jdk.nashorn.internal.codegen.types.Type; @@ -60,7 +61,7 @@ final class CompiledFunction { private static final MethodHandle HANDLE_REWRITE_EXCEPTION = findOwnMH("handleRewriteException", MethodHandle.class, CompiledFunction.class, OptimismInfo.class, RewriteException.class); private static final MethodHandle RESTOF_INVOKER = MethodHandles.exactInvoker(MethodType.methodType(Object.class, RewriteException.class)); - private static final DebugLogger LOG = new DebugLogger("recompile", "nashorn.codegen.debug"); + private static final DebugLogger LOG = RecompilableScriptFunctionData.getLogger(); /** * The method type may be more specific than the invoker, if. e.g. @@ -561,7 +562,9 @@ final class CompiledFunction { final MethodType callSiteType = type.parameterType(0) == ScriptFunction.class ? type : type.insertParameterTypes(0, ScriptFunction.class); final FunctionNode fn = oldOptimismInfo.recompile(callSiteType, re); - LOG.info(" RewriteException ", re.getMessageShort()); + if (LOG.isEnabled()) { + LOG.info(new RuntimeEvent<>(Level.INFO, re), "\tRewriteException ", re.getMessageShort()); + } // It didn't necessarily recompile, e.g. for an outer invocation of a recursive function if we already // recompiled a deoptimized version for an inner invocation. @@ -578,7 +581,7 @@ final class CompiledFunction { invoker = newInvoker.asType(type.changeReturnType(newInvoker.type().returnType())); constructor = null; // Will be regenerated when needed // Note that we only adjust the switch point after we set the invoker/constructor. This is important. - if(isOptimistic) { + if (isOptimistic) { // Otherwise, set a new switch point. oldOptimismInfo.newOptimisticAssumptions(); } else { diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Context.java b/nashorn/src/jdk/nashorn/internal/runtime/Context.java index 5c4f59a4d89..79a664b8865 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java @@ -49,6 +49,8 @@ import java.security.ProtectionDomain; import java.util.LinkedHashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicLong; +import java.util.logging.Level; + import jdk.internal.org.objectweb.asm.ClassReader; import jdk.internal.org.objectweb.asm.util.CheckClassAdapter; import jdk.nashorn.api.scripting.ScriptObjectMirror; @@ -910,7 +912,10 @@ public final class Context { Class script = findCachedClass(source); if (script != null) { - Compiler.LOG.fine("Code cache hit for ", source, " avoiding recompile."); + final DebugLogger LOG = Compiler.getLogger(); + if (LOG.isEnabled()) { + LOG.fine(new RuntimeEvent<>(Level.INFO, source), "Code cache hit for ", source, " avoiding recompile."); + } return script; } @@ -978,7 +983,7 @@ public final class Context { private final int size; private final ReferenceQueue> queue; - ClassCache(int size) { + ClassCache(final int size) { super(size, 0.75f, true); this.size = size; this.queue = new ReferenceQueue<>(); @@ -994,7 +999,7 @@ public final class Context { } @Override - public ClassReference get(Object key) { + public ClassReference get(final Object key) { for (ClassReference ref; (ref = (ClassReference)queue.poll()) != null; ) { remove(ref.source); } @@ -1014,7 +1019,7 @@ public final class Context { // Class cache management private Class findCachedClass(final Source source) { - ClassReference ref = classCache == null ? null : classCache.get(source); + final ClassReference ref = classCache == null ? null : classCache.get(source); return ref != null ? ref.get() : null; } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/DebugLogger.java b/nashorn/src/jdk/nashorn/internal/runtime/DebugLogger.java index 8631dd2b5f5..f3cfc81251b 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/DebugLogger.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/DebugLogger.java @@ -28,6 +28,9 @@ package jdk.nashorn.internal.runtime; import java.io.PrintWriter; import java.util.logging.Level; import java.util.logging.Logger; + +import jdk.nashorn.internal.objects.Global; +import jdk.nashorn.internal.runtime.RuntimeEvent; import jdk.nashorn.internal.runtime.options.Options; /** @@ -42,6 +45,9 @@ public final class DebugLogger { private static final int INDENT_SPACE = 4; + /** A quiet logger only logs {@link RuntimeEvent}s and does't output any text, regardless of level */ + private final boolean isQuiet; + /** * Constructor * @@ -65,6 +71,7 @@ public final class DebugLogger { } else { this.logger = Logging.getLogger(loggerName); } + this.isQuiet = Logging.loggerIsQuiet(loggerName); assert logger != null; this.isEnabled = getLevel() != Level.OFF; } @@ -91,6 +98,37 @@ public final class DebugLogger { return Context.getCurrentErr(); } + /** + * Add quotes around a string + * @param str string + * @return quoted string + */ + public static String quote(final String str) { + if (str.isEmpty()) { + return "''"; + } + + char startQuote = '\0'; + char endQuote = '\0'; + char quote = '\0'; + + if (str.startsWith("\\") || str.startsWith("\"")) { + startQuote = str.charAt(0); + } + if (str.endsWith("\\") || str.endsWith("\"")) { + endQuote = str.charAt(str.length() - 1); + } + + if (startQuote == '\0' || endQuote == '\0') { + quote = startQuote == '\0' ? endQuote : startQuote; + } + if (quote == '\0') { + quote = '\''; + } + + return (startQuote == '\0' ? "" : startQuote) + str + (endQuote == '\0' ? "" : endQuote); + } + /** * Check if the logger is enabled * @return true if enabled @@ -128,6 +166,17 @@ public final class DebugLogger { } } + private static void logEvent(final RuntimeEvent event) { + if (event != null) { + final Global global = Context.getGlobal(); + if (global.has("Debug")) { + final ScriptObject debug = (ScriptObject)global.get("Debug"); + final ScriptFunction addRuntimeEvent = (ScriptFunction)debug.get("addRuntimeEvent"); + ScriptRuntime.apply(addRuntimeEvent, debug, event); + } + } + } + /** * Check if the logger is above the level of detail given * @see java.util.logging.Level @@ -190,6 +239,16 @@ public final class DebugLogger { log(Level.FINEST, str); } + /** + * Shorthand for outputting a log string as log level {@link java.util.logging.Level#FINEST} on this logger + * @param event optional runtime event to log + * @param str the string to log + */ + public void finest(final RuntimeEvent event, final String str) { + finest(str); + logEvent(event); + } + /** * Shorthand for outputting a log string as log level * {@link java.util.logging.Level#FINEST} on this logger @@ -199,6 +258,17 @@ public final class DebugLogger { log(Level.FINEST, objs); } + /** + * Shorthand for outputting a log string as log level + * {@link java.util.logging.Level#FINEST} on this logger + * @param event optional runtime event to log + * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead + */ + public void finest(final RuntimeEvent event, final Object... objs) { + finest(objs); + logEvent(event); + } + /** * Shorthand for outputting a log string as log level * {@link java.util.logging.Level#FINER} on this logger @@ -208,6 +278,17 @@ public final class DebugLogger { log(Level.FINER, str); } + /** + * Shorthand for outputting a log string as log level + * {@link java.util.logging.Level#FINER} on this logger + * @param event optional runtime event to log + * @param str the string to log + */ + public void finer(final RuntimeEvent event, final String str) { + finer(str); + logEvent(event); + } + /** * Shorthand for outputting a log string as log level * {@link java.util.logging.Level#FINER} on this logger @@ -217,6 +298,17 @@ public final class DebugLogger { log(Level.FINER, objs); } + /** + * Shorthand for outputting a log string as log level + * {@link java.util.logging.Level#FINER} on this logger + * @param event optional runtime event to log + * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead + */ + public void finer(final RuntimeEvent event, final Object... objs) { + finer(objs); + logEvent(event); + } + /** * Shorthand for outputting a log string as log level * {@link java.util.logging.Level#FINE} on this logger @@ -226,6 +318,17 @@ public final class DebugLogger { log(Level.FINE, str); } + /** + * Shorthand for outputting a log string as log level + * {@link java.util.logging.Level#FINE} on this logger + * @param event optional runtime event to log + * @param str the string to log + */ + public void fine(final RuntimeEvent event, final String str) { + fine(str); + logEvent(event); + } + /** * Shorthand for outputting a log string as log level * {@link java.util.logging.Level#FINE} on this logger @@ -235,6 +338,17 @@ public final class DebugLogger { log(Level.FINE, objs); } + /** + * Shorthand for outputting a log string as log level + * {@link java.util.logging.Level#FINE} on this logger + * @param event optional runtime event to log + * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead + */ + public void fine(final RuntimeEvent event, final Object... objs) { + fine(objs); + logEvent(event); + } + /** * Shorthand for outputting a log string as log level * {@link java.util.logging.Level#CONFIG} on this logger @@ -244,6 +358,17 @@ public final class DebugLogger { log(Level.CONFIG, str); } + /** + * Shorthand for outputting a log string as log level + * {@link java.util.logging.Level#CONFIG} on this logger + * @param event optional runtime event to log + * @param str the string to log + */ + public void config(final RuntimeEvent event, final String str) { + config(str); + logEvent(event); + } + /** * Shorthand for outputting a log string as log level * {@link java.util.logging.Level#CONFIG} on this logger @@ -253,6 +378,17 @@ public final class DebugLogger { log(Level.CONFIG, objs); } + /** + * Shorthand for outputting a log string as log level + * {@link java.util.logging.Level#CONFIG} on this logger + * @param event optional runtime event to log + * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead + */ + public void config(final RuntimeEvent event, final Object... objs) { + config(objs); + logEvent(event); + } + /** * Shorthand for outputting a log string as log level * {@link java.util.logging.Level#INFO} on this logger @@ -262,6 +398,17 @@ public final class DebugLogger { log(Level.INFO, str); } + /** + * Shorthand for outputting a log string as log level + * {@link java.util.logging.Level#INFO} on this logger + * @param event optional runtime event to log + * @param str the string to log + */ + public void info(final RuntimeEvent event, final String str) { + info(str); + logEvent(event); + } + /** * Shorthand for outputting a log string as log level * {@link java.util.logging.Level#FINE} on this logger @@ -271,6 +418,17 @@ public final class DebugLogger { log(Level.INFO, objs); } + /** + * Shorthand for outputting a log string as log level + * {@link java.util.logging.Level#FINE} on this logger + * @param event optional runtime event to log + * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead + */ + public void info(final RuntimeEvent event, final Object... objs) { + info(objs); + logEvent(event); + } + /** * Shorthand for outputting a log string as log level * {@link java.util.logging.Level#WARNING} on this logger @@ -280,6 +438,17 @@ public final class DebugLogger { log(Level.WARNING, str); } + /** + * Shorthand for outputting a log string as log level + * {@link java.util.logging.Level#WARNING} on this logger + * @param event optional runtime event to log + * @param str the string to log + */ + public void warning(final RuntimeEvent event, final String str) { + warning(str); + logEvent(event); + } + /** * Shorthand for outputting a log string as log level * {@link java.util.logging.Level#FINE} on this logger @@ -289,6 +458,17 @@ public final class DebugLogger { log(Level.WARNING, objs); } + /** + * Shorthand for outputting a log string as log level + * {@link java.util.logging.Level#FINE} on this logger + * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead + * @param event optional runtime event to log + */ + public void warning(final RuntimeEvent event, final Object... objs) { + warning(objs); + logEvent(event); + } + /** * Shorthand for outputting a log string as log level * {@link java.util.logging.Level#SEVERE} on this logger @@ -298,6 +478,17 @@ public final class DebugLogger { log(Level.SEVERE, str); } + /** + * Shorthand for outputting a log string as log level + * {@link java.util.logging.Level#SEVERE} on this logger + * @param str the string to log + * @param event optional runtime event to log + */ + public void severe(final RuntimeEvent event, final String str) { + severe(str); + logEvent(event); + } + /** * Shorthand for outputting a log string as log level * {@link java.util.logging.Level#FINE} on this logger @@ -307,6 +498,17 @@ public final class DebugLogger { log(Level.SEVERE, objs); } + /** + * Shorthand for outputting a log string as log level + * {@link java.util.logging.Level#FINE} on this logger + * @param event optional runtime event to log + * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead + */ + public void severe(final RuntimeEvent event, final Object... objs) { + severe(objs); + logEvent(event); + } + /** * Output log line on this logger at a given level of verbosity * @see java.util.logging.Level @@ -315,7 +517,7 @@ public final class DebugLogger { * @param str string to log */ public void log(final Level level, final String str) { - if (isEnabled) { + if (isEnabled && !isQuiet) { final StringBuilder sb = new StringBuilder(); for (int i = 0 ; i < indent ; i++) { sb.append(' '); @@ -333,15 +535,12 @@ public final class DebugLogger { * @param objs objects for which to invoke toString and concatenate to log */ public void log(final Level level, final Object... objs) { - if (isEnabled) { + if (isEnabled && !isQuiet) { final StringBuilder sb = new StringBuilder(); - for (int i = 0 ; i < indent ; i++) { - sb.append(' '); - } for (final Object obj : objs) { sb.append(obj); } - logger.log(level, sb.toString()); + log(level, sb.toString()); } } } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java b/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java index fc774fbd784..9de2c713650 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java @@ -90,7 +90,7 @@ public final class JSONFunctions { } final Global global = Context.getGlobal(); - Object unfiltered = convertNode(global, node); + final Object unfiltered = convertNode(global, node); return applyReviver(global, unfiltered, reviver); } @@ -101,7 +101,6 @@ public final class JSONFunctions { // apply 'reviver' function if available private static Object applyReviver(final Global global, final Object unfiltered, final Object reviver) { if (reviver instanceof ScriptFunction) { - assert global instanceof Global; final ScriptObject root = global.newObject(); root.addOwnProperty("", Property.WRITABLE_ENUMERABLE_CONFIGURABLE, unfiltered); return walk(root, "", (ScriptFunction)reviver); @@ -140,8 +139,6 @@ public final class JSONFunctions { // Converts IR node to runtime value private static Object convertNode(final Global global, final Node node) { - assert global instanceof Global; - if (node instanceof LiteralNode) { // check for array literal if (node.tokenType() == TokenType.ARRAY) { diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ListAdapter.java b/nashorn/src/jdk/nashorn/internal/runtime/ListAdapter.java index 9a3408fbbd6..25179a590c0 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ListAdapter.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ListAdapter.java @@ -34,7 +34,6 @@ import java.util.RandomAccess; import java.util.concurrent.Callable; import jdk.nashorn.api.scripting.JSObject; import jdk.nashorn.api.scripting.ScriptObjectMirror; -import jdk.nashorn.internal.objects.Global; import jdk.nashorn.internal.runtime.linker.Bootstrap; import jdk.nashorn.internal.runtime.linker.InvokeByName; @@ -174,7 +173,7 @@ public abstract class ListAdapter extends AbstractList implements Random */ protected abstract void setAt(final int index, final Object element); - private void checkRange(int index) { + private void checkRange(final int index) { if(index < 0 || index >= size()) { throw invalidIndex(index); } @@ -200,7 +199,7 @@ public abstract class ListAdapter extends AbstractList implements Random unshiftInvoker.getInvoker().invokeExact(fn, obj, e); } catch(RuntimeException | Error ex) { throw ex; - } catch(Throwable t) { + } catch(final Throwable t) { throw new RuntimeException(t); } } @@ -214,7 +213,7 @@ public abstract class ListAdapter extends AbstractList implements Random pushInvoker.getInvoker().invokeExact(fn, obj, e); } catch(RuntimeException | Error ex) { throw ex; - } catch(Throwable t) { + } catch(final Throwable t) { throw new RuntimeException(t); } } @@ -328,7 +327,7 @@ public abstract class ListAdapter extends AbstractList implements Random return shiftInvoker.getInvoker().invokeExact(fn, obj); } catch(RuntimeException | Error ex) { throw ex; - } catch(Throwable t) { + } catch(final Throwable t) { throw new RuntimeException(t); } } @@ -341,7 +340,7 @@ public abstract class ListAdapter extends AbstractList implements Random return popInvoker.getInvoker().invokeExact(fn, obj); } catch(RuntimeException | Error ex) { throw ex; - } catch(Throwable t) { + } catch(final Throwable t) { throw new RuntimeException(t); } } @@ -359,7 +358,7 @@ public abstract class ListAdapter extends AbstractList implements Random spliceRemoveInvoker.getInvoker().invokeExact(fn, obj, fromIndex, count); } catch(RuntimeException | Error ex) { throw ex; - } catch(Throwable t) { + } catch(final Throwable t) { throw new RuntimeException(t); } } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Logging.java b/nashorn/src/jdk/nashorn/internal/runtime/Logging.java index 54d83b79233..3a4c15eff65 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/Logging.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/Logging.java @@ -31,9 +31,11 @@ import java.security.Permissions; import java.security.PrivilegedAction; import java.security.ProtectionDomain; import java.util.HashMap; +import java.util.HashSet; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import java.util.logging.ConsoleHandler; import java.util.logging.Formatter; import java.util.logging.Handler; @@ -75,6 +77,8 @@ public final class Logging { /** Maps logger name to loggers. Names are typically per package */ private static final Map loggers = new HashMap<>(); + private static final Set quietLoggers = new HashSet<>(); + private static String lastPart(final String packageName) { final String[] parts = packageName.split("\\."); if (parts.length == 0) { @@ -115,6 +119,16 @@ public final class Logging { return logger; } + /** + * Is this logger "quiet", i.e. does it put events in the debug event + * queue, but refrains from printing anything? + * @param name logger name + * @return true if quiet + */ + public static boolean loggerIsQuiet(final String name) { + return quietLoggers.contains(name); + } + /** * Initialization function that is called to instantiate the logging system. It takes * logger names (keys) and logging labels respectively @@ -126,18 +140,20 @@ public final class Logging { try { for (final Entry entry : map.entrySet()) { Level level; - final String key = entry.getKey(); final String value = entry.getValue(); + final String name = Logging.lastPart(key); + if ("".equals(value)) { level = Level.INFO; + } else if ("quiet".equals(value)) { + level = Level.INFO; + quietLoggers.add(name); } else { level = Level.parse(value.toUpperCase(Locale.ENGLISH)); } - final String name = Logging.lastPart(key); final Logger logger = instantiateLogger(name, level); - Logging.loggers.put(name, logger); } } catch (final IllegalArgumentException | SecurityException e) { diff --git a/nashorn/src/jdk/nashorn/internal/runtime/PropertyListeners.java b/nashorn/src/jdk/nashorn/internal/runtime/PropertyListeners.java index 532969ccce6..03b2c93a307 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/PropertyListeners.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/PropertyListeners.java @@ -111,7 +111,7 @@ public class PropertyListeners { if (listeners == null) { return false; } - WeakPropertyMapSet set = listeners.get(key); + final WeakPropertyMapSet set = listeners.get(key); return set != null && set.contains(propertyMap); } @@ -145,9 +145,9 @@ public class PropertyListeners { */ public synchronized void propertyAdded(final Property prop) { if (listeners != null) { - WeakPropertyMapSet set = listeners.get(prop.getKey()); + final WeakPropertyMapSet set = listeners.get(prop.getKey()); if (set != null) { - for (PropertyMap propertyMap : set.elements()) { + for (final PropertyMap propertyMap : set.elements()) { propertyMap.propertyAdded(prop); } listeners.remove(prop.getKey()); @@ -162,9 +162,9 @@ public class PropertyListeners { */ public synchronized void propertyDeleted(final Property prop) { if (listeners != null) { - WeakPropertyMapSet set = listeners.get(prop.getKey()); + final WeakPropertyMapSet set = listeners.get(prop.getKey()); if (set != null) { - for (PropertyMap propertyMap : set.elements()) { + for (final PropertyMap propertyMap : set.elements()) { propertyMap.propertyDeleted(prop); } listeners.remove(prop.getKey()); @@ -181,9 +181,9 @@ public class PropertyListeners { */ public synchronized void propertyModified(final Property oldProp, final Property newProp) { if (listeners != null) { - WeakPropertyMapSet set = listeners.get(oldProp.getKey()); + final WeakPropertyMapSet set = listeners.get(oldProp.getKey()); if (set != null) { - for (PropertyMap propertyMap : set.elements()) { + for (final PropertyMap propertyMap : set.elements()) { propertyMap.propertyModified(oldProp, newProp); } listeners.remove(oldProp.getKey()); @@ -191,10 +191,13 @@ public class PropertyListeners { } } + /** + * Callback for when a proto is changed + */ public synchronized void protoChanged() { if (listeners != null) { - for (WeakPropertyMapSet set : listeners.values()) { - for (PropertyMap propertyMap : set.elements()) { + for (final WeakPropertyMapSet set : listeners.values()) { + for (final PropertyMap propertyMap : set.elements()) { propertyMap.protoChanged(); } } @@ -204,7 +207,7 @@ public class PropertyListeners { private static class WeakPropertyMapSet { - private WeakHashMap map = new WeakHashMap<>(); + private final WeakHashMap map = new WeakHashMap<>(); void add(final PropertyMap propertyMap) { map.put(propertyMap, Boolean.TRUE); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java b/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java index 7c0fc6c522c..f3e20275053 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java @@ -36,6 +36,7 @@ import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; + import jdk.internal.dynalink.support.NameCodec; import jdk.nashorn.internal.codegen.CompilationEnvironment; import jdk.nashorn.internal.codegen.CompilationEnvironment.CompilationPhases; @@ -112,6 +113,14 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { private static final DebugLogger LOG = new DebugLogger("recompile"); + /** + * Get the recompilation logger + * @return the logger + */ + public static DebugLogger getLogger() { + return LOG; + } + private final Map externalScopeDepths; private static final int GET_SET_PREFIX_LENGTH = "*et ".length(); @@ -310,7 +319,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { final Map.Entry entry = iter.next(); sb.append('['). append(entry.getKey()). - append("=>"). + append("->"). append(entry.getValue().getShortDescriptor()). append(']'); if (iter.hasNext()) { @@ -321,7 +330,9 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { } MethodHandle compileRestOfMethod(final MethodType fnCallSiteType, final Map invalidatedProgramPoints, final int[] continuationEntryPoints, final ScriptObject runtimeScope) { - LOG.info("Rest-of compilation of '", functionName, "' signature: ", fnCallSiteType, " ", stringifyInvalidations(invalidatedProgramPoints)); + if (LOG.isEnabled()) { + LOG.info("Rest-of compilation of '", functionName, "' signature: ", fnCallSiteType, " ", stringifyInvalidations(invalidatedProgramPoints)); + } final String scriptName = RECOMPILATION_PREFIX + RECOMPILE_ID.incrementAndGet() + "$restOf"; FunctionNode fn = reparse(scriptName); @@ -343,6 +354,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { compiler.install(fn); + // look up the rest of method return lookupWithExplicitType(fn, MethodType.methodType(fn.getReturnType().getTypeClass(), RewriteException.class)); } @@ -353,7 +365,10 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { FunctionNode compile(final MethodType actualCallSiteType, final Map invalidatedProgramPoints, final ScriptObject runtimeScope, final String reason) { final String scriptName = RECOMPILATION_PREFIX + RECOMPILE_ID.incrementAndGet(); final MethodType fnCallSiteType = actualCallSiteType == null ? null : actualCallSiteType.changeParameterType(0, ScriptFunction.class); - LOG.info(reason, " of '", functionName, "' signature: ", fnCallSiteType, " ", stringifyInvalidations(invalidatedProgramPoints)); + + if (LOG.isEnabled()) { + LOG.info(reason, " of '", functionName, "' signature: ", fnCallSiteType, " ", stringifyInvalidations(invalidatedProgramPoints)); + } FunctionNode fn = reparse(scriptName); final CompilationPhases phases = CompilationPhases.EAGER; @@ -509,7 +524,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { @Override CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope) { - synchronized(code) { + synchronized (code) { final CompiledFunction existingBest = super.getBest(callSiteType, runtimeScope); // TODO: what if callSiteType is vararg? return existingBest != null ? existingBest : addCode(compileTypeSpecialization(callSiteType, runtimeScope), callSiteType); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/RewriteException.java b/nashorn/src/jdk/nashorn/internal/runtime/RewriteException.java index 983467b1f4b..95cbd4713e4 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/RewriteException.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/RewriteException.java @@ -52,7 +52,9 @@ public class RewriteException extends Exception { // optimistic assumptions (which will lead to unnecessary deoptimizing recompilations). private ScriptObject runtimeScope; //contents of bytecode slots + private Object[] byteCodeSlots; + private final int[] previousContinuationEntryPoints; /** Methodhandle for getting the contents of the bytecode slots in the exception */ @@ -67,6 +69,42 @@ public class RewriteException extends Exception { /** Methodhandle for populating an array with local variable state */ private static final Call POPULATE_ARRAY = staticCall(MethodHandles.lookup(), RewriteException.class, "populateArray", Object[].class, Object[].class, int.class, Object[].class); + /** + * Constructor for a rewrite exception thrown from an optimistic function. + * @param e the {@link UnwarrantedOptimismException} that triggered this exception. + * @param byteCodeSlots contents of local variable slots at the time of rewrite at the program point + * @param byteCodeSymbolNames byte code symbol names + * @param runtimeScope the runtime scope used for known type information when recompiling + */ + public RewriteException( + final UnwarrantedOptimismException e, + final Object[] byteCodeSlots, + final String[] byteCodeSymbolNames, + final ScriptObject runtimeScope) { + this(e, byteCodeSlots, byteCodeSymbolNames, runtimeScope, null); + } + + /** + * Constructor for a rewrite exception thrown from a rest-of method. + * @param e the {@link UnwarrantedOptimismException} that triggered this exception. + * @param byteCodeSymbolNames byte code symbol names + * @param byteCodeSlots contents of local variable slots at the time of rewrite at the program point + * @param runtimeScope the runtime scope used for known type information when recompiling + * @param previousContinuationEntryPoints an array of continuation entry points that were already executed during + * one logical invocation of the function (a rest-of triggering a rest-of triggering a...) + */ + public RewriteException( + final UnwarrantedOptimismException e, + final Object[] byteCodeSlots, + final String[] byteCodeSymbolNames, + final ScriptObject runtimeScope, + final int[] previousContinuationEntryPoints) { + super("", e, false, Context.DEBUG); + this.byteCodeSlots = byteCodeSlots; + this.runtimeScope = mergeSlotsWithScope(byteCodeSlots, byteCodeSymbolNames, runtimeScope); + this.previousContinuationEntryPoints = previousContinuationEntryPoints; + } + /** * Bootstrap method for populate array * @param lookup lookup @@ -83,29 +121,6 @@ public class RewriteException extends Exception { return new ConstantCallSite(mh); } - /** - * Constructor for a rewrite exception thrown from an optimistic function. - * @param e the {@link UnwarrantedOptimismException} that triggered this exception. - * @param byteCodeSlots contents of local variable slots at the time of rewrite at the program point - */ - public RewriteException(final UnwarrantedOptimismException e, final Object[] byteCodeSlots, final String[] byteCodeSymbolNames, final ScriptObject runtimeScope) { - this(e, byteCodeSlots, byteCodeSymbolNames, runtimeScope, null); - } - - /** - * Constructor for a rewrite exception thrown from a rest-of method. - * @param e the {@link UnwarrantedOptimismException} that triggered this exception. - * @param byteCodeSlots contents of local variable slots at the time of rewrite at the program point - * @param previousContinuationEntryPoints an array of continuation entry points that were already executed during - * one logical invocation of the function (a rest-of triggering a rest-of triggering a...) - */ - public RewriteException(final UnwarrantedOptimismException e, final Object[] byteCodeSlots, final String[] byteCodeSymbolNames, final ScriptObject runtimeScope, final int[] previousContinuationEntryPoints) { - super("", e, false, Context.DEBUG); - this.byteCodeSlots = byteCodeSlots; - this.runtimeScope = mergeSlotsWithScope(byteCodeSlots, byteCodeSymbolNames, runtimeScope); - this.previousContinuationEntryPoints = previousContinuationEntryPoints; - } - private static ScriptObject mergeSlotsWithScope(final Object[] byteCodeSlots, final String[] byteCodeSymbolNames, final ScriptObject runtimeScope) { final ScriptObject locals = Global.newEmptyInstance(); @@ -204,7 +219,7 @@ public class RewriteException extends Exception { @Override public String getMessage() { - return "programPoint=" + getProgramPoint() + " slots=" + Arrays.asList(byteCodeSlots) + ", returnValue=" + stringify(getReturnValueNonDestructive()) + ", returnType=" + getReturnType(); + return "programPoint=" + getProgramPoint() + " slots=" + (byteCodeSlots == null ? "null" : Arrays.asList(byteCodeSlots)) + ", returnValue=" + stringify(getReturnValueNonDestructive()) + ", returnType=" + getReturnType(); } /** diff --git a/nashorn/src/jdk/nashorn/internal/runtime/RuntimeEvent.java b/nashorn/src/jdk/nashorn/internal/runtime/RuntimeEvent.java new file mode 100644 index 00000000000..bb5f273d05f --- /dev/null +++ b/nashorn/src/jdk/nashorn/internal/runtime/RuntimeEvent.java @@ -0,0 +1,62 @@ +package jdk.nashorn.internal.runtime; + +import java.util.logging.Level; + +import jdk.nashorn.internal.objects.NativeDebug; +import jdk.nashorn.internal.runtime.options.Options; + +/** + * Class for representing a runtime event, giving less global dependencies than logger. + * Every {@link NativeDebug} object keeps a queue of RuntimeEvents that can be explored + * through the debug API. + * + * @param class of the value this event wraps + */ +public class RuntimeEvent { + /** Queue size for the runtime event buffer */ + public static final int RUNTIME_EVENT_QUEUE_SIZE = Options.getIntProperty("nashorn.runtime.event.queue.size", 1024); + + private final Level level; + private final T value; + + /** + * Constructor + * @param level log level for runtime event to create + * @param object object to wrap + */ + public RuntimeEvent(final Level level, final T object) { + this.level = level; + this.value = object; + } + + /** + * Return the value wrapped in this runtime event + * @return value + */ + public T getValue() { + return value; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + + sb.append('['). + append(level). + append("] "). + append(value == null ? "null" : getValueClass().getSimpleName()). + append(" value="). + append(value); + + return sb.toString(); + } + + /** + * Descriptor for this runtime event, must be overridden and + * implemented, e.g. "RewriteException" + * @return event name + */ + public final Class getValueClass() { + return value.getClass(); + } +} diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java index f21f414b843..2286301623a 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java @@ -68,7 +68,7 @@ public abstract class ScriptFunction extends ScriptObject { private static final MethodHandle WRAPFILTER = findOwnMH_S("wrapFilter", Object.class, Object.class); - private static final MethodHandle GLOBALFILTER = findOwnMH_S("globalFilter", Object.class, Object.class); + private static final MethodHandle SCRIPTFUNCTION_GLOBALFILTER = findOwnMH_S("globalFilter", Object.class, Object.class); /** method handle to scope getter for this ScriptFunction */ public static final Call GET_SCOPE = virtualCallNoLookup(ScriptFunction.class, "getScope", ScriptObject.class); @@ -554,7 +554,7 @@ public abstract class ScriptFunction extends ScriptObject { if (data.needsCallee()) { if (scopeCall && needsWrappedThis()) { // (callee, this, args...) => (callee, [this], args...) - boundHandle = MH.filterArguments(callHandle, 1, GLOBALFILTER); + boundHandle = MH.filterArguments(callHandle, 1, SCRIPTFUNCTION_GLOBALFILTER); } else { // It's already (callee, this, args...), just what we need boundHandle = callHandle; @@ -566,7 +566,7 @@ public abstract class ScriptFunction extends ScriptObject { } else if (scopeCall && needsWrappedThis()) { // Make a handle that drops the passed "this" argument and substitutes either Global or Undefined // (this, args...) => ([this], args...) - boundHandle = MH.filterArguments(callHandle, 0, GLOBALFILTER); + boundHandle = MH.filterArguments(callHandle, 0, SCRIPTFUNCTION_GLOBALFILTER); // ([this], args...) => ([callee], [this], args...) boundHandle = MH.dropArguments(boundHandle, 0, type.parameterType(0)); } else { @@ -684,7 +684,7 @@ public abstract class ScriptFunction extends ScriptObject { private static MethodHandle bindImplicitThis(final Object fn, final MethodHandle mh) { final MethodHandle bound; if(fn instanceof ScriptFunction && ((ScriptFunction)fn).needsWrappedThis()) { - bound = MH.filterArguments(mh, 1, GLOBALFILTER); + bound = MH.filterArguments(mh, 1, SCRIPTFUNCTION_GLOBALFILTER); } else { bound = mh; } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java index 8a90a8f7482..73cfaf4d39c 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java @@ -219,8 +219,7 @@ public abstract class ScriptFunctionData { /** * If we can have lazy code generation, this is a hook to ensure that the code has been compiled. - * This does not guarantee the code been installed in this {@code ScriptFunctionData} instance; - * use {@link #ensureCodeGenerated()} to install the actual method handles. + * This does not guarantee the code been installed in this {@code ScriptFunctionData} instance */ protected void ensureCompiled() { //empty diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java index 32f29e8c4ae..adf0d67898b 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -1890,7 +1890,7 @@ public abstract class ScriptObject implements PropertyAccess { mh = find.getGetter(returnType, programPoint); // Get the appropriate guard for this callsite and property. - MethodHandle guard = NashornGuards.getGuard(this, property, desc, explicitInstanceOfCheck); + final MethodHandle guard = NashornGuards.getGuard(this, property, desc, explicitInstanceOfCheck); final ScriptObject owner = find.getOwner(); final Class exception = explicitInstanceOfCheck ? null : ClassCastException.class; @@ -1915,11 +1915,10 @@ public abstract class ScriptObject implements PropertyAccess { exception); } - private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name, - final boolean isMethod, final boolean isScope) { - ObjectClassGenerator.LOG.warning("Megamorphic getter: " + desc + " " + name + " " +isMethod); + private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name, final boolean isMethod, final boolean isScope) { + ObjectClassGenerator.getLogger().warning("Megamorphic getter: " + desc + " " + name + " " +isMethod); final MethodHandle invoker = MH.insertArguments(MEGAMORPHIC_GET, 1, name, isMethod, isScope); - final MethodHandle guard = getScriptObjectGuard(desc.getMethodType(), true); + final MethodHandle guard = getScriptObjectGuard(desc.getMethodType(), true); return new GuardedInvocation(invoker, guard); } @@ -2004,7 +2003,7 @@ public abstract class ScriptObject implements PropertyAccess { } for (ScriptObject obj = this; obj != owner && obj.getProto() != null; obj = obj.getProto()) { - ScriptObject parent = obj.getProto(); + final ScriptObject parent = obj.getProto(); parent.getMap().addListener(name, obj.getMap()); } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java index 8fe17c997a1..40d7211af63 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java @@ -30,9 +30,11 @@ import java.lang.invoke.MethodHandles.Lookup; import java.lang.invoke.MethodType; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; + import jdk.internal.dynalink.CallSiteDescriptor; import jdk.internal.dynalink.support.AbstractCallSiteDescriptor; import jdk.internal.dynalink.support.CallSiteDescriptorFactory; +import jdk.nashorn.internal.ir.debug.NashornTextifier; /** * Nashorn-specific implementation of Dynalink's {@link CallSiteDescriptor}. The reason we have our own subclass is that @@ -96,7 +98,7 @@ public final class NashornCallSiteDescriptor extends AbstractCallSiteDescriptor private static final ClassValue> canonicals = new ClassValue>() { @Override - protected ConcurrentMap computeValue(Class type) { + protected ConcurrentMap computeValue(final Class type) { return new ConcurrentHashMap<>(); } }; @@ -107,6 +109,12 @@ public final class NashornCallSiteDescriptor extends AbstractCallSiteDescriptor private final MethodType methodType; private final int flags; + /** + * Function used by {@link NashornTextifier} to represent call site flags in + * human readable form + * @param flags call site flags + * @return human readable form of this callsite descriptor + */ public static String toString(final int flags) { final StringBuilder sb = new StringBuilder(); if ((flags & CALLSITE_SCOPE) != 0) { diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java index 0bb93d3e440..20abb5612a3 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java @@ -49,7 +49,8 @@ public final class NashornGuards { private static final MethodHandle IS_INSTANCEOF_2 = findOwnMH("isInstanceOf2", boolean.class, Object.class, Class.class, Class.class); private static final MethodHandle IS_SCRIPTOBJECT = findOwnMH("isScriptObject", boolean.class, Object.class); private static final MethodHandle SAME_OBJECT = findOwnMH("sameObject", boolean.class, Object.class, WeakReference.class); - private static final MethodHandle IS_SCRIPTFUNCTION = findOwnMH("isScriptFunction", boolean.class, Object.class); + //TODO - maybe put this back in ScriptFunction instead of the ClassCastException.class relinkage + //private static final MethodHandle IS_SCRIPTFUNCTION = findOwnMH("isScriptFunction", boolean.class, Object.class); private static final boolean CCE_ONLY = Options.getBooleanProperty("nashorn.cce"); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java index 62b63e3fbc1..d0bd1122340 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java @@ -39,7 +39,6 @@ import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; import jdk.internal.dynalink.support.TypeUtilities; import jdk.nashorn.internal.objects.Global; import jdk.nashorn.internal.runtime.ConsString; -import jdk.nashorn.internal.runtime.Context; /** * Internal linker for String, Boolean, and Number objects, only ever used by Nashorn engine and not exposed to other @@ -62,10 +61,9 @@ final class NashornPrimitiveLinker implements TypeBasedGuardingDynamicLinker, Gu final LinkRequest request = origRequest.withoutRuntimeContext(); // Nashorn has no runtime context final Object self = request.getReceiver(); - final Global global = Context.getGlobal(); final NashornCallSiteDescriptor desc = (NashornCallSiteDescriptor) request.getCallSiteDescriptor(); - return Bootstrap.asTypeSafeReturn(global.primitiveLookup(request, self), linkerServices, desc); + return Bootstrap.asTypeSafeReturn(Global.primitiveLookup(request, self), linkerServices, desc); } /** diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java index 7665be7fcb3..690f4c9bfa8 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java @@ -59,6 +59,7 @@ public final class PrimitiveLookup { * creates a transient native wrapper of the same type as {@code wrappedReceiver} for subsequent invocations of the * method - it will be combined into the returned invocation as an argument filter on the receiver. * @return a guarded invocation representing the operation at the call site when performed on a JavaScript primitive + * @param protoFilter A method handle that walks up the proto chain of this receiver object * type {@code receiverClass}. */ public static GuardedInvocation lookupPrimitive(final LinkRequest request, final Class receiverClass, @@ -77,6 +78,7 @@ public final class PrimitiveLookup { * @param wrapFilter A method handle that takes a primitive value of type guarded by the {@code guard} and * creates a transient native wrapper of the same type as {@code wrappedReceiver} for subsequent invocations of the * method - it will be combined into the returned invocation as an argument filter on the receiver. + * @param protoFilter A method handle that walks up the proto chain of this receiver object * @return a guarded invocation representing the operation at the call site when performed on a JavaScript primitive * type (that is implied by both {@code guard} and {@code wrappedReceiver}). */ @@ -86,7 +88,7 @@ public final class PrimitiveLookup { final CallSiteDescriptor desc = request.getCallSiteDescriptor(); final String operator = CallSiteDescriptorFactory.tokenizeOperators(desc).get(0); if ("setProp".equals(operator) || "setElem".equals(operator)) { - MethodType type = desc.getMethodType(); + final MethodType type = desc.getMethodType(); MethodHandle method = MH.asType(Lookup.EMPTY_SETTER, MH.type(void.class, Object.class, type.parameterType(1))); if (type.parameterCount() == 3) { method = MH.dropArguments(method, 2, type.parameterType(2)); diff --git a/nashorn/src/jdk/nashorn/tools/Shell.java b/nashorn/src/jdk/nashorn/tools/Shell.java index ab31ae40bed..cb775fca543 100644 --- a/nashorn/src/jdk/nashorn/tools/Shell.java +++ b/nashorn/src/jdk/nashorn/tools/Shell.java @@ -52,7 +52,6 @@ import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.Property; import jdk.nashorn.internal.runtime.ScriptEnvironment; import jdk.nashorn.internal.runtime.ScriptFunction; -import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptRuntime; import jdk.nashorn.internal.runtime.Source; import jdk.nashorn.internal.runtime.options.Options; diff --git a/nashorn/test/script/trusted/JDK-8006529.js b/nashorn/test/script/trusted/JDK-8006529.js index d7b122153fb..c95fae5266d 100644 --- a/nashorn/test/script/trusted/JDK-8006529.js +++ b/nashorn/test/script/trusted/JDK-8006529.js @@ -39,7 +39,7 @@ * and FunctionNode because of package-access check and so reflective calls. */ -var forName = java.lang.Class["forName(String)"]; +var forName = java.lang.Class["forName(String)"]; var Parser = forName("jdk.nashorn.internal.parser.Parser").static var Compiler = forName("jdk.nashorn.internal.codegen.Compiler").static var Context = forName("jdk.nashorn.internal.runtime.Context").static diff --git a/nashorn/test/script/trusted/event_queue.js b/nashorn/test/script/trusted/event_queue.js new file mode 100644 index 00000000000..ae6c74f4467 --- /dev/null +++ b/nashorn/test/script/trusted/event_queue.js @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2010, 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. + */ + +/** + * Debug.eventqueue test - instead of screen scraping, test the concept of asking Debug for + * an event log of favourable events. + * + * @test + * @fork + * @option -Dnashorn.debug=true + * @option --log=recompile:quiet + */ + +print(Debug); +print(); + +var forName = java.lang.Class["forName(String)"]; +var RuntimeEvent = forName("jdk.nashorn.internal.runtime.RuntimeEvent").static; +var getValue = RuntimeEvent.class.getMethod("getValue"); +var getValueClass = RuntimeEvent.class.getMethod("getValueClass"); + +print(RuntimeEvent); + +var RewriteException = forName("jdk.nashorn.internal.runtime.RewriteException").static; +var getReturnType = RewriteException.class.getMethod("getReturnType"); + +print(RewriteException); + +var a = [1.1, 2.2]; +function f() { + var sum = 2; + for (var i = 0; i < a.length; i++) { + sum *= a[i]; + } + return sum; +} + +function g() { + var diff = 17; + for (var i = 0; i < a.length; i++) { + diff -= a[i]; + } + return diff; +} + +//kill anything that may already be in the event queue from earlier debug runs +Debug.clearRuntimeEvents(); + +print(); +print(f()); +print(g()); + +print(); +events = Debug.getRuntimeEvents(); +print("Done with " + events.length + " in the event queue"); +//make sure we got runtime events +print("events = " + (events.toString().indexOf("RuntimeEvent") != -1)); +print("events.length = " + events.length); + +var lastInLoop = undefined; +for (var i = 0; i < events.length; i++) { + var e = events[i]; + print("event #" + i); + print("\tevent class=" + e.getClass()); + print("\tvalueClass in event=" + getValueClass.invoke(e)); + var v = getValue.invoke(e); + print("\tclass of value=" + v.getClass()); + print("\treturn type=" + getReturnType.invoke(v)); + lastInLoop = events[i]; +} + +print(); +print("in loop last class = " + lastInLoop.getClass()); +print("in loop last value class = " + getValueClass.invoke(lastInLoop)); +var rexInLoop = getValue.invoke(lastInLoop); +print("in loop rex class = " + rexInLoop.getClass()); +print("in loop rex return type = " + getReturnType.invoke(rexInLoop)); + +//try last runtime events +var last = Debug.getLastRuntimeEvent(); +//the code after the loop creates additional rewrite exceptions +print(); +print(last !== lastInLoop); +print(); + +print("last class = " + last.getClass()); +print("last value class = " + getValueClass.invoke(last)); +var rex = getValue.invoke(last); +print("rex class = " + rex.getClass()); +print("rex return type = " + getReturnType.invoke(rex)); + +//try the capacity setter +print(); +print(Debug.getEventQueueCapacity()); +Debug.setEventQueueCapacity(2048); +print(Debug.getEventQueueCapacity()); + +//try clear events +print(); +Debug.clearRuntimeEvents(); +print(Debug.getRuntimeEvents().length); + diff --git a/nashorn/test/script/trusted/event_queue.js.EXPECTED b/nashorn/test/script/trusted/event_queue.js.EXPECTED new file mode 100644 index 00000000000..ffc494fa71c --- /dev/null +++ b/nashorn/test/script/trusted/event_queue.js.EXPECTED @@ -0,0 +1,38 @@ +[object Debug] + +[JavaClass jdk.nashorn.internal.runtime.RuntimeEvent] +[JavaClass jdk.nashorn.internal.runtime.RewriteException] + +4.840000000000001 +13.7 + +Done with 2 in the event queue +events = true +events.length = 2 +event #0 + event class=class jdk.nashorn.internal.runtime.RuntimeEvent + valueClass in event=class jdk.nashorn.internal.runtime.RewriteException + class of value=class jdk.nashorn.internal.runtime.RewriteException + return type=double +event #1 + event class=class jdk.nashorn.internal.runtime.RuntimeEvent + valueClass in event=class jdk.nashorn.internal.runtime.RewriteException + class of value=class jdk.nashorn.internal.runtime.RewriteException + return type=double + +in loop last class = class jdk.nashorn.internal.runtime.RuntimeEvent +in loop last value class = class jdk.nashorn.internal.runtime.RewriteException +in loop rex class = class jdk.nashorn.internal.runtime.RewriteException +in loop rex return type = double + +true + +last class = class jdk.nashorn.internal.runtime.RuntimeEvent +last value class = class jdk.nashorn.internal.runtime.RewriteException +rex class = class jdk.nashorn.internal.runtime.RewriteException +rex return type = object + +1024 +2048 + +0 diff --git a/nashorn/test/src/jdk/nashorn/internal/runtime/NoPersistenceCachingTest.java b/nashorn/test/src/jdk/nashorn/internal/runtime/NoPersistenceCachingTest.java index 7b84f5a7af3..54ccb2becfb 100644 --- a/nashorn/test/src/jdk/nashorn/internal/runtime/NoPersistenceCachingTest.java +++ b/nashorn/test/src/jdk/nashorn/internal/runtime/NoPersistenceCachingTest.java @@ -59,8 +59,8 @@ public class NoPersistenceCachingTest { prevStderr = System.err; System.setErr(new PrintStream(stderr)); NashornScriptEngineFactory nashornFactory = null; - ScriptEngineManager sm = new ScriptEngineManager(); - for (ScriptEngineFactory fac : sm.getEngineFactories()) { + final ScriptEngineManager sm = new ScriptEngineManager(); + for (final ScriptEngineFactory fac : sm.getEngineFactories()) { if (fac instanceof NashornScriptEngineFactory) { nashornFactory = (NashornScriptEngineFactory) fac; break; @@ -69,7 +69,10 @@ public class NoPersistenceCachingTest { if (nashornFactory == null) { fail("Cannot find nashorn factory!"); } - String[] options = new String[]{"--log=compiler:finest"}; + // fine is enough for cache hits, finest produces way too much information + // TODO this should be ported to use the RuntimeEvents instead of screen scraping + // logs, as obviously this is very brittle + final String[] options = new String[]{"--log=compiler:fine"}; engine = nashornFactory.getScriptEngine(options); context1 = engine.getContext(); context2 = new SimpleScriptContext(); @@ -83,18 +86,18 @@ public class NoPersistenceCachingTest { System.setErr(prevStderr); } - public void runTest(int numberOfContext, String expectedOutputPattern, - int expectedPatternOccurrence) { + public void runTest(final int numberOfContext, final String expectedOutputPattern, + final int expectedPatternOccurrence) { try { switch (numberOfContext) { case 2: - String scriptTwoContexts = "print('HelloTwoContexts')"; + final String scriptTwoContexts = "print('HelloTwoContexts')"; engine.eval(scriptTwoContexts, context1); engine.eval(scriptTwoContexts, context2); break; case 3: - String scriptThreeContexts = "print('HelloThreeContexts')"; + final String scriptThreeContexts = "print('HelloThreeContexts')"; engine.eval(scriptThreeContexts, context1); engine.eval(scriptThreeContexts, context2); engine.eval(scriptThreeContexts, context3); @@ -104,8 +107,8 @@ public class NoPersistenceCachingTest { se.printStackTrace(); fail(se.getMessage()); } - Pattern deoptimizing = Pattern.compile(expectedOutputPattern); - Matcher matcher = deoptimizing.matcher(stderr.toString()); + final Pattern deoptimizing = Pattern.compile(expectedOutputPattern); + final Matcher matcher = deoptimizing.matcher(stderr.toString()); int matches = 0; while (matcher.find()) { matches++;