NativeDebug.java revision 1101:be3f5ca1edbf
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.ScriptRuntime; 43import jdk.nashorn.internal.runtime.events.RuntimeEvent; 44import jdk.nashorn.internal.runtime.linker.LinkerCallSite; 45import 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") 53public 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} 398