/* * @see Flash.Tools.Debugger.Session#setScalarMember(int, java.lang.String, int, java.lang.String) */ public virtual FaultEvent setValue(int type, String value) { FaultEvent fault = null; if (m_session != null && m_session is PlayerSession) { fault = ((PlayerSession)m_session).setScalarMember(m_nonProtoParentId, m_rawName, type, value); if (fault == null) { m_firedGetter = false; if (!needsToInvokeGetter()) { DValue debugValue = m_value as DValue; if (debugValue.getType() == VariableType.BOOLEAN) { debugValue.Value = value.ToLower() == "true"; } else if (debugValue.getType() == VariableType.NUMBER) { debugValue.Value = Double.Parse(value); } else if (debugValue.getType() == VariableType.STRING) { debugValue.Value = value; } } } } return(fault); }
/// <summary> Create a variable and its value. /// /// </summary> /// <param name="name">the name of the variable within the context of its parent. For example, /// when resolving member "bar" of object "foo", the name will be "bar". /// </param> /// <param name="value">the variable's value. /// </param> public DVariable(String name, DValue value) { m_rawName = name; // If the name contains "::", then the name is of the form "namespace::name" if (name != null) { int doubleColon = name.LastIndexOf("::"); //$NON-NLS-1$ if (doubleColon >= 0) { m_namespace = name.Substring(0, (doubleColon) - (0)); int at = m_namespace.IndexOf('@'); if (at != -1) { m_namespace = m_namespace.Substring(0, (at) - (0)); } name = name.Substring(doubleColon + 2); } } m_name = name; m_attribs = value.getAttributes(); m_nonProtoParentId = Value.UNKNOWN_ID; m_value = value; }
public virtual void addMember(DVariable v) { if (m_members == null) { m_members = new System.Collections.Hashtable(); } // if we are a proto member house away our original parent id String name = v.getName(); DValue val = (DValue)v.getValue(); val.m_nonProtoId = (name != null && name.Equals("__proto__"))?m_nonProtoId:val.Id; //$NON-NLS-1$ // TODO is this right? v.m_nonProtoParentId = m_nonProtoId; m_members[name] = v; }
/// <summary> Create a variable and its value. /// /// </summary> /// <param name="name">the name of the variable within the context of its parent. For example, /// when resolving member "bar" of object "foo", the name will be "bar". /// </param> /// <param name="value">the variable's value. /// </param> public DVariable(String name, DValue value) { m_rawName = name; // If the name contains "::", then the name is of the form "namespace::name" if (name != null) { int doubleColon = name.LastIndexOf("::"); //$NON-NLS-1$ if (doubleColon >= 0) { m_namespace = name.Substring(0, (doubleColon) - (0)); int at = m_namespace.IndexOf('@'); if (at != - 1) m_namespace = m_namespace.Substring(0, (at) - (0)); name = name.Substring(doubleColon + 2); } } m_name = name; m_attribs = value.getAttributes(); m_nonProtoParentId = Value.UNKNOWN_ID; m_value = value; }
/// <summary> Get the value of the variable named 'name' using varId /// as the context id for the Variable. /// /// This call is used to fire getters, where the id must /// be that of the original object and not the object id /// of where the getter actually lives. For example /// a getter a() may live under o.__proto__.__proto__ /// but you must use the id of o and the name of 'a' /// in order for the getter to fire correctly. [Note: This /// paragraph was written for AS2; __proto__ doesn't exist /// in AS3. TODO: revise this paragraph] /// </summary> public virtual Value getValue(int varId, String name) { Value v = null; if (Suspended) { int fireGetter = getPreference(SessionManager.PREF_INVOKE_GETTERS); // disable children attaching to parent variables and clear our // most recently seen variable m_manager.clearLastVariable(); m_manager.enableChildAttach(false); try { requestVariable(varId, name, (fireGetter != 0), false); v = m_manager.lastVariable().getValue(); } catch (NoResponseException e) { if (fireGetter != 0) { // We fired a getter -- most likely, what happened is that that getter // (which is actual code in the user's movie) just took too long to // calculate its value. So rather than throwing an exception, we store // some error text for the value of the variable itself. // // TODO [mmorearty 4/20/06] Even though I wrote the below code, I now // am wondering if it is incorrect that I am calling addVariableMember(), // because in every other case, this function does not add members to // existing objects. Need to revisit this. v = new DValue(VariableType.STRING, "String", "String", ValueAttribute.IS_EXCEPTION, e.getLocalizedMessage()); DVariable var = new DVariable(name, (DValue) v); m_manager.enableChildAttach(true); m_manager.addVariableMember(varId, var); } else { throw e; // re-throw } } finally { // reset our attach flag, so that children attach to parent variables. m_manager.enableChildAttach(true); } } else throw new NotSuspendedException(); return v; }
/// <summary> 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. /// </summary> private void mapOldFramesToNew() { int oldSize = m_previousFrames.Count; int newSize = m_frames.Count; // 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) m_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 = (DStackContext) m_previousFrames[oldDepth]; DStackContext newFrame = (DStackContext) m_frames[newDepth]; if (oldFrame != null && newFrame != null) { if (stringsEqual(oldFrame.CallSignature, newFrame.CallSignature)) { DValue frame = oldFrames[oldDepth]; if (frame != null) m_previousValues.put(Value.BASE_ID - newDepth, frame); } } oldDepth--; newDepth--; } }
internal virtual void addVariableMember(DValue parent, DVariable child) { if (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. DVariable existingChildWithSameName = parent.findMember(child.getName()); if (existingChildWithSameName != null) { int existingScope = existingChildWithSameName.Scope; int newScope = child.Scope; 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 { parent.addMember(child); } // put child in the registry if it has an id and not already there DValue childValue = (DValue) child.getValue(); int childId = childValue.Id; if (childId != Value.UNKNOWN_ID) { DValue existingValue = getValue(childId); if (existingValue != null) { Debug.Assert(existingValue == childValue); // TODO is this right? what about getters? } else { putValue(childId, childValue); } } } }
internal virtual void putValue(long id, DValue v) { if (id != Value.UNKNOWN_ID) { m_values.put((int) id, v); } }
/// <summary> Variables</summary> internal virtual DValue getOrCreateValue(long id) { DValue v = getValue(id); if (v == null) { v = new DValue(id); putValue(id, v); } return v; }
/// <summary> Does the job of pulling together a variable based on /// the type of object encountered. /// </summary> internal virtual 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$ /* now we vary depending upon type */ switch (oType) { case DMessage.kNumberType: { String s = msg.getString(); double dval = 0; try { System.Globalization.NumberFormatInfo nfi = new System.Globalization.NumberFormatInfo(); dval = Double.Parse(s, nfi); } catch (FormatException) { } value = (double) dval; vType = VariableType.NUMBER; typeName = "Number"; //$NON-NLS-1$ break; } case DMessage.kBooleanType: { int bval = msg.getByte(); value = (bval == 0)?false:true; vType = VariableType.BOOLEAN; typeName = "Boolean"; //$NON-NLS-1$ break; } case DMessage.kStringType: { String s = msg.getString(); value = s; vType = VariableType.STRING; typeName = "String"; //$NON-NLS-1$ break; } case DMessage.kObjectType: case DMessage.kNamespaceType: { long oid = msg.getDWord(); 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$ className = DVariable.classNameFor(cType, false); value = (long) oid; vType = (isFnc == 0)?VariableType.OBJECT:VariableType.FUNCTION; break; } case DMessage.kMovieClipType: { long oid = msg.getDWord(); 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 = (long) oid; vType = VariableType.MOVIECLIP; break; } case DMessage.kNullType: { vType = VariableType.NULL; typeName = "null"; //$NON-NLS-1$ break; } case DMessage.kUndefinedType: { vType = VariableType.UNDEFINED; typeName = "undefined"; //$NON-NLS-1$ 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; } } // create the variable based on the content we received. DValue valueObject = null; if (value is Int64) { valueObject = getValue((long) ((Int64) value)); } if (valueObject == null) { valueObject = new DValue(vType, typeName, className, toAttributes(flags), value); if (value is Int64 && (toAttributes(flags) & VariableAttribute.HAS_GETTER) == 0) putValue((long) ((Int64) value), valueObject); } else { valueObject.setType(vType); valueObject.setTypeName(typeName); valueObject.setClassName(className); valueObject.setAttributes(toAttributes(flags)); valueObject.Value = value; } DVariable var = new DVariable(name, valueObject); return var; }
/// <summary> 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. /// </summary> internal virtual void populateRootNode(DValue frame, System.Collections.ArrayList orderedChildList) { // first populate the stack node with children populateFrame(0, orderedChildList); /* * 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_Renamed = getOrCreateValue(Value.BASE_ID); base_Renamed.MembersObtained = 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 }