NativeDebug.java revision 1040:cc3000241e57
1/*
2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package jdk.nashorn.internal.objects;
27
28import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
29import java.io.PrintWriter;
30import java.util.LinkedList;
31import java.util.Objects;
32import jdk.nashorn.internal.objects.annotations.Attribute;
33import jdk.nashorn.internal.objects.annotations.Function;
34import jdk.nashorn.internal.objects.annotations.ScriptClass;
35import jdk.nashorn.internal.objects.annotations.Where;
36import jdk.nashorn.internal.runtime.Context;
37import jdk.nashorn.internal.runtime.JSType;
38import jdk.nashorn.internal.runtime.PropertyListeners;
39import jdk.nashorn.internal.runtime.PropertyMap;
40import jdk.nashorn.internal.runtime.ScriptFunction;
41import jdk.nashorn.internal.runtime.ScriptObject;
42import jdk.nashorn.internal.runtime.events.RuntimeEvent;
43import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
44import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
45
46/**
47 * Nashorn specific debug utils. This is meant for Nashorn developers.
48 * The interface is subject to change without notice!!
49 *
50 */
51@ScriptClass("Debug")
52public final class NativeDebug extends ScriptObject {
53
54    // initialized by nasgen
55    @SuppressWarnings("unused")
56    private static PropertyMap $nasgenmap$;
57
58    private NativeDebug() {
59        // don't create me!
60        throw new UnsupportedOperationException();
61    }
62
63    @Override
64    public String getClassName() {
65        return "Debug";
66    }
67
68    /**
69     * Nashorn extension: get context, context utility
70     *
71     * @param self self reference
72     * @return context
73     */
74    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
75    public static Object getContext(final Object self) {
76        final SecurityManager sm = System.getSecurityManager();
77        if (sm != null) {
78            sm.checkPermission(new RuntimePermission(Context.NASHORN_GET_CONTEXT));
79        }
80        return Global.getThisContext();
81    }
82
83    /**
84     * Nashorn extension: get map from {@link ScriptObject}
85     *
86     * @param self self reference
87     * @param obj script object
88     * @return the map for the current ScriptObject
89     */
90    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
91    public static Object map(final Object self, final Object obj) {
92        if (obj instanceof ScriptObject) {
93            return ((ScriptObject)obj).getMap();
94        }
95        return UNDEFINED;
96    }
97
98    /**
99     * Check object identity comparison regardless of type
100     *
101     * @param self self reference
102     * @param obj1 first object in comparison
103     * @param obj2 second object in comparison
104     * @return true if reference identity
105     */
106    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
107    public static boolean identical(final Object self, final Object obj1, final Object obj2) {
108        return obj1 == obj2;
109    }
110
111    /**
112     * Returns true if if the two objects are both property maps, and they have identical properties in the same order,
113     * but allows the properties to differ in their types.
114     * @param self self
115     * @param m1 first property map
116     * @param m2 second property map
117     * @return true if they have identical properties in same order, with possibly different types.
118     */
119    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
120    public static Object equalWithoutType(final Object self, final Object m1, final Object m2) {
121        return ((PropertyMap)m1).equalsWithoutType((PropertyMap)m2);
122    }
123
124    /**
125     * Returns a diagnostic string representing the difference of two property maps.
126     * @param self self
127     * @param m1 first property map
128     * @param m2 second property map
129     * @return a diagnostic string representing the difference of two property maps.
130     */
131    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
132    public static Object diffPropertyMaps(final Object self, final Object m1, final Object m2) {
133        return PropertyMap.diff((PropertyMap)m1, (PropertyMap)m2);
134    }
135
136    /**
137     * Object util - getClass
138     *
139     * @param self self reference
140     * @param obj  object
141     * @return class of {@code obj}
142     */
143    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
144    public static Object getClass(final Object self, final Object obj) {
145        if (obj != null) {
146            return obj.getClass();
147        }
148        return UNDEFINED;
149    }
150
151    /**
152     * Object util - equals
153     *
154     * @param self self reference
155     * @param obj1 first object in comparison
156     * @param obj2 second object in comparison
157     * @return return {@link Object#equals(Object)} for objects.
158     */
159    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
160    public static boolean equals(final Object self, final Object obj1, final Object obj2) {
161        return Objects.equals(obj1, obj2);
162    }
163
164    /**
165     * Object util - toJavaString
166     *
167     * @param self self reference
168     * @param obj  object to represent as a string
169     * @return Java string representation of {@code obj}
170     */
171    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
172    public static String toJavaString(final Object self, final Object obj) {
173        return Objects.toString(obj);
174    }
175
176    /**
177     * Do not call overridden toString -- use default toString impl
178     *
179     * @param self self reference
180     * @param obj  object to represent as a string
181     * @return string representation
182     */
183    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
184    public static String toIdentString(final Object self, final Object obj) {
185        if (obj == null) {
186            return "null";
187        }
188
189        final int hash = System.identityHashCode(obj);
190        return obj.getClass() + "@" + Integer.toHexString(hash);
191    }
192
193    /**
194     * Returns the property listener count for a script object
195     *
196     * @param self self reference
197     * @param obj  script object whose listener count is returned
198     * @return listener count
199     */
200    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
201    public static int getListenerCount(final Object self, final Object obj) {
202        return (obj instanceof ScriptObject) ? PropertyListeners.getListenerCount((ScriptObject) obj) : 0;
203    }
204
205    /**
206     * Dump all Nashorn debug mode counters. Calling this may be better if
207     * you want to print all counters. This way you can avoid too many callsites
208     * due to counter access itself!!
209     * @param self self reference
210     * @return undefined
211     */
212    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
213    public static Object dumpCounters(final Object self) {
214        final PrintWriter out = Context.getCurrentErr();
215
216        out.println("ScriptObject count " + ScriptObject.getCount());
217        out.println("Scope count " + ScriptObject.getScopeCount());
218        out.println("ScriptObject listeners added " + PropertyListeners.getListenersAdded());
219        out.println("ScriptObject listeners removed " + PropertyListeners.getListenersRemoved());
220        out.println("ScriptFunction constructor calls " + ScriptFunction.getConstructorCount());
221        out.println("ScriptFunction invokes " + ScriptFunction.getInvokes());
222        out.println("ScriptFunction allocations " + ScriptFunction.getAllocations());
223        out.println("PropertyMap count " + PropertyMap.getCount());
224        out.println("PropertyMap cloned " + PropertyMap.getClonedCount());
225        out.println("PropertyMap history hit " + PropertyMap.getHistoryHit());
226        out.println("PropertyMap proto invalidations " + PropertyMap.getProtoInvalidations());
227        out.println("PropertyMap proto history hit " + PropertyMap.getProtoHistoryHit());
228        out.println("PropertyMap setProtoNewMapCount " + PropertyMap.getSetProtoNewMapCount());
229        out.println("Callsite count " + LinkerCallSite.getCount());
230        out.println("Callsite misses " + LinkerCallSite.getMissCount());
231        out.println("Callsite misses by site at " + LinkerCallSite.getMissSamplingPercentage() + "%");
232
233        LinkerCallSite.getMissCounts(out);
234
235        return UNDEFINED;
236    }
237
238    /*
239     * Framework for logging runtime events
240     */
241
242    private static final String EVENT_QUEUE          = "__eventQueue__";
243    private static final String EVENT_QUEUE_CAPACITY = "__eventQueueCapacity__";
244
245    /**
246     * Get the capacity of the event queue
247     * @param self self reference
248     * @return capacity of event queue as an integer
249     */
250    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
251    public static Object getEventQueueCapacity(final Object self) {
252        final ScriptObject sobj = (ScriptObject)self;
253        Integer cap;
254        if (sobj.has(EVENT_QUEUE_CAPACITY)) {
255            cap = JSType.toInt32(sobj.get(EVENT_QUEUE_CAPACITY));
256        } else {
257            setEventQueueCapacity(self, cap = RuntimeEvent.RUNTIME_EVENT_QUEUE_SIZE);
258        }
259        return cap;
260    }
261
262    /**
263     * Set the event queue capacity
264     * @param self an event queue
265     * @param newCapacity new capacity
266     */
267    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
268    public static void setEventQueueCapacity(final Object self, final Object newCapacity) {
269        ((ScriptObject)self).set(EVENT_QUEUE_CAPACITY, newCapacity, NashornCallSiteDescriptor.CALLSITE_STRICT);
270    }
271
272    /**
273     * Add a runtime event to the runtime event queue. The queue has a fixed
274     * size {@link RuntimeEvent#RUNTIME_EVENT_QUEUE_SIZE} and the oldest
275     * entry will be thrown out of the queue is about to overflow
276     * @param self self reference
277     * @param event event to add
278     */
279    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
280    public static void addRuntimeEvent(final Object self, final Object event) {
281        final LinkedList<RuntimeEvent<?>> q = getEventQueue(self);
282        final int cap = (Integer)getEventQueueCapacity(self);
283        while (q.size() >= cap) {
284            q.removeFirst();
285        }
286        q.addLast(getEvent(event));
287    }
288
289    /**
290     * Expands the event queue capacity, or truncates if capacity is lower than
291     * current capacity. Then only the newest entries are kept
292     * @param self self reference
293     * @param newCapacity new capacity
294     */
295    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
296    public static void expandEventQueueCapacity(final Object self, final Object newCapacity) {
297        final LinkedList<RuntimeEvent<?>> q = getEventQueue(self);
298        final int nc = JSType.toInt32(newCapacity);
299        while (q.size() > nc) {
300            q.removeFirst();
301        }
302        setEventQueueCapacity(self, nc);
303    }
304
305    /**
306     * Clear the runtime event queue
307     * @param self self reference
308     */
309    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
310    public static void clearRuntimeEvents(final Object self) {
311        final LinkedList<RuntimeEvent<?>> q = getEventQueue(self);
312        q.clear();
313    }
314
315    /**
316     * Remove a specific runtime event from the event queue
317     * @param self self reference
318     * @param event event to remove
319     */
320    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
321    public static void removeRuntimeEvent(final Object self, final Object event) {
322        final LinkedList<RuntimeEvent<?>> q  = getEventQueue(self);
323        final RuntimeEvent<?>             re = getEvent(event);
324        if (!q.remove(re)) {
325            throw new IllegalStateException("runtime event " + re + " was not in event queue");
326        }
327    }
328
329    /**
330     * Return all runtime events in the queue as an array
331     * @param self self reference
332     * @return array of events
333     */
334    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
335    public static Object getRuntimeEvents(final Object self) {
336        final LinkedList<RuntimeEvent<?>> q = getEventQueue(self);
337        return q.toArray(new RuntimeEvent<?>[q.size()]);
338    }
339
340    /**
341     * Return the last runtime event in the queue
342     * @param self self reference
343     * @return the freshest event, null if queue is empty
344     */
345    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
346    public static Object getLastRuntimeEvent(final Object self) {
347        final LinkedList<RuntimeEvent<?>> q = getEventQueue(self);
348        return q.isEmpty() ? null : q.getLast();
349    }
350
351    @SuppressWarnings("unchecked")
352    private static LinkedList<RuntimeEvent<?>> getEventQueue(final Object self) {
353        final ScriptObject sobj = (ScriptObject)self;
354        LinkedList<RuntimeEvent<?>> q;
355        if (sobj.has(EVENT_QUEUE)) {
356            q = (LinkedList<RuntimeEvent<?>>)((ScriptObject)self).get(EVENT_QUEUE);
357        } else {
358            ((ScriptObject)self).set(EVENT_QUEUE, q = new LinkedList<>(), NashornCallSiteDescriptor.CALLSITE_STRICT);
359        }
360        return q;
361    }
362
363    private static RuntimeEvent<?> getEvent(final Object event) {
364        return (RuntimeEvent<?>)event;
365    }
366}
367