/*
 * Copyright (c) 2010, 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.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

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.PropertySwitchPoints;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.Scope;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.events.RuntimeEvent;
import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;

Nashorn specific debug utils. This is meant for Nashorn developers. The interface is subject to change without notice!!
/** * Nashorn specific debug utils. This is meant for Nashorn developers. * The interface is subject to change without notice!! * */
@ScriptClass("Debug") public final class NativeDebug extends ScriptObject { // initialized by nasgen @SuppressWarnings("unused") private static PropertyMap $nasgenmap$; private NativeDebug() { // don't create me! throw new UnsupportedOperationException(); } @Override public String getClassName() { return "Debug"; }
Return the ArrayData class for this ScriptObject
Params:
  • self – self
  • obj – script object to check
Returns:ArrayData class, or undefined if no ArrayData is present
/** * Return the ArrayData class for this ScriptObject * @param self self * @param obj script object to check * @return ArrayData class, or undefined if no ArrayData is present */
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object getArrayDataClass(final Object self, final Object obj) { try { return ((ScriptObject)obj).getArray().getClass(); } catch (final ClassCastException e) { return ScriptRuntime.UNDEFINED; } }
Return the ArrayData for this ScriptObject
Params:
  • self – self
  • obj – script object to check
Returns:ArrayData, ArrayDatas have toString methods, return Undefined if data missing
/** * Return the ArrayData for this ScriptObject * @param self self * @param obj script object to check * @return ArrayData, ArrayDatas have toString methods, return Undefined if data missing */
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object getArrayData(final Object self, final Object obj) { try { return ((ScriptObject)obj).getArray(); } catch (final ClassCastException e) { return ScriptRuntime.UNDEFINED; } }
Nashorn extension: get context, context utility
Params:
  • self – self reference
Returns:context
/** * Nashorn extension: get context, context utility * * @param self self reference * @return context */
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object getContext(final Object self) { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new RuntimePermission(Context.NASHORN_GET_CONTEXT)); } return Global.getThisContext(); }
Nashorn extension: get map from ScriptObject
Params:
  • self – self reference
  • obj – script object
Returns:the map for the current ScriptObject
/** * Nashorn extension: get map from {@link ScriptObject} * * @param self self reference * @param obj script object * @return the map for the current ScriptObject */
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object map(final Object self, final Object obj) { if (obj instanceof ScriptObject) { return ((ScriptObject)obj).getMap(); } return UNDEFINED; }
Check object identity comparison regardless of type
Params:
  • self – self reference
  • obj1 – first object in comparison
  • obj2 – second object in comparison
Returns:true if reference identity
/** * Check object identity comparison regardless of type * * @param self self reference * @param obj1 first object in comparison * @param obj2 second object in comparison * @return true if reference identity */
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static boolean identical(final Object self, final Object obj1, final Object obj2) { return obj1 == obj2; }
Returns true if if the two objects are both property maps, and they have identical properties in the same order, but allows the properties to differ in their types.
Params:
  • self – self
  • m1 – first property map
  • m2 – second property map
Returns:true if they have identical properties in same order, with possibly different types.
/** * Returns true if if the two objects are both property maps, and they have identical properties in the same order, * but allows the properties to differ in their types. * @param self self * @param m1 first property map * @param m2 second property map * @return true if they have identical properties in same order, with possibly different types. */
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object equalWithoutType(final Object self, final Object m1, final Object m2) { return ((PropertyMap)m1).equalsWithoutType((PropertyMap)m2); }
Returns a diagnostic string representing the difference of two property maps.
Params:
  • self – self
  • m1 – first property map
  • m2 – second property map
Returns:a diagnostic string representing the difference of two property maps.
/** * Returns a diagnostic string representing the difference of two property maps. * @param self self * @param m1 first property map * @param m2 second property map * @return a diagnostic string representing the difference of two property maps. */
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object diffPropertyMaps(final Object self, final Object m1, final Object m2) { return PropertyMap.diff((PropertyMap)m1, (PropertyMap)m2); }
Object util - getClass
Params:
  • self – self reference
  • obj – object
Returns:class of obj
/** * Object util - getClass * * @param self self reference * @param obj object * @return class of {@code obj} */
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object getClass(final Object self, final Object obj) { if (obj != null) { return obj.getClass(); } return UNDEFINED; }
Object util - equals
Params:
  • self – self reference
  • obj1 – first object in comparison
  • obj2 – second object in comparison
Returns:return Object.equals(Object) for objects.
/** * Object util - equals * * @param self self reference * @param obj1 first object in comparison * @param obj2 second object in comparison * @return return {@link Object#equals(Object)} for objects. */
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static boolean equals(final Object self, final Object obj1, final Object obj2) { return Objects.equals(obj1, obj2); }
Object util - toJavaString
Params:
  • self – self reference
  • obj – object to represent as a string
Returns:Java string representation of obj
/** * Object util - toJavaString * * @param self self reference * @param obj object to represent as a string * @return Java string representation of {@code obj} */
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static String toJavaString(final Object self, final Object obj) { return Objects.toString(obj); }
Do not call overridden toString -- use default toString impl
Params:
  • self – self reference
  • obj – object to represent as a string
Returns:string representation
/** * Do not call overridden toString -- use default toString impl * * @param self self reference * @param obj object to represent as a string * @return string representation */
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static String toIdentString(final Object self, final Object obj) { if (obj == null) { return "null"; } final int hash = System.identityHashCode(obj); return obj.getClass() + "@" + Integer.toHexString(hash); }
Returns true if passed object is a function that is fully debuggable (has all vars in scope).
Params:
  • self – self reference
  • obj – object
Returns:true obj is a debuggable function
/** * Returns {@code true} if passed object is a function that is fully debuggable (has all vars in scope). * * @param self self reference * @param obj object * @return true {@code obj} is a debuggable function */
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object isDebuggableFunction(final Object self, final Object obj) { return (obj instanceof ScriptFunction && ((ScriptFunction) obj).hasAllVarsInScope()); }
Returns the property listener count for a script object
Params:
  • self – self reference
  • obj – script object whose listener count is returned
Returns:listener count
/** * Returns the property listener count for a script object * * @param self self reference * @param obj script object whose listener count is returned * @return listener count */
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static int getListenerCount(final Object self, final Object obj) { return (obj instanceof ScriptObject) ? PropertySwitchPoints.getSwitchPointCount((ScriptObject) obj) : 0; }
Dump all Nashorn debug mode counters. Calling this may be better if you want to print all counters. This way you can avoid too many callsites due to counter access itself!!
Params:
  • self – self reference
Returns:undefined
/** * Dump all Nashorn debug mode counters. Calling this may be better if * you want to print all counters. This way you can avoid too many callsites * due to counter access itself!! * @param self self reference * @return undefined */
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object dumpCounters(final Object self) { final PrintWriter out = Context.getCurrentErr(); out.println("ScriptObject count " + ScriptObject.getCount()); out.println("Scope count " + Scope.getScopeCount()); out.println("Property SwitchPoints added " + PropertySwitchPoints.getSwitchPointsAdded()); out.println("Property SwitchPoints invalidated " + PropertySwitchPoints.getSwitchPointsInvalidated()); out.println("ScriptFunction constructor calls " + ScriptFunction.getConstructorCount()); out.println("ScriptFunction invokes " + ScriptFunction.getInvokes()); out.println("ScriptFunction allocations " + ScriptFunction.getAllocations()); out.println("PropertyMap count " + PropertyMap.getCount()); out.println("PropertyMap cloned " + PropertyMap.getClonedCount()); out.println("PropertyMap history hit " + PropertyMap.getHistoryHit()); out.println("PropertyMap proto invalidations " + PropertyMap.getProtoInvalidations()); out.println("PropertyMap proto history hit " + PropertyMap.getProtoHistoryHit()); out.println("PropertyMap setProtoNewMapCount " + PropertyMap.getSetProtoNewMapCount()); out.println("Callsite count " + LinkerCallSite.getCount()); out.println("Callsite misses " + LinkerCallSite.getMissCount()); out.println("Callsite misses by site at " + LinkerCallSite.getMissSamplingPercentage() + "%"); LinkerCallSite.getMissCounts(out); 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
Params:
  • self – self reference
Returns:capacity of event queue as an integer
/** * 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
Params:
  • self – an event queue
  • newCapacity – new capacity
/** * Set the event queue capacity * @param self an event queue * @param newCapacity new capacity */
@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, NashornCallSiteDescriptor.CALLSITE_STRICT); }
Add a runtime event to the runtime event queue. The queue has a fixed size RuntimeEvent.RUNTIME_EVENT_QUEUE_SIZE and the oldest entry will be thrown out of the queue is about to overflow
Params:
  • self – self reference
  • event – event to add
/** * 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<RuntimeEvent<?>> 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
Params:
  • self – self reference
  • newCapacity – new capacity
/** * 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<RuntimeEvent<?>> q = getEventQueue(self); final int nc = JSType.toInt32(newCapacity); while (q.size() > nc) { q.removeFirst(); } setEventQueueCapacity(self, nc); }
Clear the runtime event queue
Params:
  • self – self reference
/** * 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<RuntimeEvent<?>> q = getEventQueue(self); q.clear(); }
Remove a specific runtime event from the event queue
Params:
  • self – self reference
  • event – event to remove
/** * 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<RuntimeEvent<?>> 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
Params:
  • self – self reference
Returns:array of events
/** * 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 Object getRuntimeEvents(final Object self) { final LinkedList<RuntimeEvent<?>> q = getEventQueue(self); return q.toArray(new RuntimeEvent<?>[0]); }
Return the last runtime event in the queue
Params:
  • self – self reference
Returns:the freshest event, null if queue is empty
/** * 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 Object getLastRuntimeEvent(final Object self) { final LinkedList<RuntimeEvent<?>> q = getEventQueue(self); return q.isEmpty() ? null : q.getLast(); } @SuppressWarnings("unchecked") private static LinkedList<RuntimeEvent<?>> getEventQueue(final Object self) { final ScriptObject sobj = (ScriptObject)self; LinkedList<RuntimeEvent<?>> q; if (sobj.has(EVENT_QUEUE)) { q = (LinkedList<RuntimeEvent<?>>)((ScriptObject)self).get(EVENT_QUEUE); } else { ((ScriptObject)self).set(EVENT_QUEUE, q = new LinkedList<>(), NashornCallSiteDescriptor.CALLSITE_STRICT); } return q; } private static RuntimeEvent<?> getEvent(final Object event) { return (RuntimeEvent<?>)event; } }