PageRenderTime 85ms CodeModel.GetById 11ms app.highlight 65ms RepoModel.GetById 2ms app.codeStats 0ms

/interpreter/tags/at2dist130208/src/edu/vub/at/objects/natives/NATObject.java

http://ambienttalk.googlecode.com/
Java | 846 lines | 415 code | 99 blank | 332 comment | 54 complexity | b8893432be4a39a0ab83d26935e65f16 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.ATTable;
 49import edu.vub.at.objects.ATTypeTag;
 50import edu.vub.at.objects.coercion.Coercer;
 51import edu.vub.at.objects.coercion.NativeTypeTags;
 52import edu.vub.at.objects.grammar.ATBegin;
 53import edu.vub.at.objects.grammar.ATDefinition;
 54import edu.vub.at.objects.grammar.ATMessageCreation;
 55import edu.vub.at.objects.grammar.ATSplice;
 56import edu.vub.at.objects.grammar.ATStatement;
 57import edu.vub.at.objects.grammar.ATSymbol;
 58import edu.vub.at.objects.grammar.ATUnquoteSplice;
 59import edu.vub.at.objects.mirrors.NativeClosure;
 60import edu.vub.at.objects.mirrors.PrimitiveMethod;
 61import edu.vub.at.objects.natives.grammar.AGSplice;
 62import edu.vub.at.objects.natives.grammar.AGSymbol;
 63import edu.vub.at.util.logging.Logging;
 64
 65import java.io.IOException;
 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 type tags 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
122			_EQL_NAME_, NATTable.atValue(new ATObject[] { AGSymbol.jAlloc("comparand")})) {
123      private static final long serialVersionUID = -4475956316807558583L;
124      
125		public ATObject base_apply(ATTable arguments, ATContext ctx) throws InterpreterException {
126			if (!arguments.base_length().equals(NATNumber.ONE)) {
127				throw new XArityMismatch("==", 1, arguments.base_length().asNativeNumber().javaValue);
128			}
129			
130			ATObject comparand = arguments.base_at(NATNumber.ONE);
131			
132			// make other object perform the actual pointer equality
133			// if comparand is a proxy, it can delegate this request to its principal
134			return comparand.impl_identityEquals(ctx.base_lexicalScope());
135		}
136	};
137	/** def new(@initargs) { nil } */
138	private static final PrimitiveMethod _PRIM_NEW_ = new PrimitiveMethod(
139			_NEW_NAME_, NATTable.atValue(new ATObject[] { new AGSplice(AGSymbol.jAlloc("initargs")) })) {
140        private static final long serialVersionUID = -5475956316807558583L;
141
142		public ATObject base_apply(ATTable arguments, ATContext ctx) throws InterpreterException {
143			return ctx.base_lexicalScope().base_new(arguments.asNativeTable().elements_);
144		}
145	};
146	/** def init(@initargs) { nil } */
147	private static final PrimitiveMethod _PRIM_INI_ = new PrimitiveMethod(
148			_INI_NAME_, NATTable.atValue(new ATObject[] { new AGSplice(AGSymbol.jAlloc("initargs")) })) {
149	    private static final long serialVersionUID = -6475956316807558583L;
150
151		public ATObject base_apply(ATTable arguments, ATContext ctx) throws InterpreterException {
152			return ctx.base_lexicalScope().asAmbientTalkObject().prim_init(ctx.base_self(), arguments.asNativeTable().elements_);
153		}
154	};
155	
156	/**
157	 * Does the selector signify a 'primitive' method, present in each AmbientTalk object?
158	 */
159	public static boolean isPrimitive(ATSymbol name) {
160		return name.equals(_EQL_NAME_) || name.equals(_NEW_NAME_) || name.equals(_INI_NAME_);
161	}
162	
163	// Auxiliary static methods to support the type of dynamic parent
164	public static final boolean _IS_A_ 		= true;
165	public static final boolean _SHARES_A_ 	= false;
166	
167	/**
168	 * This flag determines the type of parent pointer of this object. We distinguish two cases:
169	 *  - 1: an is-a link, which results in a recursive cloning of the parent when this object is cloned.
170	 *  - 0: a shares-a link, which ensures that clones of this object share the same parent.
171	 */
172	private static final byte _ISAPARENT_FLAG_ = 1<<0;
173	
174	/**
175	 * This flag determines whether or not the field map of this object is shared by other objects:
176	 *  - 1: the map is shared, so modifications must be performed on a copy
177	 *  - 0: the map is not shared, modifications may be directly performed on it
178	 *  
179	 * This flag is important for maintaining the semantics that clones are self-sufficient objects:
180	 * they share field names and methods only at the implementation-level.
181	 */
182	private static final byte _SHARE_MAP_FLAG_ = 1<<1;
183	
184	/**
185	 * Similar to _SHARE_MAP_FLAG__ but for determining the shared status of the method dictionary.
186	 */
187	private static final byte _SHARE_DCT_FLAG_ = 1<<2;
188	
189	/**
190	 * This flag determines whether or not the object is an isolate and hence pass-by-copy:
191	 *  - 1: the object is an isolate, pass-by-copy and no lexical parent except for the root
192	 *  - 0: the object is pass-by-reference and can have any lexical parent
193	 */
194	private static final byte _IS_ISOLATE_FLAG_ = 1<<3;
195
196	/**
197	 * An empty type tag array shared by those objects that do not have any type tags.
198	 */
199	public static final ATTypeTag[] _NO_TYPETAGS_ = new ATTypeTag[0];
200	
201	/**
202	 * The flags of an AmbientTalk object encode the following boolean information:
203	 *  Format: 0b0000idap where
204	 *   p = parent flag: if set, dynamic parent is 'is-a' parent, otherwise 'shares-a' parent
205	 *   a = shares map flag: if set, the map of this object is shared between clones
206	 *   d = shares dictionary flag: if set, the method dictionary of this object is shared between clones
207	 *   i = is isolate flag: if set, the object is passed by copy in inter-actor communication
208	 */
209	private byte flags_;
210	
211	// inherited from NATCallframe:
212	// private FieldMap 	variableMap_;
213	// private Vector	stateVector_;
214	// private LinkedList customFields_;
215	
216	/**
217	 * The method dictionary of this object. It maps method selectors to ATMethod objects.
218	 */
219	private MethodDictionary methodDictionary_;
220	
221	/**
222	 * The types with which this object has been tagged.
223	 */
224	protected ATTypeTag[] typeTags_;
225	
226	/* ------------------
227	 * -- Constructors --
228	 * ------------------ */
229	
230	/**
231	 * Creates an object tagged with the at.types.Isolate type.
232	 * Such an object is called an isolate because:
233	 *  - it has no access to an enclosing lexical scope (except for the root lexical scope)
234	 *  - it can therefore be passed by copy
235	 */
236	public static NATObject createIsolate() {
237		return new NATObject(new ATTypeTag[] { NativeTypeTags._ISOLATE_ });
238	}
239	
240	/**
241	 * Constructs a new AmbientTalk object whose lexical parent is the
242	 * global scope and whose dynamic parent is the dynamic root.
243	 */
244	public NATObject() {
245		this(Evaluator.getGlobalLexicalScope());
246	}
247	
248	/**
249	 * Construct a new AmbientTalk object directly tagged with the given type tags.
250	 */
251	public NATObject(ATTypeTag[] tags) {
252		this(Evaluator.getGlobalLexicalScope(), tags);
253	}
254	
255	/**
256	 * Constructs a new ambienttalk object parametrised by a lexical scope. The 
257	 * object is thus not equipped with a pointer to a dynamic parent.
258	 * @param lexicalParent - the lexical scope in which the object's definition was nested
259	 */
260	public NATObject(ATObject lexicalParent) {
261		this(OBJNil._INSTANCE_, lexicalParent, _SHARES_A_);
262	}
263	
264	/**
265	 * Constructs a new ambienttalk object parametrised by a lexical scope.
266	 * The object's dynamic parent is nil and is tagged with the given table of type tags
267	 */
268	public NATObject(ATObject lexicalParent, ATTypeTag[] tags) {
269		this(OBJNil._INSTANCE_, lexicalParent, _SHARES_A_, tags);
270	}
271
272	/**
273	 * Constructs a new ambienttalk object with the given dynamic parent.
274	 * The lexical parent is assumed to be the global scope.
275	 * @param dynamicParent - the dynamic parent of the new object
276	 * @param parentType - the type of parent link
277	 */
278	public NATObject(ATObject dynamicParent, boolean parentType) {
279		this(dynamicParent, Evaluator.getGlobalLexicalScope(), parentType);
280	}
281
282	/**
283	 * Constructs a new ambienttalk object based on a set of parent pointers.
284	 * The object has no types.
285	 * @param dynamicParent - the parent object of the newly created object
286	 * @param lexicalParent - the lexical scope in which the object's definition was nested
287	 * @param parentType - how this object extends its dynamic parent (is-a or shares-a)
288	 */
289	public NATObject(ATObject dynamicParent, ATObject lexicalParent, boolean parentType) {
290	   this(dynamicParent, lexicalParent, parentType, _NO_TYPETAGS_);
291	}
292	
293	/**
294	 * Constructs a new ambienttalk object based on a set of parent pointers.
295	 * The object is typed with the given types.
296	 * @param dynamicParent - the parent object of the newly created object
297	 * @param lexicalParent - the lexical scope in which the object's definition was nested
298	 * @param parentType - how this object extends its dynamic parent (is-a or shares-a)
299	 * @param tags - the type tags attached to this object
300	 */
301	public NATObject(ATObject dynamicParent, ATObject lexicalParent, boolean parentType, ATTypeTag[] tags) {
302		super(lexicalParent);
303		
304        // by default, an object has a shares-a parent, does not share its map
305		// or dictionary and is no isolate, so all flags are set to 0
306		flags_ = 0;
307		
308		typeTags_ = tags;
309		
310		methodDictionary_ = new MethodDictionary();
311		
312		// bind the dynamic parent to the field named 'super'
313		// we don't pass via meta_defineField as this would trigger mirages too early
314		variableMap_.put(_SUPER_NAME_);
315		stateVector_.add(dynamicParent);
316		
317		// add ==, new and init to the method dictionary directly
318		// we don't pass via meta_addMethod as this would trigger mirages too early
319		methodDictionary_.put(_EQL_NAME_, _PRIM_EQL_);
320		methodDictionary_.put(_NEW_NAME_, _PRIM_NEW_);
321		methodDictionary_.put(_INI_NAME_, _PRIM_INI_);
322		
323		if (parentType) { // parentType == _IS_A_)
324			// requested an 'is-a' parent
325			setFlag(_ISAPARENT_FLAG_); // set is-a parent flag to 1
326		}
327		
328		try {
329            // if this object is tagged as at.types.Isolate, flag it as an isolate
330            // we cannot perform 'this.meta_isTypedAs(ISOLATE)' because this would trigger mirages too early
331			if (isLocallyTaggedAs(NativeTypeTags._ISOLATE_)
332			     || dynamicParent.meta_isTaggedAs(NativeTypeTags._ISOLATE_).asNativeBoolean().javaValue) {
333				setFlag(_IS_ISOLATE_FLAG_);
334				// isolates can only have the global lexical root as their lexical scope
335				lexicalParent_ = Evaluator.getGlobalLexicalScope();
336			}
337		} catch (InterpreterException e) {
338			// some custom type failed to match agains the Isolate type,
339			// the object is not considered an Isolate
340			Logging.Actor_LOG.error("Error testing for Isolate type, ignored:", e);
341		}
342	}
343	
344	/**
345	 * Constructs a new ambienttalk object as a clone of an existing object.
346	 * 
347	 * The caller of this method *must* ensure that the shares flags are set.
348	 * 
349	 * This constructor is responsible for manually re-initialising any custom field
350	 * objects, because the init method of such custom fields is parameterized by the
351	 * clone, which only comes into existence when this constructor runs.
352	 */
353	protected NATObject(FieldMap map,
354			         Vector state,
355			         LinkedList originalCustomFields,
356			         MethodDictionary methodDict,
357			         ATObject dynamicParent,
358			         ATObject lexicalParent,
359			         byte flags,
360			         ATTypeTag[] types) throws InterpreterException {
361		super(map, state, lexicalParent, null);
362		methodDictionary_ = methodDict;
363		
364		flags_ = flags; //a cloned object inherits all flags from original
365		
366		// clone inherits all types (this implies that clones of isolates are also isolates)
367		typeTags_ = types;
368		
369		// ==, new and init should already be present in the method dictionary
370		
371		// set the 'super' field to point to the new dynamic parent
372		setLocalField(_SUPER_NAME_, dynamicParent);
373		
374		// re-initialize all custom fields
375		if (originalCustomFields != null) {
376			customFields_ = new LinkedList();
377			Iterator it = originalCustomFields.iterator();
378			while (it.hasNext()) {
379				ATField field = (ATField) it.next();
380				customFields_.add(field.base_new(new ATObject[] { this }).asField());
381			}
382		}
383	}
384	
385	/**
386	 * Initialize a new AmbientTalk object with the given closure.
387	 * 
388	 * The closure encapsulates:
389	 *  - the code with which to initialize the object
390	 *  - the lexical parent of the object (but that parent should already be set)
391	 *  - the lexically inherited fields for the object (the parameters of the closure)
392	 */
393	public void initializeWithCode(ATClosure code) throws InterpreterException {
394		NATTable copiedBindings = Evaluator.evalMandatoryPars(
395				code.base_method().base_parameters(),
396				code.base_context());
397		code.base_applyInScope(copiedBindings, this);
398	}
399
400	/**
401	 * Invoke NATObject's primitive implementation, such that Java invocations of this
402	 * method have the same behaviour as AmbientTalk invocations.
403	 */
404    public ATObject base_init(ATObject[] initargs) throws InterpreterException {
405    	return this.prim_init(this, initargs);
406    }
407	
408	/**
409	 * The primitive implementation of init in objects is to invoke the init
410	 * method of their parent.
411	 * @param self the object that originally received the 'init' message.
412	 * 
413	 * def init(@args) {
414	 *   super^init(@args)
415	 * }
416	 */
417    private ATObject prim_init(ATObject self, ATObject[] initargs) throws InterpreterException {
418    	return base_super().meta_invoke(self, Evaluator._INIT_, NATTable.atValue(initargs));
419    }
420    
421    public ATBoolean base__opeql__opeql_(ATObject comparand) throws InterpreterException {
422    	return this.meta_invoke(this, _EQL_NAME_, NATTable.of(comparand)).asBoolean();
423    }
424
425	/* ------------------------------------------
426	 * -- Slot accessing and mutating protocol --
427	 * ------------------------------------------ */
428	
429	/**
430	 * When a new field is defined in an object, it is important to check whether or not
431	 * the field map is shared between clones or not. If it is shared, the map must be cloned first.
432	 * @throws InterpreterException 
433	 */
434	public ATNil meta_defineField(ATSymbol name, ATObject value) throws InterpreterException {
435		if (this.isFlagSet(_SHARE_MAP_FLAG_)) {
436			// copy the variable map
437			variableMap_ = variableMap_.copy();
438			// set the 'shares map' flag to false
439			unsetFlag(_SHARE_MAP_FLAG_);
440		}
441		return super.meta_defineField(name, value);
442	}
443	
444	/* ------------------------------------
445	 * -- Extension and cloning protocol --
446	 * ------------------------------------ */
447
448	/**
449	 * When cloning an object, it is first determined whether the parent
450	 * has to be shared by the clone, or whether the parent must also be cloned.
451	 * This depends on whether the dynamic parent is an 'is-a' parent or a 'shares-a'
452	 * parent. This is determined by the _ISAPARENT_FLAG_ object flag.
453	 * 
454	 * A cloned object shares with its original both the variable map
455	 * (to avoid having to copy space for field names) and the method dictionary
456	 * (method bindings are constant and can hence be shared).
457	 * 
458	 * Should either the original or the clone later modify the map or the dictionary
459	 * (at the meta-level), the map or dictionary will be copied first. Hence,
460	 * sharing between clones is an implementation-level optimization: clones
461	 * are completely self-sufficient and do not influence one another by meta-level operations.
462	 */
463	public ATObject meta_clone() throws InterpreterException {
464		ATObject dynamicParent;
465		if(this.isFlagSet(_ISAPARENT_FLAG_)) {
466			// IS-A Relation : clone the dynamic parent.
467			dynamicParent = base_super().meta_clone();
468		} else {
469			// SHARES_A Relation : share the dynamic parent.
470			dynamicParent = base_super();
471		}
472		
473		// ! set the shares flags of this object *and* of its clone
474		// both this object and the clone now share the map and method dictionary
475		setFlag(_SHARE_DCT_FLAG_);
476		setFlag(_SHARE_MAP_FLAG_);
477		
478		NATObject clone = this.createClone(variableMap_,
479				          (Vector) stateVector_.clone(), // shallow copy
480				          customFields_, // must be re-initialized by clone!
481				          methodDictionary_,
482				          dynamicParent,
483				          lexicalParent_,
484				          flags_, typeTags_);
485		
486		return clone;
487	}
488	
489	/**
490	 * When new is invoked on an object's mirror, the object is first cloned
491	 * by the mirror, after which the method named 'init' is invoked on it.
492	 * 
493	 * meta_newInstance(t) = base_init(t) o meta_clone
494	 * 
495	 * Care should be taken that a shares-a child implements its own init method
496	 * which does NOT perform a super-send. If this is not the case, then it is
497	 * possible that a shared parent is accidentally re-initialized because a
498	 * sharing child is cloned via new.
499	 */
500	public ATObject meta_newInstance(ATTable initargs) throws InterpreterException {
501		ATObject clone = this.meta_clone();
502		clone.meta_invoke(clone, Evaluator._INIT_, initargs);
503		return clone;
504	}
505
506	public ATBoolean meta_isExtensionOfParent() throws InterpreterException {
507		return NATBoolean.atValue(isFlagSet(_ISAPARENT_FLAG_));
508	}
509	
510	/* ---------------------------------
511	 * -- Structural Access Protocol  --
512	 * --------------------------------- */
513
514	/**
515	 * When a method is added to an object, it is first checked whether the method does not
516	 * already exist. Also, care has to be taken that the method dictionary of an object
517	 * does not affect clones. Therefore, if the method dictionary is shared, a copy
518	 * of the dictionary is taken before adding the method.
519	 * 
520	 * One exception to method addition are primitive methods: if the method added
521	 * would conflict with a primitive method, the primitive is replaced by the new
522	 * method instead.
523	 */
524	public ATNil meta_addMethod(ATMethod method) throws InterpreterException {
525		ATSymbol name = method.base_name();
526		if (this.hasLocalField(name) || (this.hasLocalMethod(name) && !isPrimitive(name))) {
527			throw new XDuplicateSlot(name);
528		} else {
529			// first check whether the method dictionary is shared
530			if (this.isFlagSet(_SHARE_DCT_FLAG_)) {
531				methodDictionary_ = (MethodDictionary) methodDictionary_.clone();
532				this.unsetFlag(_SHARE_DCT_FLAG_);
533			}
534			methodDictionary_.put(name, method);
535		}
536		return OBJNil._INSTANCE_;
537	}
538
539	public ATMethod meta_grabMethod(ATSymbol selector) throws InterpreterException {
540		ATMethod result = (ATMethod)methodDictionary_.get(selector);
541		if(result == null) {
542			throw new XSelectorNotFound(selector, this);
543		} else {
544			return result;
545		}
546	}
547
548	public ATTable meta_listMethods() throws InterpreterException {
549		Collection methods = methodDictionary_.values();
550		return NATTable.atValue((ATObject[]) methods.toArray(new ATObject[methods.size()]));
551	}
552	
553	public NATText meta_print() throws InterpreterException {
554		if (typeTags_.length == 0) {
555			return NATText.atValue("<object:"+this.hashCode()+">");
556		} else {
557			return NATText.atValue("<object:"+this.hashCode()+
558					               Evaluator.printElements(typeTags_, "[", ",", "]").javaValue+">");
559		}
560	}
561	
562	public boolean isCallFrame() {
563		return false;
564	}
565	
566	/* ---------------------
567	 * -- Mirror Fields   --
568	 * --------------------- */
569	
570	// protected methods, may be adapted by extensions
571	
572	protected NATObject createClone(FieldMap map,
573	         					  Vector state,
574	         					  LinkedList originalCustomFields,
575	         					  MethodDictionary methodDict,
576	         					  ATObject dynamicParent,
577	         					  ATObject lexicalParent,
578	         					  byte flags,
579	         					  ATTypeTag[] types) throws InterpreterException {
580		return new NATObject(map,
581	            state,
582	            originalCustomFields,
583	            methodDict,
584	            dynamicParent,
585	            lexicalParent,
586	            flags,
587	            types);
588	}
589		
590    /* ----------------------------------
591     * -- Object Relational Comparison --
592     * ---------------------------------- */
593    
594	public ATBoolean meta_isCloneOf(ATObject original) throws InterpreterException {
595		if(original instanceof NATObject) {
596			MethodDictionary originalMethods = ((NATObject)original).methodDictionary_;
597			FieldMap originalVariables = ((NATObject)original).variableMap_;
598			
599			return NATBoolean.atValue(
600					methodDictionary_.isDerivedFrom(originalMethods) &
601					variableMap_.isDerivedFrom(originalVariables));
602		} else {
603			return NATBoolean._FALSE_;
604		}
605	}
606
607	public ATBoolean meta_isRelatedTo(final ATObject object) throws InterpreterException {
608		return this.meta_isCloneOf(object).base_or_(
609				new NativeClosure(this) {
610					public ATObject base_apply(ATTable args) throws InterpreterException {
611						return scope_.base_super().meta_isRelatedTo(object);
612					}
613				}).asBoolean();
614	}
615	
616    /* ---------------------------------
617     * -- Type Testing and Querying --
618     * --------------------------------- */
619	
620    /**
621     * Check whether one of the type tags of this object is a subtype of the given type.
622     * If not, then delegate the query to the dynamic parent.
623     */
624    public ATBoolean meta_isTaggedAs(ATTypeTag type) throws InterpreterException {
625    	if (isLocallyTaggedAs(type)) {
626    		return NATBoolean._TRUE_;
627    	} else {
628        	// no type tags match, ask the parent
629        	return base_super().meta_isTaggedAs(type);
630    	}
631    }
632    
633    /**
634     * Return the type tags that were directly attached to this object.
635     */
636    public ATTable meta_typeTags() throws InterpreterException {
637    	// make a copy of the internal type tag array to ensure that the types
638    	// of the object are immutable. Tables allow assignment!
639    	if (typeTags_.length == 0) {
640    		return NATTable.EMPTY;
641    	} else { 
642    		ATTypeTag[] types = new ATTypeTag[typeTags_.length];
643        	System.arraycopy(typeTags_, 0, types, 0, typeTags_.length);
644        	return NATTable.atValue(types);
645    	}
646    }
647    
648    
649	// NATObject has to duplicate the NATByCopy implementation
650	// because NATObject inherits from NATByRef, and because Java has no
651	// multiple inheritance to override that implementation with that of
652    // NATByCopy if this object signifies an isolate.
653	
654    /**
655     * An isolate object does not return a proxy representation of itself
656     * during serialization, hence it is serialized itself. If the object
657     * is not an isolate, invoke the default behaviour for by-reference objects
658     */
659    public ATObject meta_pass() throws InterpreterException {
660    	if (isFlagSet(_IS_ISOLATE_FLAG_)) {
661    		return this;
662    	} else {
663    		return super.meta_pass();
664    	}
665    }
666	
667    /**
668     * An isolate object represents itself upon deserialization.
669     * If this object is not an isolate, the default behaviour for by-reference
670     * objects is invoked.
671     */
672    public ATObject meta_resolve() throws InterpreterException {
673    	if (isFlagSet(_IS_ISOLATE_FLAG_)) {
674    		// re-bind to the new local global lexical root
675    		lexicalParent_ = Evaluator.getGlobalLexicalScope();
676    		return this;
677    	} else {
678    		return super.meta_resolve();
679    	}
680    }
681    
682    /**
683     * This Java serialization hook is overridden merely to provide clearer error messages
684     * in the case of a failing deserialization.
685     */
686	private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
687		try {
688			in.defaultReadObject();
689		} catch(ArrayStoreException e) {
690			Logging.Actor_LOG.fatal("Failed to deserialize instance of " + this.getClass(), e);
691			throw new IOException("Object deserialized as wrong type: " + e.getMessage()
692					+ ". Did you forget to make a type tag object an isolate?");
693		}
694	}
695    
696    /* ---------------------------------------
697	 * -- Conversion and Testing Protocol   --
698	 * --------------------------------------- */
699	
700	public NATObject asAmbientTalkObject() { return this; }
701	
702	/**
703	 * ALL asXXX methods return a coercer object which returns a proxy of the correct interface that will 'down'
704	 * subsequent Java base-level invocations to the AmbientTalk level.
705	 * 
706	 * Coercion only happens if the object is tagged with the correct type.
707	 */
708	private Object coerce(ATTypeTag requiredType, Class providedInterface) throws InterpreterException {
709		if (this.meta_isTaggedAs(requiredType).asNativeBoolean().javaValue) {
710			return Coercer.coerce(this, providedInterface);
711		} else {
712			// if the object does not possess the right type tag, raise a type error
713			throw new XTypeMismatch(providedInterface, this);
714		}
715	}
716	
717	public ATBoolean asBoolean() throws InterpreterException { return (ATBoolean) coerce(NativeTypeTags._BOOLEAN_, ATBoolean.class); }
718	public ATClosure asClosure() throws InterpreterException { return (ATClosure) coerce(NativeTypeTags._CLOSURE_, ATClosure.class); }
719	public ATField asField() throws InterpreterException { return (ATField) coerce(NativeTypeTags._FIELD_, ATField.class); }
720	public ATMessage asMessage() throws InterpreterException { return (ATMessage) coerce(NativeTypeTags._MESSAGE_, ATMessage.class); }
721	public ATMethod asMethod() throws InterpreterException { return (ATMethod) coerce(NativeTypeTags._METHOD_, ATMethod.class); }
722	public ATHandler asHandler() throws InterpreterException { return (ATHandler) coerce(NativeTypeTags._HANDLER_, ATHandler.class); }
723	public ATNumber asNumber() throws InterpreterException { return (ATNumber) coerce(NativeTypeTags._NUMBER_, ATNumber.class); }
724	public ATTable asTable() throws InterpreterException { return (ATTable) coerce(NativeTypeTags._TABLE_, ATTable.class); }
725    public ATAsyncMessage asAsyncMessage() throws InterpreterException { return (ATAsyncMessage) coerce(NativeTypeTags._ASYNCMSG_, ATAsyncMessage.class);}
726    public ATActorMirror asActorMirror() throws InterpreterException { return (ATActorMirror) coerce(NativeTypeTags._ACTORMIRROR_, ATActorMirror.class); }
727    public ATTypeTag asTypeTag() throws InterpreterException { return (ATTypeTag) coerce(NativeTypeTags._TYPETAG_, ATTypeTag.class); }
728	
729	public ATBegin asBegin() throws InterpreterException { return (ATBegin) coerce(NativeTypeTags._BEGIN_, ATBegin.class); }
730	public ATStatement asStatement() throws InterpreterException { return (ATStatement) coerce(NativeTypeTags._STATEMENT_, ATStatement.class); }
731    public ATUnquoteSplice asUnquoteSplice() throws InterpreterException { return (ATUnquoteSplice) coerce(NativeTypeTags._UQSPLICE_, ATUnquoteSplice.class); }
732    public ATSymbol asSymbol() throws InterpreterException { return (ATSymbol) coerce(NativeTypeTags._SYMBOL_, ATSymbol.class); }
733    public ATSplice asSplice() throws InterpreterException { return (ATSplice) coerce(NativeTypeTags._SPLICE_, ATSplice.class); }
734	public ATDefinition asDefinition() throws InterpreterException { return (ATDefinition) coerce(NativeTypeTags._DEFINITION_, ATDefinition.class); }
735	public ATMessageCreation asMessageCreation() throws InterpreterException { return (ATMessageCreation) coerce(NativeTypeTags._MSGCREATION_, ATMessageCreation.class); }
736	
737	// ALL isXXX methods return true (can be overridden by programmer-defined base-level methods)
738	
739	public boolean isAmbientTalkObject() { return true; }
740	
741	// objects can only be 'cast' to a native category if they are marked with
742	// the appropriate native type
743	public boolean isSplice() throws InterpreterException { return meta_isTaggedAs(NativeTypeTags._SPLICE_).asNativeBoolean().javaValue; }
744	public boolean isSymbol() throws InterpreterException { return meta_isTaggedAs(NativeTypeTags._SYMBOL_).asNativeBoolean().javaValue; }
745	public boolean isTable() throws InterpreterException { return meta_isTaggedAs(NativeTypeTags._TABLE_).asNativeBoolean().javaValue; }
746	public boolean isUnquoteSplice() throws InterpreterException { return meta_isTaggedAs(NativeTypeTags._UQSPLICE_).asNativeBoolean().javaValue; }
747	public boolean isTypeTag() throws InterpreterException { return meta_isTaggedAs(NativeTypeTags._TYPETAG_).asNativeBoolean().javaValue; }
748	
749	
750	// private methods
751	
752	private boolean isFlagSet(byte flag) {
753		return (flags_ & flag) != 0;
754	}
755
756	private void setFlag(byte flag) {
757		flags_ = (byte) (flags_ | flag);
758	}
759
760	private void unsetFlag(byte flag) {
761		flags_ = (byte) (flags_ & (~flag));
762	}
763	
764	protected boolean hasLocalMethod(ATSymbol selector) throws InterpreterException {
765		return methodDictionary_.containsKey(selector);
766	}
767	
768	protected ATMethod getLocalMethod(ATSymbol selector) throws InterpreterException {
769		ATMethod result = ((ATObject) methodDictionary_.get(selector)).asMethod();
770		if(result == null) {
771			throw new XSelectorNotFound(selector, this);
772		} else {
773			return result;
774		}
775	}
776	
777	/**
778	 * Performs a type test for this object locally.
779	 * @return whether this object is tagged with a particular type tag or not.
780	 */
781	private boolean isLocallyTaggedAs(ATTypeTag tag) throws InterpreterException {
782    	for (int i = 0; i < typeTags_.length; i++) {
783			if (typeTags_[i].base_isSubtypeOf(tag).asNativeBoolean().javaValue) {
784				// if one type matches, return true
785				return true;
786			}
787		}
788		return false;
789	}
790	
791	/**
792	 * Auxiliary method to access the fields of an object and all of its super-objects up to (but excluding) nil.
793	 * Overridden fields of parent objects are not included.
794	 */
795	public static ATField[] listTransitiveFields(ATObject obj) throws InterpreterException {
796		Vector fields = new Vector();
797		HashSet encounteredNames = new HashSet(); // to filter duplicates
798		for (; obj != OBJNil._INSTANCE_ ; obj = obj.base_super()) {
799			ATObject[] localFields = obj.meta_listFields().asNativeTable().elements_;
800			for (int i = 0; i < localFields.length; i++) {
801				ATField field = localFields[i].asField();
802				ATSymbol fieldName = field.base_name();
803				if (!encounteredNames.contains(fieldName)) {
804					fields.add(field);
805					encounteredNames.add(fieldName);
806				}
807			}
808		}
809		return (ATField[]) fields.toArray(new ATField[fields.size()]);
810	}
811	
812	/**
813	 * Auxiliary method to access the methods of an object and all of its super-objects up to (but excluding) nil.
814	 * Overridden methods of parent objects are not included.
815	 */
816	public static ATMethod[] listTransitiveMethods(ATObject obj) throws InterpreterException {
817		Vector methods = new Vector();
818		HashSet encounteredNames = new HashSet(); // to filter duplicates		
819		for (; obj != OBJNil._INSTANCE_ ; obj = obj.base_super()) {
820			// fast-path for native objects
821			if (obj instanceof NATObject) {
822				Collection localMethods = ((NATObject) obj).methodDictionary_.values();
823				for (Iterator iter = localMethods.iterator(); iter.hasNext();) {
824					ATMethod localMethod = (ATMethod) iter.next();
825					ATSymbol methodName = localMethod.base_name();
826					if (!encounteredNames.contains(methodName)) {
827						methods.add(localMethod);
828						encounteredNames.add(methodName);
829					}
830				}
831			} else {
832				ATObject[] localMethods = obj.meta_listMethods().asNativeTable().elements_;
833				for (int i = 0; i < localMethods.length; i++) {
834					ATMethod localMethod = localMethods[i].asMethod();
835					ATSymbol methodName = localMethod.base_name();
836					if (!encounteredNames.contains(methodName)) {
837						methods.add(localMethod);
838						encounteredNames.add(methodName);
839					}
840				}
841			}
842		}
843		return (ATMethod[]) methods.toArray(new ATMethod[methods.size()]);
844	}
845	
846}