http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/flash/tools/debugger/concrete/PlayerSession.java ---------------------------------------------------------------------- diff --git a/debugger/src/flash/tools/debugger/concrete/PlayerSession.java b/debugger/src/flash/tools/debugger/concrete/PlayerSession.java deleted file mode 100644 index f41ed19..0000000 --- a/debugger/src/flash/tools/debugger/concrete/PlayerSession.java +++ /dev/null @@ -1,3069 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package flash.tools.debugger.concrete; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.io.UnsupportedEncodingException; -import java.net.Socket; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import flash.tools.debugger.AIRLaunchInfo; -import flash.tools.debugger.Frame; -import flash.tools.debugger.IDebuggerCallbacks; -import flash.tools.debugger.ILauncher; -import flash.tools.debugger.InProgressException; -import flash.tools.debugger.Isolate; -import flash.tools.debugger.IsolateController; -import flash.tools.debugger.IsolateSession; -import flash.tools.debugger.Location; -import flash.tools.debugger.NoResponseException; -import flash.tools.debugger.NotConnectedException; -import flash.tools.debugger.NotSupportedException; -import flash.tools.debugger.NotSuspendedException; -import flash.tools.debugger.PlayerDebugException; -import flash.tools.debugger.Session; -import flash.tools.debugger.SessionManager; -import flash.tools.debugger.SourceFile; -import flash.tools.debugger.SourceLocator; -import flash.tools.debugger.SuspendedException; -import flash.tools.debugger.SwfInfo; -import flash.tools.debugger.Value; -import flash.tools.debugger.ValueAttribute; -import flash.tools.debugger.Variable; -import flash.tools.debugger.VariableAttribute; -import flash.tools.debugger.VariableType; -import flash.tools.debugger.VersionException; -import flash.tools.debugger.Watch; -import flash.tools.debugger.concrete.DProtocol.ListenerIndex; -import flash.tools.debugger.events.DebugEvent; -import flash.tools.debugger.events.ExceptionFault; -import flash.tools.debugger.events.FaultEvent; -import flash.tools.debugger.expression.ECMA; -import flash.tools.debugger.expression.PlayerFaultException; -import flash.util.Trace; - - -public class PlayerSession implements Session, DProtocolNotifierIF, Runnable, IsolateController -{ - public static final int MAX_STACK_DEPTH = 256; - public static final long MAX_TERMINATE_WAIT_MILLIS = 10000; - - private Socket m_socket; - private DProtocol m_protocol; - private DManager m_manager; - private IDebuggerCallbacks m_debuggerCallbacks; - private Process m_process; - private Map<String, Object> m_prefs; // WARNING -- accessed from multiple threads - private static final String s_newline = System.getProperty("line.separator"); //$NON-NLS-1$ - - private volatile boolean m_isConnected; // WARNING -- accessed from multiple threads - private volatile boolean m_isHalted; // WARNING -- accessed from multiple threads - private volatile boolean m_incoming; // WARNING -- accessed from multiple threads - private volatile boolean m_lastResponse; // whether there was a reponse from the last message to the Player - private volatile HashMap<Integer, PlayerSessionIsolateStatus> m_isolateStatus = new HashMap<Integer, PlayerSessionIsolateStatus>(); - - private int m_watchTransactionTag; - private Boolean m_playerCanCallFunctions; - private Boolean m_playerSupportsWatchpoints; - private Boolean m_playerCanBreakOnAllExceptions; - private Boolean m_playerSupportsConcurrency; - private Boolean m_playerSupportsWideLine; - - private ILauncher launcher; - - /** - * The URL that was launched, or <code>null</code> if not known. Note: - * This is NOT the value returned by getURI(). getURI() returns the - * URL that came from the Player, and is therefore probably the URI of - * the SWF; but m_launchedUrl contains the URL that we tried to launch, - * which might be an HTML wrapper, e.g. http://localhost/myapp.html - */ - private String m_launchUrl; - - private AIRLaunchInfo m_airLaunchInfo; // null if this is not an AIR app - - static volatile boolean m_debugMsgOn; // debug ONLY; turned on with "set $debug_messages = 1" - volatile int m_debugMsgSize; // debug ONLY; controlled with "set $debug_message_size = NNN" - static volatile boolean m_debugMsgFileOn; // debug ONLY for file dump; turned on with "set $debug_message_file = 1" - volatile int m_debugMsgFileSize; // debug ONLY for file dump; controlled with "set $debug_message_file_size = NNN" - - //FIXME: Make this concurrency aware - /** - * A simple cache of previous "is" and "instanceof" queries, in order to - * avoid having to send redundant messages to the player. - */ - private Map<String, Boolean> m_evalIsAndInstanceofCache = new HashMap<String, Boolean>(); - - private volatile int m_lastPreIsolate = Isolate.DEFAULT_ID; - - private final Map<Integer, IsolateSession> m_isolateSessions; - - private static final String DEBUG_MESSAGES = "$debug_messages"; //$NON-NLS-1$ - private static final String DEBUG_MESSAGE_SIZE = "$debug_message_size"; //$NON-NLS-1$ - private static final String DEBUG_MESSAGE_FILE = "$debug_message_file"; //$NON-NLS-1$ - private static final String DEBUG_MESSAGE_FILE_SIZE = "$debug_message_file_size"; //$NON-NLS-1$ - - private static final String CONSOLE_ERRORS = "$console_errors"; //$NON-NLS-1$ - - private static final String FLASH_PREFIX = "$flash_"; //$NON-NLS-1$ - - PlayerSession(Socket s, DProtocol proto, DManager manager, IDebuggerCallbacks debuggerCallbacks) - { - m_isConnected = false; - m_isHalted = false; - m_socket = s; - m_protocol = proto; - m_manager = manager; - m_prefs = Collections.synchronizedMap(new HashMap<String, Object>()); - m_incoming = false; - m_debugMsgOn = false; - m_debugMsgSize = 16; - m_debugMsgFileOn = false; - m_debugMsgFileSize = 128; - m_watchTransactionTag = 1; // number that is sent for each watch transaction that occurs - m_playerCanCallFunctions = null; - m_debuggerCallbacks = debuggerCallbacks; - m_isolateSessions = Collections.synchronizedMap(new HashMap<Integer, IsolateSession>()); - } - - private static PlayerSession createFromSocketHelper(Socket s, IDebuggerCallbacks debuggerCallbacks, DProtocol proto) throws IOException - { - // let the manager hear incoming messages - DManager manager = new DManager(); - - PlayerSession session = new PlayerSession(s, proto, manager, debuggerCallbacks); - return session; - } - - /** - * @deprecated Use createFromSocketWithOptions - * @param s - * @param debuggerCallbacks - * @return - * @throws IOException - */ - public static PlayerSession createFromSocket(Socket s, IDebuggerCallbacks debuggerCallbacks) throws IOException - { - DProtocol proto = DProtocol.createFromSocket(s); - - return createFromSocketHelper(s, debuggerCallbacks, proto); - } - - /** - * Creates a session from the socket. Sets session specific - * socket settings and stores the callback object. - * @param s - * @param debuggerCallbacks - * @param sessionManager - * @return - * @throws IOException - */ - public static PlayerSession createFromSocketWithOptions(Socket s, IDebuggerCallbacks debuggerCallbacks, SessionManager sessionManager) throws IOException - { - DProtocol proto = DProtocol.createFromSocket(s, sessionManager); - - return createFromSocketHelper(s, debuggerCallbacks, proto); - } - - /* getter */ - public DMessageCounter getMessageCounter() { return m_protocol.getMessageCounter(); } - public String getURI() { return m_manager.getURI(); } - public boolean playerSupportsGet() { return m_manager.isGetSupported(); } - public int playerVersion() { return m_manager.getVersion(); } - public SourceLocator getSourceLocator() { return m_manager.getSourceLocator(); } - - /* - * @see flash.tools.debugger.Session#setSourceLocator(flash.tools.debugger.SourceLocator) - */ - public void setSourceLocator(SourceLocator sourceLocator) - { - m_manager.setSourceLocator(sourceLocator); - } - - /** - * If the manager started the process for us, then note it here. We will attempt to kill - * it when we go down - */ - void setProcess(Process proc) - { - m_process = proc; - } - - /* - * @see flash.tools.debugger.Session#getLaunchProcess() - */ - public Process getLaunchProcess() - { - return m_process; - } - - /** - * Set preference - * If an invalid preference is passed, it will be silently ignored. - */ - public void setPreferences(Map<String, ? extends Object> map) { m_prefs.putAll(map); mapBack(); } - public Set<String> keySet() { return m_prefs.keySet(); } - public Object getPreferenceAsObject(String pref) { return m_prefs.get(pref); } - - /** - * Set a property. Special logic for debug message boolean - */ - public void setPreference(String pref, int value) - { - m_prefs.put(pref, new Integer(value)); - mapBack(); - - // change in console messages? - if (pref.equals(CONSOLE_ERRORS)) - sendConsoleErrorsAsTrace(value == 1); - - // generic message for flash player wherein "$flash_xxx" causes "xxx" to be sent - if (pref.startsWith(FLASH_PREFIX)) - sendOptionMessage(pref.substring(FLASH_PREFIX.length()), Integer.toString(value)); - } - - // helper for mapBack() - private int mapBackOnePreference(String preferenceName, int defaultValue) - { - Object prefValue = getPreferenceAsObject(preferenceName); - if (prefValue != null) - return ((Integer)prefValue).intValue(); - else - return defaultValue; - } - - // helper for mapBack() - private boolean mapBackOnePreference(String preferenceName, boolean defaultValue) - { - Object prefValue = getPreferenceAsObject(preferenceName); - if (prefValue != null) - return ((Integer)prefValue).intValue() != 0 ? true : false; - else - return defaultValue; - } - - // look for preferences, that map back to variables - private void mapBack() - { - m_debugMsgOn = mapBackOnePreference(DEBUG_MESSAGES, m_debugMsgOn); - m_debugMsgSize = mapBackOnePreference(DEBUG_MESSAGE_SIZE, m_debugMsgSize); - - m_debugMsgFileOn = mapBackOnePreference(DEBUG_MESSAGE_FILE, m_debugMsgFileOn); - m_debugMsgFileSize = mapBackOnePreference(DEBUG_MESSAGE_FILE_SIZE, m_debugMsgFileSize); - } - - public int getPreference(String pref) - { - int val = 0; - Integer i = (Integer)m_prefs.get(pref); - if (i == null) - throw new NullPointerException(); - else - val = i.intValue(); - return val; - } - - - /* - * @see flash.tools.debugger.Session#isConnected() - */ - public boolean isConnected() - { - return m_isConnected; - } - - /* - * @see flash.tools.debugger.Session#isSuspended() - */ - public boolean isSuspended() throws NotConnectedException - { - if (!isConnected()) - throw new NotConnectedException(); - - return m_isHalted; - } - - /* - * @see flash.tools.debugger.Session#isIsolateSuspended() - */ - public boolean isWorkerSuspended(int isolateId) throws NotConnectedException - { - if (isolateId == Isolate.DEFAULT_ID) - return isSuspended(); - - if (!isConnected()) - throw new NotConnectedException(); - - if (m_isolateStatus.containsKey(isolateId)) { - return m_isolateStatus.get(isolateId).m_isHalted; - } - - return false; - } - - /** - * Start up the session listening for incoming messages on the socket - */ - public boolean bind() throws VersionException - { - boolean bound = false; - - if (m_isConnected) - return false; - - // mark that we are connected - m_isConnected = true; - - // attach us to the pipe (we are last to ensure that DManager and msg counter - // get updated first - m_protocol.addListener(ListenerIndex.PlayerSession, this); - - // start up the receiving thread - bound = m_protocol.bind(); - - // transmit our first few adjustment messages - sendStopWarning(); - sendStopOnFault(); - sendEnumerateOverride(); - sendFailureNotify(); - sendInvokeSetters(); - sendSwfloadNotify(); - sendGetterTimeout(); - sendSetterTimeout(); - boolean responded = sendSquelch(true, Isolate.DEFAULT_ID); - - // now note in our preferences whether get is working or not. - setPreference(SessionManager.PLAYER_SUPPORTS_GET, playerSupportsGet() ? 1 : 0); - if (supportsConcurrency()) { - sendConcurrentDebugger(); - } - - if (supportsWideLineNumbers()) { - sendWideLineDebugger(); - } - - // Spawn a background thread which fetches the SWF and SWD - // from the Player and uses them to build function name tables - // for each source file - Thread t = new Thread(this, "SWF/SWD reader"); //$NON-NLS-1$ - t.setDaemon(true); - t.start(); - - // we're probably using a bad version - if (!responded) - throw new VersionException(); - - return bound; - } - - /** - * Permanently stops the debugging session and breaks the - * connection to the Player - */ - public void unbind() - { - unbind(false); - } - - /** - * @param requestTerminate - * if true, and if the player to which we are attached is capable - * of terminating itself (e.g. Adobe AIR), then the player will - * be told to terminate. - * @return true if the player is capable of terminating itself and has been - * told to do so - */ - private boolean unbind(boolean requestTerminate) - { - // If the caller asked us to terminate the player, then we first check - // whether the player to which we are connected is capable of that. - // (The web-based players are not; Adobe AIR is.) - requestTerminate = requestTerminate && playerCanTerminate(); - DMessage dm = DMessageCache.alloc(1); - dm.setType(DMessage.OutExit); - dm.putByte((byte)(requestTerminate ? 1 : 0)); - sendMessage(dm); - - // unbind from the socket, so that we don't receive any more messages - m_protocol.unbind(); - - // kill the socket - try { m_socket.close(); } catch(IOException io) {} - - m_isConnected = false; - m_isHalted = false; - - return requestTerminate; // true if player was told to terminate - } - - /** - * Execute the specified AppleScript by passing it to /usr/bin/osascript. - * - * @param appleScript - * the AppleScript to execute, as a series of lines - * @param argv - * any arguments; these can be accessed from within your - * AppleScript via "item 1 or argv", "item 2 of argv", etc. - * @return any text which was sent to stdout by /usr/bin/osascript, with the - * trailing \n already removed - */ - private String executeAppleScript(String[] appleScript, String[] argv) - { - StringBuilder retval = new StringBuilder(); - try - { - List<String> execArgs = new LinkedList<String>(); - // "osascript" is the command-line way of executing AppleScript. - execArgs.add("/usr/bin/osascript"); //$NON-NLS-1$ - execArgs.add("-"); //$NON-NLS-1$ - if (argv != null) - { - for (int i=0; i<argv.length; ++i) - execArgs.add(argv[i]); - } - Process osascript = Runtime.getRuntime().exec(execArgs.toArray(new String[execArgs.size()])); - // feed our AppleScript code to osascript's stdin - OutputStream outputStream = osascript.getOutputStream(); - PrintWriter writer = new PrintWriter(outputStream, true); - writer.println("on run argv"); //$NON-NLS-1$ // this gives the name "argv" to the command-line args - for (int i=0; i<appleScript.length; ++i) - writer.println(appleScript[i]); - writer.println("end run"); //$NON-NLS-1$ - writer.close(); - InputStreamReader reader = new InputStreamReader(osascript.getInputStream()); - int ch; - while ( (ch=reader.read()) != -1 ) - retval.append((char)ch); - } - catch (IOException e) - { - // ignore - } - return retval.toString().replaceAll("\n$", ""); //$NON-NLS-1$ //$NON-NLS-2$ - } - - /** - * Execute the specified AppleScript by passing it to /usr/bin/osascript. - * - * @param appleScriptFilename - * The name of the file containing AppleScript to execute. This - * must be relative to PlayerSession.java. - * @param argv - * any arguments; these can be accessed from within your - * AppleScript via "item 1 or argv", "item 2 of argv", etc. - * @return any text which was sent to stdout by /usr/bin/osascript, with the - * trailing \n already removed - * @throws IOException - */ - private String executeAppleScript(String appleScriptFilename, String[] argv) throws IOException - { - InputStream stm = null; - try { - stm = PlayerSession.class.getResourceAsStream(appleScriptFilename); - BufferedReader reader = new BufferedReader(new InputStreamReader(stm)); - String line; - List<String> appleScriptLines = new ArrayList<String>(); - while ( (line=reader.readLine()) != null ) - appleScriptLines.add(line); - String[] lines = appleScriptLines.toArray(new String[appleScriptLines.size()]); - return executeAppleScript(lines, argv); - } finally { - if (stm != null) { - stm.close(); - } - } - } - - /** - * Checks whether the specified Macintosh web browser is currently - * running. You should only call this function if you have already - * checked that you are running on a Mac. - * - * @param browserName a name, e.g. "Safari", "Firefox", "Camino" - * @return true if currently running - */ - private Set<String> runningApplications() - { - String running = executeAppleScript( - new String[] - { - "tell application \"System Events\"", //$NON-NLS-1$ - " name of processes", //$NON-NLS-1$ - "end tell" //$NON-NLS-1$ - }, - null - ); - String[] apps = running.split(", "); //$NON-NLS-1$ - Set<String> retval = new HashSet<String>(); - for (int i=0; i<apps.length; ++i) - retval.add(apps[i]); - return retval; - } - - /** - * Destroys all objects related to the connection - * including the process that was tied to this - * session via SessionManager.launch(), if it - * exists. - */ - public void terminate() - { - boolean playerWillTerminateItself = false; - - // unbind first - try - { - // Tell player to end session. Note that this is just a hint, and will often - // do nothing. For example, the Flash player running in a browser will - // currently never terminate when you tell it to, but the AIR player will - // terminate. - playerWillTerminateItself = unbind(true); - } catch(Exception e) - { - } - - if (!playerWillTerminateItself) - { - if (System.getProperty("os.name").toLowerCase().startsWith("mac os x")) //$NON-NLS-1$ //$NON-NLS-2$ - { - if (m_airLaunchInfo != null) - { - // nothing we need to do -- Process.destroy() will kill the AIR app - } - else if (m_launchUrl != null && m_launchUrl.length() > 0) - { - boolean closedAnyWindows = false; - Set<String> runningApps = runningApplications(); - - if (!closedAnyWindows && runningApps.contains("Safari")) //$NON-NLS-1$ - { - try { - String url = m_launchUrl.replaceAll(" ", "%20"); //$NON-NLS-1$ //$NON-NLS-2$ - String safariClosedAnyWindows = executeAppleScript("appleScriptCloseSafariWindow.txt", new String[] { url }); //$NON-NLS-1$ - if ("true".equals(safariClosedAnyWindows)) { //$NON-NLS-1$ - closedAnyWindows = true; - } - else if ( "appquit".equals(safariClosedAnyWindows) ) { //$NON-NLS-1$ - closedAnyWindows = true; - //we closed Safari, verify safari was closed - runningApps = waitForMacAppQuit("Safari"); //$NON-NLS-1$ - } - } catch (IOException e) { - // ignore - } - } - - if (!closedAnyWindows && runningApps.contains("Camino")) //$NON-NLS-1$ - { - // For local file: URLs, Camino uses "file://localhost/..." instead of "file:///..." - String url = m_launchUrl.replaceFirst("^file:///", "file://localhost/"); //$NON-NLS-1$ //$NON-NLS-2$ - try { - String caminoClosedAnyWindows = executeAppleScript("appleScriptCloseCaminoWindow.txt", new String[] { url }); //$NON-NLS-1$ - if ("true".equals(caminoClosedAnyWindows)) { //$NON-NLS-1$ - closedAnyWindows = true; - } - else if ( "appquit".equals(caminoClosedAnyWindows) ) { //$NON-NLS-1$ - closedAnyWindows = true; - //we closed camino, verify camino was closed - runningApps = waitForMacAppQuit("Camino"); //$NON-NLS-1$ - } - - } catch (IOException e) { - // ignore - } - } - - // The standalone player on the Mac has gone through several name changes, - // so we have to look for all of these. - String[] macStandalonePlayerNames = - { - "Flash Player Debugger", // New name as of Player 10.1 //$NON-NLS-1$ - "Flash Player", // New name as of 12/4/06 //$NON-NLS-1$ - "SAFlashPlayer", // An older name //$NON-NLS-1$ - "standalone" // Another older name //$NON-NLS-1$ - }; - - for (int i=0; !closedAnyWindows && i<macStandalonePlayerNames.length; ++i) - { - if (runningApps.contains(macStandalonePlayerNames[i])) - { - executeAppleScript(new String[] { "tell application \"" + macStandalonePlayerNames[i] + "\" to quit" }, null); //$NON-NLS-1$ //$NON-NLS-2$ - waitForMacAppQuit(macStandalonePlayerNames[i]); - closedAnyWindows = true; - } - } - } - } - - // if we have a process pop it - if (m_process != null) - { - try - { - //if a launcher is set for handling the launcher operations then use it. - if(null != launcher) - { - m_debuggerCallbacks.terminateDebugTarget(m_process,launcher); - } - else - { - m_debuggerCallbacks.terminateDebugTarget(m_process); - } - } - catch (IOException e) - { - // ignore - } - } - } - else if (m_process != null) { - try { - m_process.waitFor(); - } - catch (Exception e) { - } - } - - // now clear it all - m_isConnected = false; - m_isHalted = false; - } - - /** - * Utility function to wait for a mac application to quit. - * This waits for a maximum of MAX_TERMINATE_WAIT_MILLIS. - * - * Waiting is important because applescript "quit" is not - * synchronous and launching a URL while the browser is - * quitting is not good. (See FB-21879) - * @return Set<String> of running applications. - */ - private Set<String> waitForMacAppQuit(String browser) { - Set<String> runningApps; - boolean appClosed = true; - final long startMillis = System.currentTimeMillis(); - final long waitMillis = 100; - do { - runningApps = runningApplications(); - if ( runningApps.contains(browser) ) { - appClosed = false; - - try { - Thread.sleep(waitMillis); - } catch (InterruptedException e) { - return runningApps; - } - - long currentMillis = System.currentTimeMillis(); - - if ( currentMillis - startMillis >= MAX_TERMINATE_WAIT_MILLIS ) - break; - } - else { - appClosed = true; - } - } - while ( !appClosed ); - return runningApps; - } - - /* - * @see flash.tools.debugger.Session#resume() - */ - public void resume() throws NotSuspendedException, NotConnectedException, NoResponseException - { - resumeWorker(Isolate.DEFAULT_ID); - } - - /* - * @see flash.tools.debugger.Session#suspend() - */ - public void suspend() throws SuspendedException, NotConnectedException, NoResponseException - { - suspendWorker(Isolate.DEFAULT_ID); - } - - /** - * Obtain all the suspend information - */ - public DSuspendInfo getSuspendInfo() - { - return getSuspendInfoIsolate(Isolate.DEFAULT_ID); - } - - /** - * Return the reason that the player has suspended itself. - */ - public int suspendReason() - { - DSuspendInfo info = getSuspendInfo(); - return info.getReason(); - } - - /** - * Return the offset in which the player has suspended itself. The BreakReason - * message contains both reason and offset. - */ - public int getSuspendOffset() - { - DSuspendInfo info = getSuspendInfo(); - return info.getOffset(); - } - - /** - * Return the offset in which the player has suspended itself. The BreakReason - * message contains both reason and offset. - */ - public int getSuspendActionIndex() - { - DSuspendInfo info = getSuspendInfo(); - return info.getActionIndex(); - } - - /** - * Obtain information about the various SWF(s) that have been - * loaded into the Player, for this session. - * - * Note: As SWFs are loaded by the Player a SwfLoadedEvent is - * fired. At this point, a call to getSwfInfo() will provide - * updated information. - * - * @return array of records describing the SWFs - */ - public SwfInfo[] getSwfs() throws NoResponseException - { - return getSwfsWorker(Isolate.DEFAULT_ID); - } - - /** - * Request information on a particular swf, used by DSwfInfo - * to fill itself correctly - */ - public void requestSwfInfo(int at, int isolateId) throws NoResponseException - { - // nope don't have it...might as well go out and ask for all of them. - DMessage dm = DMessageCache.alloc(4); - dm.setType( DMessage.OutSwfInfo ); - dm.setTargetIsolate(isolateId); - dm.putWord(at); - dm.putWord(0); // rserved - - int to = getPreference(SessionManager.PREF_CONTEXT_RESPONSE_TIMEOUT); - - if (!simpleRequestResponseMessage(dm, DMessage.InSwfInfo, to)) - throw new NoResponseException(to); - } - - /** - * Request a set of actions from the player - */ - public byte[] getActions(int which, int at, int len) throws NoResponseException - { - byte[] actions = null; - - // send a actions message - DMessage dm = DMessageCache.alloc(12); - dm.setType( DMessage.OutGetActions ); - dm.putWord(which); - dm.putWord(0); // rsrvd - dm.putDWord(at); - dm.putDWord(len); - - // request action bytes - int to = getPreference(SessionManager.PREF_CONTEXT_RESPONSE_TIMEOUT); - if (simpleRequestResponseMessage(dm, DMessage.InGetActions, to)) - actions = m_manager.getActions(); - else - throw new NoResponseException(to); - - return actions; - } - - /* - * @see flash.tools.debugger.Session#stepInto() - */ - public void stepInto() throws NotSuspendedException, NoResponseException, NotConnectedException - { - stepIntoWorker(Isolate.DEFAULT_ID); - } - - /* - * @see flash.tools.debugger.Session#stepOut() - */ - public void stepOut() throws NotSuspendedException, NoResponseException, NotConnectedException - { - stepOutWorker(Isolate.DEFAULT_ID); - } - - /* - * @see flash.tools.debugger.Session#stepOver() - */ - public void stepOver() throws NotSuspendedException, NoResponseException, NotConnectedException - { - stepOverWorker(Isolate.DEFAULT_ID); - } - - /* - * @see flash.tools.debugger.Session#stepContinue() - */ - public void stepContinue() throws NotSuspendedException, NoResponseException, NotConnectedException - { - if (!isSuspended()) - throw new NotSuspendedException(); - - // send a step-continue message and then wait for the Flash player to tell us that is has - // resumed execution - if (!simpleRequestResponseMessage(DMessage.OutStepContinue, DMessage.InContinue)) - throw new NoResponseException(getPreference(SessionManager.PREF_RESPONSE_TIMEOUT)); - } - - /** - * Sends a request to the player to obtain function names. - * The resultant message end up populating the function name array - * for the given DModule. - * - * @param moduleId - * @param lineNbr - * @return - */ - public void requestFunctionNames(int moduleId, int lineNbr, int isolateId) throws VersionException, NoResponseException - { - // only player 9 supports this message - if (m_manager.getVersion() >= 9) - { - DMessage dm = DMessageCache.alloc(8); - dm.setType(DMessage.OutGetFncNames); - dm.setTargetIsolate(isolateId); - dm.putDWord(moduleId); - dm.putDWord(lineNbr); - - if (!simpleRequestResponseMessage(dm, DMessage.InGetFncNames)) - throw new NoResponseException(0); - } - else - { - throw new VersionException(); - } - } - - /** - * From a given file identifier return a source file object - */ - public SourceFile getFile(int fileId, int isolateId) - { - return m_manager.getSource(fileId, isolateId); - } - - /** - * Get a list of breakpoints - */ - public Location[] getBreakpointList() - { - return m_manager.getBreakpoints(Isolate.DEFAULT_ID); - } - - /* - * @see flash.tools.debugger.Session#setBreakpoint(int, int) - */ - public Location setBreakpoint(int fileId, int lineNum) throws NoResponseException, NotConnectedException - { - return setBreakpointWorker(fileId, lineNum, Isolate.DEFAULT_ID); - } - - /* - * @see flash.tools.debugger.Session#clearBreakpoint(flash.tools.debugger.Location) - */ - public Location clearBreakpoint(Location local) - { - /* first find it */ - SourceFile source = local.getFile(); - int fileId = source.getId(); - int lineNum = local.getLine(); - int bp = DLocation.encodeId(fileId, lineNum); - int isolateId = local.getIsolateId(); - Location l = null; - l = m_manager.getBreakpoint(bp, isolateId); - - if (l != null) - { - /* send the message */ - int wideLineSize = 0; - if (supportsWideLineNumbers()) - wideLineSize = 4; - DMessage dm = DMessageCache.alloc(8 + wideLineSize); - dm.setType(DMessage.OutRemoveBreakpoints); - dm.setTargetIsolate(isolateId); - dm.putDWord(1); - if (!supportsWideLineNumbers()) - dm.putDWord(bp); - else { - dm.putDWord(fileId); - dm.putDWord(lineNum); - } - sendMessage(dm); - - /* no callback from the player so we remove it ourselves */ - m_manager.removeBreakpoint(bp, isolateId); - } - return l; - } - - /* - * @see flash.tools.debugger.Session#getWatchList() - */ - public Watch[] getWatchList() throws NoResponseException, NotConnectedException - { - return getWatchListWorker(Isolate.DEFAULT_ID); - } - - /* - * @see flash.tools.debugger.Session#getWatchList() - */ - public Watch[] getWatchListWorker(int isolateId) throws NoResponseException, NotConnectedException - { - return m_manager.getWatchpoints(isolateId); - } - - private Watch setWatch(long varId, String memberName, int kind, int isolateId) throws NoResponseException, NotConnectedException, NotSupportedException - { - // we really have two cases here, one where we add a completely new - // watchpoint and the other where we modify an existing one. - // In either case the DManager logic is such that the last watchpoint - // in the list will contain our id if successful. - Watch w = null; - int tag = m_watchTransactionTag++; - - if (addWatch(varId, memberName, kind, tag, isolateId)) - { - // good that we got a response now let's check that - // it actually worked. - int count = m_manager.getWatchpointCount(isolateId); - if (count > 0) - { - DWatch lastWatch = m_manager.getWatchpoint(count-1, isolateId); - if (lastWatch.getTag() == tag) - w = lastWatch; - } - } - return w; - } - - /* - * @see flash.tools.debugger.Session#setWatch(flash.tools.debugger.Variable, java.lang.String, int) - */ - public Watch setWatch(Value v, String memberName, int kind) throws NoResponseException, NotConnectedException, NotSupportedException - { - return setWatch(v.getId(), memberName, kind, v.getIsolateId()); - } - - public Watch setWatch(Watch watch) throws NoResponseException, NotConnectedException, NotSupportedException - { - return setWatch(watch.getValueId(), watch.getMemberName(), watch.getKind(), watch.getIsolateId()); - } - - /* - * @see flash.tools.debugger.Session#clearWatch(flash.tools.debugger.Watch) - */ - public Watch clearWatch(Watch watch) throws NoResponseException, NotConnectedException - { - Watch[] list = getWatchListWorker(watch.getIsolateId()); - Watch w = null; - if ( removeWatch(watch.getValueId(), watch.getMemberName(), watch.getIsolateId()) ) - { - // now let's first check the size of the list, it - // should now be one less - if (m_manager.getWatchpointCount(watch.getIsolateId()) < list.length) - { - // ok we made a change. So let's compare list and see which - // one went away - Watch[] newList = getWatchListWorker(watch.getIsolateId()); - for(int i=0; i<newList.length; i++) - { - // where they differ is the missing one - if (list[i] != newList[i]) - { - w = list[i]; - break; - } - } - - // might be the last one... - if (w == null) - w = list[list.length-1]; - } - } - return w; - } - - /* - * @see flash.tools.debugger.Session#getVariableList() - */ - public Variable[] getVariableList() throws NotSuspendedException, NoResponseException, NotConnectedException, VersionException - { - return getVariableListWorker(Isolate.DEFAULT_ID); - } - - public Variable[] getVariableListWorker(int isolateId) throws NotSuspendedException, NoResponseException, NotConnectedException, VersionException - { - // make sure the player has stopped and send our message awaiting a response - if (!isWorkerSuspended(isolateId)) - throw new NotSuspendedException(); - - requestFrame(0, isolateId); // our 0th frame gets our local context - - // now let's request all of the special variables too - getValueWorker(Value.GLOBAL_ID, isolateId); - getValueWorker(Value.THIS_ID, isolateId); - getValueWorker(Value.ROOT_ID, isolateId); - - // request as many levels as we can get - int i = 0; - Value v = null; - do - { - v = getValueWorker(Value.LEVEL_ID-i, isolateId); - } - while( i++ < 128 && v != null); - - // now that we've primed the DManager we can request the base variable whose - // children are the variables that are available - v = m_manager.getValue(Value.BASE_ID, isolateId); - if (v == null) - throw new VersionException(); - return v.getMembers(this); - } - - /* - * @see flash.tools.debugger.Session#getFrames() - */ - public Frame[] getFrames() throws NotConnectedException - { - return m_manager.getFrames(Isolate.DEFAULT_ID); - } - - /** - * Asks the player to return information regarding our current context which includes - * this pointer, arguments for current frame, locals, etc. - */ - public void requestFrame(int depth, int isolateId) throws NotSuspendedException, NoResponseException, NotConnectedException - { - if (playerSupportsGet()) - { - if (!isWorkerSuspended(isolateId)) - throw new NotSuspendedException(); - - int timeout = getPreference(SessionManager.PREF_CONTEXT_RESPONSE_TIMEOUT); - - DMessage dm = DMessageCache.alloc(4); - dm.setType(DMessage.OutGetFrame); - dm.setTargetIsolate(isolateId); - dm.putDWord(depth); // depth of zero - if (!simpleRequestResponseMessage(dm, DMessage.InFrame, timeout)) { - throw new NoResponseException(timeout); - } - - pullUpActivationObjectVariables(depth, isolateId); - } - } - - /** - * The compiler sometimes creates special local variables called - * "activation objects." When it decides to do this (e.g. if the - * current function contains any anonymous functions, try/catch - * blocks, complicated E4X expressions, or "with" clauses), then - * all locals and arguments are actually stored as children of - * this activation object, rather than the usual way. - * - * We need to hide this implementation detail from the user. So, - * if we find any activation objects among the locals of the current - * function, then we will "pull up" its members, and represent them - * as if they were actually args/locals of the function itself. - * - * @param depth the depth of the stackframe we are fixing; 0 is topmost - */ - private void pullUpActivationObjectVariables(int depth, int isolateId) throws NotSuspendedException, NoResponseException, NotConnectedException - { - DValue frame = m_manager.getValue(Value.BASE_ID-depth, isolateId); - if (frame == null) - return; - DStackContext context = m_manager.getFrame(depth, isolateId); - DVariable[] frameVars = (DVariable[]) frame.getMembers(this); - Map<String, DVariable> varmap = new LinkedHashMap<String, DVariable>(frameVars.length); // preserves order - List<DVariable> activationObjects = new ArrayList<DVariable>(); - Pattern activationObjectNamePattern = Pattern.compile("^.*\\$\\d+$"); //$NON-NLS-1$ - - // loop through all frame variables, and separate them into two - // groups: activation objects, and all others (locals and arguments) - for (int i=0; i<frameVars.length; ++i) - { - DVariable member = frameVars[i]; - Matcher matcher = activationObjectNamePattern.matcher(member.getName()); - if (matcher.matches()) - activationObjects.add(member); - else - varmap.put(member.getName(), member); - } - - // If there are no activation objects, then we don't need to do anything - if (activationObjects.size() == 0) - return; - - // overwrite existing args and locals with ones pulled from the activation objects - for (int i=0; i<activationObjects.size(); ++i) - { - DVariable activationObject = activationObjects.get(i); - DVariable[] activationMembers = (DVariable[]) activationObject.getValue().getMembers(this); - for (int j=0; j<activationMembers.length; ++j) - { - DVariable member = activationMembers[j]; - int attributes = member.getAttributes(); - - // For some odd reason, the activation object often contains a whole bunch of - // other variables that we shouldn't be displaying. I don't know what they - // are, but I do know that they are all marked "static". - if ((attributes & VariableAttribute.IS_STATIC) != 0) - continue; - - // No matter what the activation object member's scope is, we want all locals - // and arguments to be considered "public" - attributes &= ~(VariableAttribute.PRIVATE_SCOPE | VariableAttribute.PROTECTED_SCOPE | VariableAttribute.NAMESPACE_SCOPE); - attributes |= VariableAttribute.PUBLIC_SCOPE; - member.setAttributes(attributes); - - String name = member.getName(); - DVariable oldvar = varmap.get(name); - int vartype; - if (oldvar != null) - vartype = oldvar.getAttributes() & (VariableAttribute.IS_ARGUMENT | VariableAttribute.IS_LOCAL); - else - vartype = VariableAttribute.IS_LOCAL; - member.setAttributes(member.getAttributes() | vartype); - varmap.put(name, member); - } - - context.convertLocalToActivationObject(activationObject); - } - - for (DVariable var: varmap.values()) - { - frame.addMember(var); - if (var.isAttributeSet(VariableAttribute.IS_LOCAL)) - { - context.addLocal(var); - } - else if (var.isAttributeSet(VariableAttribute.IS_ARGUMENT)) - { - if (var.getName().equals("this")) //$NON-NLS-1$ - context.setThis(var); - else - context.addArgument(var); - } - } - } - - /* - * @see flash.tools.debugger.Session#getValue(int) - */ - public Value getValue(long valueId) throws NotSuspendedException, NoResponseException, NotConnectedException - { - return getValueWorker(valueId, Isolate.DEFAULT_ID); - } - - public Value getValueWorker(long valueId, int isolateId) throws NotSuspendedException, NoResponseException, NotConnectedException - { - DValue val = null; - - if (!isWorkerSuspended(isolateId)) - throw new NotSuspendedException(); - - // get it from cache if we can - val = m_manager.getValue(valueId, isolateId); - - if (val == null) - { - // if a special variable, then we need to trigger a local frame call, otherwise just use id to get it - if (valueId < Value.UNKNOWN_ID) - { - requestFrame(0, isolateId); // force our current frame to get populated, BASE_ID will be available - } - else if (valueId > Value.UNKNOWN_ID) - { - requestVariable(valueId, null, isolateId); - } - - // after all this we should have our variable cache'd so try again if it wasn't there the first time - val = m_manager.getValue(valueId, isolateId); - } - - return val; - } - - /** - * Returns the current value object for the given id; never requests it from the player. - */ - public Value getRawValue(long valueId, int isolateId) - { - return m_manager.getValue(valueId, isolateId); - } - - /** - * Returns the previous value object for the given id -- that is, the value that that - * object had the last time the player was suspended. Never requests it from the - * player (because it can't, of course). Returns <code>null</code> if we don't have - * a value for that id. - */ - public Value getPreviousValue(long valueId, int isolateId) - { - return m_manager.getPreviousValue(valueId, isolateId); - } - - /** - * Launches a request to obtain all the members of the specified variable, and - * store them in the variable which would be returned by - * {@link DManager#getVariable(long)}. - * - * @param valueId id of variable whose members we want; underlying Variable must - * already be known by the PlayerSessionManager. - * - * @throws NoResponseException - * @throws NotConnectedException - * @throws NotSuspendedException - */ - void obtainMembers(long valueId, int isolateId) throws NoResponseException, NotConnectedException, NotSuspendedException - { - if (!isWorkerSuspended(isolateId)) - throw new NotSuspendedException(); - - // Get it from cache. Normally, this should never fail; however, in - // the case of Flex Builder, which is multithreaded, it is possible - // that a thread has called this even after a different thread has - // single-stepped, so that the original variable is no longer valid. - // So, we'll check for a null return value. - DValue v = m_manager.getValue(valueId, isolateId); - - if (v != null && !v.membersObtained()) - { - requestVariable(valueId, null, false, true, isolateId); - } - } - - public Value getGlobal(String name) throws NotSuspendedException, NoResponseException, NotConnectedException - { - return getGlobalWorker(name, Isolate.DEFAULT_ID); - } - - public Value getGlobalWorker(String name, int isolateId) throws NotSuspendedException, NoResponseException, NotConnectedException - { - Value v = getValue(0, name, isolateId); - - if (v==null || v.getType() == VariableType.UNDEFINED) - return null; - else - return v; - } - - /** - * Get the value of the variable named 'name' using varId - * as the context id for the Variable. - * - * This call is used to fire getters, where the id must - * be that of the original object and not the object id - * of where the getter actually lives. For example - * a getter a() may live under o.__proto__.__proto__ - * but you must use the id of o and the name of 'a' - * in order for the getter to fire correctly. [Note: This - * paragraph was written for AS2; __proto__ doesn't exist - * in AS3. TODO: revise this paragraph] - */ - public Value getValue(long varId, String name, int isolateId) throws NotSuspendedException, NoResponseException, NotConnectedException - { - Value v = null; - if (isWorkerSuspended(isolateId)) - { - int fireGetter = getPreference(SessionManager.PREF_INVOKE_GETTERS); - - // disable children attaching to parent variables and clear our - // most recently seen variable - m_manager.clearLastVariable(isolateId); - m_manager.enableChildAttach(false, isolateId); - - try - { - requestVariable(varId, name, (fireGetter != 0), false, isolateId); - - DVariable lastVariable = m_manager.lastVariable(isolateId); - if (lastVariable != null) - v = lastVariable.getValue(); - else - v = DValue.forPrimitive(Value.UNDEFINED, isolateId); - } - catch (NoResponseException e) - { - if (fireGetter != 0) - { - // We fired a getter -- most likely, what happened is that that getter - // (which is actual code in the user's movie) just took too long to - // calculate its value. So rather than throwing an exception, we store - // some error text for the value of the variable itself. - // - // TODO [mmorearty 4/20/06] Even though I wrote the below code, I now - // am wondering if it is incorrect that I am calling addVariableMember(), - // because in every other case, this function does not add members to - // existing objects. Need to revisit this. - v = new DValue(VariableType.STRING, "String", "String", ValueAttribute.IS_EXCEPTION, //$NON-NLS-1$ //$NON-NLS-2$ - e.getLocalizedMessage(), isolateId); - if (varId != 0) { - DVariable var = new DVariable(name, (DValue)v, isolateId); - m_manager.enableChildAttach(true, isolateId); - m_manager.addVariableMember(varId, var, isolateId); - } - } - else - { - throw e; // re-throw - } - } - finally - { - // reset our attach flag, so that children attach to parent variables. - m_manager.enableChildAttach(true, isolateId); - } - } - else - throw new NotSuspendedException(); - - return v; - } - - private void requestVariable(long id, String name, int isolateId) throws NoResponseException, NotConnectedException, NotSuspendedException - { - requestVariable(id, name, false, false, isolateId); - } - - /** - * @param thisValue the value of the "this" pointer; meaningless if isConstructor is true - * @param isConstructor whether we're calling a constructor as opposed to a regular function - * @param funcname the name of the function to call (or class whose constructor we're calling) - * @param args the args to the function - * @return the return value of the function - */ - private Value callFunction(Value thisValue, boolean isConstructor, String funcname, Value[] args, int isolateId) throws PlayerDebugException - { - if (!isWorkerSuspended(isolateId)) - throw new NotSuspendedException(); - - if (!playerCanCallFunctions(isolateId)) - throw new NotSupportedException(PlayerSessionManager.getLocalizationManager().getLocalizedTextString("functionCallsNotSupported")); //$NON-NLS-1$ - - // name = getRawMemberName(id, name); - - m_manager.clearLastFunctionCall(isolateId); - - DMessage dm = buildCallFunctionMessage(isConstructor, thisValue, funcname, args); - - dm.setTargetIsolate(isolateId); - - // make sure any exception during the setter gets held onto - m_manager.beginPlayerCodeExecution(isolateId); - - // TODO wrong timeout - int timeout = getPreference(SessionManager.PREF_GETVAR_RESPONSE_TIMEOUT); - timeout += 500; // give the player enough time to raise its timeout exception - - boolean result = simpleRequestResponseMessage(dm, DMessage.InCallFunction, timeout); - - // tell manager we're done; ignore returned FaultEvent - m_manager.endPlayerCodeExecution(isolateId); - - if (!result) - throw new NoResponseException(timeout); - - DVariable lastFunctionCall = m_manager.lastFunctionCall(isolateId); - if (lastFunctionCall != null) - return lastFunctionCall.getValue(); - else - return DValue.forPrimitive(Value.UNDEFINED, isolateId); - } - - /* - * @see flash.tools.debugger.Session#callFunction(flash.tools.debugger.Value, java.lang.String, flash.tools.debugger.Value[]) - */ - public Value callFunction(Value thisValue, String funcname, Value[] args) throws PlayerDebugException - { - return callFunctionWorker(thisValue, funcname, args, Isolate.DEFAULT_ID); - } - - public Value callFunctionWorker(Value thisValue, String funcname, Value[] args, int isolateId) throws PlayerDebugException - { - Value retval = callPseudoFunction(thisValue, funcname, args, isolateId); - if (retval != null) { - return retval; - } - - return callFunction(thisValue, false, funcname, args, isolateId); - } - - /** - * Checks to see if the function being called is a debugger pseudofunction such as - * $obj(), and if so, handles that directly rather than calling the player. Returns - * null if the function being called is not a pseudofunction. - */ - private Value callPseudoFunction(Value thisValue, String funcname, Value[] args, int isolateId) throws PlayerDebugException{ - if (thisValue.getType() == VariableType.UNDEFINED || thisValue.getType() == VariableType.NULL) { - if ("$obj".equals(funcname)) { //$NON-NLS-1$ - return callObjPseudoFunction(args, isolateId); - } - } - - return null; - } - - /** - * Handles a call to the debugger pseudofunction $obj() -- e.g. $obj(1234) returns - * a pointer to the object with id 1234. - */ - private Value callObjPseudoFunction(Value[] args, int isolateId) throws PlayerDebugException { - if (args.length != 1) { - return DValue.forPrimitive(DValue.UNDEFINED, isolateId); - } - double arg = ECMA.toNumber(this, args[0]); - long id = (long) arg; - if (id != arg) { - return DValue.forPrimitive(DValue.UNDEFINED, isolateId); - } - DValue value = m_manager.getValue(id, isolateId); - if (value == null) { - return DValue.forPrimitive(DValue.UNDEFINED, isolateId); - } - return value; - } - - public Value callConstructor(String funcname, Value[] args) throws PlayerDebugException - { - return callConstructorWorker(funcname, args, Isolate.DEFAULT_ID); - } - - public Value callConstructorWorker(String funcname, Value[] args, int isolateId) throws PlayerDebugException - { - return callFunction(DValue.forPrimitive(null, isolateId), true, funcname, args, isolateId); - } - - private DMessage buildCallFunctionMessage(boolean isConstructor, Value thisValue, String funcname, Value[] args) - { - funcname = (funcname == null) ? "" : funcname; //$NON-NLS-1$ - - int messageSize = 8; // DWORD representing flags + DWORD representing frame - String thisType = DVariable.typeNameFor(thisValue.getType()); - String thisValueString = thisValue.getValueAsString(); - messageSize += DMessage.getStringLength(thisType)+1; - messageSize += DMessage.getStringLength(thisValueString)+1; - messageSize += DMessage.getStringLength(funcname)+1; - messageSize += 4; // DWORD representing the number of args - String[] argTypes = new String[args.length]; - String[] argValues = new String[args.length]; - for (int i=0; i<args.length; ++i) - { - argTypes[i] = DVariable.typeNameFor(args[i].getType()); - argValues[i] = args[i].getValueAsString(); - messageSize += DMessage.getStringLength(argValues[i])+1; - messageSize += DMessage.getStringLength(argTypes[i])+1; - } - - DMessage dm = DMessageCache.alloc(messageSize); - dm.setType(DMessage.OutCallFunction); - try - { - dm.putDWord(isConstructor ? 1 : 0); - dm.putDWord(0); // TODO: the currently active frame number - dm.putString(thisType); - dm.putString(thisValueString); - dm.putString(funcname); - dm.putDWord(args.length); - for (int i=0; i<args.length; ++i) - { - dm.putString(argTypes[i]); - dm.putString(argValues[i]); - } - } - catch(UnsupportedEncodingException uee) - { - // couldn't write out the string, so just terminate it and complete anyway - dm.putByte((byte)'\0'); - } - - return dm; - } - - private void requestVariable(long id, String name, boolean fireGetter, boolean alsoGetChildren, int isolateId) throws NoResponseException, NotConnectedException, NotSuspendedException - { - if (!isWorkerSuspended(isolateId)) - throw new NotSuspendedException(); - - name = getRawMemberName(id, name, isolateId); - - DMessage dm = buildOutGetMessage(id, name, fireGetter, alsoGetChildren); - - dm.setTargetIsolate(isolateId); - - // make sure any exception during the setter gets held onto - m_manager.beginPlayerCodeExecution(isolateId); - - int timeout = getPreference(SessionManager.PREF_GETVAR_RESPONSE_TIMEOUT); - timeout += 500; // give the player enough time to raise its timeout exception - - boolean result = simpleRequestResponseMessage(dm, DMessage.InGetVariable, timeout); - - // tell manager we're done; ignore returned FaultEvent - m_manager.endPlayerCodeExecution(isolateId); - - if (!result) - throw new NoResponseException(timeout); - } - - private DMessage buildOutGetMessage(long id, String name, boolean fireGetter, boolean alsoGetChildren) - { - final int FLAGS_SIZE = 4; - name = (name == null) ? "" : name; //$NON-NLS-1$ - - DMessage dm = DMessageCache.alloc(DMessage.getSizeofPtr() + DMessage.getStringLength(name)+1 + FLAGS_SIZE); - dm.setType( (!fireGetter) ? DMessage.OutGetVariable : DMessage.OutGetVariableWhichInvokesGetter ); - dm.putPtr(id); - try - { - dm.putString(name); - } - catch(UnsupportedEncodingException uee) - { - // couldn't write out the string, so just terminate it and complete anyway - dm.putByte((byte)'\0'); - } - - // as an optimization, newer player builds allow us to tell them not to - // send all the children of an object along with the object, because - // frequently we don't care about the children - int flags = GetVariableFlag.DONT_GET_FUNCTIONS; // we never want functions - if (fireGetter) - flags |= GetVariableFlag.INVOKE_GETTER; - if (alsoGetChildren) - flags |= GetVariableFlag.ALSO_GET_CHILDREN | GetVariableFlag.GET_CLASS_HIERARCHY; - dm.putDWord(flags); - - return dm; - } - - public FaultEvent setScalarMember(long varId, String memberName, int type, String value, int isolateId) throws NotSuspendedException, NoResponseException, NotConnectedException - { - if (!isWorkerSuspended(isolateId)) - throw new NotSuspendedException(); - - // If the varId is that of a stack frame, then we need to check whether that - // stack frame has an "activation object". If it does, then all of the - // arguments and locals are actually kept as members of that activation - // object, and so we need to change varId to be the ID of that activation - // object -- that way, the player will modify the member of the activation - // object rather than modifying the "regular" argument or local. See bug - // 155031. - if (varId <= Value.BASE_ID && varId > Value.LEVEL_ID) - { - int depth = (int) (Value.BASE_ID - varId); - DStackContext context = m_manager.getFrame(depth,isolateId); - DVariable activationObject = context.getActivationObject(); - if (activationObject != null) - varId = activationObject.getValue().getId(); - } - - memberName = getRawMemberName(varId, memberName, isolateId); - - // see if it is our any of our special variables - FaultEvent faultEvent = requestSetVariable( isPseudoVarId(varId) ? 0 : varId, memberName, type, value, isolateId); - - // now that we sent it out, we need to clear our variable cache - // if it is our special context then mark the frame as stale. - if (isPseudoVarId(varId) && m_manager.getFrameCount(isolateId) > 0) - { - m_manager.getFrame(0, isolateId).markStale(); - } - else - { - DValue parent = m_manager.getValue(varId,isolateId); - if (parent != null) - parent.removeAllMembers(); - } - - return faultEvent; - } - - /** - * Returns whether a variable ID is "real" or not. For example, - * Value.THIS_ID is a "pseudo" varId, as are all the other special - * hard-coded varIds in the Value class. - */ - private boolean isPseudoVarId(long varId) - { - /* - * Unfortunately, this is actually just taking a guess. The old code - * used "varId < 0"; however, the Linux player sometimes has real - * variable IDs which are less than zero. - */ - return (varId < 0 && varId > -65535); - } - - /** - * <code>memberName</code> might be just <code>"varname"</code>, or it - * might be <code>"namespace::varname"</code>, or it might be - * <code>"namespace@hexaddr::varname"</code>. In the third case, it is - * fully resolved, and there is nothing we need to do. But in the first - * and second cases, we may need to fully resolve it so that the Player - * will recognize it. - */ - private String getRawMemberName(long parentValueId, String memberName, int isolateId) - { - if (memberName != null) - { - DValue parent = m_manager.getValue(parentValueId, isolateId); - if (parent != null) - { - int doubleColon = memberName.indexOf("::"); //$NON-NLS-1$ - String shortName = (doubleColon==-1) ? memberName : memberName.substring(doubleColon+2); - DVariable member = parent.findMember(shortName); - if (member != null) - memberName = member.getRawName(); - } - } - return memberName; - } - - /** - * @return null for success, or fault event if a setter in the player threw an exception - */ - private FaultEvent requestSetVariable(long id, String name, int t, String value, int isolateId) throws NoResponseException - { - // convert type to typeName - String type = DVariable.typeNameFor(t); - DMessage dm = buildOutSetMessage(id, name, type, value); - dm.setTargetIsolate(isolateId); - FaultEvent faultEvent = null; -// System.out.println("setmsg id="+id+",name="+name+",t="+type+",value="+value); - - // make sure any exception during the setter gets held onto - m_manager.beginPlayerCodeExecution(isolateId); - - // turn off squelch so we can hear the response - sendSquelch(false, isolateId); - - int timeout = getPreference(SessionManager.PREF_GETVAR_RESPONSE_TIMEOUT); - - if (!simpleRequestResponseMessage(dm, (t == VariableType.STRING) ? DMessage.InSetVariable : DMessage.InSetVariable2, timeout)) - throw new NoResponseException(getPreference(SessionManager.PREF_RESPONSE_TIMEOUT)); - - // turn it back on - sendSquelch(true, isolateId); - - // tell manager we're done, and get exception if any - faultEvent = m_manager.endPlayerCodeExecution(isolateId); - - // hammer the variable cache and context array - m_manager.freeValueCache(isolateId); - return faultEvent; - } - - private DMessage buildOutSetMessage(long id, String name, String type, String v) - { - DMessage dm = DMessageCache.alloc(DMessage.getSizeofPtr()+ - DMessage.getStringLength(name)+ - DMessage.getStringLength(type)+ - DMessage.getStringLength(v)+ - 3); - dm.setType(DMessage.OutSetVariable); - dm.putPtr(id); - try { dm.putString(name); } catch(UnsupportedEncodingException uee) { dm.putByte((byte)'\0'); } - try { dm.putString(type); } catch(UnsupportedEncodingException uee) { dm.putByte((byte)'\0'); } - try { dm.putString(v); } catch(UnsupportedEncodingException uee) { dm.putByte((byte)'\0'); } - return dm; - } - - /* - * @see flash.tools.debugger.Session#waitForEvent() - */ - public void waitForEvent() throws NotConnectedException, InterruptedException - { - Object eventNotifier = m_manager.getEventNotifier(); - synchronized (eventNotifier) - { - while (getEventCount() == 0 && isConnected()) - { - eventNotifier.wait(); - } - } - - // We should NOT call isConnected() to test for a broken connection! That - // is because we may have received one or more events AND lost the connection, - // almost simultaneously. If there are any messages available for the - // caller to process, we should not throw an exception. - if (getEventCount() == 0 && !isConnected()) - throw new NotConnectedException(); - } - - /* - * @see flash.tools.debugger.Session#getEventCount() - */ - public int getEventCount() - { - return m_manager.getEventCount(); - } - - /* - * @see flash.tools.debugger.Session#nextEvent() - */ - public DebugEvent nextEvent() - { - return m_manager.nextEvent(); - } - - /** - * Adds a watchpoint on the given expression - * @throws NotConnectedException - * @throws NoResponseException - * @throws NotSupportedException - * @throws NotSuspendedException - */ - public boolean addWatch(long varId, String varName, int type, int tag, int isolateId) throws NoResponseException, NotConnectedException, NotSupportedException - { - // TODO check for NoResponse, NotConnected - - if (!supportsWatchpoints(isolateId)) - throw new NotSupportedException(PlayerSessionManager.getLocalizationManager().getLocalizedTextString("watchpointsNotSupported")); //$NON-NLS-1$ - - varName = getRawMemberName(varId, varName, isolateId); - DMessage dm = DMessageCache.alloc(4+DMessage.getSizeofPtr()+DMessage.getStringLength(varName)+1); - dm.setType(DMessage.OutAddWatch2); - dm.setTargetIsolate(isolateId); - dm.putPtr(varId); - try { dm.putString(varName); } catch(UnsupportedEncodingException uee) { dm.putByte((byte)'\0'); } - dm.putWord(type); - dm.putWord(tag); - - int timeout = getPreference(SessionManager.PREF_GETVAR_RESPONSE_TIMEOUT); - boolean result = simpleRequestResponseMessage(dm, DMessage.InWatch2, timeout); - return result; - } - - /** - * Removes a watchpoint on the given expression - * @throws NotConnectedException - * @throws NoResponseException - * @throws NotSuspendedException - */ - public boolean removeWatch(long varId, String memberName, int isolateId) throws NoResponseException, NotConnectedException - { - memberName = getRawMemberName(varId, memberName, isolateId); - DMessage dm = DMessageCache.alloc(DMessage.getSizeofPtr()+DMessage.getStringLength(memberName)+1); - dm.setType(DMessage.OutRemoveWatch2); - dm.putPtr(varId); - try { dm.putString(memberName); } catch(UnsupportedEncodingException uee) { dm.putByte((byte)'\0'); } - - int timeout = getPreference(SessionManager.PREF_GETVAR_RESPONSE_TIMEOUT); - boolean result = simpleRequestResponseMessage(dm, DMessage.InWatch2, timeout); - return result; - } - - /** - * Send a message that contains no data - */ - void sendMessage(int message) - { - DMessage dm = DMessageCache.alloc(0); - dm.setType(message); - sendMessage(dm); - } - - /** - * Send a message that contains no data - */ - void sendMessageIsolate(int message, int isolateId) - { - DMessage dm = DMessageCache.alloc(0); - dm.setTargetIsolate(isolateId); - dm.setType(message); - sendMessage(dm); - } - - /** - * Send a fully formed message and release it when done - */ - synchronized void sendMessage(DMessage dm) - { - try - { - if (dm.getType() != DMessage.OutSetActiveIsolate) { - int isolate = dm.getTargetIsolate(); - if (isolate != getActiveIsolate().getId()) { - DMessage dm1 = DMessageCache.alloc(4); - dm1.setTargetIsolate(isolate); - dm1.setType(DMessage.OutSetActiveIsolate); - dm1.putDWord(isolate); - - /* Use sendMessage here to avoid waiting for a response. - * The assumption is that once the message is sent, subsequent - * messages are for that isolate regardless of the player confirming - * it. With this change, performance has improved considerably; player - * debugger has not gone out of sync since the ProcessTag messages - * flood issue was resolved. */ - sendMessage(dm1); - - m_manager.setActiveIsolate(m_manager.getIsolate(isolate)); - - } - } - m_protocol.txMessage(dm); - - if (m_debugMsgOn || m_debugMsgFileOn) - trace(dm, false); - } - catch(IOException io) - { - if (Trace.error) - { - Trace.trace("Attempt to send message "+dm.outToString()+" failed"); //$NON-NLS-1$ //$NON-NLS-2$ - io.printStackTrace(); - } - } - DMessageCache.free(dm); - } - - /** - * Tell the player to shut-up - */ - boolean sendSquelch(boolean on, int isolateId) - { - boolean responded; - DMessage dm = DMessageCache.alloc(4); - dm.setType(DMessage.OutSetSquelch); - dm.setTargetIsolate(isolateId); - dm.putDWord( on ? 1 : 0); - responded = simpleRequestResponseMessage(dm, DMessage.InSquelch); - return responded; - } - - void sendStopWarning() - { - // Currently, "disable_script_stuck_dialog" only works for AS2, not for AS3. - String option = "disable_script_stuck_dialog"; //$NON-NLS-1$ - String value = "on"; //$NON-NLS-1$ - - sendOptionMessage(option, value); - - // HACK: Completely disable the script-stuck notifications, so that we can - // get AS3 debugging working. - option = "disable_script_stuck"; //$NON-NLS-1$ - value = "on"; //$NON-NLS-1$ - - sendOptionMessage(option, value); - } - - void sendStopOnFault() - { - String option = "break_on_fault"; //$NON-NLS-1$ - String value = "on"; //$NON-NLS-1$ - - sendOptionMessage(option, value); - } - - void sendEnumerateOverride() - { - String option = "enumerate_override"; //$NON-NLS-1$ - String value = "on"; //$NON-NLS-1$ - - sendOptionMessage(option, value); - } - - void sendFailureNotify() - { - String option = "notify_on_failure"; //$NON-NLS-1$ - String value = "on"; //$NON-NLS-1$ - - sendOptionMessage(option, value); - } - - void sendInvokeSetters() - { - String option = "invoke_setters"; //$NON-NLS-1$ - String value = "on"; //$NON-NLS-1$ - - sendOptionMessage(option, value); - } - - void sendSwfloadNotify() - { - String option = "swf_load_messages"; //$NON-NLS-1$ - String value = "on"; //$NON-NLS-1$ - - sendOptionMessage(option, value); - } - - void sendConsoleErrorsAsTrace(boolean on) - { - String option = "console_errors"; //$NON-NLS-1$ - String value = (on) ? "on" : "off"; //$NON-NLS-1$ //$NON-NLS-2$ - - sendOptionMessage(option, value); - } - - void sendGetterTimeout() - { - String option = "getter_timeout"; //$NON-NLS-1$ - String value = "" + getPreference(SessionManager.PREF_GETVAR_RESPONSE_TIMEOUT); //$NON-NLS-1$ - - sendOptionMessage(option, value); - } - - void sendSetterTimeout() - { - String option = "setter_timeout"; //$NON-NLS-1$ - String value = "" + getPreference(SessionManager.PREF_SETVAR_RESPONSE_TIMEOUT); //$NON-NLS-1$ - - sendOptionMessage(option, value); - } - - void sendConcurrentDebugger() - { - String option = "concurrent_debugger"; //$NON-NLS-1$ - String value = "on"; //$NON-NLS-1$ - - sendOptionMessage(option, value); - } - - void sendWideLineDebugger() - { - String option = "wide_line_debugger"; //$NON-NLS-1$ - String value = "on"; //$NON-NLS-1$ - - sendOptionMessage(option, value); - m_manager.setWideLines(true); - } - - void sendOptionMessage(String option, String value) - { - int msgSize = DMessage.getStringLength(option)+DMessage.getStringLength(value)+2; // add 2 for trailing nulls of each string - - DMessage dm = DMessageCache.alloc(msgSize); - dm.setType(DMessage.OutSetOption); - try { dm.putString(option); } catch(UnsupportedEncodingException uee) { dm.putByte((byte)'\0'); } - try { dm.putString(value); } catch(UnsupportedEncodingException uee) { dm.putByte((byte)'\0'); } - simpleRequestResponseMessage(dm, DMessage.InOption); - } - - public boolean supportsWatchpoints() - { - return supportsWatchpoints(Isolate.DEFAULT_ID); - } - - public boolean supportsWatchpoints(int isolateId) - { - if (m_playerSupportsWatchpoints == null) - m_playerSupportsWatchpoints = new Boolean(getOption("can_set_watchpoints", false, isolateId)); //$NON-NLS-1$ - return m_playerSupportsWatchpoints.booleanValue(); - } - - public boolean playerCanBreakOnAllExceptions() - { - return playerCanBreakOnAllExceptions(Isolate.DEFAULT_ID); - } - - public boolean playerCanBreakOnAllExceptions(int isolateId) - { - if (m_playerCanBreakOnAllExceptions == null) - m_playerCanBreakOnAllExceptions = new Boolean(getOption("can_break_on_all_exceptions", false, isolateId)); //$NON-NLS-1$ - return m_playerCanBreakOnAllExceptions.booleanValue(); - } - - public boolean supportsConcurrency(int isolateId) - { - if (m_playerSupportsConcurrency == null) - m_playerSupportsConcurrency = new Boolean(getOption("concurrent_player", false, isolateId)); //$NON-NLS-1$ - return m_playerSupportsConcurrency.booleanValue(); - } - - public boolean supportsConcurrency() - { - return supportsConcurrency(Isolate.DEFAULT_ID); - } - - public boolean supportsWideLineNumbers() - { - return supportsWideLineNumbers(Isolate.DEFAULT_ID); - } - - public boolean supportsWideLineNumbers(int isolateId) - { - if (m_playerSupportsWideLine == null) - m_playerSupportsWideLine = new Boolean(getOption("wide_line_player", false, isolateId)); //$NON-NLS-1$ - return m_playerSupportsWideLine.booleanValue(); - } - - public boolean playerCanTerminate() - { - return getOption("can_terminate", false, Isolate.DEFAULT_ID); //$NON-NLS-1$ - } - - public boolean playerCanCallFunctions() - { - return playerCanCallFunctions(Isolate.DEFAULT_ID); - } - - public boolean playerCanCallFunctions(int isolateId) - { - if (m_playerCanCallFunctions == null) - m_playerCanCallFunctions = new Boolean(getOption("can_call_functions", false, isolateId)); //$NON-NLS-1$ - return m_playerCanCallFunctions.booleanValue(); - } - - /** - * Returns the value of a Flash Player boolean option that was requested by - * OutGetOption and returned by InOption. - * - * @param optionName - * the name of the option - * @return its value, or null - */ - public boolean getOption(String optionName, boolean defaultValue, int isolateId) - { - boolean retval = defaultValue; - String optionValue = getOption(optionName, null, isolateId); - - if (optionValue != null) - retval = Boolean.valueOf(optionValue).booleanValue(); - - return retval; - } - - /** - * Returns the value of a Flash Player string option that was requested by - * OutGetOption and returned by InOption. - * - * @param optionName - * the name of the option - * @return its value, or null - */ - public String getOption(String optionName, String defaultValue, int isolateId) - { - String optionValue = defaultValue; - - int msgSize = DMessage.getStringLength(optionName)+1; // add 1 for trailing null of string - - DMessage dm = DMessageCache.alloc(msgSize); - dm.setTargetIsolate(isolateId); - dm.setType(DMessage.OutGetOption); - try { dm.putString(optionName); } catch(UnsupportedEncodingException uee) { dm.putByte((byte)'\0'); } - if (simpleRequestResponseMessage(dm, DMessage.InOption)) - optionValue = m_manager.getOption(optionName); - return optionValue; - } - - long getMessageInCount(DMessageCounter counter, long isolate, int msgType) { - if (isolate == Isolate.DEFAULT_ID) { - return counter.getInCount(msgType); - } - else { - return counter.getIsolateInCount(isolate, msgType); - } - } - - Object getMessageInLock(DMessageCounter counter, long isolate) { - if (isolate == Isolate.DEFAULT_ID) { - return counter.getInLock(); - } - else { - return counter.getIsolateInLock(isolate); - } - } - - /** - * Send our message and assume that the next response that is received is - * ours. Primitive but there is no use in setting up a full request / response - * pattern since the player doesn't follow it. - * - * @return false is no response. - */ - boolean simpleRequestResponseMessage(DMessage msg, int msgType, int timeout) - { - boolean response = false; - - //FIXME: Check if timeout needs to adjust to the isolate switching - // delay - // use default or user supplied timeout - timeout = (timeout > 0) ? timeout : getPreference(SessionManager.PREF_RESPONSE_TIMEOUT); - - // note the number of messages of this type before our send - DMessageCounter msgCounter = getMessageCounter(); - int isolate = msg.getTargetIsolate(); - long num = getMessageInCount(msgCounter, isolate, msgType); - long expect = num+1; - - // send the message - sendMessage(msg); - - long startTime = System.currentTimeMillis(); -// System.out.println("sending- "+DMessage.outTypeName(msg.getType())+",timeout="+timeout+",start="+start); - - // now wait till we see a message come in - m_incoming = false; - synchronized (getMessageInLock(msgCounter, isolate)) - { - while( (expect > getMessageInCount(msgCounter, isolate, msgType)) && - System.currentTimeMillis() < startTime + timeout && - isConnected()) - { - // block until the message counter tells us that some message has been received - try - { - getMessageInLock(msgCounter, isolate).wait(timeout); - } - catch (InterruptedException e) - { - // this should never happen - e.printStackTrace(); - //FIXME: Will resetting the interrupted status here - //cause any problems? -// Thread.currentThread().interrupt(); - } - - // if we see incoming messages, then we should reset our timeout - synchronized (this) - { - if (m_incoming) - { - startTime = System.currentTimeMillis(); - m_incoming = false; - } - } - } - } - - if (getMessageInCount(msgCounter, isolate, msgType) >= expect) - response = true; - else if (timeout <= 0 && Trace.error) - Trace.trace("Timed-out waiting for "+DMessage.inTypeName(msgType)+" response to message "+msg.outToString()); //$NON-NLS-1$ //$NON-NLS-2$ - -// long endTime = System.currentTimeMillis(); -// System.out.println(" response- "+response+",timeout="+timeout+",elapsed="+(endTime-startTime)); - m_lastResponse = response; - return response; - } - - // use default timeout - boolean simpleRequestResponseMessage(DMessage msg, int msgType) { return simpleRequestResponseMessage(msg, msgType, -1); } - - boolean simpleRequestResponseMessageIsolate(DMessage msg, int msgType, int isolateId) { - return simpleRequestResponseMessageIsolate(msg, msgType, -1, isolateId); - } - - boolean simpleRequestResponseMessageIsolate(DMessage msg, int msgType, int timeout, int isolateId) - { - msg.setTargetIsolate(isolateId); - return simpleRequestResponseMessage(msg, msgType, timeout); - } - - boolean simpleRequestResponseMessage(int msg, int msgType) { return simpleRequestResponseMessage(msg, msgType, -1); } - - boolean simpleRequestResponseMessageIsolate(int msg, int msgType, int isolateId) { - return simpleRequestResponseMessageIsolate(msg, msgType, -1, isolateId); - } - - boolean simpleRequestResponseMessageIsolate(int msg, int msgType, int timeout, int isolateId) - { - DMessage dm = DMessageCache.alloc(0); - dm.setType(msg); - dm.setTargetIsolate(isolateId); - return simpleRequestResponseMessage(dm, msgType, timeout); - } - - // Convenience function - boolean simpleRequestResponseMessage(int msg, int msgType, int timeout) - { - DMessage dm = DMessageCache.alloc(0); - dm.setType(msg); - return simpleRequestResponseMessage(dm, msgType, timeout); - } - - /** - * We register ourself as a listener to DMessages from the pipe for the - * sole purpose of monitoring the state of the debugger. All other - * object management occurs with DManager - */ - /** - * Issued when the socket connection to the player is cut - */ - public void disconnected() - { - m_isHalted = false; - m_isConnected = false; - m_manager.disconnected(); - } - - /** - * This is the core routine for decoding incoming messages and deciding what should be - * done with them. We have registered ourself with DProtocol to be notified when any - * incoming messages have been received. - * - * It is important to note that we should not rely on the contents of the message - * since it may be reused after we exit this method. - */ - public void messageArrived(DMessage msg, DProtocol which) - { - preMessageArrived(msg, which); - msg.reset(); // allow the message to be re-parsed - m_manager.messageArrived(msg, which); - msg.reset(); // allow the message to be re-parsed - postMessageArrived(msg, which); - } - - /** - * Processes the message before it is passed to the DManager. - */ - private void preMessageArrived(DMessage msg, DProtocol which) - { - switch (msg.getType()) - { - case DMessage.InIsolate: - - m_lastPreIsolate = (int)msg.getDWord(); - - break; - - case DMessage.InAskBreakpoints: - case DMessage.InBreakAt: - case DMessage.InBreakAtExt: - { - // We need to set m_isHalted to true before the DManager processes - // the message, because the DManager may add a BreakEvent to the - // event queue, which the host debugger may immediately process; - // if the debugger calls back to the Session, the Session must be - // correctly marked as halted. - if (m_lastPreIsolate == Isolate.DEFAULT_ID) - m_isHalted = true; - else - updateHaltIsolateStatus(m_lastPreIsolate, true); - break; - } - } - } - - /** - * Processes the message after it has been passed to the DManager. - */ - private void postMessageArrived(DMessage msg, DProtocol which) - { - if (m_debugMsgOn || m_debugMsgFileOn) - trace(msg, true); - - /* at this point we just open up a big switch statement and walk through all possible cases */ - int type = msg.getType(); - switch(type) - { - case DMessage.InExit: - { - m_isConnected = false; - break; - } - - case DMessage.InProcessTag: - { - // need to send a response to this message to keep the player going - sendMessageIsolate(DMessage.OutProcessedTag, msg.getTargetIsolate()); - break; - } - - case DMessage.InContinue: - { - if (msg.getTargetIsolate() == Isolate.DEFAULT_ID) - m_isHalted = false; - else { - updateHaltIsolateStatus(msg.getTargetIsolate(), false); - } - break; - } - - case DMessage.InOption: - { - //workers inherit options, so only store options - //from main thread. - if (msg.getTargetIsolate() == Isolate.DEFAULT_ID) { - String s = msg.getString(); - String v = msg.getString(); - - // add it to our properties, for DEBUG purposes only - m_prefs.put(s, v); - } - break; - } - - case DMessage.InSwfInfo: - case DMessage.InScript: - case DMessage.InRemoveScript: - { - //FIXME: Clear this cache only for affected - //workers. Right now, the key contains worker - //id, so we are safe. But we unnecessarily flush - //the queue. - m_evalIsAndInstanceofCache.clear(); - - m_incoming = true; - break; - } - - default: - { - /** - * Simple indicator that we have received a message. We - * put this indicator in default so that InProcessTag msgs - * wouldn't generate false triggers. Mainly, we want to - * reset our timeout counter when we receive trace messages. - */ - m_incoming = true; - break; - } - } - - // something came in so assume that we can now talk - // to the player - m_lastResponse = true; - } - - private void updateHaltIsolateStatus(int targetIsolate, boolean value) { - if (!m_isolateStatus.containsKey(targetIsolate)) { - PlayerSessionIsolateStatus status = new PlayerSessionIsolateStatus(); - status.m_isHalted = value; - m_isolateStatus.put(targetIsolate, status); - } - else { - m_isolateStatus.get(targetIsolate).m_isHalted = value; - } - } - - /** - * A background thread which wakes up periodically and fetches the SWF and SWD - * from the Player for new movies that have loaded. It then uses these to create - * an instance of MovieMetaData (a class shared with the Profiler) from which - * fdb can cull function names. - * This work is done on a background thread because it can take several - * seconds, and we want the fdb user to be able to execute other commands - * while it is happening. - */ - public void run() - { - long last = 0; - while(isConnected()) - { - // try every 250ms - try { Thread.sleep(250); } catch(InterruptedException ie) {} - - try - { - // let's make sure that the traffic level is low before - // we do our requests. - long current = m_protocol.messagesReceived(); - long delta = last - current; - last = current; - - // if the last message that went out was not responded to - // or we are not suspended and have high traffic - // then wait for later. - if (!m_lastResponse || (!isSuspended() && delta > 5)) - throw new NotSuspendedException(); - - // we are either suspended or low enough traffic - - // get the list of swfs we have - for (Isolate isolate : m_manager.getIsolates()) { - int isolateId = isolate.getId(); - if (isolateId != Isolate.DEFAULT_ID && !isWorkerSuspended(isolateId) && delta > 5) { - throw new NotSuspendedException(); - } - int count = m_manager.getSwfInfoCount(isolateId); - for(int i=0; i<count; i++) - { - DSwfInfo info = m_manager.getSwfInfo(i, isolateId); - - // no need to process if it's been removed - if (info == null || info.isUnloaded() || info.isPopulated() || (info.getVmVersion() > 0) ) - continue; - - // see if the swd has been loaded, throws exception if unable to load it. - // Also triggers a callback into the info object to freshen its contents - // if successful - //FIXME: remove sysout - info.getSwdSize(this); - // check since our vm version info could get updated in between. - if (info.getVmVersion() > 0) - { - // mark it populated if we haven't already done so - info.setPopulated(); - continue; - } - - // so by this point we know that we've got good swd data, - // or we've made too many attempts and gave up. - if (!info.isSwdLoading() && !info.isUnloaded()) - { - // now load the swf, if we haven't already got it - if (info.getSwf() == null && !info.isUnloaded()) - info.setSwf(requestSwf(i)); - - // only get the swd if we haven't got it - if (info.getSwd() == null && !info.isUnloaded()) - info.setSwd(requestSwd(i)); - - try - { - // now go populate the functions tables... - if (!info.isUnloaded()) - info.parseSwfSwd(m_manager); - } - catch(Throwable e) - { - // oh this is not good and means that we should probably - // give up. - if (Trace.error) - { - Trace.trace("Error while parsing swf/swd '"+info.getUrl()+"'. Giving up and marking it processed"); //$NON-NLS-1$ //$NON-NLS-2$ - e.printStackTrace(); - } - - info.setPopulated(); - } - } - } - } - } - catch(InProgressException ipe) - { - // swd is still loading so give us a bit of - // time and then come back and try again - } - catch(NoResponseException nre) - { - // timed out on one of our requests so don't bother - // continuing right now, try again later - } - catch(NotSuspendedException nse) - { - // probably want to wait until we are halted before - // doing this heavy action - } - catch(Exception e) - { - // maybe not good - if (Trace.error) - { - Trace.trace("Exception in background swf/swd processing thread"); //$NON-NLS-1$ - e.printStackTrace(); - } - } - } - } - - byte[] requestSwf(int index) throws NoResponseException - { - /* send the message */ - int to = getPreference(SessionManager.PREF_SWFSWD_LOAD_TIMEOUT); - byte[] swf = null; - - // the query - DMessage dm = DMessageCache.alloc(2); - dm.setType(DMessage.OutGetSwf); - dm.putWord(index); - - if (simpleRequestResponseMessage(dm, DMessage.InGetSwf, to)) - swf = m_manager.getSWF(); - else - throw new NoResponseException(to); - - return swf; - } - - byte[] requestSwd(int index) throws NoResponseException - { - /* send the message */ - int to = getPreference(SessionManager.PREF_SWFSWD_LOAD_TIMEOUT); - byte[] swd = null; - - // the query - DMessage dm = DMessageCache.alloc(2); - dm.setType(DMessage.OutGetSwd); - dm.putWord(index); - - if (simpleRequestResponseMessage(dm, DMessage.InGetSwd, to)) - swd = m_manager.getSWD(); - else - throw new NoResponseException(to); - - return swd; - } - - // - // Debug purposes only. Dump contents of our messages to the screen - // and/or file. - // - synchronized void trace(DMessage dm, boolean in) - { - try - { - if (m_debugMsgOn) { - System.out.println( (in) ? dm.inToString(m_debugMsgSize) : dm.outToString(m_debugMsgSize) ); - } - - if (m_debugMsgFileOn) - { - traceFile().write( (in) ? dm.inToString(m_debugMsgFileSize) : dm.outToString(m_debugMsgFileSize) ); - m_trace.write(s_newline); - m_trace.flush(); - } - } - catch(Exception e) {} - } - - // i/o for tracing - java.io.Writer m_trace; - - - java.io.Writer traceFile() throws IOException - { - if (m_trace == null) - { - m_trace = new java.io.FileWriter("mm_debug_api_trace.txt"); //$NON-NLS-1$ - try { m_trace.write(new java.util.Date().toString()); } catch(Exception e) { m_trace.write("Date unknown"); } //$NON-NLS-1$ - try - { - m_trace.write(s_newline); - - // java properties dump - java.util.Properties props = System.getProperties(); - props.list(new java.io.PrintWriter(m_trace)); - - m_trace.write(s_newline); - - // property dump - for (String key: m_prefs.keySet()) - { - Object value = m_prefs.get(key); - m_trace.write(key); - m_trace.write(" = "); //$NON-NLS-1$ - m_trace.write(value.toString()); - m_trace.write(s_newline); - } - } - catch(Exception e) { if (Trace.error) e.printStackTrace(); } - m_trace.write(s_newline); - } - return m_trace; - } - - public void setLaunchUrl(String url) - { - if (url.startsWith("/")) { //$NON-NLS-1$ - url = "file://" + url; //$NON-NLS-1$ - } - m_launchUrl = url; - } - - public void setAIRLaunchInfo(AIRLaunchInfo airLaunchInfo) - { - m_airLaunchInfo = airLaunchInfo; - } - - public void breakOnCaughtExceptions(boolean b) throws NotSupportedException, NoResponseException { - breakOnCaughtExceptions(b, Isolate.DEFAULT_ID); - } - - public void breakOnCaughtExceptions(boolean b, int isolateId) throws NotSupportedException, NoResponseException { - if (!playerCanBreakOnAllExceptions(isolateId)) - throw new NotSupportedException(PlayerSessionManager.getLocalizationManager().getLocalizedTextString("exceptionBreakpointsNotSupported")); //$NON-NLS-1$ - - DMessage dm = DMessageCache.alloc(1); - dm.setType(DMessage.OutPassAllExceptionsToDebugger); - dm.putByte((byte)(b ? 1 : 0)); - dm.setTargetIsolate(isolateId); - /* TODO: Verify that sendMessage below is a bug */ -// sendMessage(dm); - if (!simpleRequestResponseMessage(dm, DMessage.InPassAllExceptionsToDebugger)) - throw new NoResponseException(getPreference(SessionManager.PREF_RESPONSE_TIMEOUT)); - } - - - public boolean evalIs(Value value, Value type) throws PlayerDebugException, PlayerFaultException - { - return evalIsOrInstanceof(BinaryOp.Is, value, type, Isolate.DEFAULT_ID); - } - - public boolean evalIs(Value value, String type) throws PlayerDebugException, PlayerFaultException - { - return evalIsOrInstanceof(BinaryOp.Is, value, type, Isolate.DEFAULT_ID); - } - - public boolean evalInstanceof(Value value, Value type) throws PlayerDebugException, PlayerFaultException - { - return evalIsOrInstanceof(BinaryOp.Instanceof, value, type, Isolate.DEFAULT_ID); - } - - public boolean evalInstanceof(Value value, String type) throws PlayerDebugException, PlayerFaultException - { - return evalIsOrInstanceof(BinaryOp.Instanceof, value, type, Isolate.DEFAULT_ID); - } - - // isolate version - - public boolean evalIsWorker(Value value, Value type, int isolateId) throws PlayerDebugException, PlayerFaultException - { - return evalIsOrInstanceof(BinaryOp.Is, value, type, isolateId); - } - - public boolean evalIsWorker(Value value, String type, int isolateId) throws PlayerDebugException, PlayerFaultException - { - return evalIsOrInstanceof(BinaryOp.Is, value, type, isolateId); - } - - public boolean evalInstanceofWorker(Value value, Value type, int isolateId) throws PlayerDebugException, PlayerFaultException - { - return evalIsOrInstanceof(BinaryOp.Instanceof, value, type, isolateId); - } - - public boolean evalInstanceofWorker(Value value, String type, int isolateId) throws PlayerDebugException, PlayerFaultException - { - return evalIsOrInstanceof(BinaryOp.Instanceof, value, type, isolateId); - } - - private boolean evalIsOrInstanceof(BinaryOp op, Value value, Value type, int isolateId) throws PlayerDebugException, PlayerFaultException - { - String key = value.getTypeName() + " " + op + " " + type.getTypeName() + " " + String.valueOf(isolateId); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - Boolean retval = m_evalIsAndInstanceofCache.get(key); - if (retval == null) - { - retval = new Boolean(ECMA.toBoolean(evalBinaryOp(op, value, type, isolateId))); - m_evalIsAndInstanceofCache.put(key, retval); - } - - return retval.booleanValue(); - } - - private boolean evalIsOrInstanceof(BinaryOp op, Value value, String type, int isolateId) throws PlayerDebugException, PlayerFaultException - { - String key = value.getTypeName() + " " + op + " " + type + " " + String.valueOf(isolateId); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - Boolean retval = m_evalIsAndInstanceofCache.get(key); - if (retval == null) - { - Value typeval = getGlobalWorker(type, isolateId); - if (typeval == null) - retval = Boolean.FALSE; - else - retval = new
<TRUNCATED>