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