module: dm-internals synopsis: Functions for low-level access to the layout of dylan objects. author: Paul Howard Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND ///// READ-DYLAN-VALUE // Wraps up read-value from access path. Handles the access-violation // condition. // TODO: Check page protection on the address. If the page is guarded, // the value must be read within the context of the application // via a function in the spy. define variable success = #f; define variable val = as-remote-value(0); define method read-dylan-value (ap :: , address :: ) => (v :: , ok :: ) success := #f; val := as-remote-value(0); block () val := read-value (ap.debug-target-access-path, address); success := #t; exception (x :: ) val := as-remote-value(0); success := #f; end block; values (val, success); end method; ///// READ-INSTANCE-HEADER // Given an instance of any dylan object, read the header field and // return it as a remote value. "ok" determines whether the read was // successful. define method read-instance-header (ap :: , object :: ) => (v :: , ok :: ) read-dylan-value (ap, indexed-remote-value (object, 0)); end method; ///// READ-INSTANCE-SLOT-ELEMENT // Given an instance of any dylan object, return the i'th slot value // as a define method read-instance-slot-element (ap :: , object :: , i :: ) => (v :: , ok :: ) read-dylan-value (ap, indexed-remote-value (object, i + 1)); end method; ///// WRAPPER-TO-CLASS // Given an instance of a wrapper, find the class and return it as // a . define method wrapper-to-class (ap :: , wrapper :: ) => (c :: , ok :: ) read-instance-slot-element (ap, wrapper, 0) end method; ///// GET-METHOD-SPECIALIZERS // Given a (remote) instance of , return the vector of specializers // as a . define method get-method-specializers (ap :: , method-object :: ) => (s :: , ok :: ) let (siggy, ok) = read-instance-slot-element (ap, method-object, 1); if (ok) let (required-args, ok2) = read-instance-slot-element (ap, siggy, 0); if (ok2) values (required-args, #t) else values (as-remote-value(0), #f) end if else values (as-remote-value(0), #f) end if end method; ///// METHOD-IEP // Given an instance of , return the method's IEP // as a . define method method-iep (ap :: , method-object :: ) => (iep :: , ok :: ) read-instance-slot-element (ap, method-object, 3); end method; ///// GF-METHODS // Given a remote instance of , returns the vector // of methods as a define method gf-methods (ap :: , gf :: ) => (m :: , ok :: ) read-instance-slot-element (ap, gf, 6); end method; ///// DYLAN-INTEGER-DATA // Untag a dylan integer and return it as an actual define method dylan-integer-data (ap :: , integer-instance :: ) => (i :: ) tagged-remote-value-as-integer (integer-instance) end method; ///// DYLAN-CHARACTER-DATA // Untag a dylan character and return it as an actual define method dylan-character-data (ap :: , character-instance :: ) => (c :: ) tagged-remote-value-as-character (character-instance) end method; ///// DYLAN-VECTOR-SIZE // Given a simple-object-vector instance, return its size as an integer. define method dylan-vector-size (ap :: , sov-instance :: ) => (i :: ) let (size, ok) = read-instance-slot-element (ap, sov-instance, 0); if (ok) tagged-remote-value-as-integer(size); else 0; end if; end method; ///// DYLAN-VECTOR-ELEMENT // Given a simple-object-vector instance and an index, return the // appropriate vector element as a define method dylan-vector-element (ap :: , sov-instance :: , i :: ) => (v :: ) let (slot, ok) = read-instance-slot-element (ap, sov-instance, i + 1); if (ok) slot; else as-remote-value(0); end if end method; ///// DYLAN-HEAD // Given an instance of a dylan pair, return the first element as a // define method dylan-head (ap :: , pair :: ) => (val :: ) let (hd, ok) = read-instance-slot-element (ap, pair, 0); if (ok) hd; else as-remote-value(0); end if end method; ///// DYLAN-TAIL // Given an instance of a dylan pair, return the second element as a // define method dylan-tail (ap :: , pair :: ) => (val :: ) let (tl, ok) = read-instance-slot-element (ap, pair, 1); if (ok) tl; else as-remote-value(0); end if end method; ///// DYLAN-CLASS-NON-CLASS-DESCRIPTORS // What a bloody strange name... // Given a class instance, this returns an instance which shoul be a simple- // object-vector of slot descriptors. define method dylan-class-non-class-descriptors (ap :: , class-object :: ) => (val :: ) let (descrs, ok) = read-instance-slot-element (ap, class-object, 15); if (ok) descrs; else as-remote-value(0); end if end method; ///// DYLAN-CLASS-DIRECT-SUPERCLASSES // What a bloody strange name... // Given a class instance, this returns an instance which should be a // vector of direct superclasses. define method dylan-class-direct-superclasses (ap :: , class-object :: ) => (val :: ) let (sups, ok) = read-instance-slot-element (ap, class-object, 1); if (ok) sups; else as-remote-value(0); end if end method; ///// DYLAN-CLASS-ALL-SUPERCLASSES // Given a class instance, this returns an instance which should be a // sequence of superclasses define method dylan-class-all-superclasses (ap :: , class-object :: ) => (val :: ) let (sups, ok) = read-instance-slot-element (ap, class-object, 2); if (ok) sups; else as-remote-value(0); end if end method; ///// DYLAN-CLASS-MM-WRAPPER // Given a class instance, this returns the wrapper that direct // instances of the class will posess. define method dylan-class-mm-wrapper (ap :: , class-object :: ) => (val :: ) let (wrapper, ok) = read-instance-slot-element (ap, class-object, 12); if (ok) wrapper; else as-remote-value(0); end if end method; ///// DYLAN-CLASS-REPEATED-SLOT-DESCRIPTOR // Given a class instance, returns the repeated slot descriptor. define method dylan-class-repeated-slot-descriptor (ap :: , class-object :: ) => (val :: ) let (descr, ok) = read-instance-slot-element (ap, class-object, 14); if (ok) descr; else as-remote-value(0); end if end method; ///// DYLAN-SLOT-GETTER // Given a slot descriptor instance, returns the "getter" object, presumably // of type . define method dylan-slot-getter (ap :: , slot-descriptor :: ) => (getter-function :: ) let (getter, ok) = read-instance-slot-element (ap, slot-descriptor, 7); if (ok) getter; else as-remote-value(0); end if end method; ///// DYLAN-STRING-DATA // Given a instance, returns a local copy. define method dylan-string-data (ap :: , string-instance :: ) => (val :: ) let (size, ok) = read-instance-slot-element (ap, string-instance, 0); size := tagged-remote-value-as-integer(size); if (ok) read-byte-string (ap.debug-target-access-path, indexed-remote-value (string-instance, 2), size); else ""; end if; end method; ///// DYLAN-HANDLER-TYPE // Given a remote instance, returns a remote instance. define method dylan-handler-type (application :: , handler-instance :: ) => (type-instance :: ) let (type-val, ok) = read-instance-slot-element(application, handler-instance, 0); if (ok) type-val; else as-remote-value(0); end if end method; ///// DYLAN-HANDLER-FUNCTION // Given a remote instance, returns a remote instance. define method dylan-handler-function (application :: , handler-instance :: ) => (function-instance :: ) let (function-val, ok) = read-instance-slot-element(application, handler-instance, 1); if (ok) function-val; else as-remote-value(0); end if end method; ///// DYLAN-HANDLER-TEST // Given a remote instance, returns a remote instance. define method dylan-handler-test (application :: , handler-instance :: ) => (test-instance :: ) let (test-val, ok) = read-instance-slot-element(application, handler-instance, 2); if (ok) test-val; else as-remote-value(0); end if end method; ///// DYLAN-HANDLER-INIT-ARGUMENTS // Given a remote instance, returns a remote instance. define method dylan-handler-init-arguments (application :: , handler-instance :: ) => (vector-instance :: ) let (vector-val, ok) = read-instance-slot-element(application, handler-instance, 3); if (ok) vector-val; else as-remote-value(0); end if end method; ///// DYLAN-THREAD-NAME // Given a remote instance, returns the name of the thread // as a define method dylan-thread-name (application :: , thread-instance :: ) => (string-instance :: ) let (string-instance, ok) = read-instance-slot-element(application, thread-instance, 3); if (ok) string-instance; else as-remote-value(0); end if end method; ///// DYLAN-SIMPLE-CONDITION-FORMAT-STRING // Given a remote instance, returns a remote define method dylan-simple-condition-format-string (application :: , condition-instance :: ) => (string-instance :: ) let (string-val, ok) = read-instance-slot-element(application, condition-instance, 0); if (ok) string-val; else as-remote-value(0); end if; end method; ///// DYLAN-SIMPLE-CONDITION-FORMAT-ARGUMENTS // Given a remote instance, returns a remote define method dylan-simple-condition-format-arguments (application :: , condition-instance :: ) => (vector-instance :: ) let (vector-val, ok) = read-instance-slot-element(application, condition-instance, 1); if (ok) vector-val; else as-remote-value(0); end if; end method; ///// DYLAN-SINGLE-FLOAT-DATA // Given a single-float instance, returns a local copy. define method dylan-single-float-data (ap :: , float-instance :: ) => (val :: ) let x :: = 0.0; // block () x := read-single-float (ap.debug-target-access-path, indexed-remote-value (float-instance, 1)); // exception (pants :: ) // x := 0.0; // end block; x; end method; ///// DYLAN-OBJECT? // Returns #t if the supplied instance looks like a dylan object. // Strategy: If the object is tagged as an integer or character, then // it is a dylan object. Otherwise, it is treated as a pointer to // a dylan object, which should have a header pointing to a valid // wrapper... define method dylan-object? (ap :: , instance :: ) => (val :: ) let integer-representation = as-integer(instance); if (logand (integer-representation, 3) > 0) // This instance has a tag. if (logand (integer-representation, 1) > 0) // Integer instance #t elseif (logand (integer-representation, 2) > 0) // Character instance #t else // I think this can't happen!!! #f end if else // This is an untagged instance. // If it's a dylan object, it's header should point to a wrapper, and the // header of the wrapper should point back to itself. This algorithm // tests for this, returning false if any reads fail. let (wrapper, ok1) = read-instance-header (ap, instance); if (ok1) let (wrapper-wrapper, ok2) = read-instance-header (ap, wrapper); if (ok2) let (wrapper-wrapper-header, ok3) = read-instance-header (ap, wrapper-wrapper); if ((ok3) & (wrapper-wrapper = wrapper-wrapper-header)) #t else #f end if else #f end if else #f end if end if end method; ///// DYLAN-INSTANCE-SYMBOLIC-NAME // Given any direct (but untagged) instance, this attempts to find a // name in the symbol table whose definition points to this object. define method dylan-instance-symbolic-name (ap :: , untagged-instance :: ) => (lib :: , mod :: , name :: ) let (closest, offset) = symbol-relative-address(ap.debug-target-access-path, untagged-instance); if (closest) demangle-qualified-name(closest.remote-symbol-name) else values ("pants", "poo", "nothing"); end if end method; ///// DYLAN-SLOT-NAME // Given a corresponding to a dylan slot descriptor, returns // the name of the slot if it can be found. define method dylan-slot-name (ap :: , slot-descriptor :: ) => (name :: ) let (lib, mod, nm) = dylan-instance-symbolic-name (ap, dylan-slot-getter (ap, slot-descriptor)); nm; end method; ///// DYLAN-SYMBOL-NAME // Given a remote instance of , returns a remote instance of // naming the symbol. define method dylan-symbol-name (ap :: , sym :: ) => (name :: , ok :: ) read-instance-slot-element (ap, sym, 0); end method; ///// DYLAN-SINGLETON-OBJECT // Given a remote instance of , returns a remote instance of // that the singleton type represents. define method dylan-singleton-object (application :: , single :: ) => (remote-instance :: , ok :: ) read-instance-slot-element(application, single, 0); end method; ///// DYLAN-MACHINE-WORD-DATA // Given a remote instance of , returns the // that holds it. define method dylan-machine-word-data (application :: , mw :: ) => (remote-word :: , ok :: ) read-instance-slot-element(application, mw, 0); end method; ///// DYLAN-STRETCHY-VECTOR-REPRESENTATION // Given a stretchy vector representation instance, returns the filled // size of the stretchy vector define method dylan-stretchy-vector-representation (ap :: , svec-instance :: ) => (rep :: ) svec-instance; end method; ///// DYLAN-STRETCHY-VECTOR-SIZE // Given a stretchy vector representation instance, returns the filled // size of the stretchy vector define method dylan-stretchy-vector-size (ap :: , svr-instance :: ) => (i :: ) let (size, ok) = read-instance-slot-element (ap, svr-instance, 0); if (ok) tagged-remote-value-as-integer(size); else 0; end if; end method; ///// DYLAN-STRETCHY-VECTOR-ELEMENT // Given a stretchy-vector-representation instance and an index, return the // appropriate vector element as a define method dylan-stretchy-vector-element (ap :: , svr-instance :: , i :: ) => (v :: ) let (vec, ok) = read-instance-slot-element (ap, svr-instance, 1); if (ok) dylan-vector-element(ap, vec, i); else as-remote-value(0); end if end method; ///// DYLAN-TABLE-VECTOR // Given a remote instance of , returns the appropriate // instance. define method dylan-table-vector (application :: , table-instance :: ) => (table-vector :: ) let (slot, ok) = read-instance-slot-element(application, table-instance, 0); if (ok) slot else as-remote-value(0); end if end method; ///// DYLAN-TABLE-KEYS-VECTOR // Given a remote instance of
, returns the vector instance that // holds the keys. define method dylan-table-keys-vector (application :: , table-instance :: ) => (keys-vector :: ) let table-vector = dylan-table-vector(application, table-instance); if (table-vector = as-remote-value(0)) table-vector else let (slot, ok) = read-instance-slot-element(application, table-vector, 9); if (ok) slot else as-remote-value(0) end if end if end method; ///// DYLAN-TABLE-VALUES-VECTOR // Given a remote instance of
, returns the vector instance that // holds the values. define method dylan-table-values-vector (application :: , table-instance :: ) => (keys-vector :: ) let table-vector = dylan-table-vector(application, table-instance); if (table-vector = as-remote-value(0)) table-vector else let (slot, ok) = read-instance-slot-element(application, table-vector, 10); if (ok) slot else as-remote-value(0) end if end if end method;