Package flash.tools.debugger.concrete

Source Code of flash.tools.debugger.concrete.DManager

/*
* 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.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import flash.tools.debugger.Isolate;
import flash.tools.debugger.SourceLocator;
import flash.tools.debugger.SuspendReason;
import flash.tools.debugger.SwfInfo;
import flash.tools.debugger.Value;
import flash.tools.debugger.VariableAttribute;
import flash.tools.debugger.VariableType;
import flash.tools.debugger.events.BreakEvent;
import flash.tools.debugger.events.ConsoleErrorFault;
import flash.tools.debugger.events.DebugEvent;
import flash.tools.debugger.events.DivideByZeroFault;
import flash.tools.debugger.events.ExceptionFault;
import flash.tools.debugger.events.FaultEvent;
import flash.tools.debugger.events.FileListModifiedEvent;
import flash.tools.debugger.events.InvalidWithFault;
import flash.tools.debugger.events.IsolateCreateEvent;
import flash.tools.debugger.events.IsolateExitEvent;
import flash.tools.debugger.events.ProtoLimitFault;
import flash.tools.debugger.events.RecursionLimitFault;
import flash.tools.debugger.events.ScriptTimeoutFault;
import flash.tools.debugger.events.StackUnderFlowFault;
import flash.tools.debugger.events.SwfLoadedEvent;
import flash.tools.debugger.events.SwfUnloadedEvent;
import flash.tools.debugger.events.TraceEvent;
import flash.util.Trace;

/**
* Implements the receiving and updating of debug state from the socket
* connection of the Flash Player.
*/
public class DManager implements DProtocolNotifierIF, SourceLocator {
  private final HashMap<String, String> m_parms;

  private final HashMap<Integer, DIsolate> m_isolates; /*
                             * WARNING: accessed
                             * from multiple threads
                             */

  /**
   * The currently active isolate or worker
   */
  private Isolate m_activeIsolate = DEFAULT_ISOLATE;

  private LinkedList<DebugEvent> m_event; /*
                       * our event queue; WARNING:
                       * accessed from multiple threads
                       */
  private SourceLocator m_sourceLocator;


  private boolean m_squelchEnabled; /*
                   * true if we are talking to a squelch
                   * enabled debug player
                   */
  private int m_playerVersion; /*
                 * player version number obtained from InVersion
                 * message; e.g. 9 for Flash Player 9.0
                 */

  private boolean m_sourceListModified; /*
                     * deprecated; indicates m_source has
                     * changed since last call to
                     * getSource(). WARNING: lock with
                     * synchronized (m_source) { ... }
                     */
  private byte[] m_actions; /* deprecated */
  private String[] m_lastConstantPool; /* deprecated */

  // SWF/SWD fetching and parsing
  private String m_uri;
  private byte[] m_swf; // latest swf obtained from get swf
  private byte[] m_swd; // latest swd obtained from get swd

  private Map<String, String> m_options = new HashMap<String, String>(); // Player
                                      // options
                                      // that
                                      // have
                                      // been
                                      // queried
                                      // by
                                      // OutGetOption,
                                      // and
                                      // come
                                      // back
                                      // via
                                      // InOption

  public static final String ARGUMENTS_MARKER = "$arguments"; //$NON-NLS-1$
  public static final String SCOPE_CHAIN_MARKER = "$scopechain"; //$NON-NLS-1$
 
  private static final DIsolate DEFAULT_ISOLATE = DIsolate.DEFAULT_ISOLATE;
  private Isolate m_inIsolate = DEFAULT_ISOLATE;
  private final Object m_inIsolateLock;
  private final Object m_activeIsolateLock;
  private boolean m_wideLines;
  private DManagerIsolateState m_mainState;
  private HashMap<Integer, DManagerIsolateState> m_isolateState;


  class DManagerIsolateState {
    public DSuspendInfo m_suspendInfo;
    public DSwfInfo m_lastSwfInfo; /*
                     * hack for syncing swfinfo records with
                     * incoming InScript messages
                     */
    public DVariable m_lastInGetVariable;/*
                       * hack for getVariable call to work
                       * with getters
                       */
    public boolean m_attachChildren; /*
                     * hack for getVariable call to work
                     * with getters
                     */
    public DVariable m_lastInCallFunction; /* hack for callFunction to work */
    public DVariable m_lastInBinaryOp;
    private boolean m_executingPlayerCode;
    private FaultEvent m_faultEventDuringPlayerCodeExecution;

    public final ArrayList<DLocation> m_breakpoints; /*
                             * WARNING: accessed
                             * from multiple threads
                             */
    public final Map<Integer, DModule> m_source; /*
                           * WARNING: accessed from
                           * multiple threads
                           */
    private final ArrayList<DSwfInfo> m_swfInfo; /*
                           * WARNING: accessed from
                           * multiple threads
                           */
    private final ArrayList<DWatch> m_watchpoints; /*
                             * WARNING: accessed
                             * from multiple threads
                             */

    /**
     * The currently active stack frames.
     */
    public ArrayList<DStackContext> m_frames;

    /**
     * The stack frames that were active the last time the player was
     * suspended.
     */
    public ArrayList<DStackContext> m_previousFrames;

    /**
     * A list of all known variables in the player. Stored as a mapping from
     * an object's id to its DValue.
     */
    public Map<Long, DValue> m_values;

    /**
     * A list of all known variables in the player from the previous time
     * the player was suspended. Stored as a mapping from an object's id to
     * its DValue.
     */
    public Map<Long, DValue> m_previousValues;

    public DManagerIsolateState() {
      m_source = new HashMap<Integer, DModule>();
      m_values = new HashMap<Long, DValue>();
      m_previousValues = new HashMap<Long, DValue>();
      m_frames = new ArrayList<DStackContext>();
      m_previousFrames = new ArrayList<DStackContext>();
      m_suspendInfo = null;
      m_lastInCallFunction = null;
      m_breakpoints = new ArrayList<DLocation>();
      m_swfInfo = new ArrayList<DSwfInfo>();
      m_watchpoints = new ArrayList<DWatch>();
      m_suspendInfo = null;
      m_lastInGetVariable = null;
      m_attachChildren = true;
      m_lastInCallFunction = null;

    }
  }

  private DManagerIsolateState getIsolateState(int isolateId) {
    if (isolateId == Isolate.DEFAULT_ID)
      return m_mainState;
   
    DManagerIsolateState isolateState = null;
    if (!m_isolateState.containsKey(isolateId)) {
      isolateState = new DManagerIsolateState();
      m_isolateState.put(isolateId, isolateState);
    } else
      isolateState = m_isolateState.get(isolateId);
    return isolateState;
  }

  public DManager() {
    m_parms = new HashMap<String, String>();
   
    m_isolates = new HashMap<Integer, DIsolate>();
    m_isolates.put(Isolate.DEFAULT_ID, DEFAULT_ISOLATE);
    m_event = new LinkedList<DebugEvent>();
    m_sourceLocator = null;
    m_squelchEnabled = false;
    m_lastConstantPool = null;
    m_playerVersion = -1; // -1 => unknown
    m_isolateState = new HashMap<Integer, DManagerIsolateState>();
    m_mainState = new DManagerIsolateState();
    m_isolateState.put(Isolate.DEFAULT_ID, m_mainState);
    m_inIsolateLock = new Object();
    m_activeIsolateLock = new Object();
    m_wideLines = false;
  }

  public void setWideLines(boolean value) {
    m_wideLines = value;
  }
 
  public String getURI() {
    return m_uri;
  }

  public byte[] getSWF() {
    return m_swf;
  }

  public byte[] getSWD() {
    return m_swd;
  }

  public byte[] getActions() {
    return m_actions;
  }

  /** Returns the Flash Player version number; e.g. 9 for Flash Player 9.0 */
  public int getVersion() {
    return m_playerVersion;
  }

  public SourceLocator getSourceLocator() {
    return m_sourceLocator;
  }

  public void setSourceLocator(SourceLocator sl) {
    m_sourceLocator = sl;
  }

  /**
   * If this feature is enabled then we do not attempt to attach child
   * variables to parents.
   */
  public void enableChildAttach(boolean enable, int isolateId) {
    getIsolateState(isolateId).m_attachChildren = enable;
  }

  // return/clear the last variable seen from an InGetVariable message
  public DVariable lastVariable(int isolateId) {
    return getIsolateState(isolateId).m_lastInGetVariable;
  }

  public void clearLastVariable(int isolateId) {
    getIsolateState(isolateId).m_lastInGetVariable = null;
  }

  // return/clear the last variable seen from an InCallFunction message
  public DVariable lastFunctionCall(int isolateId) {
    return getIsolateState(isolateId).m_lastInCallFunction;
  }

  public void clearLastFunctionCall(int isolateId) {
    getIsolateState(isolateId).m_lastInCallFunction = null;
  }

  // return/clear the last binary op result seen from an InBinaryOp message
  public DVariable lastBinaryOp(int isolateId) {
    return getIsolateState(isolateId).m_lastInBinaryOp;
  }

  public void clearLastBinaryOp(int isolateId) {
    getIsolateState(isolateId).m_lastInBinaryOp = null;
  }

  /*
   * Frees up any information we have kept about
   */
  void freeCaches(int isolateId) {
    clearFrames(isolateId);
    freeValueCache(isolateId);
  }

  void freeValueCache(int isolateId) {
    DManagerIsolateState state = getIsolateState(isolateId);
    state.m_previousValues = state.m_values;
    state.m_values = new HashMap<Long, DValue>();

    int size = getFrameCount(isolateId);
    for (int i = 0; i < size; i++)
      getFrame(i, isolateId).markStale();
  }

  // continuing our execution
  void continuing(int isolateId) {
    freeCaches(isolateId);
    getIsolateState(isolateId).m_suspendInfo = null;
  }

  /**
   * Variables
   */
  DValue getOrCreateValue(long id, int isolateId) {
    DValue v = getValue(id, isolateId);
    if (v == null) {
      v = new DValue(id, isolateId);
      putValue(id, v, isolateId);
    }
    return v;
  }

  public DSwfInfo[] getSwfInfos(int isolateId) {
    ArrayList<DSwfInfo> swfInfos = getIsolateState(isolateId).m_swfInfo;
    synchronized (swfInfos) {
      return swfInfos.toArray(new DSwfInfo[swfInfos.size()]);
    }
  }

  public DSwfInfo getSwfInfo(int at, int isolateId) {
    ArrayList<DSwfInfo> swfInfos = getIsolateState(isolateId).m_swfInfo;
    synchronized (swfInfos) {
      return swfInfos.get(at);
    }
  }

  public int getSwfInfoCount(int isolateId) {
    ArrayList<DSwfInfo> swfInfos = getIsolateState(isolateId).m_swfInfo;
    synchronized (swfInfos) {
      return swfInfos.size();
    }
  }

  /**
   * Obtains a SwfInfo object at the given index or if one doesn't yet exist
   * at that location, creates a new empty one there and returns it.
   */
  DSwfInfo getOrCreateSwfInfo(int at, int isolateId) {
    ArrayList<DSwfInfo> swfInfos = getIsolateState(isolateId).m_swfInfo;
    synchronized (swfInfos) {
      DSwfInfo i = (at > -1 && at < getSwfInfoCount(isolateId)) ? getSwfInfo(
          at, isolateId) : null;
      if (i == null) {
        // are we above water
        at = (at < 0) ? 0 : at;

        // fill all the gaps with null; really shouldn't be any...
        while (at >= swfInfos.size())
          swfInfos.add(null);

        i = new DSwfInfo(at, isolateId);
        swfInfos.set(at, i);
      }
      return i;
    }
  }

  /**
   * Get the most recently active swfInfo object. We define active as the most
   * recently seen swfInfo
   */
  DSwfInfo getActiveSwfInfo(int isolateId) {
    int count = getSwfInfoCount(isolateId);

    // pick up the last one seen
    DSwfInfo swf = getIsolateState(isolateId).m_lastSwfInfo;

    // still don't have one then get or create the most recent one
    // works if count = 0
    if (swf == null)
      swf = getOrCreateSwfInfo(count - 1, isolateId);

    if (swf.hasAllSource()) {
      // already full so create a new one on the end
      swf = getOrCreateSwfInfo(count, isolateId);
    }
    return swf;
  }

  /**
   * Walk the list of scripts and add them to our swfInfo object This method
   * may be called when min/max are zero and the swd has not yet fully loaded
   * in the player or it could be called before we have all the scripts.
   */
  void tieScriptsToSwf(DSwfInfo info, int isolateId) {
    if (!info.hasAllSource()) {
      int min = info.getFirstSourceId();
      int max = info.getLastSourceId();
      // System.out.println("attaching scripts "+min+"-"+max+" to "+info.getUrl());
      for (int i = min; i <= max; i++) {
        DModule m = getSource(i, isolateId);
        if (m == null) {
          // this is ok, it means the scripts are coming...
        } else {
          info.addSource(i, m);
        }
      }
    }
  }

  /**
   * Record a new source file.
   *
   * @param name
   *            filename in "basepath;package;filename" format
   * @param swfIndex
   *            the index of the SWF with which this source is associated, or
   *            -1 is we don't know
   * @return true if our list of source files was modified, or false if we
   *         already knew about that particular source file.
   */
  private boolean putSource(int swfIndex, int moduleId, int bitmap,
      String name, String text, int isolateId) {
    // if isolateIndex is not -1, augment swfIndex and moduleId with isolate
    // info.
    Map<Integer, DModule> source = getIsolateState(isolateId).m_source;
    synchronized (source) {
      // if we haven't already recorded this script then do so.
      if (!source.containsKey(moduleId)) {
        DModule s = new DModule(this, moduleId, bitmap, name, text, isolateId);

        // put source in our large pool
        source.put(moduleId, s);

        // put the source in the currently active swf
        DSwfInfo swf;
        if (swfIndex == -1) // caller didn't tell us what swf thi is for
          swf = getActiveSwfInfo(isolateId); // ... so guess
        else
          swf = getOrCreateSwfInfo(swfIndex, isolateId);

        swf.addSource(moduleId, s);

        return true;
      }

      return false;
    }
  }

  /**
   * Remove our record of a particular source file.
   *
   * @param id
   *            the id of the file to forget about.
   * @return true if source file was removed; false if we didn't know about it
   *         to begin with.
   */
  private boolean removeSource(int id, int isolateId) {
    Map<Integer, DModule> source = getIsolateState(isolateId).m_source;
    synchronized (source) {
      try {
        source.remove(id);
      } catch (Exception e) {
        return false;
      }
      return true;
    }
  }

  public DModule getSource(int id, int isolateId) {
    Map<Integer, DModule> source = getIsolateState(isolateId).m_source;
    synchronized (source) {
      return source.get(id);
    }
  }

  // @deprecated
  public DModule[] getSources() {
    Map<Integer, DModule> source = getIsolateState(Isolate.DEFAULT_ID).m_source;
    synchronized (source) {
      m_sourceListModified = false;

      /* find out the size of the array */
      int count = source.size();
      DModule[] ar = new DModule[count];

      count = 0;
      for (DModule sf : source.values())
        ar[count++] = sf;
      return ar;
    }
  }

  // @deprecated
  boolean sourceListModified() {
    Map<Integer, DModule> source = getIsolateState(Isolate.DEFAULT_ID).m_source;
    synchronized (source) {
      return m_sourceListModified;
    }
  }

  public DValue getValue(long id, int isolateId) {
    return getIsolateState(isolateId).m_values.get(id);
  }

  /**
   * 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 DValue getPreviousValue(long id, int isolateId) {
    return getIsolateState(isolateId).m_previousValues.get(id);
  }

  void putValue(long id, DValue v, int isolateId) {
    if (id != Value.UNKNOWN_ID) {
      getIsolateState(isolateId).m_values.put(id, v);
    }
  }

  DValue removeValue(long id, int isolateId) {
    return getIsolateState(isolateId).m_values.remove((int)id);
  }

  void addVariableMember(long parentId, DVariable child, int isolateId) {
    DValue parent = getValue(parentId, isolateId);
    addVariableMember(parent, child, isolateId);
  }

  void addVariableMember(DValue parent, DVariable child, int isolateId) {
    if (getIsolateState(isolateId).m_attachChildren) {
      // There are certain situations when the Flash player will send us
      // more
      // than one variable or getter with the same name. Basically, when a
      // subclass implements (or overrides) something that was also
      // declared in a
      // superclass, then we'll see that variable or getter in both the
      // superclass and the subclass.
      //
      // Here are a few situations where that affects the debugger in
      // different
      // ways:
      //
      // 1. When a class implements an interface, the class instance
      // actually has
      // *two* members for each implemented function: One which is public
      // and
      // represents the implementation function, and another which is
      // internal
      // to the interface, and represents the declaration of the function.
      // Both of these come in to us. In the UI, the one we want to show
      // is
      // the public one. They come in in random order (they are stored in
      // a
      // hash table in the VM), so we don't know which one will come
      // first.
      //
      // 2. When a superclass has a private member "m", and a subclass has
      // its own
      // private member with the same name "m", we will receive both of
      // them.
      // (They are scoped by different packages.) In this case, the first
      // one
      // the player sent us is the one from the subclass, and that is the
      // one
      // we want to display in the debugger.
      //
      // The following logic correctly deals with all variations of those
      // cases.
      if (parent != null) {
        DVariable existingChildWithSameName = parent.findMember(child
            .getName());
        if (existingChildWithSameName != null) {
          int existingScope = existingChildWithSameName.getScope();
          int newScope = child.getScope();

          if (existingScope == VariableAttribute.NAMESPACE_SCOPE
              && newScope == VariableAttribute.PUBLIC_SCOPE) {
            // This is the case described above where a class
            // implements an interface,
            // so that class's definition includes both a
            // namespace-scoped declaration
            // and a public declaration, in random order; in this
            // case, the
            // namespace-scoped declaration came first. We want to
            // use the public
            // declaration.
            parent.addMember(child);
          } else if (existingScope == VariableAttribute.PUBLIC_SCOPE
              && newScope == VariableAttribute.NAMESPACE_SCOPE) {
            // One of two things happened here:
            //
            // 1. This is the case described above where a class
            // implements an interface,
            // so that class's definition includes both a
            // namespace-scoped declaration
            // and a public declaration, in random order; in this
            // case, the
            // public declaration came first. It is tempting to use
            // the public
            // member in this case, but there is a catch...
            // 2. It might be more complicated than that: Perhaps
            // there is interface I,
            // and class C1 implements I, but class C2 extends C1,
            // and overrides
            // one of the members of I that was already implemented
            // by C1. In this
            // case, the public declaration from C2 came first, but
            // now we are seeing
            // a namespace-scoped declaration in C1. We need to
            // record that the
            // member is public, but we also need to record that it
            // is a member
            // of the base class, not just a member of the
            // superclass.
            //
            // The easiest way to deal with both cases is to use the
            // child that came from
            // the superclass, but to change its scope to public.
            child.makePublic();
            parent.addMember(child);
          } else if (existingScope != VariableAttribute.PRIVATE_SCOPE
              && existingScope == newScope) {
            // This is a public, protected, internal, or
            // namespace-scoped member which
            // was defined in a base class and overridden in a
            // subclass. We want to
            // use the member from the base class, to that the
            // debugger knows where the
            // variable was actually defined.
            parent.addMember(child);
          } else if (existingScope == VariableAttribute.PRIVATE_SCOPE
              && existingScope == newScope) {
            parent.addInheritedPrivateMember(child);
          }
        } else {
          parent.addMember(child);
        }
      }
      // put child in the registry if it has an id and not already there
      DValue childValue = (DValue) child.getValue();
      long childId = childValue.getId();
      if (childId != Value.UNKNOWN_ID) {
        DValue existingValue = getValue(childId, isolateId);
        if (existingValue != null) {
          assert existingValue == childValue; // TODO is this right?
                            // what about getters?
        } else {
          putValue(childId, childValue, isolateId);
        }
      }
    }
  }

  // TODO is this right?
  void addVariableMember(long parentId, DVariable child, long doubleAsId,
      int isolateId) {
    addVariableMember(parentId, child, isolateId);

    // double book the child under another id
    if (getIsolateState(isolateId).m_attachChildren)
      putValue(doubleAsId, (DValue) child.getValue(), isolateId);
  }

  // @deprecated last pool that was read
  public String[] getConstantPool() {
    return m_lastConstantPool;
  }

  /**
   * Breakpoints
   */
  public DLocation getBreakpoint(int id, int isolateId) {
    ArrayList<DLocation> breakpoints = getIsolateState(isolateId).m_breakpoints;
    synchronized (breakpoints) {
      DLocation loc = null;
      int which = findBreakpoint(id, isolateId);
      if (which > -1)
        loc = breakpoints.get(which);
      return loc;
    }
  }

  int findBreakpoint(int id, int isolateId) {
    ArrayList<DLocation> breakpoints = getIsolateState(isolateId).m_breakpoints;
    synchronized (breakpoints) {
      int which = -1;
      int size = breakpoints.size();
      for (int i = 0; which < 0 && i < size; i++) {
        DLocation l = breakpoints.get(i);
        if (l.getId() == id)
          which = i;
      }
      return which;
    }
  }

  DLocation removeBreakpoint(int id, int isolateId) {
    ArrayList<DLocation> breakpoints = getIsolateState(isolateId).m_breakpoints;
    synchronized (breakpoints) {
      DLocation loc = null;
      int which = findBreakpoint(id, isolateId);
      if (which > -1) {
        loc = breakpoints.get(which);
        breakpoints.remove(which);
      }

      return loc;
    }
  }

  void addBreakpoint(int id, DLocation l, int isolateId) {
    ArrayList<DLocation> breakpoints = getIsolateState(isolateId).m_breakpoints;
    synchronized (breakpoints) {
                breakpoints.add(l);
            }
    }

  public DLocation[] getBreakpoints(int isolateId) {
    ArrayList<DLocation> breakpoints = getIsolateState(isolateId).m_breakpoints;
    synchronized (breakpoints) {
      return breakpoints.toArray(new DLocation[breakpoints.size()]);
    }
  }

  /**
   * Watchpoints
   */
  public DWatch getWatchpoint(int at, int isolateId) {
    DManagerIsolateState state = getIsolateState(isolateId);
    synchronized (state.m_watchpoints) {
      return state.m_watchpoints.get(at);
    }
  }

  public int getWatchpointCount(int isolateId) {
    DManagerIsolateState state = getIsolateState(isolateId);
    synchronized (state.m_watchpoints) {
      return state.m_watchpoints.size();
    }
  }

  public DWatch[] getWatchpoints(int isolateId) {
    DManagerIsolateState state = getIsolateState(isolateId);
    synchronized (state.m_watchpoints) {
      return state.m_watchpoints.toArray(new DWatch[state.m_watchpoints.size()]);
    }
  }

  boolean addWatchpoint(DWatch w, int isolateId) {
    ArrayList<DWatch> lockObject = getIsolateState(isolateId).m_watchpoints;
    synchronized (lockObject) {
      return lockObject.add(w);
    }
  }

  DWatch removeWatchpoint(int tag, int isolateId) {
    ArrayList<DWatch> lockObject = getIsolateState(isolateId).m_watchpoints;
    synchronized (lockObject) {
      DWatch w = null;
      int at = findWatchpoint(tag, isolateId);
      if (at > -1)
        w = lockObject.remove(at);
      return w;
    }
  }

  int findWatchpoint(int tag, int isolateId) {
    ArrayList<DWatch> lockObject = getIsolateState(isolateId).m_watchpoints;
    synchronized (lockObject) {
      int at = -1;
      int size = getWatchpointCount(isolateId);
      for (int i = 0; i < size && at < 0; i++) {
        DWatch w = getWatchpoint(i, isolateId);
        if (w.getTag() == tag)
          at = i;
      }
      return at;
    }
  }

  /**
   * Isolates
   */
  public DIsolate getIsolate(int at) {

    if (at == Isolate.DEFAULT_ID)
      return (DIsolate) DEFAULT_ISOLATE;

    synchronized (m_isolates) {
      return m_isolates.get(at);
    }
  }

  public DIsolate getOrCreateIsolate(int at) {
    synchronized (m_isolates) {
      if (m_isolates.containsKey(at)) {
        return m_isolates.get(at);
      } else {
        DIsolate isolate = new DIsolate(at);
        m_isolates.put(at, isolate);
        return isolate;
      }
    }
  }

  public int getIsolateCount() {
    synchronized (m_isolates) {
      return m_isolates.size();
    }
  }

  public DIsolate[] getIsolates() {
    synchronized (m_isolates) {
      return m_isolates.values().toArray(new DIsolate[m_isolates.size()]);
    }
  }

  boolean addIsolate(DIsolate t) {
    synchronized (m_isolates) {
      m_isolates.put(t.getId(), t);
      return true;
    }
  }

  void clearIsolates() {
    synchronized (m_isolates) {
      m_isolates.clear();
    }
  }

  DIsolate removeIsolate(int id) {
    synchronized (m_isolates) {
      DIsolate t = null;
      int at = findIsolate(id);
      if (at > -1)
        t = m_isolates.remove(at);
      return t;
    }
  }

  int findIsolate(int id) {
    synchronized (m_isolates) {
      if (m_isolates.containsKey(id))
        return id;
      else
        return -1;
    }
  }

  void setActiveIsolate(Isolate t) {
    synchronized (m_activeIsolateLock) {
      if (t == null) {
        m_activeIsolate = DEFAULT_ISOLATE;
      } else
        m_activeIsolate = t;
    }
  }
 
  Isolate getActiveIsolate() {
    synchronized (m_activeIsolateLock) {
      return m_activeIsolate;
    }
  }


  void setInIsolate(Isolate t) {
    synchronized (m_inIsolateLock) {
      if (t == null) {
        m_inIsolate = DEFAULT_ISOLATE;
      } else
        m_inIsolate = t;
    }
  }

  Isolate getInIsolate() {
    synchronized (m_inIsolateLock) {
      return m_inIsolate;
    }
  }

  Isolate getDefaultIsolate() {
    return DEFAULT_ISOLATE;
  }


  /**
   * Frame stack management related stuff
   *
   * @return true if we added this frame; false if we ignored it
   */
  boolean addFrame(DStackContext ds, int isolateId) {
    getIsolateState(isolateId).m_frames.add(ds);
    return true;
  }

  void clearFrames(int isolateId) {
    if (getIsolateState(isolateId).m_frames.size() > 0)
      getIsolateState(isolateId).m_previousFrames = getIsolateState(isolateId).m_frames;
    getIsolateState(isolateId).m_frames = new ArrayList<DStackContext>();
  }

  public DStackContext getFrame(int at, int isolateId) {
    return getIsolateState(isolateId).m_frames.get(at);
  }

  public int getFrameCount(int isolateId) {
    return getIsolateState(isolateId).m_frames.size();
  }

  public DStackContext[] getFrames(int isolateId) {
    ArrayList<DStackContext> frames = getIsolateState(isolateId).m_frames;
    return frames.toArray(new DStackContext[frames.size()]);
  }

  private boolean stringsEqual(String s1, String s2) {
    if (s1 == null)
      return s2 == null;
    else
      return s1.equals(s2);
  }

  /**
   * Correlates the old list of stack frames, from the last time the player
   * was suspended, with the new list of stack frames, attempting to guess
   * which frames correspond to each other. This is done so that
   * Variable.hasValueChanged() can work correctly for local variables.
   */
  private void mapOldFramesToNew(int isolateId) {
    ArrayList<DStackContext> previousFrames = null;
    ArrayList<DStackContext> frames = null;
    Map<Long, DValue> previousValues = null;

    previousFrames = getIsolateState(isolateId).m_previousFrames;
    frames = getIsolateState(isolateId).m_frames;
    previousValues = getIsolateState(isolateId).m_previousValues;

    int oldSize = previousFrames.size();
    int newSize = frames.size();

    // discard all old frames (we will restore some of them below)
    DValue[] oldFrames = new DValue[oldSize];
    for (int depth = 0; depth < oldSize; depth++) {
      oldFrames[depth] = (DValue) previousValues.remove(Value.BASE_ID
          - depth);
    }

    // Start at the end of the stack (the stack frame farthest from the
    // current one), and try to match up stack frames
    int oldDepth = oldSize - 1;
    int newDepth = newSize - 1;
    while (oldDepth >= 0 && newDepth >= 0) {
      DStackContext oldFrame = previousFrames.get(oldDepth);
      DStackContext newFrame = frames.get(newDepth);
      if (oldFrame != null && newFrame != null) {
        if (stringsEqual(oldFrame.getCallSignature(),
            newFrame.getCallSignature())) {
          DValue frame = oldFrames[oldDepth];
          if (frame != null)
            previousValues.put(Value.BASE_ID - newDepth, frame);
        }
      }
      oldDepth--;
      newDepth--;
    }
  }

  /**
   * Get function is only supported in players that recognize the squelch
   * message.
   */
  public boolean isGetSupported() {
    return m_squelchEnabled;
  }


  /**
   * Returns a suspend information on why the Player has suspended execution.
   *
   * @return see SuspendReason
   */
  public DSuspendInfo getSuspendInfo(int isolateId) {
    if (m_isolateState.containsKey(isolateId)) {
      return m_isolateState.get(isolateId).m_suspendInfo;
    }
    return null;
  }

  public ArrayList<SwfInfo> getIsolateSwfList() {
    ArrayList<SwfInfo> result = new ArrayList<SwfInfo>();

    for (DManagerIsolateState state : m_isolateState.values()) {
      if (state.m_swfInfo != null) {
        result.addAll(state.m_swfInfo);
      }
    }

    return result;
  }

  /**
   * Event management related stuff
   */
  public int getEventCount() {
    synchronized (m_event) {
      return m_event.size();
    }
  }

  /**
   * Get an object on which callers can call wait(), in order to wait until
   * something happens.
   *
   * Note: The object will be signalled when EITHER of the following happens:
   * (1) An event is added to the event queue; (2) The network connection is
   * broken (and thus there will be no more events).
   *
   * @return an object on which the caller can call wait()
   */
  public Object getEventNotifier() {
    return m_event;
  }

  public DebugEvent nextEvent() {
    DebugEvent s = null;
    synchronized (m_event) {
      if (m_event.size() > 0)
        s = m_event.removeFirst();
    }
    return s;
  }

  public synchronized void addEvent(DebugEvent e) {
    synchronized (m_event) {
      m_event.add(e);
      m_event.notifyAll(); // wake up listeners (see getEventNotifier())
    }
  }

  /**
   * Issued when the socket connection to the player is cut
   */
  public void disconnected() {
    synchronized (m_event) {
      m_event.notifyAll(); // see getEventNotifier()
    }
  }

  /**
   * 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) {
    /*
     * at this point we just open up a big switch statement and walk through
     * all possible cases
     */
    int type = msg.getType();
    // System.out.println("manager msg = "+DMessage.inTypeName(type));
    int inIsolateId = getInIsolate() != null ? getInIsolate().getId()
        : Isolate.DEFAULT_ID;
    if (inIsolateId != Isolate.DEFAULT_ID) {
      msg.setTargetIsolate(inIsolateId);
    }
    switch (type) {
    case DMessage.InVersion: {
      long ver = msg.getDWord();
      m_playerVersion = (int) ver;

      // Newer players will send another byte, which is the pointer size
      // that is used by the player (in bytes).
      int pointerSize;
      if (msg.getRemaining() >= 1)
        pointerSize = msg.getByte();
      else
        pointerSize = 4;
      DMessage.setSizeofPtr(pointerSize);
      break;
    }

    case DMessage.InErrorExecLimit: {
      handleFaultEvent(new RecursionLimitFault(msg.getTargetIsolate()));
      break;
    }

    case DMessage.InErrorWith: {
      handleFaultEvent(new InvalidWithFault(msg.getTargetIsolate()));
      break;
    }

    case DMessage.InErrorProtoLimit: {
      handleFaultEvent(new ProtoLimitFault(msg.getTargetIsolate()));
      break;
    }

    case DMessage.InErrorURLOpen: {
//      String url = msg.getString();
//      handleFaultEvent(new InvalidURLFault(url, msg.getTargetIsolate()));
      break;
    }

    case DMessage.InErrorTarget: {
//      String name = msg.getString();
//      handleFaultEvent(new InvalidTargetFault(name, msg.getTargetIsolate()));
      break;
    }

    case DMessage.InErrorException: {
      long offset = msg.getDWord();
      // As of FP9, the player will also send the "toString()" message
      // of the exception. But for backward compatibility with older
      // players, we won't assume that that is there.
      String exceptionMessage;
      boolean willExceptionBeCaught = false;
      Value thrown = null;
      if (msg.getRemaining() > 0) {
        exceptionMessage = msg.getString();
        if (msg.getRemaining() > 0) {
          if (msg.getByte() != 0) {
            willExceptionBeCaught = (msg.getByte() != 0 ? true
                : false);
            msg.getPtr();
            DVariable thrownVar = extractVariable(msg);
            thrown = thrownVar.getValue();
          }
        }
      } else {
        exceptionMessage = ""; //$NON-NLS-1$
      }
      ExceptionFault exceptionFault = new ExceptionFault(
          exceptionMessage, willExceptionBeCaught, thrown, msg.getTargetIsolate());
      exceptionFault.isolateId = msg.getTargetIsolate();
      handleFaultEvent(exceptionFault);
      break;
    }

    case DMessage.InErrorStackUnderflow: {
//      long offset = msg.getDWord();
      handleFaultEvent(new StackUnderFlowFault(msg.getTargetIsolate()));
      break;
    }

    case DMessage.InErrorZeroDivide: {
//      long offset = msg.getDWord();
      handleFaultEvent(new DivideByZeroFault(msg.getTargetIsolate()));
      break;
    }

    case DMessage.InErrorScriptStuck: {
      handleFaultEvent(new ScriptTimeoutFault(msg.getTargetIsolate()));
      break;
    }

    case DMessage.InErrorConsole: {
      String s = msg.getString();
      handleFaultEvent(new ConsoleErrorFault(s, msg.getTargetIsolate()));
      break;
    }

    case DMessage.InTrace: {
      String text = msg.getString();
      addEvent(new TraceEvent(text));
      break;
    }

    case DMessage.InSquelch: {
      long state = msg.getDWord();
      m_squelchEnabled = (state != 0) ? true : false;
      break;
    }

    case DMessage.InParam: {
      String name = msg.getString();
      String value = msg.getString();

      // here's where we get movie = URL and password which I'm not sure
      // what to do with?
      // System.out.println(name+"="+value);
      m_parms.put(name, value);

      // if string is a "movie", then this is a URL
      if (name.startsWith("movie")) //$NON-NLS-1$
        m_uri = convertToURI(value);
      break;
    }

    case DMessage.InPlaceObject: {
      long objId = msg.getPtr();
      String path = msg.getString();
      // m_bag.placeObject((int)objId, path);
      break;
    }

    case DMessage.InSetProperty: {
      long objId = msg.getPtr();
      int item = msg.getWord();
      String value = msg.getString();
      break;
    }

    case DMessage.InNewObject: {
      long objId = msg.getPtr();
      break;
    }

    case DMessage.InRemoveObject: {
      long objId = msg.getPtr();
      // m_bag.removeObject((int)objId);
      break;
    }

    case DMessage.InSetVariable: {
      long objId = msg.getPtr();
      String name = msg.getString();
      int dType = msg.getWord();
      int flags = (int) msg.getDWord();
      String value = msg.getString();

      // m_bag.createVariable((int)objId, name, dType, flags, value);
      break;
    }

    case DMessage.InDeleteVariable: {
      long objId = msg.getPtr();
      String name = msg.getString();
      // m_bag.deleteVariable((int)objId, name);
      break;
    }

    case DMessage.InScript: {
      int module = (int) msg.getDWord();
      int bitmap = (int) msg.getDWord();
      String name = msg.getString(); // in "basepath;package;filename"
                      // format
      String text = msg.getString();
      int swfIndex = -1;
      int isolateIndex = -1;

      /* new in flash player 9: player tells us what swf this is for */
      if (msg.getRemaining() >= 4)
        swfIndex = (int) msg.getDWord();

      isolateIndex = msg.getTargetIsolate();
      getOrCreateIsolate(isolateIndex);
      if (putSource(swfIndex, module, bitmap, name, text,
          isolateIndex)) {
        // have we changed the list since last query
        if (!m_sourceListModified)
          addEvent(new FileListModifiedEvent());

        m_sourceListModified = true;
      }
      break;
    }

    case DMessage.InRemoveScript: {
      long module = msg.getDWord();
      int isolateId = msg.getTargetIsolate();
      Map<Integer, DModule> source = getIsolateState(isolateId).m_source;
      synchronized (source) {
        if (removeSource((int) module, isolateId)) {
          // have we changed the list since last query
          if (!m_sourceListModified)
            addEvent(new FileListModifiedEvent());

          m_sourceListModified = true; /* current source list is stale */
        }
      }
      break;
    }

    case DMessage.InAskBreakpoints: {
      // the player has just loaded a swf and we know the player
      // has halted, waiting for us to continue. The only caveat
      // is that it looks like it still does a number of things in
      // the background which take a few seconds to complete.
      int targetIsolate = msg.getTargetIsolate();
      DSuspendInfo iSusInfo = getIsolateState(targetIsolate).m_suspendInfo;
      if (iSusInfo == null) {
        iSusInfo = new DSuspendInfo(SuspendReason.ScriptLoaded, 0,
            0, 0, 0);
      }
      break;
    }

    case DMessage.InBreakAt: {
      long bp = 0, wideLine = 0, wideModule = 0;
      if (!m_wideLines) {
        bp = msg.getDWord();
      }
      else {
        wideModule = msg.getDWord();
        wideLine = msg.getDWord();
      }
      long id = msg.getPtr();
      String stack = msg.getString();
      int targetIsolate = msg.getTargetIsolate();

      int module = DLocation.decodeFile(bp);
      int line = DLocation.decodeLine(bp);
      if (m_wideLines) {
        module = (int)wideModule;
        line = (int)wideLine;
      }
      addEvent(new BreakEvent(module, line, targetIsolate));
      break;
    }

    case DMessage.InContinue: {
      /* we are running again so trash all our variable contents */
      continuing(msg.getTargetIsolate());
      break;
    }

    case DMessage.InSetLocalVariables: {
//      long objId = msg.getPtr();
      // m_bag.markObjectLocal((int)objId, true);
      break;
    }

    case DMessage.InSetBreakpoint: {
      long count = msg.getDWord();
      int targetIsolate = msg.getTargetIsolate();
      while (count-- > 0) {
        long bp = 0, moduleNumber = 0, lineNumber = 0;
        if (!m_wideLines) {
          bp = msg.getDWord();
        }
        else {
          moduleNumber = msg.getDWord();
          lineNumber = msg.getDWord();
        }

        int fileId = DLocation.decodeFile(bp);
        int line = DLocation.decodeLine(bp);
        if (m_wideLines) {
          fileId = (int)moduleNumber;
          line = (int)lineNumber;
        }

        DModule file = null;
        file = getSource(fileId, targetIsolate);

        DLocation l = new DLocation(file, line, targetIsolate);

        if (file != null) {
          addBreakpoint((int) bp, l, targetIsolate);
        }
      }
      break;
    }

    case DMessage.InNumScript: {
      /* lets us know how many scripts there are */
      int num = (int) msg.getDWord();
      int targetIsolate = msg.getTargetIsolate();
      DSwfInfo swf;

      /*
       * New as of flash player 9: another dword indicating which swf this
       * is for. That means we don't have to guess whether this is for an
       * old SWF which has just had some more modules loaded, or for a new
       * SWF!
       */
      if (msg.getRemaining() >= 4) {
        int swfIndex = (int) msg.getDWord();
        swf = getOrCreateSwfInfo(swfIndex, targetIsolate);
        getIsolateState(targetIsolate).m_lastSwfInfo = swf;
      } else {
        /*
         * This is not flash player 9 (or it is an early build of fp9).
         *
         * We use this message as a trigger that a new swf has been
         * loaded, so make sure we are ready to accept the scripts.
         */
        swf = getActiveSwfInfo(targetIsolate);
      }

      // It is NOT an error for the player to have sent us a new,
      // different sourceExpectedCount from whatever we had before!
      // In fact, this happens all the time, whenever a SWF has more
      // than one ABC.
      swf.setSourceExpectedCount(num);
      break;
    }

    case DMessage.InRemoveBreakpoint: {
      long count = msg.getDWord();
      int isolateId = msg.getTargetIsolate();
      while (count-- > 0) {
        long bp = msg.getDWord();
        removeBreakpoint((int) bp, isolateId);
      }
      break;

    }

    case DMessage.InBreakAtExt: {
      long bp = 0, wideLine = 0, wideModule = 0;
      if (!m_wideLines) {
        bp = msg.getDWord();
      }
      else {
        wideModule = msg.getDWord();
        wideLine = msg.getDWord();
      }
      long num = msg.getDWord();

      int targetIsolate = msg.getTargetIsolate();
      // System.out.println(msg.getInTypeName()+",bp="+(bp&0xffff)+":"+(bp>>16));
      /* we have stack info to store away */
      clearFrames(targetIsolate); // just in case
      int depth = 0;

      while (num-- > 0) {
        long bpi = 0, wideLinei= 0, wideModulei = 0;
        if (!m_wideLines) {
          bpi = msg.getDWord();
        }
        else {
          wideModulei = msg.getDWord();
          wideLinei = msg.getDWord();
        }
        long id = msg.getPtr();
        String stack = msg.getString();
        int module = DLocation.decodeFile(bpi);
        int line = DLocation.decodeLine(bpi);
        if (m_wideLines) {
          module = (int)wideModulei;
          line = (int)wideLinei;
        }
        DModule m = null;
        m = getSource(module, targetIsolate);
        DStackContext c = new DStackContext(module, line, m, id, stack,
            depth, targetIsolate);
        // If addFrame() returns false, that means it chose to ignore
        // this
        // frame, so we do NOT want to increment our depth for the next
        // time through the loop. If it returns true, then we do want
        // to.
        if (addFrame(c, targetIsolate))
          ++depth;
        // System.out.println("   this="+id+",@"+(bpi&0xffff)+":"+(bpi>>16)+",stack="+stack);
      }
      mapOldFramesToNew(targetIsolate);
      if (targetIsolate != Isolate.DEFAULT_ID) {
        // ask for isolate id if it is present
        appendIsolateInfoToFrame(targetIsolate);

      }
      break;

    }

    case DMessage.InFrame: {
      // For InFrame the first element is really our frame id
      DValue frame = null;
      DVariable child = null;
      ArrayList<DVariable> v = new ArrayList<DVariable>();
      ArrayList<DVariable> registers = new ArrayList<DVariable>();
      int targetIsolate = msg.getTargetIsolate();
      int depth = (int) msg.getDWord(); // depth of frame

      // make sure we have a valid depth
      if (depth > -1) {
        // first thing is number of registers
        int num = (int) msg.getDWord();
        for (int i = 0; i < num; i++)
          registers.add(extractRegister(msg, i + 1));
      }

      int currentArg = -1;
      boolean gettingScopeChain = false;

      // then our frame itself
      while (msg.getRemaining() > 0) {
        long frameId = msg.getPtr();

        if (frame == null) {
          frame = getOrCreateValue(frameId, targetIsolate);
          extractVariable(msg); // put the rest of the info in the
                      // trash
        } else {
          child = extractVariable(msg);
          if (currentArg == -1
              && child.getName().equals(ARGUMENTS_MARKER)) {
            currentArg = 0;
            gettingScopeChain = false;
          } else if (child.getName().equals(SCOPE_CHAIN_MARKER)) {
            currentArg = -1;
            gettingScopeChain = true;
          } else if (currentArg >= 0) {
            // work around a compiler bug: If the variable's name is
            // "undefined",
            // then change its name to "_argN", where "N" is the
            // argument index,
            // e.g. _arg1, _arg2, etc.
            ++currentArg;
            if (child.getName().equals("undefined")) //$NON-NLS-1$
              child.setName("_arg" + currentArg); //$NON-NLS-1$
          }

          // All args and locals get added as "children" of
          // the frame; but scope chain entries do not.
          if (!gettingScopeChain)
            addVariableMember(frameId, child, targetIsolate);

          // Everything gets added to the ordered list of
          // variables that came in.
          v.add(child);
        }
      }

      // let's transfer our newly gained knowledge into the stack context
      if (depth == 0)
        populateRootNode(frame, v, targetIsolate);
      else
        populateFrame(depth, v, targetIsolate);

      break;
    }

    case DMessage.InOption: {
      String s = msg.getString();
      String v = msg.getString();
      m_options.put(s, v);
      break;
    }

    case DMessage.InGetVariable: {
      // For InGetVariable the first element is the original entity we
      // requested
      DValue parent = null;
      DVariable child = null;
      String definingClass = null;
      int level = 0;
      int targetIsolate = msg.getTargetIsolate();
      int highestLevelWithMembers = -1;
      List<String> classes = new ArrayList<String>();

      while (msg.getRemaining() > 0) {
        long parentId = msg.getPtr();

        // build or get parent node
        if (parent == null) {
          String name = msg.getString();

          // pull the contents of the node which normally are disposed
          // of except if we did a 0,name call
          getIsolateState(targetIsolate).m_lastInGetVariable = extractVariable(msg, name);

          parent = getOrCreateValue(parentId, targetIsolate);
        } else {
          // extract the child and add it to the parent.
          child = extractVariable(msg);
          if (showMember(child)) {
            if (child.isAttributeSet(VariableAttribute.IS_DYNAMIC)) {
              // Dynamic attributes always come in marked as a
              // member of
              // class "Object"; but to the user, it makes more
              // sense to
              // consider them as members of the topmost class.
              if (classes.size() > 0) {
                child.setDefiningClass(0, classes.get(0));
                highestLevelWithMembers = Math.max(
                    highestLevelWithMembers, 0);
              }
            } else {
              child.setDefiningClass(level, definingClass);
              if (definingClass != null) {
                highestLevelWithMembers = Math.max(
                    highestLevelWithMembers, level);
              }
            }
            addVariableMember(parent.getId(), child, targetIsolate);
          } else {
            if (isTraits(child)) {
              definingClass = child.getQualifiedName();
              level = classes.size();

              // If the traits name end with "$", then it
              // represents a class object --
              // in other words, the variables inside it are
              // static variables of that
              // class. In that case, we need to juggle the
              // information. For example,
              // if we are told that a variable is a member of
              // "MyClass$", we actually
              // store it into the information for "MyClass".
              if (definingClass.endsWith("$")) { //$NON-NLS-1$
                String classWithoutDollar = definingClass
                    .substring(0,
                        definingClass.length() - 1);
                int indexOfClass = classes
                    .indexOf(classWithoutDollar);
                if (indexOfClass != -1) {
                  level = indexOfClass;
                  definingClass = classWithoutDollar;
                }
              }

              // It wasn't static -- so, add this class to the end
              // of the list of classes
              if (level == classes.size()) {
                classes.add(definingClass);
              }
            }
          }
        }
      }

      if (parent != null && parent.getClassHierarchy(true) == null) {
        parent.setClassHierarchy(
            classes.toArray(new String[classes.size()]),
            highestLevelWithMembers + 1);
      }

      break;
    }

    case DMessage.InWatch: // for AS2; sends 16-bit ID field
    case DMessage.InWatch2: // for AS3; sends 32-bit ID field
    {
      // This message is sent whenever a watchpoint is added
      // modified or removed.
      //
      // For an addition, flags will be non-zero and
      // success will be true.
      //
      // For a modification flags will be non-zero.
      // and oldFlags will be non-zero and success
      // will be true. Additionally oldFlags will not
      // be equal to flags.
      //
      // For a removal flags will be zero. oldFlags
      // will be non-zero.
      //
      // flags identifies the type of watchpoint added,
      // see WatchKind.
      //
      // success indicates whether the operation was successful
      //
      // request. It will be associated with the watchpoint.
      int success = msg.getWord();
      int oldFlags = msg.getWord();
      int oldTag = msg.getWord();
      int flags = msg.getWord();
      int tag = msg.getWord();
      // for AS2, the ID came in above as a Word. For AS3, the above value
      // is
      // bogus, and it has been sent again as a DWord.
      long id = ((type == DMessage.InWatch2) ? msg.getPtr() : msg
          .getWord());
      String name = msg.getString();
      int targetIsolate = msg.getTargetIsolate();

      if (success != 0) {
        if (flags == 0) {
          removeWatchpoint(oldTag, targetIsolate);
        } else {
          // modification or addition is the same to us
          // a new watch is created and added into the table
          // while any old entry if it exists is removed.
          removeWatchpoint(oldTag, targetIsolate);
          DWatch w = new DWatch(id, name, flags, tag, targetIsolate);
          addWatchpoint(w, targetIsolate);
        }
      }
      break;
    }

    case DMessage.InGetSwf: {
      // we only house the swf temporarily, PlayerSession then
      // pieces it back into swfinfo record. Also, we don't
      // send any extra data in the message so that we need not
      // copy the bytes.
      m_swf = msg.getData();
      break;
    }

    case DMessage.InGetSwd: {
      // we only house the swd temporarily, PlayerSession then
      // pieces it back into swfinfo record.
      m_swd = msg.getData();
      break;
    }

    case DMessage.InBreakReason: {
      // the id map 1-1 with out SuspendReason interface constants
      int suspendReason = msg.getWord();
      int suspendPlayer = msg.getWord(); // item index of player
      int breakOffset = (int) msg.getDWord(); // current script offset
      int prevBreakOffset = (int) msg.getDWord(); // prev script offset
      int nextBreakOffset = (int) msg.getDWord(); // next script offset
      int targetIsolate = msg.getTargetIsolate();

      getIsolateState(targetIsolate).m_suspendInfo = new DSuspendInfo(
          suspendReason, suspendPlayer, breakOffset,
          prevBreakOffset, nextBreakOffset);

      // augment the current frame with this information. It
      // should work ok since we only get this message after a
      // InBreakAtExt message
      try {
        DStackContext c = getFrame(0, targetIsolate);
        c.setOffset(breakOffset);
        c.setSwfIndex(suspendPlayer);
      } catch (Exception e) {
        if (Trace.error) {
          Trace.trace("Oh my god, gag me with a spoon...getFrame(0) call failed"); //$NON-NLS-1$
          e.printStackTrace();
        }
      }
      break;
    }

      // obtain raw action script byte codes
    case DMessage.InGetActions: {
      int item = msg.getWord();
      int rsvd = msg.getWord();
      int at = (int) msg.getDWord();
      int len = (int) msg.getDWord();
      int i = 0;

      m_actions = (len <= 0) ? null : new byte[len];
      while (len-- > 0)
        m_actions[i++] = (byte) msg.getByte();

      break;
    }

      // obtain data about a SWF
    case DMessage.InSwfInfo: {
      int count = msg.getWord();
      int targetIsolate = msg.getTargetIsolate();
      for (int i = 0; i < count; i++) {
        long index = msg.getDWord();
        long id = msg.getPtr();

        // get it
        DSwfInfo info = null;

        info = getOrCreateSwfInfo((int) index, targetIsolate);
        getIsolateState(targetIsolate).m_lastSwfInfo = info;

        // remember which was last seen

        if (id != 0) {
          boolean debugComing = (msg.getByte() == 0) ? false : true;
          byte vmVersion = (byte) msg.getByte(); // AS vm version
                              // number (1 = avm+,
                              // 0 == avm-)
          int rsvd1 = msg.getWord();

          long swfSize = msg.getDWord();
          long swdSize = msg.getDWord();
          long scriptCount = msg.getDWord();
          long offsetCount = msg.getDWord();
          long breakpointCount = msg.getDWord();

          long port = msg.getDWord();
          String path = msg.getString();
          String url = msg.getString();
          String host = msg.getString();
          Map<Long, Integer> local2global = new HashMap<Long, Integer>();
          int minId = Integer.MAX_VALUE;
          int maxId = Integer.MIN_VALUE;
          // now we read in the swd debugging map (which provides
          // local to global mappings of the script ids
          /* anirudhs: Parsing this is only necessary if we are in
             AVM1. (See PlayerSession::run(), there is a vmVersion
             check before calling parseSwfSwd(). */
          if (swdSize > 0) {
            long num = msg.getDWord();
            for (int j = 0; j < num; j++) {
              if (msg.getRemaining() < DMessage.getSizeofPtr()) {
                /* The SWD debugging map sent out by
                 * AVM2 often runs short usually in 64-bit
                 * debug player. We can stop with what we know
                 * and move on.
                 */
                break;
              }
              long local = msg.getPtr();
              int global = (int) msg.getDWord();
              local2global.put(local, global);
              minId = (global < minId) ? global : minId;
              maxId = (global > maxId) ? global : maxId;
            }
          }
          // If its a new record then the swf size would have been
          // unknown at creation time
          boolean justCreated = (info.getSwfSize() == 0);

          // if we are a avm+ engine then we don't wait for the swd to
          // load
          if (vmVersion > 0) {
            debugComing = false;
            info.setVmVersion(vmVersion);
            info.setPopulated(); // added by mmorearty on 9/5/05 for
                        // RSL debugging
          }

          // update this swfinfo with the lastest data
          info.freshen(id, path, url, host, port, debugComing,
              swfSize, swdSize, breakpointCount, offsetCount,
              scriptCount, local2global, minId, maxId);
          // now tie any scripts that have been loaded into this
          // swfinfo object
          tieScriptsToSwf(info, targetIsolate);

          // notify if its newly created
          if (justCreated)
            addEvent(new SwfLoadedEvent(id, (int) index, path, url,
                host, port, swfSize));
        } else {
          // note our state before marking it
          boolean alreadyUnloaded = info.isUnloaded();

          // clear it out
          info.setUnloaded();

          // notify if this information is new.
          if (!alreadyUnloaded)
            addEvent(new SwfUnloadedEvent(info.getId(),
                info.getPath(), (int) index));
        }
        // System.out.println("[SWFLOAD] Loaded "+path+", size="+swfSize+", scripts="+scriptCount);
      }
      break;
    }

      // obtain the constant pool of some player
    case DMessage.InConstantPool: {
      int item = msg.getWord();
      int count = (int) msg.getDWord();

      String[] pool = new String[count];
      for (int i = 0; i < count; i++) {
        long id = msg.getPtr();
        DVariable var = extractVariable(msg);

        // we only need the contents of the variable
        pool[i] = var.getValue().getValueAsString();
      }
      m_lastConstantPool = pool;
      break;
    }

      // obtain one or more function name line number mappings.
    case DMessage.InGetFncNames: {
      long id = msg.getDWord(); // module id
      long count = msg.getDWord(); // number of entries

      // get the DModule
      DModule m = getSource((int) id, msg.getTargetIsolate());
      if (m != null) {
        for (int i = 0; i < count; i++) {
          int offset = (int) msg.getDWord();
          int firstLine = (int) msg.getDWord();
          int lastLine = (int) msg.getDWord();
          String name = msg.getString();

          // now add the entries
          m.addLineFunctionInfo(offset, firstLine, lastLine, name);
        }
      }
      break;
    }

    case DMessage.InCallFunction:
    case DMessage.InBinaryOp: {
      // For InCallFunction the first element is the original function we
      // requested
      DValue parent = null;
      int targetIsolate = msg.getTargetIsolate();
      DVariable child = null;
      String definingClass = null;
      int level = 0;
      int highestLevelWithMembers = -1;
      List<String> classes = new ArrayList<String>();

      if (type == DMessage.InBinaryOp)
        msg.getDWord(); // id

      while (msg.getRemaining() > 0) {
        long parentId = msg.getPtr();

        // build or get parent node
        if (parent == null) {
          String name = msg.getString();

          // pull the contents of the node which normally are disposed
          // of except if we did a 0,name call
          DVariable var = extractVariable(msg, name);
          if (type == DMessage.InCallFunction) {
            getIsolateState(targetIsolate).m_lastInCallFunction = var;
          }
          else {
            getIsolateState(targetIsolate).m_lastInBinaryOp = var;
          }

          parent = getOrCreateValue(parentId, targetIsolate);
        } else {
          // extract the child and add it to the parent.
          child = extractVariable(msg);
          if (showMember(child)) {
            if (child.isAttributeSet(VariableAttribute.IS_DYNAMIC)) {
              // Dynamic attributes always come in marked as a
              // member of
              // class "Object"; but to the user, it makes more
              // sense to
              // consider them as members of the topmost class.
              if (classes.size() > 0) {
                child.setDefiningClass(0, classes.get(0));
                highestLevelWithMembers = Math.max(
                    highestLevelWithMembers, 0);
              }
            } else {
              child.setDefiningClass(level, definingClass);
              if (definingClass != null) {
                highestLevelWithMembers = Math.max(
                    highestLevelWithMembers, level);
              }
            }
            addVariableMember(parent.getId(), child, targetIsolate);
          } else {
            if (isTraits(child)) {
              definingClass = child.getQualifiedName();
              level = classes.size();

              // If the traits name end with "$", then it
              // represents a class object --
              // in other words, the variables inside it are
              // static variables of that
              // class. In that case, we need to juggle the
              // information. For example,
              // if we are told that a variable is a member of
              // "MyClass$", we actually
              // store it into the information for "MyClass".
              if (definingClass.endsWith("$")) { //$NON-NLS-1$
                String classWithoutDollar = definingClass
                    .substring(0,
                        definingClass.length() - 1);
                int indexOfClass = classes
                    .indexOf(classWithoutDollar);
                if (indexOfClass != -1) {
                  level = indexOfClass;
                  definingClass = classWithoutDollar;
                }
              }

              // It wasn't static -- so, add this class to the end
              // of the list of classes
              if (level == classes.size()) {
                classes.add(definingClass);
              }
            }
          }
        }
      }

      if (parent != null && parent.getClassHierarchy(true) == null) {
        parent.setClassHierarchy(
            classes.toArray(new String[classes.size()]),
            highestLevelWithMembers + 1);
      }

      break;
    }

    case DMessage.InIsolateCreate: {
      long id = msg.getDWord();
      isolateCreate((int) id);

      break;
    }

    case DMessage.InIsolateExit: {
      long id = msg.getDWord();
      // Implementation dependency on runtime in case id mechanism is
      // changed:
      // Typecast id into an int.
      DIsolate isolate = removeIsolate((int) id);
      addEvent(new IsolateExitEvent(isolate));

      break;
    }

    case DMessage.InIsolateEnumerate: {
      // clearIsolates();
      //
      // long lenIsolate = msg.getDWord();
      //
      // for ( int i = 0; i < lenIsolate; i++) {
      // long id = msg.getDWord();
      // addIsolate(new DIsolate(id));
      // }

      break;
    }

    case DMessage.InSetActiveIsolate: {
      long id = msg.getDWord();

      boolean success = msg.getByte() != 0 ? true : false;

      /** Ignore inset since we don't wait
       * for response anymore.
       */
//      synchronized (m_activeIsolateLock) {
//        if (success) {
//          int at = findIsolate((int) id);
//          if (at > -1)
//            setActiveIsolate(getIsolate(at));
//        } else {
//          setActiveIsolate(null);
//        }
//      }

      break;
    }

    case DMessage.InIsolate: {
      long id = msg.getDWord();
      synchronized (m_inIsolateLock) {
        int at = findIsolate((int) id);
        if (at != -1)
          setInIsolate(getIsolate(at));
        else {
          if (id != Isolate.DEFAULT_ID) {
            setInIsolate(isolateCreate((int) id));
          } else
            setInIsolate(null);
        }
      }
      break;
    }
   
    case DMessage.InSetExceptionBreakpoint: {

      int result = msg.getWord();
      String exceptionBP = msg.getString();
      int remaining = msg.getRemaining();
      break;
    }

    case DMessage.InRemoveExceptionBreakpoint: {
      int result = msg.getWord();
      String exceptionBP = msg.getString();
      int remaining = msg.getRemaining();
      break;
    }

    default: {
      break;
    }
    }
  }

  private DIsolate isolateCreate(int id) {
    int idx = findIsolate(id);
    if (idx == -1) {
      DIsolate isolate = new DIsolate(id);
      addIsolate(isolate);
      setInIsolate(isolate);
      addEvent(new IsolateCreateEvent(isolate));
      return isolate;
    }
    return getIsolate(idx);

  }

  private void appendIsolateInfoToFrame(int isolateid) {
    // augment the current frame with this information. It
    // should work ok since we only get this message after a
    // InBreakAtExt message
    try {
      DStackContext c = getFrame(0, isolateid);
      c.setIsolateId(isolateid);
    } catch (Exception e) {
      if (Trace.error) {
        Trace.trace("Oh my god, gag me with a spoon...getFrame(0) call failed"); //$NON-NLS-1$
        e.printStackTrace();
      }
    }
  }

  /**
   * Returns whether a given child member should be shown, or should be
   * filtered out.
   */
  private boolean showMember(DVariable child) {
    if (isTraits(child))
      return false;
    return true;
  }

  /**
   * Returns whether this is not a variable at all, but is instead a
   * representation of a "traits" object. A "traits" object is the Flash
   * player's way of describing one class.
   */
  private boolean isTraits(DVariable variable) {
    Value value = variable.getValue();
    if (value.getType() == VariableType.UNKNOWN
        && Value.TRAITS_TYPE_NAME.equals(value.getTypeName())) {
      return true;
    }
    return false;
  }

  /**
   * Here's where some ugly stuff happens. Since our context contains more
   * info than what's contained within the stackcontext, we augment it with
   * the variables. Also, we build up a list of variables that appears under
   * root, that can be accessed without further qualification; this includes
   * args, locals and _global.
   */
  void populateRootNode(DValue frame, ArrayList<DVariable> orderedChildList,
      int isolateId) {
    // first populate the stack node with children
    populateFrame(0, orderedChildList, isolateId);

    /**
     * We mark it as members obtained so that we don't go to the player and
     * request it, which would be bad, since its our artifical creation.
     */
    DValue base = getOrCreateValue(Value.BASE_ID, isolateId);
    base.setMembersObtained(true);

    /**
     * Technically, we don't need to create the following nodes, but we like
     * to give them nice type names
     */

    // now let's create a _global node and attach it to base
  }

  /**
   * We are done, so let's look for a number of special variables, since our
   * frame comes in 3 pieces. First off is a "this" pointer, followed by a
   * "$arguments" dummy node, followed by a "super" which marks the end of the
   * arguments.
   *
   * All of this stuff gets pulled apart after we build the frame node.
   */
  void populateFrame(int depth, ArrayList<DVariable> frameVars, int isolateId) {
    // get our stack context
    DStackContext context = null;
    boolean inArgs = false;
    int nArgs = -1;
    boolean inScopeChain = false;

    // create a root node for each stack frame; first is at BASE_ID
    DValue root = getOrCreateValue(Value.BASE_ID - depth, isolateId);

    if (depth < getFrameCount(isolateId))
      context = getFrame(depth, isolateId);

    // trim all current args from this context
    if (context != null)
      context.removeAllVariables();

    // use the ordered child list
    Iterator<DVariable> e = frameVars.iterator();
    while (e.hasNext()) {
      DVariable v = e.next();
      String name = v.getName();

      // let's clear a couple of attributes that may get in our way
      v.clearAttribute(VariableAttribute.IS_LOCAL);
      v.clearAttribute(VariableAttribute.IS_ARGUMENT);
      if (name.equals("this")) //$NON-NLS-1$
      {
        if (context != null)
          context.setThis(v);

        // from our current frame, put a pseudo this entry into the
        // cache and hang it off base, mark it as an implied arg
        v.setAttribute(VariableAttribute.IS_ARGUMENT);
        addVariableMember(root, v, isolateId);

        // also add this variable under THIS_ID
        if (depth == 0)
          putValue(Value.THIS_ID, (DValue) v.getValue(), isolateId);
      } else if (name.equals("super")) //$NON-NLS-1$
      {
        // we are at the end of the arg list and let's make super part
        // of global
        inArgs = false;
      } else if (name.equals(ARGUMENTS_MARKER)) {
        inArgs = true;

        // see if we can extract an arg count from this variable
        try {
          nArgs = ((Number) (v.getValue().getValueAsObject()))
              .intValue();
        } catch (NumberFormatException nfe) {
        }
      } else if (name.equals(SCOPE_CHAIN_MARKER)) {
        inArgs = false;
        inScopeChain = true;
      } else {
        // add it to our root, marking it as an arg if we know,
        // otherwise local
        if (inArgs) {
          v.setAttribute(VariableAttribute.IS_ARGUMENT);

          if (context != null)
            context.addArgument(v);

          // decrement arg count if we have it
          if (nArgs > -1) {
            if (--nArgs <= 0)
              inArgs = false;
          }
        } else if (inScopeChain) {
          if (context != null)
            context.addScopeChainEntry(v);
        } else {
          v.setAttribute(VariableAttribute.IS_LOCAL);
          if (context != null)
            context.addLocal(v);
        }

        // add locals and arguments to root
        if (!inScopeChain)
          addVariableMember(root, v, isolateId);
      }
    }
  }

  /**
   * Map DMessage / Player attributes to VariableAttributes
   */
  int toAttributes(int pAttr) {
    int attr = pAttr; /* 1-1 mapping */
    return attr;
  }

  DVariable extractVariable(DMessage msg) {
    DVariable v = extractVariable(msg, msg.getString());
    return v;
  }

  /**
   * Build a variable based on the information we can extract from the
   * messsage
   */
  DVariable extractVariable(DMessage msg, String name) {
    int oType = msg.getWord();
    int flags = (int) msg.getDWord();
    return extractAtom(msg, name, oType, flags);
  }

  /**
   * Extracts an builds a register variable
   */
  DVariable extractRegister(DMessage msg, int number) {
    int oType = msg.getWord();
    return extractAtom(msg, "$" + number, oType, 0); //$NON-NLS-1$
  }

  /**
   * Does the job of pulling together a variable based on the type of object
   * encountered.
   */
  DVariable extractAtom(DMessage msg, String name, int oType, int flags) {
    int vType = VariableType.UNKNOWN;
    Object value = null;
    String typeName = ""; //$NON-NLS-1$
    String className = ""; //$NON-NLS-1$
    boolean isPrimitive = false;

    /* now we vary depending upon type */
    switch (oType) {
    case DMessage.kNumberType: {
      String s = msg.getString();
      double dval = Double.NaN;
      try {
        dval = Double.parseDouble(s);
      } catch (NumberFormatException nfe) {
      }

      value = new Double(dval);
      isPrimitive = true;
      break;
    }

    case DMessage.kBooleanType: {
      int bval = msg.getByte();
      value = new Boolean((bval == 0) ? false : true);
      isPrimitive = true;
      break;
    }

    case DMessage.kStringType: {
      String s = msg.getString();

      value = s;
      isPrimitive = true;
      break;
    }

    case DMessage.kObjectType:
    case DMessage.kNamespaceType: {
      long oid = msg.getPtr();
      long cType = (oid == -1) ? 0 : msg.getDWord();
      int isFnc = (oid == -1) ? 0 : msg.getWord();
      int rsvd = (oid == -1) ? 0 : msg.getWord();
      typeName = (oid == -1) ? "" : msg.getString(); //$NON-NLS-1$
      /* anirudhs: Date fix for expression evaluation */
      /* Player 10.2 onwards, the typename for Date comes
       * as <dateformat>@oid where example of date format is:
       * <Tue Feb 7 15:41:16 GMT+0530 2012>
       * We have to fix the typename to how it originally
       * appeared prior to this bug which is Date@oid.
       * Note that even player 9 did not send oType as 11,
       * instead oType was Object where as typeName was Date.
       * What the customer sees is expression evaluation will
       * always try to interpret date as a number. (ECMA.defaultValue
       * has a check for preferredType of Date to be String)
       */
      if (typeName.startsWith("<")) { //$NON-NLS-1$
        int atIndex = typeName.indexOf('@');
        String dateVal = typeName;
        if (atIndex > -1) {
          dateVal = typeName.substring(0, atIndex);
        }
        SimpleDateFormat dFormat = new SimpleDateFormat("<EEE MMM d HH:mm:ss 'GMT'z yyyy>"); //$NON-NLS-1$
        try {
          Date dateObj = dFormat.parse(dateVal);
          if (dateObj != null && dateObj.getTime() != 0) {
            oType = DMessage.kDateType;
            typeName = "Date" + typeName.substring(atIndex); //$NON-NLS-1$
          }
        }
        catch (ParseException e) {
          //ignore
        }
      }
     
      className = DVariable.classNameFor(cType, false);
      value = new Long(oid);
      vType = (isFnc == 0) ? VariableType.OBJECT : VariableType.FUNCTION;
      break;
    }

    case DMessage.kMovieClipType: {
      long oid = msg.getPtr();
      long cType = (oid == -1) ? 0 : msg.getDWord();
      long rsvd = (oid == -1) ? 0 : msg.getDWord();
      typeName = (oid == -1) ? "" : msg.getString(); //$NON-NLS-1$
      className = DVariable.classNameFor(cType, true);

      value = new Long(oid);
      vType = VariableType.MOVIECLIP;
      break;
    }

    case DMessage.kNullType: {
      value = null;
      isPrimitive = true;
      break;
    }

    case DMessage.kUndefinedType: {
      value = Value.UNDEFINED;
      isPrimitive = true;
      break;
    }

    case DMessage.kTraitsType: {
      // This one is special: When passed to the debugger, it indicates
      // that the "variable" is not a variable at all, but rather is a
      // class name. For example, if class Y extends class X, then
      // we will send a kDTypeTraits for class Y; then we'll send all the
      // members of class Y; then we'll send a kDTypeTraits for class X;
      // and then we'll send all the members of class X. This is only
      // used by the AVM+ debugger.
      vType = VariableType.UNKNOWN;
      typeName = Value.TRAITS_TYPE_NAME;
      break;
    }

    case DMessage.kReferenceType:
    case DMessage.kArrayType:
    case DMessage.kObjectEndType:
    case DMessage.kStrictArrayType:
    case DMessage.kDateType:
    case DMessage.kLongStringType:
    case DMessage.kUnsupportedType:
    case DMessage.kRecordSetType:
    case DMessage.kXMLType:
    case DMessage.kTypedObjectType:
    case DMessage.kAvmPlusObjectType:
    default: {
      // System.out.println("<unknown>");
      break;
    }
    }
    int isolateId = msg.getTargetIsolate();
    // create the variable based on the content we received.
    DValue valueObject = null;

    // If value is a Long, then it is the ID of a non-primitive object;
    // look up to see if we already have that object in our cache. If
    // it is already in our cache, then we just want to modify the
    // existing object with the new values.
    if (value instanceof Long) {
      valueObject = getValue(((Long) value).longValue(), isolateId);
    }

    if (valueObject == null) {
      // we didn't find it in the cache, so make a new Value

      if (isPrimitive) {
        valueObject = DValue.forPrimitive(value, isolateId);
        valueObject.setAttributes(toAttributes(flags));
      } else {
        valueObject = new DValue(vType, typeName, className,
            toAttributes(flags), value, isolateId);
      }

      if (value instanceof Long
          && (toAttributes(flags) & VariableAttribute.HAS_GETTER) == 0)
        putValue(((Long) value).longValue(), valueObject, isolateId);
    } else {
      // we found it in the cache, so just modify the properties
      // of the old Value

      if (isPrimitive) {
        // figure out some of the properties
        DValue temp = DValue.forPrimitive(value, isolateId);
        vType = temp.getType();
        typeName = temp.getTypeName();
        className = temp.getClassName();
      }

      valueObject.setType(vType);
      valueObject.setTypeName(typeName);
      valueObject.setClassName(className);
      valueObject.setAttributes(toAttributes(flags));
      valueObject.setValue(value);
    }
    if (valueObject != null) {
      valueObject.setIsolateId(isolateId);
    }
    DVariable var = new DVariable(name, valueObject, isolateId);
    return var;
  }

  /**
   * The player sends us a URI using '|' instead of ':'
   */
  public static String convertToURI(String playerURL) {
    int index = playerURL.indexOf('|');
    StringBuilder sb = new StringBuilder(playerURL);
    while (index > 0) {
      sb.setCharAt(index, ':');
      index = playerURL.indexOf('|', index + 1);
    }
    return sb.toString();
  }

  /**
   * Tell us that we are about to start executing user code in the player,
   * such as a getter, a setter, or a function call. If a FaultEvent comes in
   * while the code is executing, it is not added to the event queue in the
   * normal way -- instead, it is saved, and is returned when
   * endPlayerCodeExecution() is called.
   */
  public void beginPlayerCodeExecution(int isolateId) {
    DManagerIsolateState state = getIsolateState(isolateId);
    state.m_executingPlayerCode = true;
    state.m_faultEventDuringPlayerCodeExecution = null;
  }

  /**
   * Informs us that user code is no longer executing, and returns the fault,
   * if any, which occurred while the code was executing.
   */
  public FaultEvent endPlayerCodeExecution(int isolateId) {
    DManagerIsolateState state = getIsolateState(isolateId);
    state.m_executingPlayerCode = false;
    FaultEvent e = state.m_faultEventDuringPlayerCodeExecution;
    state.m_faultEventDuringPlayerCodeExecution = null;
    return e;
  }

  /**
   * When we've just received any FaultEvent from the player, this function
   * gets called. If a getter/setter is currently executing, we'll save the
   * fault for someone to get later by calling endGetterSetter(). Otherwise,
   * normal code execution is taking place, so we'll add the event to the
   * event queue.
   */
  private void handleFaultEvent(FaultEvent faultEvent) {
    DManagerIsolateState isolateState = getIsolateState(faultEvent.isolateId);
    boolean executingPlayerCode = isolateState.m_executingPlayerCode;
    if (executingPlayerCode) {
      FaultEvent faultEventDuringPlayerCodeExecution = isolateState.m_faultEventDuringPlayerCodeExecution;
     
      if (faultEventDuringPlayerCodeExecution == null) // only save the
                                // first fault
      {
        // save the event away so that when someone later calls
        // endGetterSetter(), we can return the fault that
        // occurred
        isolateState.m_faultEventDuringPlayerCodeExecution = faultEvent;
      }
    } else {
      // regular code is running; so post the event to the
      // event queue which the client debugger will see
      addEvent(faultEvent);
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see flash.tools.debugger.SourceLocator#locateSource(java.lang.String,
   * java.lang.String, java.lang.String)
   */
  public InputStream locateSource(String path, String pkg, String name) {
    if (m_sourceLocator != null)
      return m_sourceLocator.locateSource(path, pkg, name);

    return null;
  }

  /*
   * (non-Javadoc)
   *
   * @see flash.tools.debugger.SourceLocator#getChangeCount()
   */
  public int getChangeCount() {
    if (m_sourceLocator != null)
      return m_sourceLocator.getChangeCount();

    return 0;
  }

  /**
   * Returns the value of a Flash Player 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) {
    return m_options.get(optionName);
  }
}
TOP

Related Classes of flash.tools.debugger.concrete.DManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.