LinkerCallSite.java revision 1416:a750a66640e0
1258057Sbr/* 2258057Sbr * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3258057Sbr * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4258057Sbr * 5258057Sbr * This code is free software; you can redistribute it and/or modify it 6258057Sbr * under the terms of the GNU General Public License version 2 only, as 7258057Sbr * published by the Free Software Foundation. Oracle designates this 8258057Sbr * particular file as subject to the "Classpath" exception as provided 9258057Sbr * by Oracle in the LICENSE file that accompanied this code. 10258057Sbr * 11258057Sbr * This code is distributed in the hope that it will be useful, but WITHOUT 12258057Sbr * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13258057Sbr * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14258057Sbr * version 2 for more details (a copy is included in the LICENSE file that 15258057Sbr * accompanied this code). 16258057Sbr * 17258057Sbr * You should have received a copy of the GNU General Public License version 18258057Sbr * 2 along with this work; if not, write to the Free Software Foundation, 19258057Sbr * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20258057Sbr * 21258057Sbr * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22258057Sbr * or visit www.oracle.com if you need additional information or have any 23258057Sbr * questions. 24258057Sbr */ 25258057Sbr 26258057Sbrpackage jdk.nashorn.internal.runtime.linker; 27258057Sbr 28258057Sbrimport static jdk.nashorn.internal.lookup.Lookup.MH; 29258057Sbr 30258057Sbrimport java.io.FileNotFoundException; 31258057Sbrimport java.io.FileOutputStream; 32258057Sbrimport java.io.PrintWriter; 33258057Sbrimport java.lang.invoke.MethodHandle; 34258057Sbrimport java.lang.invoke.MethodHandles; 35258057Sbrimport java.lang.invoke.MethodType; 36258057Sbrimport java.util.ArrayList; 37258057Sbrimport java.util.Collections; 38258057Sbrimport java.util.Comparator; 39258057Sbrimport java.util.HashMap; 40258057Sbrimport java.util.LinkedList; 41258057Sbrimport java.util.Map; 42258057Sbrimport java.util.Map.Entry; 43258057Sbrimport java.util.Random; 44258057Sbrimport java.util.Set; 45258057Sbrimport java.util.concurrent.atomic.AtomicInteger; 46258057Sbrimport java.util.concurrent.atomic.LongAdder; 47258057Sbrimport jdk.internal.dynalink.ChainedCallSite; 48258057Sbrimport jdk.internal.dynalink.DynamicLinker; 49258057Sbrimport jdk.internal.dynalink.linker.GuardedInvocation; 50258057Sbrimport jdk.nashorn.internal.runtime.Context; 51258057Sbrimport jdk.nashorn.internal.runtime.Debug; 52258057Sbrimport jdk.nashorn.internal.runtime.ScriptObject; 53258057Sbrimport jdk.nashorn.internal.runtime.ScriptRuntime; 54258057Sbrimport jdk.nashorn.internal.runtime.options.Options; 55258057Sbr 56258057Sbr 57258057Sbr/** 58258057Sbr * Relinkable form of call site. 59258057Sbr */ 60258057Sbrpublic class LinkerCallSite extends ChainedCallSite { 61258057Sbr /** Maximum number of arguments passed directly. */ 62258057Sbr public static final int ARGLIMIT = 250; 63258057Sbr 64258057Sbr private static final String PROFILEFILE = Options.getStringProperty("nashorn.profilefile", "NashornProfile.txt"); 65258057Sbr 66258057Sbr private static final MethodHandle INCREASE_MISS_COUNTER = MH.findStatic(MethodHandles.lookup(), LinkerCallSite.class, "increaseMissCount", MH.type(Object.class, String.class, Object.class)); 67258057Sbr private static final MethodHandle ON_CATCH_INVALIDATION = MH.findStatic(MethodHandles.lookup(), LinkerCallSite.class, "onCatchInvalidation", MH.type(ChainedCallSite.class, LinkerCallSite.class)); 68258057Sbr 69258057Sbr private int catchInvalidations; 70258057Sbr 71258057Sbr LinkerCallSite(final NashornCallSiteDescriptor descriptor) { 72258057Sbr super(descriptor); 73258057Sbr if (Context.DEBUG) { 74258057Sbr LinkerCallSite.count.increment(); 75258057Sbr } 76258057Sbr } 77258057Sbr 78258057Sbr @Override 79258057Sbr protected MethodHandle getPruneCatches() { 80258057Sbr return MH.filterArguments(super.getPruneCatches(), 0, ON_CATCH_INVALIDATION); 81258057Sbr } 82258057Sbr 83258057Sbr /** 84258057Sbr * Action to perform when a catch guard around a callsite triggers. Increases 85258057Sbr * catch invalidation counter 86258057Sbr * @param callSite callsite 87258057Sbr * @return the callsite, so this can be used as argument filter 88258057Sbr */ 89258057Sbr @SuppressWarnings("unused") 90258057Sbr private static ChainedCallSite onCatchInvalidation(final LinkerCallSite callSite) { 91258057Sbr ++callSite.catchInvalidations; 92258057Sbr return callSite; 93258057Sbr } 94258057Sbr 95258057Sbr /** 96258057Sbr * Get the number of catch invalidations that have happened at this call site so far 97258057Sbr * @param callSiteToken call site token, unique to the callsite. 98258057Sbr * @return number of catch invalidations, i.e. thrown exceptions caught by the linker 99258057Sbr */ 100258057Sbr public static int getCatchInvalidationCount(final Object callSiteToken) { 101258057Sbr if (callSiteToken instanceof LinkerCallSite) { 102258057Sbr return ((LinkerCallSite)callSiteToken).catchInvalidations; 103258057Sbr } 104258057Sbr return 0; 105258057Sbr } 106258057Sbr /** 107258057Sbr * Construct a new linker call site. 108258057Sbr * @param name Name of method. 109258057Sbr * @param type Method type. 110258057Sbr * @param flags Call site specific flags. 111258057Sbr * @return New LinkerCallSite. 112258057Sbr */ 113258057Sbr static LinkerCallSite newLinkerCallSite(final MethodHandles.Lookup lookup, final String name, final MethodType type, final int flags) { 114258057Sbr final NashornCallSiteDescriptor desc = NashornCallSiteDescriptor.get(lookup, name, type, flags); 115258057Sbr 116258057Sbr if (desc.isProfile()) { 117258057Sbr return ProfilingLinkerCallSite.newProfilingLinkerCallSite(desc); 118258057Sbr } 119258057Sbr 120258057Sbr if (desc.isTrace()) { 121258057Sbr return new TracingLinkerCallSite(desc); 122258057Sbr } 123258057Sbr 124258057Sbr return new LinkerCallSite(desc); 125258057Sbr } 126258057Sbr 127258057Sbr @Override 128258057Sbr public String toString() { 129258057Sbr return getDescriptor().toString(); 130258057Sbr } 131258057Sbr 132258057Sbr /** 133258057Sbr * Get the descriptor for this callsite 134258057Sbr * @return a {@link NashornCallSiteDescriptor} 135258057Sbr */ 136258057Sbr public NashornCallSiteDescriptor getNashornDescriptor() { 137258057Sbr return (NashornCallSiteDescriptor)getDescriptor(); 138258057Sbr } 139258057Sbr 140258057Sbr @Override 141258057Sbr public void relink(final GuardedInvocation invocation, final MethodHandle relink) { 142258057Sbr super.relink(invocation, getDebuggingRelink(relink)); 143258057Sbr } 144258057Sbr 145258057Sbr @Override 146258057Sbr public void resetAndRelink(final GuardedInvocation invocation, final MethodHandle relink) { 147258057Sbr super.resetAndRelink(invocation, getDebuggingRelink(relink)); 148258057Sbr } 149258057Sbr 150258057Sbr private MethodHandle getDebuggingRelink(final MethodHandle relink) { 151258057Sbr if (Context.DEBUG) { 152258057Sbr return MH.filterArguments(relink, 0, getIncreaseMissCounter(relink.type().parameterType(0))); 153258057Sbr } 154258057Sbr return relink; 155258057Sbr } 156258057Sbr 157258057Sbr private MethodHandle getIncreaseMissCounter(final Class<?> type) { 158258057Sbr final MethodHandle missCounterWithDesc = MH.bindTo(INCREASE_MISS_COUNTER, getDescriptor().getName() + " @ " + getScriptLocation()); 159258057Sbr if (type == Object.class) { 160258057Sbr return missCounterWithDesc; 161258057Sbr } 162258057Sbr return MH.asType(missCounterWithDesc, missCounterWithDesc.type().changeParameterType(0, type).changeReturnType(type)); 163258057Sbr } 164258057Sbr 165258057Sbr private static String getScriptLocation() { 166258057Sbr final StackTraceElement caller = DynamicLinker.getLinkedCallSiteLocation(); 167258057Sbr return caller == null ? "unknown location" : (caller.getFileName() + ":" + caller.getLineNumber()); 168258057Sbr } 169258057Sbr 170258057Sbr /** 171258057Sbr * Instrumentation - increase the miss count when a callsite misses. Used as filter 172258057Sbr * @param desc descriptor for table entry 173261410Sian * @param self self reference 174261410Sian * @return self reference 175261410Sian */ 176258057Sbr public static Object increaseMissCount(final String desc, final Object self) { 177258057Sbr missCount.increment(); 178258057Sbr if (r.nextInt(100) < missSamplingPercentage) { 179258057Sbr final AtomicInteger i = missCounts.get(desc); 180258057Sbr if (i == null) { 181258057Sbr missCounts.put(desc, new AtomicInteger(1)); 182258057Sbr } else { 183258057Sbr i.incrementAndGet(); 184258057Sbr } 185258057Sbr } 186258057Sbr return self; 187258057Sbr } 188258057Sbr 189258057Sbr /* 190258057Sbr * Debugging call sites. 191258057Sbr */ 192258057Sbr 193258057Sbr private static class ProfilingLinkerCallSite extends LinkerCallSite { 194258057Sbr /** List of all profiled call sites. */ 195258057Sbr private static LinkedList<ProfilingLinkerCallSite> profileCallSites = null; 196258057Sbr 197258057Sbr /** Start time when entered at zero depth. */ 198258057Sbr private long startTime; 199258057Sbr 200258057Sbr /** Depth of nested calls. */ 201258057Sbr private int depth; 202258057Sbr 203258057Sbr /** Total time spent in this call site. */ 204258057Sbr private long totalTime; 205258057Sbr 206258057Sbr /** Total number of times call site entered. */ 207258057Sbr private long hitCount; 208258057Sbr 209258057Sbr private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); 210258057Sbr 211258057Sbr private static final MethodHandle PROFILEENTRY = MH.findVirtual(LOOKUP, ProfilingLinkerCallSite.class, "profileEntry", MH.type(Object.class, Object.class)); 212258057Sbr private static final MethodHandle PROFILEEXIT = MH.findVirtual(LOOKUP, ProfilingLinkerCallSite.class, "profileExit", MH.type(Object.class, Object.class)); 213258057Sbr private static final MethodHandle PROFILEVOIDEXIT = MH.findVirtual(LOOKUP, ProfilingLinkerCallSite.class, "profileVoidExit", MH.type(void.class)); 214258057Sbr 215258057Sbr /* 216258057Sbr * Constructor 217258057Sbr */ 218258057Sbr 219258057Sbr ProfilingLinkerCallSite(final NashornCallSiteDescriptor desc) { 220258057Sbr super(desc); 221258057Sbr } 222258057Sbr 223258057Sbr public static ProfilingLinkerCallSite newProfilingLinkerCallSite(final NashornCallSiteDescriptor desc) { 224258057Sbr if (profileCallSites == null) { 225258057Sbr profileCallSites = new LinkedList<>(); 226258057Sbr 227258057Sbr final Thread profileDumperThread = new Thread(new ProfileDumper()); 228258057Sbr Runtime.getRuntime().addShutdownHook(profileDumperThread); 229258057Sbr } 230258057Sbr 231258057Sbr final ProfilingLinkerCallSite callSite = new ProfilingLinkerCallSite(desc); 232258057Sbr profileCallSites.add(callSite); 233258057Sbr 234258057Sbr return callSite; 235258057Sbr } 236258057Sbr 237258057Sbr @Override 238258057Sbr public void setTarget(final MethodHandle newTarget) { 239258057Sbr final MethodType type = type(); 240258057Sbr final boolean isVoid = type.returnType() == void.class; 241258057Sbr 242258057Sbr MethodHandle methodHandle = MH.filterArguments(newTarget, 0, MH.bindTo(PROFILEENTRY, this)); 243258057Sbr 244258057Sbr if (isVoid) { 245258057Sbr methodHandle = MH.filterReturnValue(methodHandle, MH.bindTo(PROFILEVOIDEXIT, this)); 246258057Sbr } else { 247258057Sbr final MethodType filter = MH.type(type.returnType(), type.returnType()); 248258057Sbr methodHandle = MH.filterReturnValue(methodHandle, MH.asType(MH.bindTo(PROFILEEXIT, this), filter)); 249258057Sbr } 250258057Sbr 251258057Sbr super.setTarget(methodHandle); 252258057Sbr } 253258057Sbr 254258057Sbr /** 255258057Sbr * Start the clock for a profile entry and increase depth 256258057Sbr * @param self argument to filter 257258057Sbr * @return preserved argument 258258057Sbr */ 259258057Sbr @SuppressWarnings("unused") 260258057Sbr public Object profileEntry(final Object self) { 261258057Sbr if (depth == 0) { 262258057Sbr startTime = System.nanoTime(); 263258057Sbr } 264258057Sbr 265258057Sbr depth++; 266258057Sbr hitCount++; 267258057Sbr 268258057Sbr return self; 269258057Sbr } 270258057Sbr 271258057Sbr /** 272258057Sbr * Decrease depth and stop the clock for a profile entry 273258057Sbr * @param result return value to filter 274258057Sbr * @return preserved argument 275258057Sbr */ 276258057Sbr @SuppressWarnings("unused") 277258057Sbr public Object profileExit(final Object result) { 278258057Sbr depth--; 279258057Sbr 280258057Sbr if (depth == 0) { 281258057Sbr totalTime += System.nanoTime() - startTime; 282258057Sbr } 283258057Sbr 284258057Sbr return result; 285258057Sbr } 286258057Sbr 287258057Sbr /** 288258057Sbr * Decrease depth without return value filter 289258057Sbr */ 290258057Sbr @SuppressWarnings("unused") 291258057Sbr public void profileVoidExit() { 292258057Sbr depth--; 293258057Sbr 294258057Sbr if (depth == 0) { 295258057Sbr totalTime += System.nanoTime() - startTime; 296258057Sbr } 297258057Sbr } 298258057Sbr 299258057Sbr static class ProfileDumper implements Runnable { 300258057Sbr @Override 301258057Sbr public void run() { 302258057Sbr PrintWriter out = null; 303258057Sbr boolean fileOutput = false; 304258057Sbr 305258057Sbr try { 306258057Sbr try { 307258057Sbr out = new PrintWriter(new FileOutputStream(PROFILEFILE)); 308258057Sbr fileOutput = true; 309258057Sbr } catch (final FileNotFoundException e) { 310258057Sbr out = Context.getCurrentErr(); 311258057Sbr } 312258057Sbr 313258057Sbr dump(out); 314258057Sbr } finally { 315258057Sbr if (out != null && fileOutput) { 316258057Sbr out.close(); 317258057Sbr } 318258057Sbr } 319258057Sbr } 320258057Sbr 321258057Sbr private static void dump(final PrintWriter out) { 322258057Sbr int index = 0; 323258057Sbr for (final ProfilingLinkerCallSite callSite : profileCallSites) { 324258057Sbr out.println("" + (index++) + '\t' + 325258057Sbr callSite.getDescriptor().getName() + '\t' + 326258057Sbr callSite.totalTime + '\t' + 327258057Sbr callSite.hitCount); 328258057Sbr } 329258057Sbr } 330258057Sbr } 331258057Sbr } 332258057Sbr 333258057Sbr /** 334258057Sbr * Debug subclass for LinkerCallSite that allows tracing 335258057Sbr */ 336258057Sbr private static class TracingLinkerCallSite extends LinkerCallSite { 337258057Sbr private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); 338258057Sbr 339258057Sbr private static final MethodHandle TRACEOBJECT = MH.findVirtual(LOOKUP, TracingLinkerCallSite.class, "traceObject", MH.type(Object.class, MethodHandle.class, Object[].class)); 340258057Sbr private static final MethodHandle TRACEVOID = MH.findVirtual(LOOKUP, TracingLinkerCallSite.class, "traceVoid", MH.type(void.class, MethodHandle.class, Object[].class)); 341258057Sbr private static final MethodHandle TRACEMISS = MH.findVirtual(LOOKUP, TracingLinkerCallSite.class, "traceMiss", MH.type(void.class, String.class, Object[].class)); 342258057Sbr 343258057Sbr TracingLinkerCallSite(final NashornCallSiteDescriptor desc) { 344258057Sbr super(desc); 345258057Sbr } 346258057Sbr 347258057Sbr @Override 348258057Sbr public void setTarget(final MethodHandle newTarget) { 349258057Sbr if (!getNashornDescriptor().isTraceEnterExit()) { 350258057Sbr super.setTarget(newTarget); 351258057Sbr return; 352258057Sbr } 353258057Sbr 354258057Sbr final MethodType type = type(); 355258057Sbr final boolean isVoid = type.returnType() == void.class; 356258057Sbr 357258057Sbr MethodHandle traceMethodHandle = isVoid ? TRACEVOID : TRACEOBJECT; 358258057Sbr traceMethodHandle = MH.bindTo(traceMethodHandle, this); 359258057Sbr traceMethodHandle = MH.bindTo(traceMethodHandle, newTarget); 360258057Sbr traceMethodHandle = MH.asCollector(traceMethodHandle, Object[].class, type.parameterCount()); 361258057Sbr traceMethodHandle = MH.asType(traceMethodHandle, type); 362258057Sbr 363258057Sbr super.setTarget(traceMethodHandle); 364258057Sbr } 365258057Sbr 366258057Sbr @Override 367258057Sbr public void initialize(final MethodHandle relinkAndInvoke) { 368258057Sbr super.initialize(getFallbackLoggingRelink(relinkAndInvoke)); 369258057Sbr } 370258057Sbr 371258057Sbr @Override 372258057Sbr public void relink(final GuardedInvocation invocation, final MethodHandle relink) { 373258057Sbr super.relink(invocation, getFallbackLoggingRelink(relink)); 374258057Sbr } 375258057Sbr 376258057Sbr @Override 377258057Sbr public void resetAndRelink(final GuardedInvocation invocation, final MethodHandle relink) { 378258057Sbr super.resetAndRelink(invocation, getFallbackLoggingRelink(relink)); 379258057Sbr } 380258057Sbr 381258057Sbr private MethodHandle getFallbackLoggingRelink(final MethodHandle relink) { 382258057Sbr if (!getNashornDescriptor().isTraceMisses()) { 383258057Sbr // If we aren't tracing misses, just return relink as-is 384258057Sbr return relink; 385258057Sbr } 386258057Sbr final MethodType type = relink.type(); 387258057Sbr return MH.foldArguments(relink, MH.asType(MH.asCollector(MH.insertArguments(TRACEMISS, 0, this, "MISS " + getScriptLocation() + " "), Object[].class, type.parameterCount()), type.changeReturnType(void.class))); 388258057Sbr } 389258057Sbr 390258057Sbr private void printObject(final PrintWriter out, final Object arg) { 391258057Sbr if (!getNashornDescriptor().isTraceObjects()) { 392258057Sbr out.print((arg instanceof ScriptObject) ? "ScriptObject" : arg); 393258057Sbr return; 394258057Sbr } 395258057Sbr 396258057Sbr if (arg instanceof ScriptObject) { 397258057Sbr final ScriptObject object = (ScriptObject)arg; 398258057Sbr 399258057Sbr boolean isFirst = true; 400258057Sbr final Set<Object> keySet = object.keySet(); 401258057Sbr 402258057Sbr if (keySet.isEmpty()) { 403258057Sbr out.print(ScriptRuntime.safeToString(arg)); 404258057Sbr } else { 405258057Sbr out.print("{ "); 406258057Sbr 407258057Sbr for (final Object key : keySet) { 408258057Sbr if (!isFirst) { 409258057Sbr out.print(", "); 410258057Sbr } 411258057Sbr 412258057Sbr out.print(key); 413258057Sbr out.print(":"); 414258057Sbr 415258057Sbr final Object value = object.get(key); 416258057Sbr 417258057Sbr if (value instanceof ScriptObject) { 418258057Sbr out.print("..."); 419258057Sbr } else { 420258057Sbr printObject(out, value); 421258057Sbr } 422258057Sbr 423258057Sbr isFirst = false; 424258057Sbr } 425258057Sbr 426258057Sbr out.print(" }"); 427258057Sbr } 428258057Sbr } else { 429258057Sbr out.print(ScriptRuntime.safeToString(arg)); 430258057Sbr } 431258057Sbr } 432258057Sbr 433258057Sbr private void tracePrint(final PrintWriter out, final String tag, final Object[] args, final Object result) { 434258057Sbr //boolean isVoid = type().returnType() == void.class; 435258057Sbr out.print(Debug.id(this) + " TAG " + tag); 436258057Sbr out.print(getDescriptor().getName() + "("); 437258057Sbr 438258057Sbr if (args.length > 0) { 439258057Sbr printObject(out, args[0]); 440258057Sbr for (int i = 1; i < args.length; i++) { 441258057Sbr final Object arg = args[i]; 442258057Sbr out.print(", "); 443258057Sbr 444258057Sbr if (!(arg instanceof ScriptObject && ((ScriptObject)arg).isScope())) { 445258057Sbr printObject(out, arg); 446258057Sbr } else { 447258057Sbr out.print("SCOPE"); 448258057Sbr } 449258057Sbr } 450258057Sbr } 451258057Sbr 452258057Sbr out.print(")"); 453258057Sbr 454258057Sbr if (tag.equals("EXIT ")) { 455258057Sbr out.print(" --> "); 456258057Sbr printObject(out, result); 457258057Sbr } 458258057Sbr 459258057Sbr out.println(); 460258057Sbr } 461258057Sbr 462258057Sbr /** 463258057Sbr * Trace event. Wrap an invocation with a return value 464258057Sbr * 465258057Sbr * @param mh invocation handle 466258057Sbr * @param args arguments to call 467258057Sbr * 468258057Sbr * @return return value from invocation 469258057Sbr * 470258057Sbr * @throws Throwable if invocation fails or throws exception/error 471258057Sbr */ 472258057Sbr @SuppressWarnings("unused") 473258057Sbr public Object traceObject(final MethodHandle mh, final Object... args) throws Throwable { 474258057Sbr final PrintWriter out = Context.getCurrentErr(); 475258057Sbr tracePrint(out, "ENTER ", args, null); 476258057Sbr final Object result = mh.invokeWithArguments(args); 477258057Sbr tracePrint(out, "EXIT ", args, result); 478258057Sbr 479258057Sbr return result; 480258057Sbr } 481258057Sbr 482258057Sbr /** 483258057Sbr * Trace event. Wrap an invocation that returns void 484258057Sbr * 485258057Sbr * @param mh invocation handle 486258057Sbr * @param args arguments to call 487258057Sbr * 488258057Sbr * @throws Throwable if invocation fails or throws exception/error 489258057Sbr */ 490258057Sbr @SuppressWarnings("unused") 491258057Sbr public void traceVoid(final MethodHandle mh, final Object... args) throws Throwable { 492258057Sbr final PrintWriter out = Context.getCurrentErr(); 493258057Sbr tracePrint(out, "ENTER ", args, null); 494258057Sbr mh.invokeWithArguments(args); 495258057Sbr tracePrint(out, "EXIT ", args, null); 496258057Sbr } 497258057Sbr 498258057Sbr /** 499258057Sbr * Tracer function that logs a callsite miss 500258057Sbr * 501258057Sbr * @param desc callsite descriptor string 502258057Sbr * @param args arguments to function 503258057Sbr * 504258057Sbr * @throws Throwable if invocation fails or throws exception/error 505258057Sbr */ 506258057Sbr @SuppressWarnings("unused") 507258057Sbr public void traceMiss(final String desc, final Object... args) throws Throwable { 508258057Sbr tracePrint(Context.getCurrentErr(), desc, args, null); 509258057Sbr } 510258057Sbr } 511258057Sbr 512258057Sbr // counters updated in debug mode 513258057Sbr private static LongAdder count; 514258057Sbr private static final HashMap<String, AtomicInteger> missCounts = new HashMap<>(); 515258057Sbr private static LongAdder missCount; 516258057Sbr private static final Random r = new Random(); 517258057Sbr private static final int missSamplingPercentage = Options.getIntProperty("nashorn.tcs.miss.samplePercent", 1); 518258057Sbr 519258057Sbr static { 520258057Sbr if (Context.DEBUG) { 521258057Sbr count = new LongAdder(); 522258057Sbr missCount = new LongAdder(); 523258057Sbr } 524258057Sbr } 525258057Sbr 526258057Sbr @Override 527 protected int getMaxChainLength() { 528 return 8; 529 } 530 531 /** 532 * Get the callsite count 533 * @return the count 534 */ 535 public static long getCount() { 536 return count.longValue(); 537 } 538 539 /** 540 * Get the callsite miss count 541 * @return the missCount 542 */ 543 public static long getMissCount() { 544 return missCount.longValue(); 545 } 546 547 /** 548 * Get given miss sampling percentage for sampler. Default is 1%. Specified with -Dnashorn.tcs.miss.samplePercent=x 549 * @return miss sampling percentage 550 */ 551 public static int getMissSamplingPercentage() { 552 return missSamplingPercentage; 553 } 554 555 /** 556 * Dump the miss counts collected so far to a given output stream 557 * @param out print stream 558 */ 559 public static void getMissCounts(final PrintWriter out) { 560 final ArrayList<Entry<String, AtomicInteger>> entries = new ArrayList<>(missCounts.entrySet()); 561 562 Collections.sort(entries, new Comparator<Map.Entry<String, AtomicInteger>>() { 563 @Override 564 public int compare(final Entry<String, AtomicInteger> o1, final Entry<String, AtomicInteger> o2) { 565 return o2.getValue().get() - o1.getValue().get(); 566 } 567 }); 568 569 for (final Entry<String, AtomicInteger> entry : entries) { 570 out.println(" " + entry.getKey() + "\t" + entry.getValue().get()); 571 } 572 } 573 574} 575