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
26 package jdk.nashorn.internal.objects;
27
28 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
29 import java.io.PrintWriter;
30 import java.util.LinkedList;
31 import java.util.Objects;
32 import jdk.nashorn.internal.objects.annotations.Attribute;
33 import jdk.nashorn.internal.objects.annotations.Function;
34 import jdk.nashorn.internal.objects.annotations.ScriptClass;
35 import jdk.nashorn.internal.objects.annotations.Where;
36 import jdk.nashorn.internal.runtime.Context;
37 import jdk.nashorn.internal.runtime.JSType;
38 import jdk.nashorn.internal.runtime.PropertyListeners;
39 import jdk.nashorn.internal.runtime.PropertyMap;
40 import jdk.nashorn.internal.runtime.ScriptFunction;
41 import jdk.nashorn.internal.runtime.ScriptObject;
42 import jdk.nashorn.internal.runtime.ScriptRuntime;
43 import jdk.nashorn.internal.runtime.events.RuntimeEvent;
44 import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
45 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
46
47 /**
48 * Nashorn specific debug utils. This is meant for Nashorn developers.
49 * The interface is subject to change without notice!!
50 *
51 */
52 @ScriptClass("Debug")
53 public final class NativeDebug extends ScriptObject {
54
55 // initialized by nasgen
56 @SuppressWarnings("unused")
57 private static PropertyMap $nasgenmap$;
58
59 private NativeDebug() {
60 // don't create me!
61 throw new UnsupportedOperationException();
62 }
63
64 @Override
65 public String getClassName() {
66 return "Debug";
67 }
68
69 /**
70 * Return the ArrayData class for this ScriptObject
71 * @param self self
72 * @param obj script object to check
73 * @return ArrayData class, or undefined if no ArrayData is present
74 */
75 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
76 public static Object getArrayDataClass(final Object self, final Object obj) {
77 try {
78 return ((ScriptObject)obj).getArray().getClass();
79 } catch (final ClassCastException e) {
80 return ScriptRuntime.UNDEFINED;
81 }
82 }
83
84 /**
85 * Return the ArrayData for this ScriptObject
86 * @param self self
87 * @param obj script object to check
88 * @return ArrayData, ArrayDatas have toString methods, return Undefined if data missing
89 */
90 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
91 public static Object getArrayData(final Object self, final Object obj) {
92 try {
93 return ((ScriptObject)obj).getArray();
94 } catch (final ClassCastException e) {
95 return ScriptRuntime.UNDEFINED;
96 }
97 }
98
99 /**
100 * Nashorn extension: get context, context utility
101 *
102 * @param self self reference
103 * @return context
104 */
105 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
106 public static Object getContext(final Object self) {
107 final SecurityManager sm = System.getSecurityManager();
108 if (sm != null) {
109 sm.checkPermission(new RuntimePermission(Context.NASHORN_GET_CONTEXT));
110 }
111 return Global.getThisContext();
112 }
113
114 /**
115 * Nashorn extension: get map from {@link ScriptObject}
116 *
117 * @param self self reference
118 * @param obj script object
119 * @return the map for the current ScriptObject
120 */
121 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
122 public static Object map(final Object self, final Object obj) {
123 if (obj instanceof ScriptObject) {
124 return ((ScriptObject)obj).getMap();
125 }
126 return UNDEFINED;
127 }
128
129 /**
130 * Check object identity comparison regardless of type
131 *
132 * @param self self reference
133 * @param obj1 first object in comparison
134 * @param obj2 second object in comparison
135 * @return true if reference identity
136 */
137 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
138 public static boolean identical(final Object self, final Object obj1, final Object obj2) {
139 return obj1 == obj2;
140 }
141
142 /**
143 * Returns true if if the two objects are both property maps, and they have identical properties in the same order,
144 * but allows the properties to differ in their types.
145 * @param self self
146 * @param m1 first property map
147 * @param m2 second property map
148 * @return true if they have identical properties in same order, with possibly different types.
149 */
150 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
151 public static Object equalWithoutType(final Object self, final Object m1, final Object m2) {
152 return ((PropertyMap)m1).equalsWithoutType((PropertyMap)m2);
153 }
154
155 /**
156 * Returns a diagnostic string representing the difference of two property maps.
157 * @param self self
158 * @param m1 first property map
159 * @param m2 second property map
160 * @return a diagnostic string representing the difference of two property maps.
161 */
162 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
163 public static Object diffPropertyMaps(final Object self, final Object m1, final Object m2) {
164 return PropertyMap.diff((PropertyMap)m1, (PropertyMap)m2);
165 }
166
167 /**
168 * Object util - getClass
169 *
170 * @param self self reference
171 * @param obj object
172 * @return class of {@code obj}
173 */
174 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
175 public static Object getClass(final Object self, final Object obj) {
176 if (obj != null) {
177 return obj.getClass();
178 }
179 return UNDEFINED;
180 }
181
182 /**
183 * Object util - equals
184 *
185 * @param self self reference
186 * @param obj1 first object in comparison
187 * @param obj2 second object in comparison
188 * @return return {@link Object#equals(Object)} for objects.
189 */
190 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
191 public static boolean equals(final Object self, final Object obj1, final Object obj2) {
192 return Objects.equals(obj1, obj2);
193 }
194
195 /**
196 * Object util - toJavaString
197 *
198 * @param self self reference
199 * @param obj object to represent as a string
200 * @return Java string representation of {@code obj}
201 */
202 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
203 public static String toJavaString(final Object self, final Object obj) {
204 return Objects.toString(obj);
205 }
206
207 /**
208 * Do not call overridden toString -- use default toString impl
209 *
210 * @param self self reference
211 * @param obj object to represent as a string
212 * @return string representation
213 */
214 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
215 public static String toIdentString(final Object self, final Object obj) {
216 if (obj == null) {
217 return "null";
218 }
219
220 final int hash = System.identityHashCode(obj);
221 return obj.getClass() + "@" + Integer.toHexString(hash);
222 }
223
224 /**
225 * Returns the property listener count for a script object
226 *
227 * @param self self reference
228 * @param obj script object whose listener count is returned
229 * @return listener count
230 */
231 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
232 public static int getListenerCount(final Object self, final Object obj) {
233 return (obj instanceof ScriptObject) ? PropertyListeners.getListenerCount((ScriptObject) obj) : 0;
234 }
235
236 /**
237 * Dump all Nashorn debug mode counters. Calling this may be better if
238 * you want to print all counters. This way you can avoid too many callsites
239 * due to counter access itself!!
240 * @param self self reference
241 * @return undefined
242 */
243 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
244 public static Object dumpCounters(final Object self) {
245 final PrintWriter out = Context.getCurrentErr();
246
247 out.println("ScriptObject count " + ScriptObject.getCount());
248 out.println("Scope count " + ScriptObject.getScopeCount());
249 out.println("ScriptObject listeners added " + PropertyListeners.getListenersAdded());
250 out.println("ScriptObject listeners removed " + PropertyListeners.getListenersRemoved());
251 out.println("ScriptFunction constructor calls " + ScriptFunction.getConstructorCount());
252 out.println("ScriptFunction invokes " + ScriptFunction.getInvokes());
253 out.println("ScriptFunction allocations " + ScriptFunction.getAllocations());
254 out.println("PropertyMap count " + PropertyMap.getCount());
255 out.println("PropertyMap cloned " + PropertyMap.getClonedCount());
256 out.println("PropertyMap history hit " + PropertyMap.getHistoryHit());
257 out.println("PropertyMap proto invalidations " + PropertyMap.getProtoInvalidations());
258 out.println("PropertyMap proto history hit " + PropertyMap.getProtoHistoryHit());
259 out.println("PropertyMap setProtoNewMapCount " + PropertyMap.getSetProtoNewMapCount());
260 out.println("Callsite count " + LinkerCallSite.getCount());
261 out.println("Callsite misses " + LinkerCallSite.getMissCount());
262 out.println("Callsite misses by site at " + LinkerCallSite.getMissSamplingPercentage() + "%");
263
264 LinkerCallSite.getMissCounts(out);
265
266 return UNDEFINED;
267 }
268
269 /*
270 * Framework for logging runtime events
271 */
272
273 private static final String EVENT_QUEUE = "__eventQueue__";
274 private static final String EVENT_QUEUE_CAPACITY = "__eventQueueCapacity__";
275
276 /**
277 * Get the capacity of the event queue
278 * @param self self reference
279 * @return capacity of event queue as an integer
280 */
281 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
282 public static Object getEventQueueCapacity(final Object self) {
283 final ScriptObject sobj = (ScriptObject)self;
284 Integer cap;
285 if (sobj.has(EVENT_QUEUE_CAPACITY)) {
286 cap = JSType.toInt32(sobj.get(EVENT_QUEUE_CAPACITY));
287 } else {
288 setEventQueueCapacity(self, cap = RuntimeEvent.RUNTIME_EVENT_QUEUE_SIZE);
289 }
290 return cap;
291 }
292
293 /**
294 * Set the event queue capacity
295 * @param self an event queue
296 * @param newCapacity new capacity
297 */
298 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
299 public static void setEventQueueCapacity(final Object self, final Object newCapacity) {
300 ((ScriptObject)self).set(EVENT_QUEUE_CAPACITY, newCapacity, NashornCallSiteDescriptor.CALLSITE_STRICT);
301 }
302
303 /**
304 * Add a runtime event to the runtime event queue. The queue has a fixed
305 * size {@link RuntimeEvent#RUNTIME_EVENT_QUEUE_SIZE} and the oldest
306 * entry will be thrown out of the queue is about to overflow
307 * @param self self reference
308 * @param event event to add
309 */
310 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
311 public static void addRuntimeEvent(final Object self, final Object event) {
312 final LinkedList<RuntimeEvent<?>> q = getEventQueue(self);
313 final int cap = (Integer)getEventQueueCapacity(self);
314 while (q.size() >= cap) {
315 q.removeFirst();
316 }
317 q.addLast(getEvent(event));
318 }
319
320 /**
321 * Expands the event queue capacity, or truncates if capacity is lower than
322 * current capacity. Then only the newest entries are kept
323 * @param self self reference
324 * @param newCapacity new capacity
325 */
326 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
327 public static void expandEventQueueCapacity(final Object self, final Object newCapacity) {
328 final LinkedList<RuntimeEvent<?>> q = getEventQueue(self);
329 final int nc = JSType.toInt32(newCapacity);
330 while (q.size() > nc) {
331 q.removeFirst();
332 }
333 setEventQueueCapacity(self, nc);
334 }
335
336 /**
337 * Clear the runtime event queue
338 * @param self self reference
339 */
340 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
341 public static void clearRuntimeEvents(final Object self) {
342 final LinkedList<RuntimeEvent<?>> q = getEventQueue(self);
343 q.clear();
344 }
345
346 /**
347 * Remove a specific runtime event from the event queue
348 * @param self self reference
349 * @param event event to remove
350 */
351 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
352 public static void removeRuntimeEvent(final Object self, final Object event) {
353 final LinkedList<RuntimeEvent<?>> q = getEventQueue(self);
354 final RuntimeEvent<?> re = getEvent(event);
355 if (!q.remove(re)) {
356 throw new IllegalStateException("runtime event " + re + " was not in event queue");
357 }
358 }
359
360 /**
361 * Return all runtime events in the queue as an array
362 * @param self self reference
363 * @return array of events
364 */
365 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
366 public static Object getRuntimeEvents(final Object self) {
367 final LinkedList<RuntimeEvent<?>> q = getEventQueue(self);
368 return q.toArray(new RuntimeEvent<?>[q.size()]);
369 }
370
371 /**
372 * Return the last runtime event in the queue
373 * @param self self reference
374 * @return the freshest event, null if queue is empty
375 */
376 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
377 public static Object getLastRuntimeEvent(final Object self) {
378 final LinkedList<RuntimeEvent<?>> q = getEventQueue(self);
379 return q.isEmpty() ? null : q.getLast();
380 }
381
382 @SuppressWarnings("unchecked")
383 private static LinkedList<RuntimeEvent<?>> getEventQueue(final Object self) {
384 final ScriptObject sobj = (ScriptObject)self;
385 LinkedList<RuntimeEvent<?>> q;
386 if (sobj.has(EVENT_QUEUE)) {
387 q = (LinkedList<RuntimeEvent<?>>)((ScriptObject)self).get(EVENT_QUEUE);
388 } else {
389 ((ScriptObject)self).set(EVENT_QUEUE, q = new LinkedList<>(), NashornCallSiteDescriptor.CALLSITE_STRICT);
390 }
391 return q;
392 }
393
394 private static RuntimeEvent<?> getEvent(final Object event) {
395 return (RuntimeEvent<?>)event;
396 }
397 }
--- EOF ---