PageRenderTime 58ms CodeModel.GetById 12ms app.highlight 37ms RepoModel.GetById 1ms app.codeStats 0ms

/interpreter/tags/at2-build060407/src/edu/vub/at/objects/natives/NATObject.java

http://ambienttalk.googlecode.com/
Java | 952 lines | 447 code | 99 blank | 406 comment | 70 complexity | 0dabfa187f34f4345911e0525d71e802 MD5 | raw file
  1/**
  2 * AmbientTalk/2 Project
  3 * NATObject.java created on Jul 13, 2006 at 3:52:15 PM
  4 * (c) Programming Technology Lab, 2006 - 2007
  5 * Authors: Tom Van Cutsem & Stijn Mostinckx
  6 * 
  7 * Permission is hereby granted, free of charge, to any person
  8 * obtaining a copy of this software and associated documentation
  9 * files (the "Software"), to deal in the Software without
 10 * restriction, including without limitation the rights to use,
 11 * copy, modify, merge, publish, distribute, sublicense, and/or
 12 * sell copies of the Software, and to permit persons to whom the
 13 * Software is furnished to do so, subject to the following
 14 * conditions:
 15 *
 16 * The above copyright notice and this permission notice shall be
 17 * included in all copies or substantial portions of the Software.
 18 *
 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 21 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 22 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 23 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 24 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 26 * OTHER DEALINGS IN THE SOFTWARE.
 27 */
 28package edu.vub.at.objects.natives;
 29
 30import edu.vub.at.actors.ATActorMirror;
 31import edu.vub.at.actors.ATAsyncMessage;
 32import edu.vub.at.eval.Evaluator;
 33import edu.vub.at.exceptions.InterpreterException;
 34import edu.vub.at.exceptions.XArityMismatch;
 35import edu.vub.at.exceptions.XDuplicateSlot;
 36import edu.vub.at.exceptions.XSelectorNotFound;
 37import edu.vub.at.exceptions.XTypeMismatch;
 38import edu.vub.at.objects.ATBoolean;
 39import edu.vub.at.objects.ATClosure;
 40import edu.vub.at.objects.ATContext;
 41import edu.vub.at.objects.ATField;
 42import edu.vub.at.objects.ATHandler;
 43import edu.vub.at.objects.ATMessage;
 44import edu.vub.at.objects.ATMethod;
 45import edu.vub.at.objects.ATNil;
 46import edu.vub.at.objects.ATNumber;
 47import edu.vub.at.objects.ATObject;
 48import edu.vub.at.objects.ATStripe;
 49import edu.vub.at.objects.ATTable;
 50import edu.vub.at.objects.coercion.Coercer;
 51import edu.vub.at.objects.coercion.NativeStripes;
 52import edu.vub.at.objects.grammar.ATBegin;
 53import edu.vub.at.objects.grammar.ATDefinition;
 54import edu.vub.at.objects.grammar.ATExpression;
 55import edu.vub.at.objects.grammar.ATMessageCreation;
 56import edu.vub.at.objects.grammar.ATSplice;
 57import edu.vub.at.objects.grammar.ATStatement;
 58import edu.vub.at.objects.grammar.ATSymbol;
 59import edu.vub.at.objects.grammar.ATUnquoteSplice;
 60import edu.vub.at.objects.mirrors.NativeClosure;
 61import edu.vub.at.objects.mirrors.PrimitiveMethod;
 62import edu.vub.at.objects.natives.grammar.AGSplice;
 63import edu.vub.at.objects.natives.grammar.AGSymbol;
 64import edu.vub.at.util.logging.Logging;
 65
 66import java.util.Collection;
 67import java.util.HashSet;
 68import java.util.Iterator;
 69import java.util.LinkedList;
 70import java.util.Vector;
 71
 72/**
 73 * Native implementation of a default ambienttalk object.
 74 * Although a native AmbientTalk object is implemented as a subtype of callframes,
 75 * the reality is that call frames are a special kind of object.
 76 * This is a pure form of implementation subclassing: we subclass NATCallframe only
 77 * for reusing the field definition/assignment protocol and for inheriting the
 78 * variable map, the state vector and the lexical parent.
 79 * <p>
 80 * NATObjects are one of the five native classes that (almost) fully implement the ATObject interface
 81 * (next to NATCallFrame, NATNil, NATMirage and JavaObject). The implementation is such that
 82 * a NATObject instance represents <b>both</b> a base-level AmbientTalk object, as well as a meta-level
 83 * AmbientTalk mirror on that object.
 84 * 
 85 * An AmbientTalk base-level object has the following structure:
 86 * <ul>
 87 *  <li> properties: a set of boolean flags denoting:
 88 *  <ul>
 89 *   <li> whether the dynamic parent is an IS_A or a SHARES_A parent
 90 *   <li> whether the object shares its variable map with clones
 91 *   <li> whether the object shares its method dictionary with clones
 92 *   <li> whether the object is an isolate (i.e. pass-by-copy)
 93 *  </ul>
 94 *  <li> a variable map, mapping variable names to indices into the state vector
 95 *  <li> a state vector, containing the field values of the object
 96 *  <li> a linked list containing custom field objects
 97 *  <li> a method dictionary, mapping selectors to methods
 98 *  <li> a dynamic object parent, to delegate select and invoke operations
 99 *   ( this parent slot is represented by a true AmbientTalk field, rather than by an instance variable )
100 *  <li> a lexical object parent, to support lexical scoping
101 *  <li> a table of stripes that were attached to this object (for classification purposes)
102 * </ul>
103 * 
104 * @author tvcutsem
105 * @author smostinc
106 */
107public class NATObject extends NATCallframe implements ATObject {
108	
109	// The name of the field that points to the dynamic parent
110	public static final AGSymbol _SUPER_NAME_ = AGSymbol.jAlloc("super");
111	
112	// The names of the primitive methods
113	public static final AGSymbol _EQL_NAME_ = AGSymbol.jAlloc("==");
114	public static final AGSymbol _NEW_NAME_ = AGSymbol.jAlloc("new");
115	public static final AGSymbol _INI_NAME_ = AGSymbol.jAlloc("init");
116	
117	// The primitive methods themselves
118	
119	/** def ==(comparand) { nil } */
120	private static final PrimitiveMethod _PRIM_EQL_ = new PrimitiveMethod(
121			_EQL_NAME_, NATTable.atValue(new ATObject[] { AGSymbol.jAlloc("comparand")})) {
122		public ATObject base_apply(ATTable arguments, ATContext ctx) throws InterpreterException {
123			if (!arguments.base_getLength().equals(NATNumber.ONE)) {
124				throw new XArityMismatch("==", 1, arguments.base_getLength().asNativeNumber().javaValue);
125			}
126			// primitive implementation uses pointer equality (as dictated by NATNil)
127			return NATBoolean.atValue(ctx.base_getLexicalScope() == arguments.base_at(NATNumber.ONE));
128		}
129	};
130	/** def new(@initargs) { nil } */
131	private static final PrimitiveMethod _PRIM_NEW_ = new PrimitiveMethod(
132			_NEW_NAME_, NATTable.atValue(new ATObject[] { new AGSplice(AGSymbol.jAlloc("initargs")) })) {
133		public ATObject base_apply(ATTable arguments, ATContext ctx) throws InterpreterException {
134			return ctx.base_getLexicalScope().base_new(arguments.asNativeTable().elements_);
135		}
136	};
137	/** def init(@initargs) { nil } */
138	private static final PrimitiveMethod _PRIM_INI_ = new PrimitiveMethod(
139			_INI_NAME_, NATTable.atValue(new ATObject[] { new AGSplice(AGSymbol.jAlloc("initargs")) })) {
140		public ATObject base_apply(ATTable arguments, ATContext ctx) throws InterpreterException {
141			return ctx.base_getLexicalScope().asAmbientTalkObject().prim_init(ctx.base_getSelf(), arguments.asNativeTable().elements_);
142		}
143	};
144	
145	/**
146	 * Does the selector signify a 'primitive' method, present in each AmbientTalk object?
147	 */
148	public static boolean isPrimitive(ATSymbol name) {
149		return name.equals(_EQL_NAME_) || name.equals(_NEW_NAME_) || name.equals(_INI_NAME_);
150	}
151	
152	// Auxiliary static methods to support the type of dynamic parent
153	public static final boolean _IS_A_ 		= true;
154	public static final boolean _SHARES_A_ 	= false;
155	
156	/**
157	 * This flag determines the type of parent pointer of this object. We distinguish two cases:
158	 *  - 1: an is-a link, which results in a recursive cloning of the parent when this object is cloned.
159	 *  - 0: a shares-a link, which ensures that clones of this object share the same parent.
160	 */
161	private static final byte _ISAPARENT_FLAG_ = 1<<0;
162	
163	/**
164	 * This flag determines whether or not the field map of this object is shared by other objects:
165	 *  - 1: the map is shared, so modifications must be performed on a copy
166	 *  - 0: the map is not shared, modifications may be directly performed on it
167	 *  
168	 * This flag is important for maintaining the semantics that clones are self-sufficient objects:
169	 * they share field names and methods only at the implementation-level.
170	 */
171	private static final byte _SHARE_MAP_FLAG_ = 1<<1;
172	
173	/**
174	 * Similar to _SHARE_MAP_FLAG__ but for determining the shared status of the method dictionary.
175	 */
176	private static final byte _SHARE_DCT_FLAG_ = 1<<2;
177	
178	/**
179	 * This flag determines whether or not the object is an isolate and hence pass-by-copy:
180	 *  - 1: the object is an isolate, pass-by-copy and no lexical parent except for the root
181	 *  - 0: the object is pass-by-reference and can have any lexical parent
182	 */
183	private static final byte _IS_ISOLATE_FLAG_ = 1<<3;
184
185	/**
186	 * An empty stripe array shared by those objects that do not have any stripes.
187	 */
188	public static final ATStripe[] _NO_STRIPES_ = new ATStripe[0];
189	
190	/**
191	 * The flags of an AmbientTalk object encode the following boolean information:
192	 *  Format: 0b0000idap where
193	 *   p = parent flag: if set, dynamic parent is 'is-a' parent, otherwise 'shares-a' parent
194	 *   a = shares map flag: if set, the map of this object is shared between clones
195	 *   d = shares dictionary flag: if set, the method dictionary of this object is shared between clones
196	 *   i = is isolate flag: if set, the object is passed by copy in inter-actor communication
197	 */
198	private byte flags_;
199	
200	// inherited from NATCallframe:
201	// private FieldMap 	variableMap_;
202	// private Vector	stateVector_;
203	// private LinkedList customFields_;
204	
205	/**
206	 * The method dictionary of this object. It maps method selectors to ATMethod objects.
207	 */
208	private MethodDictionary methodDictionary_;
209	
210	/**
211	 * The stripes with which this object has been striped.
212	 */
213	protected ATStripe[] stripes_;
214	
215	/* ------------------
216	 * -- Constructors --
217	 * ------------------ */
218	
219	/**
220	 * Creates an object striped with the at.stripes.Isolate stripe.
221	 * Such an object is called an isolate because:
222	 *  - it has no access to an enclosing lexical scope (except for the root lexical scope)
223	 *  - it can therefore be passed by copy
224	 */
225	public static NATObject createIsolate() {
226		return new NATObject(new ATStripe[] { NativeStripes._ISOLATE_ });
227	}
228	
229	/**
230	 * Constructs a new AmbientTalk object whose lexical parent is the
231	 * global scope and whose dynamic parent is the dynamic root.
232	 */
233	public NATObject() {
234		this(Evaluator.getGlobalLexicalScope());
235	}
236	
237	public NATObject(ATStripe[] stripes) {
238		this(Evaluator.getGlobalLexicalScope(), stripes);
239	}
240	
241	/**
242	 * Constructs a new ambienttalk object parametrised by a lexical scope. The 
243	 * object is thus not equipped with a pointer to a dynamic parent.
244	 * @param lexicalParent - the lexical scope in which the object's definition was nested
245	 */
246	public NATObject(ATObject lexicalParent) {
247		this(NATNil._INSTANCE_, lexicalParent, _SHARES_A_);
248	}
249	
250	/**
251	 * Constructs a new ambienttalk object parametrised by a lexical scope.
252	 * The object's dynamic parent is nil and is striped with the given table of stripes
253	 */
254	public NATObject(ATObject lexicalParent, ATStripe[] stripes) {
255		this(NATNil._INSTANCE_, lexicalParent, _SHARES_A_, stripes);
256	}
257
258	/**
259	 * Constructs a new ambienttalk object with the given dynamic parent.
260	 * The lexical parent is assumed to be the global scope.
261	 * @param dynamicParent - the dynamic parent of the new object
262	 * @param parentType - the type of parent link
263	 */
264	public NATObject(ATObject dynamicParent, boolean parentType) {
265		this(dynamicParent, Evaluator.getGlobalLexicalScope(), parentType);
266	}
267
268	/**
269	 * Constructs a new ambienttalk object based on a set of parent pointers.
270	 * The object has no stripes.
271	 * @param dynamicParent - the parent object of the newly created object
272	 * @param lexicalParent - the lexical scope in which the object's definition was nested
273	 * @param parentType - how this object extends its dynamic parent (is-a or shares-a)
274	 */
275	public NATObject(ATObject dynamicParent, ATObject lexicalParent, boolean parentType) {
276	   this(dynamicParent, lexicalParent, parentType, _NO_STRIPES_);
277	}
278	
279	/**
280	 * Constructs a new ambienttalk object based on a set of parent pointers.
281	 * The object is striped with the given stripes.
282	 * @param dynamicParent - the parent object of the newly created object
283	 * @param lexicalParent - the lexical scope in which the object's definition was nested
284	 * @param parentType - how this object extends its dynamic parent (is-a or shares-a)
285	 * @param stripes - the stripes attached to this object
286	 */
287	public NATObject(ATObject dynamicParent, ATObject lexicalParent, boolean parentType, ATStripe[] stripes) {
288		super(lexicalParent);
289		
290        // by default, an object has a shares-a parent, does not share its map
291		// or dictionary and is no isolate, so all flags are set to 0
292		flags_ = 0;
293		
294		stripes_ = stripes;
295		
296		methodDictionary_ = new MethodDictionary();
297		
298		// bind the dynamic parent to the field named 'super'
299		// we don't pass via meta_defineField as this would trigger mirages too early
300		variableMap_.put(_SUPER_NAME_);
301		stateVector_.add(dynamicParent);
302		
303		// add ==, new and init to the method dictionary directly
304		// we don't pass via meta_addMethod as this would trigger mirages too early
305		methodDictionary_.put(_EQL_NAME_, _PRIM_EQL_);
306		methodDictionary_.put(_NEW_NAME_, _PRIM_NEW_);
307		methodDictionary_.put(_INI_NAME_, _PRIM_INI_);
308		
309		if (parentType) { // parentType == _IS_A_)
310			// requested an 'is-a' parent
311			setFlag(_ISAPARENT_FLAG_); // set is-a parent flag to 1
312		}
313		
314		try {
315            // if this object is striped as at.stripes.Isolate, flag it as an isolate
316            // we cannot perform 'this.meta_isStripedWith(ISOLATE)' because this would trigger mirages too early
317			if (isLocallyStripedWith(NativeStripes._ISOLATE_)
318			     || dynamicParent.meta_isStripedWith(NativeStripes._ISOLATE_).asNativeBoolean().javaValue) {
319				setFlag(_IS_ISOLATE_FLAG_);
320				// isolates can only have the global lexical root as their lexical scope
321				lexicalParent_ = Evaluator.getGlobalLexicalScope();
322			}
323		} catch (InterpreterException e) {
324			// some custom stripe failed to match agains the Isolate stripe,
325			// the object is not considered an Isolate
326			Logging.Actor_LOG.error("Error testing for Isolate stripe, ignored:", e);
327		}
328	}
329	
330	/**
331	 * Constructs a new ambienttalk object as a clone of an existing object.
332	 * 
333	 * The caller of this method *must* ensure that the shares flags are set.
334	 * 
335	 * This constructor is responsible for manually re-initialising any custom field
336	 * objects, because the init method of such custom fields is parameterized by the
337	 * clone, which only comes into existence when this constructor runs.
338	 */
339	protected NATObject(FieldMap map,
340			         Vector state,
341			         LinkedList originalCustomFields,
342			         MethodDictionary methodDict,
343			         ATObject dynamicParent,
344			         ATObject lexicalParent,
345			         byte flags,
346			         ATStripe[] stripes) throws InterpreterException {
347		super(map, state, lexicalParent, null);
348		methodDictionary_ = methodDict;
349		
350		flags_ = flags; //a cloned object inherits all flags from original
351		
352		// clone inherits all stripes (this implies that clones of isolates are also isolates)
353		stripes_ = stripes;
354		
355		// ==, new and init should already be present in the method dictionary
356		
357		// set the 'super' field to point to the new dynamic parent
358		setLocalField(_SUPER_NAME_, dynamicParent);
359		
360		// re-initialize all custom fields
361		if (originalCustomFields != null) {
362			customFields_ = new LinkedList();
363			Iterator it = originalCustomFields.iterator();
364			while (it.hasNext()) {
365				ATField field = (ATField) it.next();
366				customFields_.add(field.base_new(new ATObject[] { this }).asField());
367			}
368		}
369	}
370	
371	/**
372	 * Initialize a new AmbientTalk object with the given closure.
373	 * 
374	 * The closure encapsulates:
375	 *  - the code with which to initialize the object
376	 *  - the lexical parent of the object (but that parent should already be set)
377	 *  - the lexically inherited fields for the object (the parameters of the closure)
378	 */
379	public void initializeWithCode(ATClosure code) throws InterpreterException {
380		NATTable copiedBindings = Evaluator.evalMandatoryPars(
381				code.base_getMethod().base_getParameters(),
382				code.base_getContext());
383		code.base_applyInScope(copiedBindings, this);
384	}
385
386	/**
387	 * Invoke NATObject's primitive implementation, such that Java invocations of this
388	 * method have the same behaviour as AmbientTalk invocations.
389	 */
390    public ATObject base_init(ATObject[] initargs) throws InterpreterException {
391    	return this.prim_init(this, initargs);
392    }
393	
394	/**
395	 * The primitive implementation of init in objects is to invoke the init
396	 * method of their parent.
397	 * @param self the object that originally received the 'init' message.
398	 * 
399	 * def init(@args) {
400	 *   super^init(@args)
401	 * }
402	 */
403    private ATObject prim_init(ATObject self, ATObject[] initargs) throws InterpreterException {
404    	ATObject parent = base_getSuper();
405    	return parent.meta_invoke(self, Evaluator._INIT_, NATTable.atValue(initargs));
406    }
407    
408    public ATBoolean base__opeql__opeql_(ATObject comparand) throws InterpreterException {
409    	return this.meta_invoke(this, _EQL_NAME_, NATTable.of(comparand)).asBoolean();
410    }
411	
412	/* ------------------------------
413	 * -- Message Sending Protocol --
414	 * ------------------------------ */
415	
416	/**
417	 * Invocations on an object ( <tt>o.m( args )</tt> ) are handled by looking up the requested
418	 * selector in the dynamic parent chain of the receiver. This dynamic lookup process
419	 * yields exactly the same result as a selection (e.g. <tt>o.m</tt>). The result
420	 * ought to be a closure (a method and its corresponding evaluation context), which
421	 * is applied to the provided arguments.
422	 * 
423	 * The code for meta_invoke is actually equivalent to
424	 * <pre>return this.meta_select(receiver, selector).asClosure().meta_apply(arguments);</pre>
425	 * but has a specialized implementation for performance reasons (no unnecessary closure is created)
426	 */
427	public ATObject meta_invoke(ATObject receiver, ATSymbol selector, ATTable arguments) throws InterpreterException {
428		if (this.hasLocalField(selector)) {
429			return this.getLocalField(selector).asClosure().base_apply(arguments);
430		} else if (this.hasLocalMethod(selector)) {
431			// immediately execute the method in the context ctx where
432			//  ctx.scope = the implementing scope, being this object, under which an additional callframe will be inserted
433			//  ctx.self  = the late bound receiver, being the passed receiver
434			return this.getLocalMethod(selector).base_apply(arguments, new NATContext(this, receiver));
435		} else {
436			return base_getSuper().meta_invoke(receiver, selector, arguments);
437		}
438	}
439	
440	/**
441	 * An ambienttalk object can respond to a message if a corresponding field or method exists
442	 * either in the receiver object locally, or in one of its dynamic parents.
443	 */
444	public ATBoolean meta_respondsTo(ATSymbol selector) throws InterpreterException {
445		if (this.hasLocalField(selector) || this.hasLocalMethod(selector))
446			return NATBoolean._TRUE_;
447		else
448			return base_getSuper().meta_respondsTo(selector);
449	}
450
451
452	/* ------------------------------------------
453	 * -- Slot accessing and mutating protocol --
454	 * ------------------------------------------ */
455	
456	/**
457	 * meta_select is used to evaluate code of the form <tt>o.m</tt>.
458	 * 
459	 * To select a slot from an object:
460	 *  - first, the list of fields of the current receiver ('this') is searched.
461	 *    If a matching field exists, its value is returned.
462	 *  - second, the list of methods of the current receiver is searched.
463	 *    If a matching method exists, it is returned, but wrapped in a closure.
464	 *    This wrapping is vital to ensure that the method is paired with the correct 'self'.
465	 *    This 'self' does not necessarily equal 'this'.
466	 *  - third, the search for the slot is carried out recursively in the dynamic parent.
467	 *    As such, slot selection traverses the dynamic parent chain up to a dynamic root.
468	 *    The dynamic root deals with an unbound slot by sending the 'doesNotUnderstand' message
469	 *    to the original receiver.
470	 *    
471	 * @param receiver the original receiver of the selection
472	 * @param selector the selector to look up
473	 * @return the value of the found field, or a closure wrapping a found method
474	 */
475	public ATObject meta_select(ATObject receiver, ATSymbol selector) throws InterpreterException {
476		if (this.hasLocalField(selector)) {
477			return this.getLocalField(selector);
478		} else if (this.hasLocalMethod(selector)) {
479			// return a new closure (mth, ctx) where
480			//  mth = the method found in this object
481			//  ctx.scope = the implementing scope, being this object
482			//  ctx.self  = the late bound receiver, being the passed receiver
483			//  ctx.super = the parent of the implementor
484			return new NATClosure(this.getLocalMethod(selector), this, receiver);
485		} else {
486			return base_getSuper().meta_select(receiver, selector);
487		}
488	}
489	
490	/**
491	 * This method corresponds to code of the form ( x ) within the scope of this 
492	 * object. It searches for the requested selector among the methods and fields 
493	 * of the object and its dynamic parents.
494	 * 
495	 * Overridden from NATCallframe to take methods into account as well.
496	 * 
497	 * This method is used to evaluate code of the form <tt>selector</tt> within the scope
498	 * of this object. An object resolves such a lookup request as follows:
499	 *  - If a field corresponding to the selector exists locally, the field's value is returned.
500	 *  - If a method corresponding to the selector exists locally, the method is wrapped
501	 *    using the current object itself as implementor AND as 'self'.
502	 *    The reason for setting the closure's 'self' to the implementor is because a lookup can only
503	 *    be initiated by the object itself or a lexically nested one. Lexical nesting, however, has
504	 *    nothing to do with dynamic delegation, and it would be wrong to bind 'self' to a nested object
505	 *    which need not be a dynamic child of the implementor.
506	 *    
507	 *  - Otherwise, the search continues recursively in the object's lexical parent.
508	 */
509	public ATObject meta_lookup(ATSymbol selector) throws InterpreterException {
510		if (this.hasLocalField(selector)) {
511			return this.getLocalField(selector);
512		} else if (this.hasLocalMethod(selector)) {
513			// return a new closure (mth, ctx) where
514			//  mth = the method found in this object
515			//  ctx.scope = the implementing scope, being this object
516			//  ctx.self  = the receiver, being in this case again the implementor
517			return new NATClosure(this.getLocalMethod(selector),this, this);
518		} else {
519			return lexicalParent_.meta_lookup(selector);
520		}
521	}
522	
523	/**
524	 * When a new field is defined in an object, it is important to check whether or not
525	 * the field map is shared between clones or not. If it is shared, the map must be cloned first.
526	 * @throws InterpreterException 
527	 */
528	public ATNil meta_defineField(ATSymbol name, ATObject value) throws InterpreterException {
529		if (this.isFlagSet(_SHARE_MAP_FLAG_)) {
530			// copy the variable map
531			variableMap_ = variableMap_.copy();
532			// set the 'shares map' flag to false
533			unsetFlag(_SHARE_MAP_FLAG_);
534		}
535		return super.meta_defineField(name, value);
536	}
537	
538	/** 
539	 * meta_assignField is used to evaluate code of the form <tt>o.m := v</tt>.
540	 * 
541	 * To assign a field in an object:
542	 *  - first, the list of fields of the current receiver ('this') is searched.
543	 *    If a matching field exists, its value is set.
544	 *  - If the field is not found, the search for the slot is carried out recursively in the dynamic parent.
545	 *    As such, field assignment traverses the dynamic parent chain up to a dynamic root.
546	 *    The dynamic root deals with an unbound field by throwing an error.
547	 * @param value the value to assign to the field
548	 * @param selector the field to assign
549	 *    
550	 * @return NIL
551	 */
552	public ATNil meta_assignField(ATObject receiver, ATSymbol selector, ATObject value) throws InterpreterException {
553		if (this.setLocalField(selector, value)) {
554			return NATNil._INSTANCE_;
555		} else {
556			return base_getSuper().meta_assignField(receiver, selector, value);
557		}
558	}
559	
560	/* ------------------------------------
561	 * -- Extension and cloning protocol --
562	 * ------------------------------------ */
563
564	/**
565	 * When cloning an object, it is first determined whether the parent
566	 * has to be shared by the clone, or whether the parent must also be cloned.
567	 * This depends on whether the dynamic parent is an 'is-a' parent or a 'shares-a'
568	 * parent. This is determined by the _ISAPARENT_FLAG_ object flag.
569	 * 
570	 * A cloned object shares with its original both the variable map
571	 * (to avoid having to copy space for field names) and the method dictionary
572	 * (method bindings are constant and can hence be shared).
573	 * 
574	 * Should either the original or the clone later modify the map or the dictionary
575	 * (at the meta-level), the map or dictionary will be copied first. Hence,
576	 * sharing between clones is an implementation-level optimization: clones
577	 * are completely self-sufficient and do not influence one another by meta-level operations.
578	 */
579	public ATObject meta_clone() throws InterpreterException {
580		ATObject dynamicParent;
581		if(this.isFlagSet(_ISAPARENT_FLAG_)) {
582			// IS-A Relation : clone the dynamic parent.
583			dynamicParent = base_getSuper().meta_clone();
584		} else {
585			// SHARES_A Relation : share the dynamic parent.
586			dynamicParent = base_getSuper();
587		}
588		
589		// ! set the shares flags of this object *and* of its clone
590		// both this object and the clone now share the map and method dictionary
591		setFlag(_SHARE_DCT_FLAG_);
592		setFlag(_SHARE_MAP_FLAG_);
593		
594		NATObject clone = this.createClone(variableMap_,
595				          (Vector) stateVector_.clone(), // shallow copy
596				          customFields_, // must be re-initialized by clone!
597				          methodDictionary_,
598				          dynamicParent,
599				          lexicalParent_,
600				          flags_, stripes_);
601		
602		return clone;
603	}
604	
605	/**
606	 * When new is invoked on an object's mirror, the object is first cloned
607	 * by the mirror, after which the method named 'init' is invoked on it.
608	 * 
609	 * meta_newInstance(t) = base_init(t) o meta_clone
610	 * 
611	 * Care should be taken that a shares-a child implements its own init method
612	 * which does NOT perform a super-send. If this is not the case, then it is
613	 * possible that a shared parent is accidentally re-initialized because a
614	 * sharing child is cloned via new.
615	 */
616	public ATObject meta_newInstance(ATTable initargs) throws InterpreterException {
617		ATObject clone = this.meta_clone();
618		clone.meta_invoke(clone, Evaluator._INIT_, initargs);
619		return clone;
620	}
621
622	public ATBoolean meta_isExtensionOfParent() throws InterpreterException {
623		return NATBoolean.atValue(isFlagSet(_ISAPARENT_FLAG_));
624	}
625	
626	/* ---------------------------------
627	 * -- Structural Access Protocol  --
628	 * --------------------------------- */
629
630	/**
631	 * When a method is added to an object, it is first checked whether the method does not
632	 * already exist. Also, care has to be taken that the method dictionary of an object
633	 * does not affect clones. Therefore, if the method dictionary is shared, a copy
634	 * of the dictionary is taken before adding the method.
635	 * 
636	 * One exception to method addition are primitive methods: if the method added
637	 * would conflict with a primitive method, the primitive is replaced by the new
638	 * method instead.
639	 */
640	public ATNil meta_addMethod(ATMethod method) throws InterpreterException {
641		ATSymbol name = method.base_getName();
642		if (methodDictionary_.containsKey(name) && !isPrimitive(name)) {
643			throw new XDuplicateSlot(XDuplicateSlot._METHOD_, name);
644		} else {
645			// first check whether the method dictionary is shared
646			if (this.isFlagSet(_SHARE_DCT_FLAG_)) {
647				methodDictionary_ = (MethodDictionary) methodDictionary_.clone();
648				this.unsetFlag(_SHARE_DCT_FLAG_);
649			}
650			methodDictionary_.put(name, method);
651		}
652		return NATNil._INSTANCE_;
653	}
654
655	public ATMethod meta_grabMethod(ATSymbol selector) throws InterpreterException {
656		ATMethod result = (ATMethod)methodDictionary_.get(selector);
657		if(result == null) {
658			throw new XSelectorNotFound(selector, this);
659		} else {
660			return result;
661		}
662	}
663
664	public ATTable meta_listMethods() throws InterpreterException {
665		Collection methods = methodDictionary_.values();
666		return NATTable.atValue((ATObject[]) methods.toArray(new ATObject[methods.size()]));
667	}
668	
669	public NATText meta_print() throws InterpreterException {
670		if (stripes_.length == 0) {
671			return NATText.atValue("<object:"+this.hashCode()+">");
672		} else {
673			return NATText.atValue("<object:"+this.hashCode()+
674					               Evaluator.printElements(stripes_, "[", ",", "]").javaValue+">");
675		}
676	}
677	
678	public boolean isCallFrame() {
679		return false;
680	}
681	
682	/* ---------------------
683	 * -- Mirror Fields   --
684	 * --------------------- */
685	
686	// protected methods, may be adapted by extensions
687	
688	protected NATObject createClone(FieldMap map,
689	         					  Vector state,
690	         					  LinkedList originalCustomFields,
691	         					  MethodDictionary methodDict,
692	         					  ATObject dynamicParent,
693	         					  ATObject lexicalParent,
694	         					  byte flags,
695	         					  ATStripe[] stripes) throws InterpreterException {
696		return new NATObject(map,
697	            state,
698	            originalCustomFields,
699	            methodDict,
700	            dynamicParent,
701	            lexicalParent,
702	            flags,
703	            stripes);
704	}
705		
706    /* ----------------------------------
707     * -- Object Relational Comparison --
708     * ---------------------------------- */
709    
710	public ATBoolean meta_isCloneOf(ATObject original) throws InterpreterException {
711		if(original instanceof NATObject) {
712			MethodDictionary originalMethods = ((NATObject)original).methodDictionary_;
713			FieldMap originalVariables = ((NATObject)original).variableMap_;
714			
715			return NATBoolean.atValue(
716					methodDictionary_.isDerivedFrom(originalMethods) &
717					variableMap_.isDerivedFrom(originalVariables));
718		} else {
719			return NATBoolean._FALSE_;
720		}
721	}
722
723	public ATBoolean meta_isRelatedTo(final ATObject object) throws InterpreterException {
724		return this.meta_isCloneOf(object).base_or_(
725				new NativeClosure(this) {
726					public ATObject base_apply(ATTable args) throws InterpreterException {
727						return scope_.base_getSuper().meta_isRelatedTo(object);
728					}
729				}).asBoolean();
730	}
731	
732    /* ---------------------------------
733     * -- Stripe Testing and Querying --
734     * --------------------------------- */
735	
736    /**
737     * Check whether one of the stripes of this object is a substripe of the given stripe.
738     * If not, then delegate the query to the dynamic parent.
739     */
740    public ATBoolean meta_isStripedWith(ATStripe stripe) throws InterpreterException {
741    	if (isLocallyStripedWith(stripe)) {
742    		return NATBoolean._TRUE_;
743    	} else {
744        	// no stripes match, ask the parent
745        	return base_getSuper().meta_isStripedWith(stripe);
746    	}
747    }
748    
749    /**
750     * Return the stripes that were directly attached to this object.
751     */
752    public ATTable meta_getStripes() throws InterpreterException {
753    	// make a copy of the internal stripes array to ensure that the stripes
754    	// of the object are immutable. Tables allow assignment!
755    	if (stripes_.length == 0) {
756    		return NATTable.EMPTY;
757    	} else { 
758    		ATStripe[] stripes = new ATStripe[stripes_.length];
759        	System.arraycopy(stripes_, 0, stripes, 0, stripes_.length);
760        	return NATTable.atValue(stripes);
761    	}
762    }
763    
764    
765	// NATObject has to duplicate the NATByCopy implementation
766	// because NATObject inherits from NATByRef, and because Java has no
767	// multiple inheritance to override that implementation with that of
768    // NATByCopy if this object signifies an isolate.
769	
770    /**
771     * An isolate object does not return a proxy representation of itself
772     * during serialization, hence it is serialized itself. If the object
773     * is not an isolate, invoke the default behaviour for by-reference objects
774     */
775    public ATObject meta_pass() throws InterpreterException {
776    	if (isFlagSet(_IS_ISOLATE_FLAG_)) {
777    		return this;
778    	} else {
779    		return super.meta_pass();
780    	}
781    }
782	
783    /**
784     * An isolate object represents itself upon deserialization.
785     * If this object is not an isolate, the default behaviour for by-reference
786     * objects is invoked.
787     */
788    public ATObject meta_resolve() throws InterpreterException {
789    	if (isFlagSet(_IS_ISOLATE_FLAG_)) {
790    		// re-bind to the new local global lexical root
791    		lexicalParent_ = Evaluator.getGlobalLexicalScope();
792    		return this;
793    	} else {
794    		return super.meta_resolve();
795    	}
796    }
797    
798    /* ---------------------------------------
799	 * -- Conversion and Testing Protocol   --
800	 * --------------------------------------- */
801	
802	public NATObject asAmbientTalkObject() { return this; }
803	
804	/**
805	 * ALL asXXX methods return a coercer object which returns a proxy of the correct interface that will 'down'
806	 * subsequent Java base-level invocations to the AmbientTalk level.
807	 * 
808	 * Coercion only happens if the object is striped with the correct stripe.
809	 */
810	private Object coerce(ATStripe requiredStripe, Class providedInterface) throws InterpreterException {
811		if (this.meta_isStripedWith(requiredStripe).asNativeBoolean().javaValue) {
812			return Coercer.coerce(this, providedInterface);
813		} else {
814			// if the object does not possess the right stripe, raise a type error
815			throw new XTypeMismatch(providedInterface, this);
816		}
817	}
818	
819	public ATBoolean asBoolean() throws InterpreterException { return (ATBoolean) coerce(NativeStripes._BOOLEAN_, ATBoolean.class); }
820	public ATClosure asClosure() throws InterpreterException { return (ATClosure) coerce(NativeStripes._CLOSURE_, ATClosure.class); }
821	public ATExpression asExpression() throws InterpreterException { return (ATExpression) coerce(NativeStripes._EXPRESSION_, ATExpression.class); }
822	public ATField asField() throws InterpreterException { return (ATField) coerce(NativeStripes._FIELD_, ATField.class); }
823	public ATMessage asMessage() throws InterpreterException { return (ATMessage) coerce(NativeStripes._MESSAGE_, ATMessage.class); }
824	public ATMethod asMethod() throws InterpreterException { return (ATMethod) coerce(NativeStripes._METHOD_, ATMethod.class); }
825	public ATHandler asHandler() throws InterpreterException { return (ATHandler) coerce(NativeStripes._HANDLER_, ATHandler.class); }
826	public ATNumber asNumber() throws InterpreterException { return (ATNumber) coerce(NativeStripes._NUMBER_, ATNumber.class); }
827	public ATTable asTable() throws InterpreterException { return (ATTable) coerce(NativeStripes._TABLE_, ATTable.class); }
828    public ATAsyncMessage asAsyncMessage() throws InterpreterException { return (ATAsyncMessage) coerce(NativeStripes._ASYNCMSG_, ATAsyncMessage.class);}
829    public ATActorMirror asActorMirror() throws InterpreterException { return (ATActorMirror) coerce(NativeStripes._ACTORMIRROR_, ATActorMirror.class); }
830    public ATStripe asStripe() throws InterpreterException { return (ATStripe) coerce(NativeStripes._STRIPE_, ATStripe.class); }
831	
832	public ATBegin asBegin() throws InterpreterException { return (ATBegin) coerce(NativeStripes._BEGIN_, ATBegin.class); }
833	public ATStatement asStatement() throws InterpreterException { return (ATStatement) coerce(NativeStripes._STATEMENT_, ATStatement.class); }
834    public ATUnquoteSplice asUnquoteSplice() throws InterpreterException { return (ATUnquoteSplice) coerce(NativeStripes._UQSPLICE_, ATUnquoteSplice.class); }
835    public ATSymbol asSymbol() throws InterpreterException { return (ATSymbol) coerce(NativeStripes._SYMBOL_, ATSymbol.class); }
836    public ATSplice asSplice() throws InterpreterException { return (ATSplice) coerce(NativeStripes._SPLICE_, ATSplice.class); }
837	public ATDefinition asDefinition() throws InterpreterException { return (ATDefinition) coerce(NativeStripes._DEFINITION_, ATDefinition.class); }
838	public ATMessageCreation asMessageCreation() throws InterpreterException { return (ATMessageCreation) coerce(NativeStripes._MSGCREATION_, ATMessageCreation.class); }
839	
840	// ALL isXXX methods return true (can be overridden by programmer-defined base-level methods)
841	
842	public boolean isAmbientTalkObject() { return true; }
843	
844	// objects can only be 'cast' to a native category if they are marked with
845	// the appropriate native stripe
846	public boolean isBoolean() throws InterpreterException { return meta_isStripedWith(NativeStripes._BOOLEAN_).asNativeBoolean().javaValue; }
847	public boolean isClosure() throws InterpreterException { return meta_isStripedWith(NativeStripes._CLOSURE_).asNativeBoolean().javaValue; }
848	public boolean isMethod() throws InterpreterException { return meta_isStripedWith(NativeStripes._METHOD_).asNativeBoolean().javaValue; }
849	public boolean isSplice() throws InterpreterException { return meta_isStripedWith(NativeStripes._SPLICE_).asNativeBoolean().javaValue; }
850	public boolean isSymbol() throws InterpreterException { return meta_isStripedWith(NativeStripes._SYMBOL_).asNativeBoolean().javaValue; }
851	public boolean isTable() throws InterpreterException { return meta_isStripedWith(NativeStripes._TABLE_).asNativeBoolean().javaValue; }
852	public boolean isUnquoteSplice() throws InterpreterException { return meta_isStripedWith(NativeStripes._UQSPLICE_).asNativeBoolean().javaValue; }
853	public boolean isStripe() throws InterpreterException { return meta_isStripedWith(NativeStripes._STRIPE_).asNativeBoolean().javaValue; }
854	
855	
856	// private methods
857	
858	private boolean isFlagSet(byte flag) {
859		return (flags_ & flag) != 0;
860	}
861
862	private void setFlag(byte flag) {
863		flags_ = (byte) (flags_ | flag);
864	}
865
866	private void unsetFlag(byte flag) {
867		flags_ = (byte) (flags_ & (~flag));
868	}
869	
870	private boolean hasLocalMethod(ATSymbol selector) {
871		return methodDictionary_.containsKey(selector);
872	}
873	
874	private ATMethod getLocalMethod(ATSymbol selector) throws InterpreterException {
875		ATMethod result = ((ATObject) methodDictionary_.get(selector)).asMethod();
876		if(result == null) {
877			throw new XSelectorNotFound(selector, this);
878		} else {
879			return result;
880		}
881	}
882	
883	/**
884	 * Performs a stripe test for this object locally.
885	 * @return whether this object is striped with a particular stripe or not.
886	 */
887	private boolean isLocallyStripedWith(ATStripe stripe) throws InterpreterException {
888    	for (int i = 0; i < stripes_.length; i++) {
889			if (stripes_[i].base_isSubstripeOf(stripe).asNativeBoolean().javaValue) {
890				// if one stripe matches, return true
891				return true;
892			}
893		}
894		return false;
895	}
896	
897	/**
898	 * Auxiliary method to access the fields of an object and all of its super-objects up to (but excluding) nil.
899	 * Overridden fields of parent objects are not included.
900	 */
901	public static ATField[] listTransitiveFields(ATObject obj) throws InterpreterException {
902		Vector fields = new Vector();
903		HashSet encounteredNames = new HashSet(); // to filter duplicates
904		for (; obj != NATNil._INSTANCE_ ; obj = obj.base_getSuper()) {
905			ATObject[] localFields = obj.meta_listFields().asNativeTable().elements_;
906			for (int i = 0; i < localFields.length; i++) {
907				ATField field = localFields[i].asField();
908				ATSymbol fieldName = field.base_getName();
909				if (!encounteredNames.contains(fieldName)) {
910					fields.add(field);
911					encounteredNames.add(fieldName);
912				}
913			}
914		}
915		return (ATField[]) fields.toArray(new ATField[fields.size()]);
916	}
917	
918	/**
919	 * Auxiliary method to access the methods of an object and all of its super-objects up to (but excluding) nil.
920	 * Overridden methods of parent objects are not included.
921	 */
922	public static ATMethod[] listTransitiveMethods(ATObject obj) throws InterpreterException {
923		Vector methods = new Vector();
924		HashSet encounteredNames = new HashSet(); // to filter duplicates		
925		for (; obj != NATNil._INSTANCE_ ; obj = obj.base_getSuper()) {
926			// fast-path for native objects
927			if (obj instanceof NATObject) {
928				Collection localMethods = ((NATObject) obj).methodDictionary_.values();
929				for (Iterator iter = localMethods.iterator(); iter.hasNext();) {
930					ATMethod localMethod = (ATMethod) iter.next();
931					ATSymbol methodName = localMethod.base_getName();
932					if (!encounteredNames.contains(methodName)) {
933						methods.add(localMethod);
934						encounteredNames.add(methodName);
935					}
936				}
937			} else {
938				ATObject[] localMethods = obj.meta_listMethods().asNativeTable().elements_;
939				for (int i = 0; i < localMethods.length; i++) {
940					ATMethod localMethod = localMethods[i].asMethod();
941					ATSymbol methodName = localMethod.base_getName();
942					if (!encounteredNames.contains(methodName)) {
943						methods.add(localMethod);
944						encounteredNames.add(methodName);
945					}
946				}
947			}
948		}
949		return (ATMethod[]) methods.toArray(new ATMethod[methods.size()]);
950	}
951	
952}