/interpreter/branches/bytecode/src/edu/vub/at/objects/natives/NATObject.java

http://ambienttalk.googlecode.com/
Java | 1011 lines | 497 code | 122 blank | 392 comment | 53 complexity | c40ada96b4adf1ff5d4539468e2d2911 MD5 | raw file

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