michael@0: # Debugger.Object michael@0: michael@0: A `Debugger.Object` instance represents an object in the debuggee, michael@0: providing reflection-oriented methods to inspect and modify its referent. michael@0: The referent's properties do not appear directly as properties of the michael@0: `Debugger.Object` instance; the debugger can access them only through michael@0: methods like `Debugger.Object.prototype.getOwnPropertyDescriptor` and michael@0: `Debugger.Object.prototype.defineProperty`, ensuring that the debugger will michael@0: not inadvertently invoke the referent's getters and setters. michael@0: michael@0: SpiderMonkey creates exactly one `Debugger.Object` instance for each michael@0: debuggee object it presents to a given [`Debugger`][debugger-object] michael@0: instance: if the debugger encounters the same object through two different michael@0: routes (perhaps two functions are called on the same object), SpiderMonkey michael@0: presents the same `Debugger.Object` instance to the debugger each time. michael@0: This means that the debugger can use the `==` operator to recognize when michael@0: two `Debugger.Object` instances refer to the same debuggee object, and michael@0: place its own properties on a `Debugger.Object` instance to store metadata michael@0: about particular debuggee objects. michael@0: michael@0: JavaScript code in different compartments can have different views of the michael@0: same object. For example, in Firefox, code in privileged compartments sees michael@0: content DOM element objects without redefinitions or extensions made to michael@0: that object's properties by content code. (In Firefox terminology, michael@0: privileged code sees the element through an "xray wrapper".) To ensure that michael@0: debugger code sees each object just as the debuggee would, each michael@0: `Debugger.Object` instance presents its referent as it would be seen from a michael@0: particular compartment. This "viewing compartment" is chosen to match the michael@0: way the debugger came across the referent. As a consequence, a single michael@0: [`Debugger`][debugger-object] instance may actually have several michael@0: `Debugger.Object` instances: one for each compartment from which the michael@0: referent is viewed. michael@0: michael@0: If more than one [`Debugger`][debugger-object] instance is debugging the michael@0: same code, each [`Debugger`][debugger-object] gets a separate michael@0: `Debugger.Object` instance for a given object. This allows the code using michael@0: each [`Debugger`][debugger-object] instance to place whatever properties it michael@0: likes on its own `Debugger.Object` instances, without worrying about michael@0: interfering with other debuggers. michael@0: michael@0: While most `Debugger.Object` instances are created by SpiderMonkey in the michael@0: process of exposing debuggee's behavior and state to the debugger, the michael@0: debugger can use `Debugger.Object.prototype.makeDebuggeeValue` to create michael@0: `Debugger.Object` instances for given debuggee objects, or use michael@0: `Debugger.Object.prototype.copy` and `Debugger.Object.prototype.create` to michael@0: create new objects in debuggee compartments, allocated as if by particular michael@0: debuggee globals. michael@0: michael@0: `Debugger.Object` instances protect their referents from the garbage michael@0: collector; as long as the `Debugger.Object` instance is live, the referent michael@0: remains live. This means that garbage collection has no visible effect on michael@0: `Debugger.Object` instances. michael@0: michael@0: michael@0: ## Accessor Properties of the Debugger.Object prototype michael@0: michael@0: A `Debugger.Object` instance inherits the following accessor properties michael@0: from its prototype: michael@0: michael@0: `proto` michael@0: : The referent's prototype (as a new `Debugger.Object` instance), or michael@0: `null` if it has no prototype. michael@0: michael@0: `class` michael@0: : A string naming the ECMAScript `[[Class]]` of the referent. michael@0: michael@0: `callable` michael@0: : `true` if the referent is a callable object (such as a function or a michael@0: function proxy); false otherwise. michael@0: michael@0: `name` michael@0: : The name of the referent, if it is a named function. If the referent is michael@0: an anonymous function, or not a function at all, this is `undefined`. michael@0: michael@0: This accessor returns whatever name appeared after the `function` michael@0: keyword in the source code, regardless of whether the function is the michael@0: result of instantiating a function declaration (which binds the michael@0: function to its name in the enclosing scope) or evaluating a function michael@0: expression (which binds the function to its name only within the michael@0: function's body). michael@0: michael@0: `displayName` michael@0: : The referent's display name, if the referent is a function with a michael@0: display name. If the referent is not a function, or if it has no display michael@0: name, this is `undefined`. michael@0: michael@0: If a function has a given name, its display name is the same as its michael@0: given name. In this case, the `displayName` and `name` properties are michael@0: equal. michael@0: michael@0: If a function has no name, SpiderMonkey attempts to infer an appropriate michael@0: name for it given its context. For example: michael@0: michael@0: function f() {} // display name: f (the given name) michael@0: var g = function () {}; // display name: g michael@0: o.p = function () {}; // display name: o.p michael@0: var q = { michael@0: r: function () {} // display name: q.r michael@0: }; michael@0: michael@0: Note that the display name may not be a proper JavaScript identifier, michael@0: or even a proper expression: we attempt to find helpful names even when michael@0: the function is not immediately assigned as the value of some variable michael@0: or property. Thus, we use a/b to refer to michael@0: the b defined within a, and a< to michael@0: refer to a function that occurs somewhere within an expression that is michael@0: assigned to a. For example: michael@0: michael@0: function h() { michael@0: var i = function() {}; // display name: h/i michael@0: f(function () {}); // display name: h/< michael@0: } michael@0: var s = f(function () {}); // display name: s< michael@0: michael@0: `parameterNames` michael@0: : If the referent is a debuggee function, the names of the its parameters, michael@0: as an array of strings. If the referent is not a debuggee function, or michael@0: not a function at all, this is `undefined`. michael@0: michael@0: If the referent is a host function for which parameter names are not michael@0: available, return an array with one element per parameter, each of which michael@0: is `undefined`. michael@0: michael@0: If the referent is a function proxy, return an empty array. michael@0: michael@0: If the referent uses destructuring parameters, then the array's elements michael@0: reflect the structure of the parameters. For example, if the referent is michael@0: a function declared in this way: michael@0: michael@0: function f(a, [b, c], {d, e:f}) { ... } michael@0: michael@0: then this `Debugger.Object` instance's `parameterNames` property would michael@0: have the value: michael@0: michael@0: ["a", ["b", "c"], {d:"d", e:"f"}] michael@0: michael@0: `script` michael@0: : If the referent is a function that is debuggee code, this is that michael@0: function's script, as a [`Debugger.Script`][script] instance. If the michael@0: referent is a function proxy or not debuggee code, this is `undefined`. michael@0: michael@0: `environment` michael@0: : If the referent is a function that is debuggee code, a michael@0: [`Debugger.Environment`][environment] instance representing the lexical michael@0: environment enclosing the function when it was created. If the referent michael@0: is a function proxy or not debuggee code, this is `undefined`. michael@0: michael@0: `proxyHandler` michael@0: : If the referent is a proxy whose handler object was allocated by michael@0: debuggee code, this is its handler object—the object whose methods are michael@0: invoked to implement accesses of the proxy's properties. If the referent michael@0: is not a proxy whose handler object was allocated by debuggee code, this michael@0: is `null`. michael@0: michael@0: `proxyCallTrap` michael@0: : If the referent is a function proxy whose handler object was allocated michael@0: by debuggee code, this is its call trap function—the function called michael@0: when the function proxy is called. If the referent is not a function michael@0: proxy whose handler object was allocated by debuggee code, this is michael@0: `null`. michael@0: michael@0: `proxyConstructTrap` michael@0: : If the referent is a function proxy whose handler object was allocated michael@0: by debuggee code, its construction trap function—the function called michael@0: when the function proxy is called via a `new` expression. If the michael@0: referent is not a function proxy whose handler object was allocated by michael@0: debuggee code, this is `null`. michael@0: michael@0: `global` michael@0: : A `Debugger.Object` instance referring to the global object in whose michael@0: scope the referent was allocated. This does not unwrap cross-compartment michael@0: wrappers: if the referent is a wrapper, the result refers to the michael@0: wrapper's global, not the wrapped object's global. The result refers to michael@0: the global directly, not via a wrapper. michael@0: michael@0: `hostAnnotations` michael@0: : A JavaScript object providing further metadata about the referent, or michael@0: `null` if none is available. The metadata object is in the same michael@0: compartment as this `Debugger.Object` instance. The same metadata michael@0: object is returned each time for a given `Debugger.Object` instance. michael@0: michael@0: A typical JavaScript embedding provides "host objects" to expose michael@0: application-specific functionality to scripts. The `hostAnnotations` michael@0: accessor consults the embedding for additional information about the michael@0: referent that might be of interest to the debugger. The returned michael@0: object's properties' meanings are up to the embedding. For example, a michael@0: web browser might provide host annotations for global objects to michael@0: distinguish top-level windows, iframes, and internal JavaScript scopes. michael@0: michael@0: By convention, host annotation objects have a string-valued `"type"` michael@0: property that, taken together with the object's class, indicate what michael@0: sort of thing the referent is. The host annotation object's other michael@0: properties provide further details, as appropriate for the type. For michael@0: example, in Firefox, a metadata object for a JavaScript Module's global michael@0: object might look like this: michael@0: michael@0: { "type":"jsm", "uri":"resource:://gre/modules/XPCOMUtils.jsm" } michael@0: michael@0: Firefox provides [DebuggerHostAnnotationsForFirefox annotations] for its michael@0: host objects. michael@0: michael@0: michael@0: michael@0: ## Function Properties of the Debugger.Object prototype michael@0: michael@0: The functions described below may only be called with a `this` value michael@0: referring to a `Debugger.Object` instance; they may not be used as methods michael@0: of other kinds of objects. The descriptions use "referent" to mean "the michael@0: referent of this `Debugger.Object` instance". michael@0: michael@0: Unless otherwise specified, these methods are not michael@0: [invocation functions][inv fr]; if a call would cause debuggee code to run michael@0: (say, because it gets or sets an accessor property whose handler is michael@0: debuggee code, or because the referent is a proxy whose traps are debuggee michael@0: code), the call throws a [`Debugger.DebuggeeWouldRun`][wouldrun] exception. michael@0: michael@0: getProperty(name) michael@0: : Return the value of the referent's property named name, or michael@0: `undefined` if it has no such property. Name must be a string. michael@0: The result is a debuggee value. michael@0: michael@0: setProperty(name, value) michael@0: : Store value as the value of the referent's property named michael@0: name, creating the property if it does not exist. Name michael@0: must be a string; value must be a debuggee value. michael@0: michael@0: getOwnPropertyDescriptor(name) michael@0: : Return a property descriptor for the property named name of the michael@0: referent. If the referent has no such property, return `undefined`. michael@0: (This function behaves like the standard michael@0: `Object.getOwnPropertyDescriptor` function, except that the object being michael@0: inspected is implicit; the property descriptor returned is allocated as michael@0: if by code scoped to the debugger's global object (and is thus in the michael@0: debugger's compartment); and its `value`, `get`, and `set` properties, michael@0: if present, are debuggee values.) michael@0: michael@0: `getOwnPropertyNames()` michael@0: : Return an array of strings naming all the referent's own properties, as michael@0: if Object.getOwnPropertyNames(referent) had been michael@0: called in the debuggee, and the result copied in the scope of the michael@0: debugger's global object. michael@0: michael@0: defineProperty(name, attributes) michael@0: : Define a property on the referent named name, as described by michael@0: the property descriptor descriptor. Any `value`, `get`, and michael@0: `set` properties of attributes must be debuggee values. (This michael@0: function behaves like `Object.defineProperty`, except that the target michael@0: object is implicit, and in a different compartment from the function michael@0: and descriptor.) michael@0: michael@0: defineProperties(properties) michael@0: : Add the properties given by properties to the referent. (This michael@0: function behaves like `Object.defineProperties`, except that the target michael@0: object is implicit, and in a different compartment from the michael@0: properties argument.) michael@0: michael@0: deleteProperty(name) michael@0: : Remove the referent's property named name. Return true if the michael@0: property was successfully removed, or if the referent has no such michael@0: property. Return false if the property is non-configurable. michael@0: michael@0: `seal()` michael@0: : Prevent properties from being added to or deleted from the referent. michael@0: Return this `Debugger.Object` instance. (This function behaves like the michael@0: standard `Object.seal` function, except that the object to be sealed is michael@0: implicit and in a different compartment from the caller.) michael@0: michael@0: `freeze()` michael@0: : Prevent properties from being added to or deleted from the referent, and michael@0: mark each property as non-writable. Return this `Debugger.Object` michael@0: instance. (This function behaves like the standard `Object.freeze` michael@0: function, except that the object to be sealed is implicit and in a michael@0: different compartment from the caller.) michael@0: michael@0: `preventExtensions()` michael@0: : Prevent properties from being added to the referent. (This function michael@0: behaves like the standard `Object.preventExtensions` function, except michael@0: that the object to operate on is implicit and in a different compartment michael@0: from the caller.) michael@0: michael@0: `isSealed()` michael@0: : Return true if the referent is sealed—that is, if it is not extensible, michael@0: and all its properties have been marked as non-configurable. (This michael@0: function behaves like the standard `Object.isSealed` function, except michael@0: that the object inspected is implicit and in a different compartment michael@0: from the caller.) michael@0: michael@0: `isFrozen()` michael@0: : Return true if the referent is frozen—that is, if it is not extensible, michael@0: and all its properties have been marked as non-configurable and michael@0: read-only. (This function behaves like the standard `Object.isFrozen` michael@0: function, except that the object inspected is implicit and in a michael@0: different compartment from the caller.) michael@0: michael@0: `isExtensible()` michael@0: : Return true if the referent is extensible—that is, if it can have new michael@0: properties defined on it. (This function behaves like the standard michael@0: `Object.isExtensible` function, except that the object inspected is michael@0: implicit and in a different compartment from the caller.) michael@0: michael@0: copy(value) michael@0: : Apply the HTML5 "structured cloning" algorithm to create a copy of michael@0: value in the referent's global object (and thus in the referent's michael@0: compartment), and return a `Debugger.Object` instance referring to the michael@0: copy. michael@0: michael@0: Note that this returns primitive values unchanged. This means you can michael@0: use `Debugger.Object.prototype.copy` as a generic "debugger value to michael@0: debuggee value" conversion function—within the limitations of the michael@0: "structured cloning" algorithm. michael@0: michael@0: create(prototype, [properties]) michael@0: : Create a new object in the referent's global (and thus in the michael@0: referent's compartment), and return a `Debugger.Object` referring to michael@0: it. The new object's prototype is prototype, which must be an michael@0: `Debugger.Object` instance. The new object's properties are as given by michael@0: properties, as if properties were passed to michael@0: `Debugger.Object.prototype.defineProperties`, with the new michael@0: `Debugger.Object` instance as the `this` value. michael@0: michael@0: makeDebuggeeValue(value) michael@0: : Return the debuggee value that represents value in the debuggee. michael@0: If value is a primitive, we return it unchanged; if value michael@0: is an object, we return the `Debugger.Object` instance representing michael@0: that object, wrapped appropriately for use in this `Debugger.Object`'s michael@0: referent's compartment. michael@0: michael@0: Note that, if value is an object, it need not be one allocated michael@0: in a debuggee global, nor even a debuggee compartment; it can be any michael@0: object the debugger wishes to use as a debuggee value. michael@0: michael@0: As described above, each `Debugger.Object` instance presents its michael@0: referent as viewed from a particular compartment. Given a michael@0: `Debugger.Object` instance d and an object o, the call michael@0: d.makeDebuggeeValue(o) returns a michael@0: `Debugger.Object` instance that presents o as it would be seen michael@0: by code in d's compartment. michael@0: michael@0: decompile([pretty]) michael@0: : If the referent is a function that is debuggee code, return the michael@0: JavaScript source code for a function definition equivalent to the michael@0: referent function in its effect and result, as a string. If michael@0: pretty is present and true, produce indented code with line michael@0: breaks. If the referent is not a function that is debuggee code, return michael@0: `undefined`. michael@0: michael@0: call(this, argument, ...) michael@0: : If the referent is callable, call it with the given this value michael@0: and argument values, and return a [completion value][cv] michael@0: describing how the call completed. This should be a debuggee michael@0: value, or `{ asConstructor: true }` to invoke the referent as a michael@0: constructor, in which case SpiderMonkey provides an appropriate `this` michael@0: value itself. Each argument must be a debuggee value. All extant michael@0: handler methods, breakpoints, watchpoints, and so on remain active michael@0: during the call. If the referent is not callable, throw a `TypeError`. michael@0: This function follows the [invocation function conventions][inv fr]. michael@0: michael@0: apply(this, arguments) michael@0: : If the referent is callable, call it with the given this value michael@0: and the argument values in arguments, and return a michael@0: [completion value][cv] describing how the call completed. This michael@0: should be a debuggee value, or `{ asConstructor: true }` to invoke michael@0: function as a constructor, in which case SpiderMonkey provides michael@0: an appropriate `this` value itself. Arguments must either be an michael@0: array (in the debugger) of debuggee values, or `null` or `undefined`, michael@0: which are treated as an empty array. All extant handler methods, michael@0: breakpoints, watchpoints, and so on remain active during the call. If michael@0: the referent is not callable, throw a `TypeError`. This function michael@0: follows the [invocation function conventions][inv fr]. michael@0: michael@0: evalInGlobal(code, [options]) michael@0: : If the referent is a global object, evaluate code in that global michael@0: environment, and return a [completion value][cv] describing how it completed. michael@0: Code is a string. All extant handler methods, breakpoints, michael@0: watchpoints, and so on remain active during the call. This function michael@0: follows the [invocation function conventions][inv fr]. michael@0: If the referent is not a global object, throw a `TypeError` exception. michael@0: michael@0: Code is interpreted as strict mode code when it contains a Use michael@0: Strict Directive. michael@0: michael@0: If code is not strict mode code, then variable declarations in michael@0: code affect the referent global object. (In the terms used by the michael@0: ECMAScript specification, the `VariableEnvironment` of the execution michael@0: context for the eval code is the referent.) michael@0: michael@0: The options argument is as for [`Debugger.Frame.prototype.eval`][fr eval]. michael@0: michael@0: evalInGlobalWithBindings(code, bindings, [options]) michael@0: : Like `evalInGlobal`, but evaluate code using the referent as the michael@0: variable object, but with a lexical environment extended with bindings michael@0: from the object bindings. For each own enumerable property of michael@0: bindings named name whose value is value, include a michael@0: variable in the lexical environment in which code is evaluated michael@0: named name, whose value is value. Each value must michael@0: be a debuggee value. (This is not like a `with` statement: code michael@0: may access, assign to, and delete the introduced bindings without having michael@0: any effect on the bindings object.) michael@0: michael@0: This method allows debugger code to introduce temporary bindings that michael@0: are visible to the given debuggee code and which refer to debugger-held michael@0: debuggee values, and do so without mutating any existing debuggee michael@0: environment. michael@0: michael@0: Note that, like `evalInGlobal`, if the code passed to michael@0: `evalInGlobalWithBindings` is not strict mode code, then any michael@0: declarations it contains affect the referent global object, even as michael@0: code is evaluated in an environment extended according to michael@0: bindings. (In the terms used by the ECMAScript specification, the michael@0: `VariableEnvironment` of the execution context for non-strict eval code michael@0: is the referent, and the bindings appear in a new declarative michael@0: environment, which is the eval code's `LexicalEnvironment`.) michael@0: michael@0: The options argument is as for [`Debugger.Frame.prototype.eval`][fr eval]. michael@0: michael@0: `asEnvironment()` michael@0: : If the referent is a global object, return the [`Debugger.Environment`][environment] michael@0: instance representing the referent as a variable environment for michael@0: evaluating code. If the referent is not a global object, throw a michael@0: `TypeError`. michael@0: michael@0: setObjectWatchpoint(handler) (future plan) michael@0: : Set a watchpoint on all the referent's own properties, reporting events michael@0: by calling handler's methods. Any previous watchpoint handler on michael@0: this `Debugger.Object` instance is replaced. If handler is null, michael@0: the referent is no longer watched. Handler may have the following michael@0: methods, called under the given circumstances: michael@0: michael@0: add(frame, name, descriptor) michael@0: : A property named name has been added to the referent. michael@0: Descriptor is a property descriptor of the sort accepted by michael@0: `Debugger.Object.prototype.defineProperty`, giving the newly added michael@0: property's attributes. michael@0: michael@0: delete(frame, name) michael@0: : The property named name is about to be deleted from the referent. michael@0: michael@0: change(frame, name, oldDescriptor, newDescriptor) michael@0: : The existing property named name on the referent is being changed michael@0: from those given by oldDescriptor to those given by michael@0: newDescriptor. This handler method is only called when attributes michael@0: of the property other than its value are being changed; if only the michael@0: value is changing, SpiderMonkey calls the handler's `set` method. michael@0: michael@0: set(frame, oldValue, newValue) michael@0: : The data property named name of the referent is about to have its michael@0: value changed from oldValue to newValue. michael@0: michael@0: SpiderMonkey only calls this method on assignments to data properties michael@0: that will succeed; assignments to un-writable data properties fail michael@0: without notifying the debugger. michael@0: michael@0: extensionsPrevented(frame) michael@0: : The referent has been made non-extensible, as if by a call to michael@0: `Object.preventExtensions`. michael@0: michael@0: For all watchpoint handler methods: michael@0: michael@0: * Handler calls receive the handler object itself as the `this` value. michael@0: michael@0: * The frame argument is the current stack frame, whose code is michael@0: about to perform the operation on the object being reported. michael@0: michael@0: * If the method returns `undefined`, then SpiderMonkey makes the announced michael@0: change to the object, and continues execution normally. If the method michael@0: returns an object: michael@0: michael@0: * If the object has a `superseded` property whose value is a true value, michael@0: then SpiderMonkey does not make the announced change. michael@0: michael@0: * If the object has a `resume` property, its value is taken as a michael@0: [resumption value][rv], indicating how michael@0: execution should proceed. (However, `return` resumption values are not michael@0: supported.) michael@0: michael@0: * If a given method is absent from handler, then events of that michael@0: sort are ignored. The watchpoint consults handler's properties michael@0: each time an event occurs, so adding methods to or removing methods from michael@0: handler after setting the watchpoint enables or disables michael@0: reporting of the corresponding events. michael@0: michael@0: * Values passed to handler's methods are debuggee values. michael@0: Descriptors passed to handler's methods are ordinary objects in michael@0: the debugger's compartment, except for `value`, `get`, and `set` michael@0: properties in descriptors, which are debuggee values; they are the sort michael@0: of value expected by `Debugger.Object.prototype.defineProperty`. michael@0: michael@0: * Watchpoint handler calls are cross-compartment, intra-thread calls: the michael@0: call takes place in the same thread that changed the property, and in michael@0: handler's method's compartment (typically the same as the michael@0: debugger's compartment). michael@0: michael@0: The new watchpoint belongs to the [`Debugger`][debugger-object] instance to which this michael@0: `Debugger.Object` instance belongs; disabling the [`Debugger`][debugger-object] instance michael@0: disables this watchpoint. michael@0: michael@0: `clearObjectWatchpoint()` (future plan) michael@0: : Remove any object watchpoint set on the referent. michael@0: michael@0: setPropertyWatchpoint(name, handler) (future plan) michael@0: : Set a watchpoint on the referent's property named name, reporting michael@0: events by calling handler's methods. Any previous watchpoint michael@0: handler on this property for this `Debugger.Object` instance is michael@0: replaced. If handler is null, the property is no longer watched. michael@0: Handler is as described for michael@0: `Debugger.Object.prototype.setObjectWatchpoint`, except that it does not michael@0: receive `extensionsPrevented` events. michael@0: michael@0: clearPropertyWatchpoint(name) (future plan) michael@0: : Remove any watchpoint set on the referent's property named name. michael@0: michael@0: `unwrap()` michael@0: : If the referent is a wrapper that this `Debugger.Object`'s compartment michael@0: is permitted to unwrap, return a `Debugger.Object` instance referring to michael@0: the wrapped object. If we are not permitted to unwrap the referent, michael@0: return `null`. If the referent is not a wrapper, return this michael@0: `Debugger.Object` instance unchanged. michael@0: michael@0: `unsafeDereference()` michael@0: : Return the referent of this `Debugger.Object` instance. michael@0: michael@0: If the referent is an inner object (say, an HTML5 `Window` object), michael@0: return the corresponding outer object (say, the HTML5 `WindowProxy` michael@0: object). This makes `unsafeDereference` more useful in producing values michael@0: appropriate for direct use by debuggee code, without using [invocation functions][inv fr]. michael@0: michael@0: This method pierces the membrane of `Debugger.Object` instances meant to michael@0: protect debugger code from debuggee code, and allows debugger code to michael@0: access debuggee objects through the standard cross-compartment wrappers, michael@0: rather than via `Debugger.Object`'s reflection-oriented interfaces. This michael@0: method makes it easier to gradually adapt large code bases to this michael@0: Debugger API: adapted portions of the code can use `Debugger.Object` michael@0: instances, but use this method to pass direct object references to code michael@0: that has not yet been updated.