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.runtime;
  27 
  28 import static jdk.nashorn.internal.parser.TokenType.EOF;
  29 
  30 import jdk.nashorn.api.scripting.NashornException;
  31 import jdk.nashorn.internal.parser.Lexer;
  32 import jdk.nashorn.internal.parser.Token;
  33 import jdk.nashorn.internal.parser.TokenStream;
  34 import jdk.nashorn.internal.parser.TokenType;
  35 
  36 /**
  37  * Utilities for debugging Nashorn.
  38  *
  39  */
  40 public final class Debug {
  41     private Debug() {
  42     }
  43 
  44     /**
  45      * Return the topmost JavaScript frame in a stack trace
  46      * @param t throwable that contains the stack trace
  47      * @return line describing the topmost JavaScript frame
  48      */
  49     public static String firstJSFrame(final Throwable t) {
  50         for (final StackTraceElement ste : t.getStackTrace()) {
  51             if (ECMAErrors.isScriptFrame(ste)) {
  52                 return ste.toString();
  53             }
  54         }
  55         return "<native code>";
  56     }
  57 
  58     /**
  59      * Return the topmost JavaScript frame from the current
  60      * continuation
  61      * @return line describing the topmost JavaScript frame
  62      */
  63     public static String firstJSFrame() {
  64         return firstJSFrame(new Throwable());
  65     }
  66 
  67     /**
  68      * Return a formatted script stack trace string with frames information separated by '\n'.
  69      * This is a shortcut for {@code NashornException.getScriptStackString(new Throwable())}.
  70      * @return formatted stack trace string
  71      */
  72     public static String scriptStack() {
  73         return NashornException.getScriptStackString(new Throwable());
  74     }
  75 
  76     /**
  77      * Return the system identity hashcode for an object as a human readable
  78      * string
  79      *
  80      * @param x object
  81      * @return system identity hashcode as string
  82      */
  83     public static String id(final Object x) {
  84         return String.format("0x%08x", System.identityHashCode(x));
  85     }
  86 
  87     /**
  88      * Same as {@link Debug#id} but returns the identity hashcode as
  89      * an integer
  90      *
  91      * @param x object
  92      * @return system identity hashcode
  93      */
  94     public static int intId(final Object x) {
  95         return System.identityHashCode(x);
  96     }
  97 
  98     /**
  99      * Return a stack trace element description at a depth from where we are not
 100      *
 101      * @param depth depth
 102      * @return stack trace element as string
 103      */
 104     public static String stackTraceElementAt(final int depth) {
 105         return new Throwable().getStackTrace()[depth + 1].toString(); // add 1 to compensate for this method
 106     }
 107 
 108     /**
 109      * Determine caller for tracing purposes.
 110      * @param depth depth to trace
 111      * @param count max depth
 112      * @param ignores elements to ignore in stack trace
 113      * @return caller
 114      */
 115     public static String caller(final int depth, final int count, final String... ignores) {
 116         String result = "";
 117         final StackTraceElement[] callers = Thread.currentThread().getStackTrace();
 118 
 119         int c = count;
 120 loop:
 121         for (int i = depth + 1; i < callers.length && c != 0; i++) {
 122             final StackTraceElement element = callers[i];
 123             final String method = element.getMethodName();
 124 
 125             for (final String ignore : ignores) {
 126                 if (method.compareTo(ignore) == 0) {
 127                     continue loop;
 128                 }
 129             }
 130 
 131             result += (method + ":" + element.getLineNumber() +
 132                        "                              ").substring(0, 30);
 133             c--;
 134         }
 135 
 136         return result.isEmpty() ? "<no caller>" : result;
 137     }
 138 
 139     /**
 140      * Dump a token stream to stdout
 141      *
 142      * TODO: most other bugging goes to stderr, change?
 143      *
 144      * @param source the source
 145      * @param lexer  the lexer
 146      * @param stream the stream to dump
 147      */
 148     public static void dumpTokens(final Source source, final Lexer lexer, final TokenStream stream) {
 149         TokenType type;
 150         int k = 0;
 151         do {
 152             while (k > stream.last()) {
 153                 // Get more tokens.
 154                 lexer.lexify();
 155             }
 156 
 157             final long token = stream.get(k);
 158             type = Token.descType(token);
 159             System.out.println("" + k + ": " + Token.toString(source, token, true));
 160             k++;
 161         } while(type != EOF);
 162     }
 163 
 164 }