📄 dim.java
字号:
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino JavaScript Debugger code, released * November 21, 2000. * * The Initial Developer of the Original Code is * SeeBeyond Corporation. * Portions created by the Initial Developer are Copyright (C) 2000 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Igor Bukanov * Matt Gould * Christopher Oliver * Cameron McCormack * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */package org.mozilla.javascript.tools.debugger;import org.mozilla.javascript.*;import org.mozilla.javascript.debug.*;import java.util.*;import java.io.*;import java.net.URL;/** * Dim or Debugger Implementation for Rhino. */public class Dim { // Constants for instructing the debugger what action to perform // to end interruption. Used by 'returnValue'. public static final int STEP_OVER = 0; public static final int STEP_INTO = 1; public static final int STEP_OUT = 2; public static final int GO = 3; public static final int BREAK = 4; public static final int EXIT = 5; // Constants for the DimIProxy interface implementation class. private static final int IPROXY_DEBUG = 0; private static final int IPROXY_LISTEN = 1; private static final int IPROXY_COMPILE_SCRIPT = 2; private static final int IPROXY_EVAL_SCRIPT = 3; private static final int IPROXY_STRING_IS_COMPILABLE = 4; private static final int IPROXY_OBJECT_TO_STRING = 5; private static final int IPROXY_OBJECT_PROPERTY = 6; private static final int IPROXY_OBJECT_IDS = 7; /** * Interface to the debugger GUI. */ private GuiCallback callback; /** * Whether the debugger should break. */ private boolean breakFlag; /** * The ScopeProvider object that provides the scope in which to * evaluate script. */ private ScopeProvider scopeProvider; /** * The index of the current stack frame. */ private int frameIndex = -1; /** * Information about the current stack at the point of interruption. */ private volatile ContextData interruptedContextData; /** * The ContextFactory to listen to for debugging information. */ private ContextFactory contextFactory; /** * Synchronization object used to allow script evaluations to * happen when a thread is resumed. */ private Object monitor = new Object(); /** * Synchronization object used to wait for valid * {@link #interruptedContextData}. */ private Object eventThreadMonitor = new Object(); /** * The action to perform to end the interruption loop. */ private volatile int returnValue = -1; /** * Whether the debugger is inside the interruption loop. */ private boolean insideInterruptLoop; /** * The requested script string to be evaluated when the thread * has been resumed. */ private String evalRequest; /** * The stack frame in which to evaluate {@link #evalRequest}. */ private StackFrame evalFrame; /** * The result of evaluating {@link #evalRequest}. */ private String evalResult; /** * Whether the debugger should break when a script exception is thrown. */ private boolean breakOnExceptions; /** * Whether the debugger should break when a script function is entered. */ private boolean breakOnEnter; /** * Whether the debugger should break when a script function is returned * from. */ private boolean breakOnReturn; /** * Table mapping URLs to information about the script source. */ private final Hashtable urlToSourceInfo = new Hashtable(); /** * Table mapping function names to information about the function. */ private final Hashtable functionNames = new Hashtable(); /** * Table mapping functions to information about the function. */ private final Hashtable functionToSource = new Hashtable(); /** * ContextFactory.Listener instance attached to {@link #contextFactory}. */ private DimIProxy listener; /** * Sets the GuiCallback object to use. */ public void setGuiCallback(GuiCallback callback) { this.callback = callback; } /** * Tells the debugger to break at the next opportunity. */ public void setBreak() { this.breakFlag = true; } /** * Sets the ScopeProvider to be used. */ public void setScopeProvider(ScopeProvider scopeProvider) { this.scopeProvider = scopeProvider; } /** * Switches context to the stack frame with the given index. */ public void contextSwitch(int frameIndex) { this.frameIndex = frameIndex; } /** * Sets whether the debugger should break on exceptions. */ public void setBreakOnExceptions(boolean breakOnExceptions) { this.breakOnExceptions = breakOnExceptions; } /** * Sets whether the debugger should break on function entering. */ public void setBreakOnEnter(boolean breakOnEnter) { this.breakOnEnter = breakOnEnter; } /** * Sets whether the debugger should break on function return. */ public void setBreakOnReturn(boolean breakOnReturn) { this.breakOnReturn = breakOnReturn; } /** * Attaches the debugger to the given ContextFactory. */ public void attachTo(ContextFactory factory) { detach(); this.contextFactory = factory; this.listener = new DimIProxy(this, IPROXY_LISTEN); factory.addListener(this.listener); } /** * Detaches the debugger from the current ContextFactory. */ public void detach() { if (listener != null) { contextFactory.removeListener(listener); contextFactory = null; listener = null; } } /** * Releases resources associated with this debugger. */ public void dispose() { detach(); } /** * Returns the FunctionSource object for the given script or function. */ private FunctionSource getFunctionSource(DebuggableScript fnOrScript) { FunctionSource fsource = functionSource(fnOrScript); if (fsource == null) { String url = getNormalizedUrl(fnOrScript); SourceInfo si = sourceInfo(url); if (si == null) { if (!fnOrScript.isGeneratedScript()) { // Not eval or Function, try to load it from URL String source = loadSource(url); if (source != null) { DebuggableScript top = fnOrScript; for (;;) { DebuggableScript parent = top.getParent(); if (parent == null) { break; } top = parent; } registerTopScript(top, source); fsource = functionSource(fnOrScript); } } } } return fsource; } /** * Loads the script at the given URL. */ private String loadSource(String sourceUrl) { String source = null; int hash = sourceUrl.indexOf('#'); if (hash >= 0) { sourceUrl = sourceUrl.substring(0, hash); } try { InputStream is; openStream: { if (sourceUrl.indexOf(':') < 0) { // Can be a file name try { if (sourceUrl.startsWith("~/")) { String home = System.getProperty("user.home"); if (home != null) { String pathFromHome = sourceUrl.substring(2); File f = new File(new File(home), pathFromHome); if (f.exists()) { is = new FileInputStream(f); break openStream; } } } File f = new File(sourceUrl); if (f.exists()) { is = new FileInputStream(f); break openStream; } } catch (SecurityException ex) { } // No existing file, assume missed http:// if (sourceUrl.startsWith("//")) { sourceUrl = "http:" + sourceUrl; } else if (sourceUrl.startsWith("/")) { sourceUrl = "http://127.0.0.1" + sourceUrl; } else { sourceUrl = "http://" + sourceUrl; } } is = (new URL(sourceUrl)).openStream(); } try { source = Kit.readReader(new InputStreamReader(is)); } finally { is.close(); } } catch (IOException ex) { System.err.println ("Failed to load source from "+sourceUrl+": "+ ex); } return source; } /** * Registers the given script as a top-level script in the debugger. */ private void registerTopScript(DebuggableScript topScript, String source) { if (!topScript.isTopLevel()) { throw new IllegalArgumentException(); } String url = getNormalizedUrl(topScript); DebuggableScript[] functions = getAllFunctions(topScript); final SourceInfo sourceInfo = new SourceInfo(source, functions, url); synchronized (urlToSourceInfo) { SourceInfo old = (SourceInfo)urlToSourceInfo.get(url); if (old != null) { sourceInfo.copyBreakpointsFrom(old); } urlToSourceInfo.put(url, sourceInfo); for (int i = 0; i != sourceInfo.functionSourcesTop(); ++i) { FunctionSource fsource = sourceInfo.functionSource(i); String name = fsource.name(); if (name.length() != 0) { functionNames.put(name, fsource); } } } synchronized (functionToSource) { for (int i = 0; i != functions.length; ++i) { FunctionSource fsource = sourceInfo.functionSource(i); functionToSource.put(functions[i], fsource); } } callback.updateSourceText(sourceInfo); } /** * Returns the FunctionSource object for the given function or script. */ private FunctionSource functionSource(DebuggableScript fnOrScript) { return (FunctionSource)functionToSource.get(fnOrScript); } /** * Returns an array of all function names. */ public String[] functionNames() { String[] a; synchronized (urlToSourceInfo) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -