You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by ah...@apache.org on 2016/04/26 06:29:12 UTC
[20/63] [abbrv] [partial] git commit: [flex-falcon]
[refs/heads/develop] - move stuff to where I think Maven wants it
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flash/tools/debugger/concrete/DLocation.java
----------------------------------------------------------------------
diff --git a/debugger/src/main/java/flash/tools/debugger/concrete/DLocation.java b/debugger/src/main/java/flash/tools/debugger/concrete/DLocation.java
new file mode 100644
index 0000000..01c5ab3
--- /dev/null
+++ b/debugger/src/main/java/flash/tools/debugger/concrete/DLocation.java
@@ -0,0 +1,73 @@
+/*
+ * 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 flash.tools.debugger.Location;
+import flash.tools.debugger.SourceFile;
+
+public class DLocation implements Location
+{
+ SourceFile m_source;
+ int m_line;
+ int m_isolateId;
+ boolean m_removed;
+
+ DLocation(SourceFile src, int line, int isolateId)
+ {
+ m_source = src;
+ m_line = line;
+ m_removed = false;
+ m_isolateId = isolateId;
+ }
+
+ /* getters/setters */
+ public SourceFile getFile() { return m_source; }
+ public int getLine() { return m_line; }
+ public boolean isRemoved() { return m_removed; }
+ public void setRemoved(boolean removed) { m_removed = removed; }
+
+ public int getId() { return encodeId(getFile().getId(), getLine()); }
+
+ /* encode /decode */
+ public static final int encodeId(int fileId, int line)
+ {
+ return ( (line << 16) | fileId );
+ }
+
+ public static final int decodeFile(long id)
+ {
+ return (int)(id & 0xffff);
+ }
+
+ public static final int decodeLine(long id)
+ {
+ return (int)(id >> 16 & 0xffff);
+ }
+
+ /** for debugging */
+ @Override
+ public String toString()
+ {
+ return m_source.toString() + ":" + m_line; //$NON-NLS-1$
+ }
+
+ @Override
+ public int getIsolateId() {
+ return m_isolateId;
+ }
+}
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flash/tools/debugger/concrete/DManager.java
----------------------------------------------------------------------
diff --git a/debugger/src/main/java/flash/tools/debugger/concrete/DManager.java b/debugger/src/main/java/flash/tools/debugger/concrete/DManager.java
new file mode 100644
index 0000000..a8b1c8a
--- /dev/null
+++ b/debugger/src/main/java/flash/tools/debugger/concrete/DManager.java
@@ -0,0 +1,2583 @@
+/*
+ * 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);
+ }
+}