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