PageRenderTime 63ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/src/record.d

https://github.com/ynd/clisp-branch--ynd-devel
D | 2130 lines | 1424 code | 92 blank | 614 comment | 197 complexity | a29e563290651b2ce2b7341b98c91442 MD5 | raw file
Possible License(s): LGPL-2.0, GPL-2.0, BSD-3-Clause
  1. /*
  2. * Functions for records and structures in CLISP
  3. * Bruno Haible 1990-2005
  4. * Sam Steingold 1998-2008
  5. * German comments translated into English: Stefan Kain 2002-04-16
  6. */
  7. #include "lispbibl.c"
  8. /* ===========================================================================
  9. * general records:
  10. (SYS::%RECORD-REF record index) return the index'th entry in the record.
  11. (SYS::%RECORD-STORE record index value) store value as the index'th
  12. entry in the record and return value.
  13. (SYS::%RECORD-LENGTH record) return the length of the record.
  14. Error message
  15. > STACK_1: record
  16. > STACK_0: (bad) index
  17. > limit: exclusive upper bound on the index */
  18. nonreturning_function(local, error_index, (uintL limit)) {
  19. pushSTACK(STACK_0); /* TYPE-ERROR slot DATUM */
  20. {
  21. var object tmp;
  22. pushSTACK(S(integer)); pushSTACK(Fixnum_0); pushSTACK(UL_to_I(limit));
  23. tmp = listof(1); pushSTACK(tmp); tmp = listof(3);
  24. pushSTACK(tmp); /* TYPE-ERROR slot EXPECTED-TYPE */
  25. }
  26. pushSTACK(STACK_(1+2)); /* record */
  27. pushSTACK(STACK_(0+3)); /* index */
  28. pushSTACK(TheSubr(subr_self)->name); /* function name */
  29. error(type_error,GETTEXT("~S: ~S is not a valid index into ~S"));
  30. }
  31. /* Error message
  32. > STACK_0: (bad) record */
  33. nonreturning_function(local, error_record, (void)) {
  34. pushSTACK(TheSubr(subr_self)->name); /* function name */
  35. error(error_condition, /* type_error ?? */
  36. GETTEXT("~S: ~S is not a record"));
  37. }
  38. /* Subroutine for record access functions
  39. > STACK_1: record argument
  40. > STACK_0: index argument
  41. < STACK: cleared up
  42. < returns: the address of the referred record item */
  43. local gcv_object_t* record_up (void) {
  44. /* the record must be a Closure/Structure/Stream/OtherRecord: */
  45. if_recordp(STACK_1, ; , { skipSTACK(1); error_record(); } );
  46. var object record = STACK_1;
  47. var uintL length = Record_length(record);
  48. var uintV index;
  49. if (!(posfixnump(STACK_0) && ((index = posfixnum_to_V(STACK_0)) < length)))
  50. /* extract and check index */
  51. error_index(length);
  52. skipSTACK(2); /* clear up stack */
  53. return &TheRecord(record)->recdata[index]; /* record element address */
  54. }
  55. /* (SYS::%RECORD-REF record index) return the index'th entry in the record */
  56. LISPFUNNR(record_ref,2)
  57. {
  58. VALUES1(*(record_up())); /* record element as value */
  59. }
  60. /* (SYS::%RECORD-STORE record index value) store value as the index'th
  61. entry in the record and return value. */
  62. LISPFUNN(record_store,3)
  63. {
  64. var object value = popSTACK();
  65. VALUES1(*(record_up()) = value); /* set record element */
  66. }
  67. /* (SYS::%RECORD-LENGTH record) return the length of the record. */
  68. LISPFUNNR(record_length,1)
  69. {
  70. /* the record must be a Closure/Structure/Stream/OtherRecord: */
  71. if_recordp(STACK_0, ; , { error_record(); } );
  72. var object record = popSTACK();
  73. var uintL length = Record_length(record);
  74. VALUES1(fixnum(length)); /* length as Fixnum */
  75. }
  76. /* check that the length is of type (INTEGER (0) (65536))
  77. > STACK_0: length
  78. < uintV length: checked length */
  79. #define test_record_length(length) \
  80. if (!(posfixnump(STACK_0) \
  81. && ((length = posfixnum_to_V(STACK_0)) <= (uintV)(vbitm(intWsize)-1)) \
  82. && (length>0))) \
  83. error_record_length()
  84. nonreturning_function(local, error_record_length, (void)) {
  85. /* STACK_0 = length, TYPE-ERROR slot DATUM */
  86. pushSTACK(O(type_posint16)); /* TYPE-ERROR slot EXPECTED-TYPE */
  87. pushSTACK(O(type_posint16)); /* type */
  88. pushSTACK(STACK_2); /* length */
  89. pushSTACK(TheSubr(subr_self)->name); /* function name */
  90. error(type_error,GETTEXT("~S: length ~S should be of type ~S"));
  91. }
  92. /* ===========================================================================
  93. * Structures:
  94. (SYS::%STRUCTURE-REF type structure index) returns for a structure of
  95. given Type type (a Symbol) the entry at index>=1.
  96. (SYS::%STRUCTURE-STORE type structure index object) stores object as
  97. Entry index in a structure of given Type type and returns object.
  98. (SYS::%MAKE-STRUCTURE type length) creates a structure with length>=1
  99. elements of Type type.
  100. (COPY-STRUCTURE structure) returns a copy of the Structure structure,
  101. of the same type.
  102. (SYS::%STRUCTURE-TYPE-P type object) checks if object is a
  103. structure that has the Type type, which can be recognized in
  104. component 0. There, an object (name_1 ... name_i-1 name_i) should
  105. be located with one of the names EQ to type.
  106. */
  107. /* subroutine for structure-access-functions:
  108. > STACK_2: type-argument
  109. > STACK_1: structure-argument
  110. > STACK_0: index-argument
  111. < result: Address of the structure-element */
  112. local gcv_object_t* structure_up (void) {
  113. /* structure must be of Type structure: */
  114. if (!structurep(STACK_1)) {
  115. error_bad_structure: /* STACK_2 = type, STACK_1 = structure */
  116. pushSTACK(STACK_1); /* TYPE-ERROR slot DATUM */
  117. pushSTACK(STACK_(2+1)); /* TYPE-ERROR slot EXPECTED-TYPE */
  118. pushSTACK(STACK_(2+2));
  119. pushSTACK(STACK_(1+3));
  120. pushSTACK(TheSubr(subr_self)->name); /* function name */
  121. error(type_error,GETTEXT("~S: ~S is not a structure of type ~S"));
  122. }
  123. var object structure = STACK_1;
  124. /* check if type occurs in namelist = (name_1 ... name_i-1 name_i) : */
  125. if (!nullp(memq(STACK_2,TheStructure(structure)->structure_types)))
  126. goto yes;
  127. /* type did not occur -> Error: */
  128. goto error_bad_structure;
  129. yes: { /* type did occur: */
  130. var uintL length = (uintL)Structure_length(structure);
  131. var uintV index;
  132. /* fetch index and check */
  133. if (!(posfixnump(STACK_0) && ((index = posfixnum_to_V(STACK_0)) < length)))
  134. error_index(length);
  135. /* address of the structure-component */
  136. return &TheStructure(structure)->recdata[index];
  137. }
  138. }
  139. /* (SYS::%%STRUCTURE-REF type structure index) returns for a structure of
  140. the given Type type (a symbol) the entry index>=1.
  141. #<UNBOUND> is possible. */
  142. LISPFUNNR(pstructure_ref,3) {
  143. VALUES1(*(structure_up())); /* structure-element as value */
  144. skipSTACK(3); /* clean up stack */
  145. }
  146. /* (SYS::%STRUCTURE-REF type structure index) returns for a structure of
  147. the given Type type (a symbol) the entry index>=1. */
  148. LISPFUNNR(structure_ref,3) {
  149. VALUES1(*(structure_up())); /* structure-element as value */
  150. if (!boundp(value1)) {
  151. /* could be = #<UNBOUND> , after use of SLOT-MAKUNBOUND
  152. or after incomplete INITIALIZE-INSTANCE */
  153. dynamic_bind(S(print_length),Fixnum_0); /* bind *PRINT-LENGTH* to 0 */
  154. pushSTACK(STACK_(1+3)); /* UNBOUND-SLOT slot INSTANCE */
  155. /* (clos:slot-definition-name
  156. (find index (clos::class-slots (find-class type))
  157. :key #'clos:slot-definition-location)) */
  158. pushSTACK(STACK_(2+3+1)); funcall(L(find_class),1);
  159. pushSTACK(value1); funcall(S(class_slots),1);
  160. pushSTACK(STACK_(0+3+1)); pushSTACK(value1); pushSTACK(S(Kkey));
  161. pushSTACK(Symbol_function(S(slot_definition_location))); funcall(L(find),4);
  162. value1 = TheSlotDefinition(value1)->slotdef_name;
  163. pushSTACK(value1); /* UNBOUND-SLOT slot NAME */
  164. pushSTACK(STACK_(1+3+2));
  165. pushSTACK(value1);
  166. pushSTACK(S(structure_ref));
  167. error(unbound_slot,GETTEXT("~S: Slot ~S of ~S has no value"));
  168. }
  169. skipSTACK(3); /* clean up stack */
  170. }
  171. /* (SYS::%STRUCTURE-STORE type structure index object) stores object as
  172. entry index in a structure of given Type type and returns object. */
  173. LISPFUNN(structure_store,4) {
  174. var object value = popSTACK();
  175. VALUES1(*(structure_up()) = value); /* enter structure-element */
  176. skipSTACK(3); /* clean up stack */
  177. }
  178. /* (SYS::%MAKE-STRUCTURE type length) creates a structure with length>=1
  179. elements of Type type. */
  180. LISPFUNNR(make_structure,2) {
  181. /* check length, should be a fixnum /=0 that fits into a uintW: */
  182. var uintV length;
  183. test_record_length(length);
  184. skipSTACK(1);
  185. var object structure = allocate_structure(length);
  186. /* new structure, filled with NILs */
  187. TheStructure(structure)->structure_types = popSTACK(); /* type component */
  188. VALUES1(structure); /* structure as value */
  189. }
  190. /* check_structure_replacement(obj)
  191. > obj: not a structure object
  192. < result: a structure object, a replacement
  193. can trigger GC */
  194. global maygc object check_structure_replacement (object obj) {
  195. do {
  196. pushSTACK(NIL); /* no PLACE */
  197. pushSTACK(obj); /* TYPE-ERROR slot DATUM */
  198. pushSTACK(S(structure_object)); /* TYPE-ERROR slot EXPECTED-TYPE */
  199. pushSTACK(S(structure_object)); pushSTACK(obj);
  200. pushSTACK(TheSubr(subr_self)->name); /* function name */
  201. check_value(type_error,GETTEXT("~S: ~S is not a ~S"));
  202. obj = value1;
  203. } while (!structurep(obj));
  204. return obj;
  205. }
  206. /* (COPY-STRUCTURE structure) returns a copy of the Structure structure
  207. of the same type. */
  208. LISPFUNNR(copy_structure,1) {
  209. STACK_0 = check_structure(STACK_0);
  210. var uintC length = Structure_length(STACK_0);
  211. var object new_structure = allocate_structure(length);
  212. copy_mem_o(&TheStructure(new_structure)->structure_types,
  213. &TheStructure(popSTACK())->structure_types,length);
  214. VALUES1(new_structure);
  215. }
  216. /* (SYS::%STRUCTURE-TYPE-P type object) checks if object is a
  217. structure that has the Type type, which can be recognized in
  218. component 0. There, an object (name_1 ... name_i-1 name_i) should
  219. be located with one of the names EQ to type. */
  220. LISPFUNNR(structure_type_p,2) {
  221. /* check object for structure: */
  222. if (!structurep(STACK_0)) { skipSTACK(2); goto no; }
  223. {
  224. var object namelist = TheStructure(popSTACK())->structure_types;
  225. var object type = popSTACK();
  226. /* test, if type occurs in namelist = (name_1 ... name_i-1 name_i) : */
  227. if (!nullp(memq(type,namelist)))
  228. goto yes;
  229. }
  230. no: /* type did not occur: */
  231. VALUES1(NIL); return; /* 1 value NIL */
  232. yes: /* type did occur: */
  233. VALUES1(T); return;
  234. }
  235. /* ===========================================================================
  236. * Closures:
  237. (SYS::CLOSURE-NAME closure) returns the name of a closure.
  238. (SYS::CLOSURE-CODEVEC closure) returns the code-vector of a compiled
  239. closure as an array of fixnums >=0, <256.
  240. (SYS::CLOSURE-CONSTS closure) returns a list of all constants of a
  241. compiled closure.
  242. (SYS::MAKE-CLOSURE &key name code constants seclass lambda-list documentation
  243. jitc-p) returns a closure with given name (a symbol), given code-vector
  244. (a list of bytes), given constants, seclass, lalist, doc string and JITC_p.
  245. (SYS::MAKE-CONSTANT-INITFUNCTION value) returns a closure that, when called
  246. with 0 arguments, returns the given value.
  247. (SYS::CONSTANT-INITFUNCTION-P object) tests whether an object was returned by
  248. SYS::MAKE-CONSTANT-INITFUNCTION.
  249. (CLOS:SET-FUNCALLABLE-INSTANCE-FUNCTION closure function) redirects closure
  250. so that it calls the given function.
  251. (SYS::%COPY-GENERIC-FUNCTION venv closure) copies the closure, which must be
  252. a generic function with venv slot, copying in the given venv.
  253. (SYS::GENERIC-FUNCTION-EFFECTIVE-METHOD-FUNCTION generic-function)
  254. returns a function, which delivers the effective methods, so that
  255. (APPLY generic-function arguments)
  256. == (APPLY (APPLY result arguments) arguments) .
  257. */
  258. /* error, if argument is not a closure */
  259. nonreturning_function(local, error_closure, (object obj)) {
  260. pushSTACK(obj);
  261. pushSTACK(TheSubr(subr_self)->name); /* function name */
  262. error(error_condition, /* type_error ?? */
  263. GETTEXT("~S: ~S is not a closure"));
  264. }
  265. /* (SYS::CLOSURE-NAME closure) returns the name of a closure. */
  266. LISPFUNNR(closure_name,1) {
  267. var object closure = popSTACK();
  268. if (!closurep(closure)) error_closure(closure);
  269. VALUES1(Closure_name(closure));
  270. }
  271. /* ((SETF SYS::CLOSURE-NAME) new-value closure) changes the name of a
  272. closure. */
  273. LISPFUNN(set_closure_name,2) {
  274. var object closure = popSTACK();
  275. if (!closurep(closure)) error_closure(closure);
  276. var object new_name = popSTACK();
  277. if (Closure_instancep(closure))
  278. TheCclosure(closure)->clos_consts[1] = new_name;
  279. else
  280. TheClosure(closure)->clos_name_or_class_version = new_name;
  281. VALUES1(new_name);
  282. }
  283. /* error, if argument is not a compiled closure */
  284. nonreturning_function(local, error_cclosure, (object obj)) {
  285. pushSTACK(obj);
  286. pushSTACK(TheSubr(subr_self)->name); /* function name */
  287. error(error_condition, /* type_error ?? */
  288. GETTEXT("~S: ~S is not a compiled closure"));
  289. }
  290. /* (SYS::CLOSURE-CODEVEC closure) returns the code-vector of a compiled
  291. closure, as an array of fixnums >=0, <256. */
  292. LISPFUNNR(closure_codevec,1) {
  293. var object closure = popSTACK();
  294. if (!cclosurep(closure)) error_cclosure(closure);
  295. var object codevec = TheCclosure(closure)->clos_codevec;
  296. VALUES1(codevec);
  297. }
  298. /* (SYS::CLOSURE-CONSTS closure) returns a list of all constants of a
  299. compiled closure. */
  300. LISPFUNNR(closure_consts,1) {
  301. var object closure = popSTACK();
  302. if (!cclosurep(closure)) error_cclosure(closure);
  303. /* put elements 2,3,... to a list: */
  304. var uintB ccv_flags =
  305. TheCodevec(TheCclosure(closure)->clos_codevec)->ccv_flags;
  306. var uintC index = Cclosure_last_const(closure) + 1
  307. - ccv_flags_jitc_p(ccv_flags) - ccv_flags_documentation_p(ccv_flags)
  308. - ccv_flags_lambda_list_p(ccv_flags);
  309. /* step through closure from behind and push constants onto a list: */
  310. pushSTACK(closure); /* closure */
  311. pushSTACK(NIL); /* list := () */
  312. while (index != 0) {
  313. index--; /* decrement index */
  314. /* put new cons in front of the list: */
  315. var object new_cons = allocate_cons();
  316. Cdr(new_cons) = popSTACK();
  317. Car(new_cons) = TheCclosure(STACK_0)->clos_consts[(uintP)index]; /* fetch constant */
  318. pushSTACK(new_cons);
  319. }
  320. VALUES1(STACK_0); skipSTACK(2); /* list as value */
  321. }
  322. /* return the address of the Nth constant
  323. > STACK_0: position
  324. > STACK_1: compiled closure
  325. < address of the constant
  326. can trigger GC */
  327. local maygc gcv_object_t* closure_const (void) {
  328. var uintV pos = posfixnum_to_V(check_posfixnum(STACK_0));
  329. var object closure = STACK_1;
  330. if (!cclosurep(closure)) error_cclosure(closure);
  331. var uintB ccv_flags =
  332. TheCodevec(TheCclosure(closure)->clos_codevec)->ccv_flags;
  333. var uintC max_index = Cclosure_last_const(closure)
  334. - ccv_flags_documentation_p(ccv_flags) - ccv_flags_lambda_list_p(ccv_flags);
  335. if (pos > max_index) error_index(max_index);
  336. return &(TheCclosure(closure)->clos_consts[(uintP)pos]);
  337. }
  338. /* (SYS::CLOSURE-CONST closure n)
  339. returns the n-th constant of the compiled closure. */
  340. LISPFUNNR(closure_const,2) {
  341. VALUES1(*closure_const()); skipSTACK(2);
  342. }
  343. /* (SYS::SET-CLOSURE-CONST value closure n)
  344. set the n-th constant of the compiled closure. */
  345. LISPFUNN(set_closure_const,3) {
  346. VALUES1(*closure_const() = STACK_2); skipSTACK(3);
  347. }
  348. /* make_code_vector(list) converts a list of fixnums >=0, <256
  349. into a simple-8bit-vector of the same length, that contains these numbers
  350. as bytes. */
  351. local maygc void make_code_vector (gcv_object_t *code) {
  352. var object bv = allocate_bit_vector(Atype_8Bit,llength(*code)); /* simple-8bit-vector */
  353. /* fill: */
  354. var object listr = *code; /* list */
  355. var uintB* ptr = &TheSbvector(bv)->data[0]; /* loop through the bit-vector */
  356. while (consp(listr)) {
  357. var uintV byte;
  358. /* list element must be a fixnum >=0, <256 : */
  359. if (!(posfixnump(Car(listr))
  360. && ((byte = posfixnum_to_V(Car(listr))) < (1<<intBsize))))
  361. goto bad_byte;
  362. /* put into the bit-vector: */
  363. *ptr++ = (uintB)byte;
  364. listr = Cdr(listr);
  365. }
  366. *code = bv;
  367. return;
  368. bad_byte:
  369. pushSTACK(Car(listr)); /* TYPE-ERROR slot DATUM */
  370. pushSTACK(O(type_uint8)); /* TYPE-ERROR slot EXPECTED-TYPE */
  371. pushSTACK(STACK_1);
  372. error(type_error,GETTEXT("~S is not a valid code-vector byte"));
  373. }
  374. /* parse the seclass object (NIL or SECLASS, see compiler.lisp)
  375. into a seclass_t */
  376. local seclass_t parse_seclass (object sec, object closure)
  377. {
  378. if (nullp(sec)) return seclass_foldable;
  379. if (!consp(sec) || !consp(Cdr(sec)) || !consp(Cdr(Cdr(sec)))) {
  380. pushSTACK(closure); pushSTACK(sec);
  381. pushSTACK(TheSubr(subr_self)->name);
  382. error(error_condition,GETTEXT("~S: invalid side-effect class ~S for function ~S"));
  383. }
  384. var object modifies = Car(Cdr(sec));
  385. return (nullp(Car(sec))
  386. ? (nullp(modifies) ? seclass_no_se : seclass_write)
  387. : (nullp(modifies) ? seclass_read : seclass_default));
  388. }
  389. /* (SYS::%MAKE-CLOSURE name codevec consts seclassJ lambda-list documentation)
  390. returns a closure with given name (a symbol),
  391. given code-vector (a simple-bit-vector), given constants,
  392. given side-effect class, lambda-list and documentation. */
  393. LISPFUN(make_closure,seclass_default,0,0,norest,key,7,(kw(name),kw(code),
  394. kw(constants),kw(seclass),kw(lambda_list),kw(documentation),kw(jitc_p)))
  395. {
  396. var bool jitc_p = !eq(Fixnum_0,popSTACK());
  397. var seclass_t seclass = parse_seclass(STACK_2,STACK_5);
  398. /* convert code to a simple-bit-vector: */
  399. if (listp(STACK_4)) make_code_vector(&STACK_4);
  400. /* create a new closure of length
  401. (+ 2 (length consts) lalist-p doc-p jitc_p) : */
  402. var uintL length = 2+llength(STACK_3) + (jitc_p ? 1 : 0)
  403. +(listp(STACK_1) ? 1 : 0)+(nullp(STACK_0) || stringp(STACK_0) ? 1 : 0);
  404. if (!(length <= (uintL)(bitm(intWsize)-1))) { /* should fit into a uintW */
  405. pushSTACK(STACK_3/* constants */);
  406. pushSTACK(STACK_6/* name */);
  407. pushSTACK(TheSubr(subr_self)->name);
  408. error(error_condition,GETTEXT("~S: function ~S is too big: ~S"));
  409. }
  410. var object closure = allocate_closure(length,seclass<<4);
  411. TheCclosure(closure)->clos_name_or_class_version = STACK_5; /* fill name */
  412. TheCclosure(closure)->clos_codevec = STACK_4; /* fill codevector */
  413. /* fill constants: */
  414. var object constsr = STACK_3;
  415. var gcv_object_t* ptr = &TheCclosure(closure)->clos_consts[0];
  416. while (consp(constsr)) {
  417. *ptr++ = Car(constsr); constsr = Cdr(constsr);
  418. }
  419. var uintB *ccv_flags = &(TheCodevec(STACK_4)->ccv_flags);
  420. if (listp(STACK_1)) {
  421. *ccv_flags |= bit(1);
  422. *ptr++ = STACK_1;
  423. } else *ccv_flags &= ~bit(1);
  424. if (nullp(STACK_0) || stringp(STACK_0)) {
  425. *ccv_flags |= bit(2);
  426. *ptr++ = STACK_0;
  427. } else *ccv_flags &= ~bit(2);
  428. if (jitc_p) *ccv_flags |= bit(5);
  429. else *ccv_flags &= ~bit(5);
  430. VALUES1(closure); skipSTACK(6);
  431. }
  432. /* (SYS::MAKE-CONSTANT-INITFUNCTION value) returns a closure that, when called
  433. with 0 arguments, returns the given value. */
  434. LISPFUNN(make_constant_initfunction,1)
  435. {
  436. var object consts = listof(1);
  437. pushSTACK(S(constant_initfunction));
  438. pushSTACK(O(constant_initfunction_code));
  439. pushSTACK(consts);
  440. pushSTACK(O(seclass_no_se));
  441. pushSTACK(Fixnum_0); /* no lalist */
  442. pushSTACK(Fixnum_0); /* no doc */
  443. pushSTACK(Fixnum_0); /* no jitc */
  444. C_make_closure();
  445. }
  446. /* (SYS::CONSTANT-INITFUNCTION-P object) tests whether an object was returned by
  447. SYS::MAKE-CONSTANT-INITFUNCTION. */
  448. #define CONSTANT_INITFUNCTION_P(obj) (closurep(obj) \
  449. && eq(TheClosure(obj)->clos_name_or_class_version,S(constant_initfunction)) \
  450. && eq(TheClosure(obj)->clos_codevec,O(constant_initfunction_code)))
  451. LISPFUNN(constant_initfunction_p,1) {
  452. var object obj = popSTACK();
  453. VALUES_IF(CONSTANT_INITFUNCTION_P(obj));
  454. }
  455. LISPFUNN(closure_set_seclass,2)
  456. { /* (CLOSURE-SET-SECLASS closure new-seclass)
  457. - for adding methods to generic functions; return the old seclass */
  458. var object closure = STACK_1;
  459. if (!cclosurep(closure)) error_cclosure(closure);
  460. var seclass_t new_seclass = parse_seclass(STACK_0,closure);
  461. VALUES1(seclass_object((seclass_t)Cclosure_seclass(closure)));
  462. Cclosure_set_seclass(closure,new_seclass);
  463. skipSTACK(2);
  464. }
  465. LISPFUNNR(closure_documentation,1)
  466. { /* return the doc string, if any */
  467. var object closure = popSTACK();
  468. if (!cclosurep(closure)) error_cclosure(closure);
  469. var uintB ccv_flags =
  470. TheCodevec(TheCclosure(closure)->clos_codevec)->ccv_flags;
  471. /* depending on bit(5), the ultimate or the penultimate constant */
  472. VALUES1(ccv_flags_documentation_p(ccv_flags)
  473. ? (object)TheCclosure(closure)->clos_consts
  474. [Cclosure_last_const(closure)-ccv_flags_jitc_p(ccv_flags)]
  475. : NIL);
  476. }
  477. LISPFUNN(closure_set_documentation,2)
  478. { /* set the doc string, if possible*/
  479. if (!nullp(STACK_0)) STACK_0 = check_string(STACK_0);
  480. var object closure = STACK_1;
  481. if (!cclosurep(closure)) error_cclosure(closure);
  482. var uintB ccv_flags =
  483. TheCodevec(TheCclosure(closure)->clos_codevec)->ccv_flags;
  484. if (ccv_flags_documentation_p(ccv_flags))
  485. TheCclosure(closure)->clos_consts
  486. [Cclosure_last_const(closure)-ccv_flags_jitc_p(ccv_flags)] = STACK_0;
  487. VALUES1(STACK_0); skipSTACK(2);
  488. }
  489. LISPFUNNR(closure_lambda_list,1)
  490. { /* return the lambda list, if any */
  491. var object closure = popSTACK();
  492. if (!cclosurep(closure)) error_cclosure(closure);
  493. var uintB ccv_flags =
  494. TheCodevec(TheCclosure(closure)->clos_codevec)->ccv_flags;
  495. /* depending on bit(2) & bit(5), the ultimate, penultimate
  496. or pre-penultimate constant */
  497. VALUES1(ccv_flags_lambda_list_p(ccv_flags)
  498. ? (object)TheCclosure(closure)->clos_consts
  499. [Cclosure_last_const(closure)-ccv_flags_documentation_p(ccv_flags)
  500. -ccv_flags_jitc_p(ccv_flags)]
  501. : NIL);
  502. }
  503. /* (CLOS:SET-FUNCALLABLE-INSTANCE-FUNCTION closure function) redirects closure
  504. so that it calls the given function. */
  505. LISPFUNN(set_funcallable_instance_function,2)
  506. {
  507. var object closure = STACK_1;
  508. if (!funcallable_instance_p(closure)) {
  509. pushSTACK(closure); pushSTACK(TheSubr(subr_self)->name);
  510. error(error_condition, /* type_error ?? */
  511. GETTEXT("~S: argument is not a funcallable instance: ~S"));
  512. }
  513. var object function = STACK_0;
  514. if (!(subrp(function) || closurep(function) || ffunctionp(function))) {
  515. pushSTACK(function); /* TYPE-ERROR slot DATUM */
  516. pushSTACK(S(function)); /* TYPE-ERROR slot EXPECTED-TYPE */
  517. pushSTACK(function); pushSTACK(TheSubr(subr_self)->name);
  518. error(type_error, GETTEXT("~S: argument is not a function: ~S"));
  519. }
  520. var object codevec;
  521. var object venv;
  522. if (cclosurep(function) && Cclosure_length(function) <= 3) {
  523. codevec = TheCclosure(function)->clos_codevec;
  524. venv = (Cclosure_length(function) >= 3
  525. ? (object)TheCclosure(function)->clos_venv : NIL);
  526. } else {
  527. codevec = (pushSTACK(function), funcall(S(make_trampoline),1), value1);
  528. venv = STACK_0;
  529. closure = STACK_1;
  530. }
  531. if (record_flags(TheClosure(closure)) & instflags_forwarded_B) {
  532. var object closure_forwarded = TheClosure(closure)->clos_name_or_class_version;
  533. /* We know that there is at most one indirection. */
  534. ASSERT(!(record_flags(TheClosure(closure_forwarded)) & instflags_forwarded_B));
  535. /* Replace codevec and venv in both the original and the forwarded closure. */
  536. TheCclosure(closure_forwarded)->clos_codevec = codevec;
  537. TheCclosure(closure_forwarded)->clos_venv = venv;
  538. }
  539. TheCclosure(closure)->clos_codevec = codevec;
  540. TheCclosure(closure)->clos_venv = venv;
  541. VALUES1(closure); skipSTACK(2);
  542. }
  543. /* check_genericlambda_function(obj)
  544. > obj: an object
  545. < result: a function with a code vector produced by %GENERIC-FUNCTION-LAMBDA,
  546. either the same as obj or a replacement
  547. can trigger GC */
  548. local maygc object check_genericlambda_function_replacement (object obj) {
  549. do {
  550. pushSTACK(NIL); /* no PLACE */
  551. pushSTACK(obj); /* TYPE-ERROR slot DATUM */
  552. pushSTACK(S(standard_generic_function)); /* slot EXPECTED-TYPE */
  553. pushSTACK(S(standard_generic_function)); pushSTACK(obj);
  554. pushSTACK(TheSubr(subr_self)->name); /* function name */
  555. check_value(type_error,GETTEXT("~S: ~S is not a ~S"));
  556. obj = value1;
  557. } while (!genericlambda_function_p(obj));
  558. return obj;
  559. }
  560. local inline maygc object check_genericlambda_function (object obj) {
  561. if (!genericlambda_function_p(obj))
  562. obj = check_genericlambda_function_replacement(obj);
  563. return obj;
  564. }
  565. /* (SYS::%COPY-GENERIC-FUNCTION venv closure) copies the closure, which must be
  566. a generic function with venv slot, copying in the given venv. */
  567. LISPFUNN(copy_generic_function,2) {
  568. /* Note: closure's clos_venv is a simple-vector #(NIL c1 ... cn) where
  569. c1,...,cn are constant objects, and NIL is the placeholder to be replaced
  570. with the passed venv. */
  571. var object oldclos = check_genericlambda_function(STACK_0);
  572. var object vector = TheCclosure(oldclos)->clos_venv;
  573. if (!(simple_vector_p(vector)
  574. && (Svector_length(vector) > 0)
  575. && nullp(TheSvector(vector)->data[0]))) {
  576. pushSTACK(oldclos);
  577. pushSTACK(TheSubr(subr_self)->name); /* function name */
  578. error(error_condition,
  579. GETTEXT("~S: This is not a prototype of a generic function: ~S"));
  580. }
  581. vector = copy_svector(vector); /* copy the vector */
  582. TheSvector(vector)->data[0] = STACK_1; /* put in venv */
  583. STACK_1 = vector;
  584. /* Copy the function: */
  585. var object newclos = allocate_cclosure_copy(STACK_0);
  586. oldclos = STACK_0;
  587. do_cclosure_copy(newclos,oldclos);
  588. /* Put in the copied vector with venv: */
  589. TheCclosure(newclos)->clos_venv = STACK_1;
  590. VALUES1(newclos);
  591. skipSTACK(2);
  592. }
  593. /* (SYS::GENERIC-FUNCTION-EFFECTIVE-METHOD-FUNCTION generic-function)
  594. returns a function, which delivers the effective methods, so that
  595. (APPLY generic-function arguments)
  596. == (APPLY (APPLY result arguments) arguments) .
  597. is used for CALL-NEXT-METHOD; can assume that the
  598. generic-function has already been called, i.e. that the dispatch has
  599. already been installed. */
  600. LISPFUNN(generic_function_effective_method_function,1) {
  601. var object oldclos = STACK_0 = check_genericlambda_function(STACK_0);
  602. /* allocate closure of equal length: */
  603. var object newclos = allocate_cclosure_copy(oldclos);
  604. oldclos = STACK_0;
  605. do_cclosure_copy(newclos,oldclos);
  606. STACK_0 = newclos;
  607. /* copy the code-vector likewise: */
  608. var object newcodevec = copy_sbvector(TheClosure(newclos)->clos_codevec);
  609. /* set the bit therein which is queried by the RETGF-instruction: */
  610. TheCodevec(newcodevec)->ccv_flags |= bit(3);
  611. newclos = popSTACK();
  612. TheClosure(newclos)->clos_codevec = newcodevec;
  613. VALUES1(newclos);
  614. }
  615. /* ===========================================================================
  616. * load-time-eval:
  617. (SYS::MAKE-LOAD-TIME-EVAL form) returns a load-time-eval-object that
  618. - if printed and read again - evaluates form. */
  619. LISPFUN(make_load_time_eval,seclass_no_se,1,0,norest,nokey,0,NIL) {
  620. var object lte = allocate_loadtimeeval();
  621. TheLoadtimeeval(lte)->loadtimeeval_form = popSTACK();
  622. VALUES1(lte);
  623. }
  624. /* ===========================================================================
  625. * symbol-macro:
  626. (SYS::MAKE-SYMBOL-MACRO expansion) returns a symbol-macro-object
  627. that represents the given expansion.
  628. (SYS::SYMBOL-MACRO-P object) tests for symbol-macro.
  629. Due to their special meaning in the interpreter, symbol-macro-objects
  630. - like #<UNBOUND> and #<SPECDECL> - are not first class objects.
  631. They can be passed only as values. They cannot be assigned to
  632. variables, however.
  633. (SYMBOL-MACRO-EXPAND symbol) tests if a symbol represents a symbol-macro
  634. in the global environment and returns T and the expansion if true, NIL if
  635. false.
  636. */
  637. /* (SYS::MAKE-SYMBOL-MACRO expansion) returns a symbol-macro-object,
  638. that represents the given expansion. */
  639. LISPFUN(make_symbol_macro,seclass_no_se,1,0,norest,nokey,0,NIL) {
  640. var object sm = allocate_symbolmacro();
  641. TheSymbolmacro(sm)->symbolmacro_expansion = popSTACK();
  642. VALUES1(sm);
  643. }
  644. LISPFUNNF(symbol_macro_p,1)
  645. { /* (SYS::SYMBOL-MACRO-P object) tests for symbol-macro. */
  646. var object obj = popSTACK();
  647. VALUES_IF(symbolmacrop(obj));
  648. }
  649. /* (SYMBOL-MACRO-EXPAND symbol) tests if a symbol represents a symbol-macro
  650. and returns T and the expansion if true, NIL if false.
  651. (defun symbol-macro-expand (v)
  652. (unless (symbolp v) (error ...))
  653. (and (sys::global-symbol-macro-p v)
  654. (values t (sys::%record-ref (get v 'SYS::SYMBOLMACRO) 0)))) */
  655. LISPFUNN(symbol_macro_expand,1) {
  656. var object obj = check_symbol(popSTACK());
  657. if (symmacro_var_p(TheSymbol(obj))) {
  658. /* Fetch the symbol-macro definition from the property list: */
  659. var object symbolmacro = get(obj,S(symbolmacro));
  660. if (!eq(symbolmacro,unbound)) {
  661. ASSERT(globalsymbolmacrop(symbolmacro));
  662. VALUES2(T, TheSymbolmacro(TheGlobalSymbolmacro(symbolmacro)->globalsymbolmacro_definition)->symbolmacro_expansion);
  663. return;
  664. }
  665. /* Huh? The symbol-macro definition got lost. */
  666. clear_symmacro_flag(TheSymbol(obj));
  667. }
  668. VALUES1(NIL);
  669. }
  670. /* ===========================================================================
  671. * global-symbol-macro:
  672. The GlobalSymbolmacro object is used to wrap a Symbolmacro object while it
  673. is stored on the property list, so that user code that iterates over the
  674. elements of a property list in interpreted mode is not trapped.
  675. (SYS::MAKE-GLOBAL-SYMBOL-MACRO expansion) returns a global-symbol-macro object
  676. containing a symbol-macro object that represents the given expansion.
  677. (SYS::GLOBAL-SYMBOL-MACRO-DEFINITION object) unwraps a global-symbol-macro
  678. object and returns the symbol-macro object inside it.
  679. */
  680. /* (SYS::MAKE-GLOBAL-SYMBOL-MACRO expansion) returns a global-symbol-macro object
  681. containing a symbol-macro object that represents the given expansion. */
  682. LISPFUN(make_global_symbol_macro,seclass_no_se,1,0,norest,nokey,0,NIL) {
  683. pushSTACK(allocate_symbolmacro());
  684. var object gsm = allocate_globalsymbolmacro();
  685. var object sm = popSTACK();
  686. TheSymbolmacro(sm)->symbolmacro_expansion = popSTACK();
  687. TheGlobalSymbolmacro(gsm)->globalsymbolmacro_definition = sm;
  688. VALUES1(gsm);
  689. }
  690. /* (SYS::GLOBAL-SYMBOL-MACRO-DEFINITION object) unwraps a global-symbol-macro
  691. object and returns the symbol-macro object inside it. */
  692. LISPFUNN(global_symbol_macro_definition,1)
  693. {
  694. var object obj = popSTACK();
  695. while (!globalsymbolmacrop(obj)) {
  696. pushSTACK(NIL); /* no PLACE */
  697. pushSTACK(obj); /* TYPE-ERROR slot DATUM */
  698. pushSTACK(S(global_symbol_macro)); /* TYPE-ERROR slot EXPECTED-TYPE */
  699. pushSTACK(S(global_symbol_macro)); pushSTACK(obj);
  700. pushSTACK(S(global_symbol_macro_definition)); /* function name */
  701. check_value(type_error,GETTEXT("~S: ~S is not a ~S"));
  702. obj = value1;
  703. }
  704. VALUES1(TheGlobalSymbolmacro(obj)->globalsymbolmacro_definition);
  705. }
  706. /* ===========================================================================
  707. * Macro:
  708. (SYS::MAKE-MACRO expander lambdalist) returns a Macro object with the given
  709. expander function and macro lambda list.
  710. (SYS::MACROP object) tests for a Macro.
  711. (SYS::MACRO-EXPANDER macro) returns the macro's expander function. */
  712. /* (SYS::MAKE-MACRO expander lambdalist)
  713. returns a Macro object with the given expander function. */
  714. LISPFUN(make_macro,seclass_no_se,2,0,norest,nokey,0,NIL) {
  715. STACK_1 = check_function(STACK_1);
  716. var object m = allocate_macro();
  717. TheMacro(m)->macro_lambda_list = popSTACK();
  718. TheMacro(m)->macro_expander = popSTACK();
  719. VALUES1(m);
  720. }
  721. /* (SYS::MACROP object) tests for a Macro. */
  722. LISPFUNN(macrop,1) {
  723. var object obj = popSTACK();
  724. VALUES_IF(macrop(obj));
  725. }
  726. /* UP: check that the argument is a macro
  727. > mac: macro
  728. < mac: same
  729. can trigger GC */
  730. local maygc object check_macro (object obj) {
  731. while (!macrop(obj)) {
  732. pushSTACK(NIL); /* no PLACE */
  733. pushSTACK(obj); /* TYPE-ERROR slot DATUM */
  734. pushSTACK(S(macro)); /* TYPE-ERROR slot EXPECTED-TYPE */
  735. pushSTACK(S(macro)); pushSTACK(obj);
  736. pushSTACK(TheSubr(subr_self)->name); /* function name */
  737. check_value(type_error,GETTEXT("~S: ~S is not a ~S"));
  738. obj = value1;
  739. }
  740. return obj;
  741. }
  742. /* (SYS::MACRO-EXPANDER macro) returns the macro's expander function. */
  743. LISPFUNN(macro_expander,1) {
  744. var object obj = check_macro(popSTACK());
  745. VALUES1(TheMacro(obj)->macro_expander);
  746. }
  747. /* (SYS::MACRO-LAMBDA-LIST macro) returns the macro's lambda list. */
  748. LISPFUNN(macro_lambda_list,1) {
  749. STACK_0 = check_macro(STACK_0);
  750. var object lalist = TheMacro(STACK_0)->macro_lambda_list;
  751. if (!listp(lalist))
  752. error(error_condition,GETTEXT("Due to the compiler optimization settings, lambda list for ~S is not available"));
  753. VALUES1(lalist); skipSTACK(1);
  754. }
  755. /* ===========================================================================
  756. * FunctionMacro:
  757. (SYS::MAKE-FUNCTION-MACRO function expander) returns a FunctionMacro object
  758. for the given function and with the given expander function.
  759. (SYS::FUNCTION-MACRO-P object) tests for a FunctionMacro.
  760. (SYS::FUNCTION-MACRO-FUNCTION macro) returns the functionmacro's function.
  761. (SYS::FUNCTION-MACRO-EXPANDER macro) returns the functionmacro's expander. */
  762. /* (SYS::MAKE-FUNCTION-MACRO function expander) returns a FunctionMacro object
  763. for the given function and with the given expander function. */
  764. LISPFUNN(make_function_macro,2) {
  765. STACK_0 = check_function(STACK_0);
  766. STACK_1 = check_function(STACK_1);
  767. var object m = allocate_functionmacro();
  768. TheFunctionMacro(m)->functionmacro_macro_expander = popSTACK();
  769. TheFunctionMacro(m)->functionmacro_function = popSTACK();
  770. VALUES1(m);
  771. }
  772. /* (SYS::FUNCTION-MACRO-P object) tests for a FunctionMacro. */
  773. LISPFUNN(function_macro_p,1) {
  774. var object obj = popSTACK();
  775. VALUES_IF(functionmacrop(obj));
  776. }
  777. /* ensure that the OBJ is a FUNCTION-MACRO and return it
  778. can trigger GC */
  779. local maygc object check_function_macro (object obj) {
  780. while (!functionmacrop(obj)) {
  781. pushSTACK(NIL); /* no PLACE */
  782. pushSTACK(obj); /* TYPE-ERROR slot DATUM */
  783. pushSTACK(S(function_macro)); /* TYPE-ERROR slot EXPECTED-TYPE */
  784. pushSTACK(S(function_macro)); pushSTACK(obj);
  785. pushSTACK(S(function_macro_expander)); /* function name */
  786. check_value(type_error,GETTEXT("~S: ~S is not a ~S"));
  787. obj = value1;
  788. }
  789. return obj;
  790. }
  791. /* (SYS::FUNCTION-MACRO-FUNCTION macro)
  792. returns the FunctionMacro's function. */
  793. LISPFUNN(function_macro_function,1) {
  794. var object obj = check_function_macro(popSTACK());
  795. VALUES1(TheFunctionMacro(obj)->functionmacro_function);
  796. }
  797. /* (SYS::FUNCTION-MACRO-EXPANDER macro)
  798. returns the FunctionMacro's expander. */
  799. LISPFUNN(function_macro_expander,1) {
  800. var object obj = check_function_macro(popSTACK());
  801. VALUES1(TheFunctionMacro(obj)->functionmacro_macro_expander);
  802. }
  803. /* ===========================================================================
  804. * Finalizer: */
  805. /* (FINALIZE object function &optional alive)
  806. records that function is called if object dies through GC, with
  807. object and poss. alive as argument. If alive dies before object dies,
  808. nothing will be done. */
  809. LISPFUN(finalize,seclass_default,2,1,norest,nokey,0,NIL) {
  810. STACK_1 = coerce_function(STACK_1);
  811. if (!gcinvariant_object_p(STACK_2)) {
  812. var object f = allocate_finalizer();
  813. TheFinalizer(f)->fin_trigger = STACK_2;
  814. TheFinalizer(f)->fin_function = STACK_1;
  815. TheFinalizer(f)->fin_alive = STACK_0; /* The default #<UNBOUND> lives forever. */
  816. TheFinalizer(f)->fin_cdr = O(all_finalizers);
  817. O(all_finalizers) = f;
  818. }
  819. skipSTACK(3); VALUES1(NIL);
  820. }
  821. /* ===========================================================================
  822. * CLOS objects: */
  823. /* (CLOS::STRUCTURE-OBJECT-P object) tests if object is a structure. */
  824. LISPFUNNF(structure_object_p,1)
  825. {
  826. var object obj = popSTACK();
  827. VALUES_IF(structurep(obj));
  828. }
  829. /* (CLOS::STD-INSTANCE-P object) tests if object is a CLOS-object
  830. (funcallable or not). */
  831. LISPFUNNF(std_instance_p,1)
  832. {
  833. var object obj = popSTACK();
  834. VALUES_IF(instancep(obj));
  835. }
  836. /* (CLOS::FUNCALLABLE-INSTANCE-P object) tests if object is a funcallable
  837. CLOS-object. */
  838. LISPFUNNF(funcallable_instance_p,1)
  839. {
  840. var object obj = popSTACK();
  841. VALUES_IF(funcallable_instance_p(obj));
  842. }
  843. /* returns (CLOS:CLASS-OF object). Especially efficient for CLOS objects.
  844. can trigger GC */
  845. local inline maygc object class_of (object obj) {
  846. if (instancep(obj)) {
  847. var object obj_forwarded = obj;
  848. instance_un_realloc(obj_forwarded);
  849. if ((record_flags(TheInstance(obj_forwarded)) & instflags_beingupdated_B) == 0) {
  850. /* We need instance_update here because CLHS 4.3.6. says:
  851. "Updating such an instance occurs at an implementation-dependent time,
  852. but no later than the next time a slot of that instance is read or
  853. written." */
  854. instance_update(obj,obj_forwarded);
  855. var object cv = TheInstance(obj_forwarded)->inst_class_version;
  856. return TheClassVersion(cv)->cv_newest_class;
  857. } else {
  858. /* Accessing an instance which is being updated. */
  859. var object cv = TheInstance(obj_forwarded)->inst_class_version;
  860. return TheClassVersion(cv)->cv_class;
  861. }
  862. } else {
  863. pushSTACK(obj); C_class_of(); return value1;
  864. }
  865. }
  866. /* (CLOS::ALLOCATE-METAOBJECT-INSTANCE class-version n) returns a CLOS-instance
  867. of length n, with ClassVersion class-version and n-1 additional slots. It does
  868. this without marking the class as being instantiated and is therefore suitable
  869. only for classes that are never redefined, such as CLASS, SLOT-DEFINITION. */
  870. LISPFUNN(allocate_metaobject_instance,2) {
  871. /* check length, should be a fixnum >0 that fits into a uintW: */
  872. var uintV length;
  873. test_record_length(length);
  874. skipSTACK(1);
  875. {
  876. var object cv = STACK_0;
  877. if (!(simple_vector_p(cv) && Svector_length(cv) == classversion_length)) {
  878. pushSTACK(cv);
  879. pushSTACK(TheSubr(subr_self)->name); /* function name */
  880. error(error_condition,GETTEXT("~S: ~S is not a CLOS class-version"));
  881. }
  882. }
  883. var object instance =
  884. allocate_srecord(0,Rectype_Instance,length,instance_type);
  885. TheInstance(instance)->inst_class_version = popSTACK();
  886. /* fill the slots of the instance with #<UNBOUND> : */
  887. length--;
  888. if (length > 0) {
  889. var gcv_object_t* ptr = &TheInstance(instance)->other[0];
  890. dotimespV(length,length, { *ptr++ = unbound; } );
  891. }
  892. VALUES1(instance); /* instance as value */
  893. }
  894. /* (CLOS::ALLOCATE-STD-INSTANCE class n) returns a CLOS-instance of length n,
  895. with Class class and n-1 additional slots. */
  896. LISPFUNN(allocate_std_instance,2) {
  897. /* check length, should be a fixnum >0 that fits into a uintW: */
  898. var uintV length;
  899. test_record_length(length);
  900. skipSTACK(1);
  901. { /* Fetch the class-version now, before any possible GC, at which the
  902. user could redefine the class of which we are creating an instance. */
  903. var object clas = STACK_0;
  904. if_defined_class_p(clas, ; , error_class(clas); );
  905. TheClass(clas)->instantiated = T;
  906. STACK_0 = TheClass(clas)->current_version;
  907. }
  908. var object instance =
  909. allocate_srecord(0,Rectype_Instance,length,instance_type);
  910. TheInstance(instance)->inst_class_version = popSTACK();
  911. /* fill the slots of the instance with #<UNBOUND> : */
  912. length--;
  913. if (length > 0) {
  914. var gcv_object_t* ptr = &TheInstance(instance)->other[0];
  915. dotimespV(length,length, { *ptr++ = unbound; } );
  916. }
  917. VALUES1(instance); /* instance as value */
  918. }
  919. /* (CLOS::ALLOCATE-FUNCALLABLE-INSTANCE class n) returns a funcallable
  920. CLOS-instance of length n, with Class class and n-3 additional slots. */
  921. LISPFUNN(allocate_funcallable_instance,2) {
  922. /* check length, should be a fixnum >3 that fits into a uintW: */
  923. var uintV length;
  924. test_record_length(length);
  925. if (!(length>3)) error_record_length();
  926. skipSTACK(1);
  927. { /* Fetch the class-version now, before any possible GC, at which the
  928. user could redefine the class of which we are creating an instance. */
  929. var object clas = STACK_0;
  930. if_defined_class_p(clas, ; , error_class(clas); );
  931. TheClass(clas)->instantiated = T;
  932. STACK_0 = TheClass(clas)->current_version;
  933. }
  934. /* Allocate the closure. seclass is seclass_default (= *seclass-dirty*)
  935. because even simple generic functions can signal a NO-APPLICABLE-METHOD
  936. error. */
  937. var object instance =
  938. allocate_srecord(closflags_instance_B|(seclass_default<<4),
  939. Rectype_Closure,length,closure_type);
  940. TheCclosure(instance)->clos_name_or_class_version = popSTACK();
  941. /* Provide a dummy codevector, in case the funcallable instance is called too
  942. early. */
  943. TheCclosure(instance)->clos_codevec = O(endless_loop_code);
  944. TheCclosure(instance)->clos_venv = NIL;
  945. /* fill the slots of the instance with #<UNBOUND> : */
  946. length -= 3;
  947. {
  948. var gcv_object_t* ptr = &TheCclosure(instance)->clos_consts[1];
  949. dotimespV(length,length, { *ptr++ = unbound; } );
  950. }
  951. VALUES1(instance); /* instance as value */
  952. }
  953. /* Checks that the argcount last words on the STACK form an
  954. "initialization argument list". */
  955. local inline void check_initialization_argument_list (uintL argcount, object caller) {
  956. if (argcount%2 != 0)
  957. error_key_odd(argcount,caller);
  958. if (argcount > 0) {
  959. var gcv_object_t* argptr = STACK STACKop argcount;
  960. do {
  961. if (!symbolp(Next(argptr))) {
  962. pushSTACK(Next(argptr)); pushSTACK(caller);
  963. /* ANSI CL 3.5.1.5. wants a PROGRAM-ERROR here. */
  964. error(program_error,GETTEXT("~S: invalid initialization argument ~S"));
  965. }
  966. argptr skipSTACKop -2;
  967. argcount -= 2;
  968. } while (argcount > 0);
  969. }
  970. }
  971. local Values do_allocate_instance (object clas);
  972. /* (CLOS::%ALLOCATE-INSTANCE class &rest initargs)
  973. returns an instance of the class.
  974. class must be an instance of <standard-class> or <structure-class>. */
  975. LISPFUN(pallocate_instance,seclass_read,1,0,rest,nokey,0,NIL) {
  976. check_initialization_argument_list(argcount,S(allocate_instance));
  977. /* No need to check the validity of the initargs, because ANSI CL says
  978. "The caller of allocate-instance is expected to have already checked
  979. the initialization arguments." */
  980. set_args_end_pointer(rest_args_pointer); /* clean up STACK */
  981. return_Values do_allocate_instance(popSTACK());
  982. }
  983. local Values do_allocate_instance (object clas) {
  984. /* Make a distinction between <semi-standard-class> and <structure-class> for
  985. allocate-instance: Is (class-current-version class) a vector, or
  986. is (class-names class) a cons? */
  987. if (matomp(TheClass(clas)->current_version)) {
  988. /* <semi-standard-class>. */
  989. if (!eq(TheClass(clas)->initialized,fixnum(6))) {
  990. /* Call (CLOS:FINALIZE-INHERITANCE class). */
  991. pushSTACK(clas); /* save clas */
  992. pushSTACK(clas); funcall(S(finalize_inheritance),1);
  993. clas = popSTACK(); /* restore clas */
  994. /* The class must be finalized now, otherwise FINALIZE-INHERITANCE has
  995. not done its job. */
  996. ASSERT(eq(TheClass(clas)->initialized,fixnum(6)));
  997. }
  998. /* Make a distinction between <standard-class> and
  999. <funcallable-standard-class>. */
  1000. pushSTACK(clas); pushSTACK(TheClass(clas)->instance_size);
  1001. if (nullp(TheClass(clas)->funcallablep)) {
  1002. /* <standard-class>. */
  1003. /* (CLOS::ALLOCATE-STD-INSTANCE class (class-instance-size class)) */
  1004. C_allocate_std_instance();
  1005. } else {
  1006. /* <funcallable-standard-class>. */
  1007. /* (CLOS::ALLOCATE-FUNCALLABLE-INSTANCE class (class-instance-size class)) */
  1008. C_allocate_funcallable_instance();
  1009. }
  1010. } else {
  1011. /* <structure-class>. */
  1012. /* (SYS::%MAKE-STRUCTURE (class-names class) (class-instance-size class))*/
  1013. pushSTACK(TheClass(clas)->current_version);
  1014. pushSTACK(TheClass(clas)->instance_size);
  1015. C_make_structure();
  1016. /* fill the slots of the structure with #<UNBOUND> for
  1017. INITIALIZE-INSTANCE to enter the default-values later: */
  1018. var uintL count = Structure_length(value1)-1;
  1019. if (count > 0) {
  1020. var gcv_object_t* ptr = &TheStructure(value1)->recdata[1];
  1021. dotimespL(count,count, { *ptr++ = unbound; } );
  1022. }
  1023. }
  1024. }
  1025. /* (CLOS:SLOT-VALUE instance slot-name)
  1026. (CLOS::SET-SLOT-VALUE instance slot-name new-value)
  1027. (CLOS:SLOT-BOUNDP instance slot-name)
  1028. (CLOS:SLOT-MAKUNBOUND instance slot-name)
  1029. (CLOS:SLOT-EXISTS-P instance slot-name)
  1030. CLtL2 p. 855,857
  1031. The functions CLOS::%SLOT-...-USING-CLASS are the default methods; they
  1032. access the cell indicated by the slot's location. The functions CLOS:SLOT-...
  1033. are the general wrapper; they dispatch to the SLOT-...-USING-CLASS generic
  1034. function if necessary and - as an optimization - access the cell indicated
  1035. by the slot's location if possible. */
  1036. /* Derives the address of an existing slot in an instance of a standard-
  1037. or structure-class from a slot-location-info. */
  1038. local inline gcv_object_t* ptr_to_slot (object instance, object slotinfo,
  1039. object slotname) {
  1040. instance_un_realloc(instance); /* by this time update_instance() is done */
  1041. if (posfixnump(slotinfo)) /* local slot, slotinfo is index */
  1042. return &TheSrecord(instance)->recdata[posfixnum_to_V(slotinfo)];
  1043. if (consp(slotinfo)) /* shared slot, slotinfo is (class-version . index) */
  1044. return &TheSvector(TheClassVersion(Car(slotinfo))->cv_shared_slots)
  1045. ->data[posfixnum_to_V(Cdr(slotinfo))];
  1046. /* invalid location, probably bad :allocation slot option */
  1047. pushSTACK(instance); pushSTACK(slotname);
  1048. pushSTACK(slotinfo); pushSTACK(TheSubr(subr_self)->name);
  1049. error(error_condition,GETTEXT("~S: Invalid location ~S of slot ~S in ~S (check the :ALLOCATION slot option"));
  1050. }
  1051. /* UP: visits a slot.
  1052. slot_using_class_up()
  1053. > STACK_2: class
  1054. > STACK_1: instance
  1055. > STACK_0: slot-definition
  1056. < result: pointer to the slot */
  1057. local gcv_object_t* slot_using_class_up (void) {
  1058. /* The method applicability already guarantees that
  1059. - the class is a <semi-standard-class>,
  1060. - the slot is a <standard-effective-slot-definition>. */
  1061. var object clas = class_of(STACK_1); /* determine (CLASS-OF instance) */
  1062. if (!eq(clas,STACK_2)) {
  1063. pushSTACK(STACK_1); pushSTACK(STACK_(2+1));
  1064. pushSTACK(TheSubr(subr_self)->name);
  1065. error(error_condition,GETTEXT("~S: invalid arguments: class argument ~S is not the class of ~S"));
  1066. }
  1067. var object slotinfo = TheSlotDefinition(STACK_0)->slotdef_location;
  1068. return ptr_to_slot(STACK_1,slotinfo,STACK_0);
  1069. }
  1070. /* (CLOS::%SLOT-VALUE-USING-CLASS class instance slot) */
  1071. LISPFUNN(pslot_value_using_class,3) {
  1072. var gcv_object_t* slot = slot_using_class_up();
  1073. var object value = *slot;
  1074. if (boundp(value)) {
  1075. value1 = value;
  1076. skipSTACK(3);
  1077. } else {
  1078. /* (SLOT-UNBOUND class instance slot-name) */
  1079. STACK_0 = TheSlotDefinition(STACK_0)->slotdef_name;
  1080. funcall(S(slot_unbound),3);
  1081. }
  1082. mv_count=1;
  1083. }
  1084. /* (CLOS::%SET-SLOT-VALUE-USING-CLASS new-value class instance slot) */
  1085. LISPFUNN(pset_slot_value_using_class,4) {
  1086. var gcv_object_t* slot = slot_using_class_up();
  1087. value1 = *slot = STACK_3;
  1088. mv_count=1;
  1089. skipSTACK(4);
  1090. }
  1091. /* (CLOS::%SLOT-BOUNDP-USING-CLASS class instance slot) */
  1092. LISPFUNN(pslot_boundp_using_class,3) {
  1093. var gcv_object_t* slot = slot_using_class_up();
  1094. VALUES_IF(boundp(*slot));
  1095. skipSTACK(3);
  1096. }
  1097. /* (CLOS::%SLOT-MAKUNBOUND-USING-CLASS class instance slot) */
  1098. LISPFUNN(pslot_makunbound_using_class,3) {
  1099. var gcv_object_t* slot = slot_using_class_up();
  1100. *slot = unbound;
  1101. VALUES1(STACK_1); /* instance as value */
  1102. skipSTACK(3);
  1103. }
  1104. /* (CLOS:SLOT-VALUE instance slot-name) */
  1105. LISPFUNN(slot_value,2) {
  1106. /* stack layout: instance, slot-name. */
  1107. var object clas = class_of(STACK_1); /* determine (CLASS-OF instance) */
  1108. var object slotinfo = /* (GETHASH slot-name (class-slot-location-table class)) */
  1109. gethash(STACK_0,TheClass(clas)->slot_location_table,false);
  1110. if (!eq(slotinfo,nullobj)) { /* found? */
  1111. if (regular_instance_p(slotinfo)) {
  1112. if (!eq(TheSlotDefinition(slotinfo)->slotdef_efm_svuc,L(pslot_value_using_class))) {
  1113. /* Call the effective method of CLOS:SLOT-VALUE-USING-CLASS. */
  1114. var object efm = TheSlotDefinition(slotinfo)->slotdef_efm_svuc;
  1115. pushSTACK(clas); pushSTACK(STACK_(1+1)); pushSTACK(slotinfo);
  1116. funcall(efm,3);
  1117. goto done;
  1118. }
  1119. slotinfo = TheSlotDefinition(slotinfo)->slotdef_location;
  1120. }
  1121. var gcv_object_t* slot = ptr_to_slot(STACK_1,slotinfo,STACK_0);
  1122. var object value = *slot;
  1123. if (boundp(value)) {
  1124. value1 = value;
  1125. } else {
  1126. /* (SLOT-UNBOUND class instance slot-name) */
  1127. pushSTACK(clas); pushSTACK(STACK_(1+1)); pushSTACK(STACK_(0+2));
  1128. funcall(S(slot_unbound),3);
  1129. }
  1130. } else {
  1131. /* missing slot -> (SLOT-MISSING class instance slot-name 'slot-value) */
  1132. pushSTACK(clas); pushSTACK(STACK_(1+1)); pushSTACK(STACK_(0+2));
  1133. pushSTACK(S(slot_value));
  1134. funcall(S(slot_missing),4);
  1135. }
  1136. done:
  1137. mv_count=1;
  1138. skipSTACK(2);
  1139. }
  1140. /* (CLOS::SET-SLOT-VALUE instance slot-name new-value) */
  1141. LISPFUNN(set_slot_value,3) {
  1142. /* stack layout: instance, slot-name, new-value. */
  1143. var object clas = class_of(STACK_2); /* determine (CLASS-OF instance) */
  1144. var object slotinfo = /* (GETHASH slot-name (class-slot-location-table class)) */
  1145. gethash(STACK_1,TheClass(clas)->slot_location_table,false);
  1146. if (!eq(slotinfo,nullobj)) { /* found? */
  1147. if (regular_instance_p(slotinfo)) {
  1148. if (!eq(TheSlotDefinition(slotinfo)->slotdef_efm_ssvuc,L(pset_slot_value_using_class))) {
  1149. /* Call the effective method of (SETF CLOS:SLOT-VALUE-USING-CLASS). */
  1150. var object efm = TheSlotDefinition(slotinfo)->slotdef_efm_ssvuc;
  1151. pushSTACK(STACK_0); pushSTACK(clas); pushSTACK(STACK_(2+2));
  1152. pushSTACK(slotinfo);
  1153. funcall(efm,4);
  1154. /* It must return the new-value. But anyway, just for safety
  1155. (don't trust user-defined methods): */
  1156. value1 = STACK_0;
  1157. goto done;
  1158. }
  1159. slotinfo = TheSlotDefinition(slotinfo)->slotdef_location;
  1160. }
  1161. value1 = *ptr_to_slot(STACK_2,slotinfo,STACK_1) = STACK_0;
  1162. } else {
  1163. /* missing slot
  1164. -> (SLOT-MISSING class instance slot-name 'setf new-value) */
  1165. pushSTACK(clas); pushSTACK(STACK_(2+1)); pushSTACK(STACK_(1+2));
  1166. pushSTACK(S(setf)); pushSTACK(STACK_(0+4));
  1167. funcall(S(slot_missing),5);
  1168. value1 = STACK_0;
  1169. }
  1170. done:
  1171. mv_count=1;
  1172. skipSTACK(3);
  1173. }
  1174. /* (CLOS:SLOT-BOUNDP instance slot-name) */
  1175. LISPFUNN(slot_boundp,2) {
  1176. /* stack layout: instance, slot-name. */
  1177. var object clas = class_of(STACK_1); /* determine (CLASS-OF instance) */
  1178. var object slotinfo = /* (GETHASH slot-name (class-slot-location-table class)) */
  1179. gethash(STACK_0,TheClass(clas)->slot_location_table,false);
  1180. if (!eq(slotinfo,nullobj)) { /* found? */
  1181. if (regular_instance_p(slotinfo)) {
  1182. if (!eq(TheSlotDefinition(slotinfo)->slotdef_efm_sbuc,L(pslot_boundp_using_class))) {
  1183. /* Call the effective method of CLOS:SLOT-BOUNDP-USING-CLASS. */
  1184. var object efm = TheSlotDefinition(slotinfo)->slotdef_efm_sbuc;
  1185. pushSTACK(clas); pushSTACK(STACK_(1+1)); pushSTACK(slotinfo);
  1186. funcall(efm,3);
  1187. goto done;
  1188. }
  1189. slotinfo = TheSlotDefinition(slotinfo)->slotdef_location;
  1190. }
  1191. var gcv_object_t* slot = ptr_to_slot(STACK_1,slotinfo,STACK_0);
  1192. VALUES_IF(boundp(*slot));
  1193. } else {
  1194. /* missing slot -> (SLOT-MISSING class instance slot-name 'slot-boundp) */
  1195. pushSTACK(clas); pushSTACK(STACK_(1+1)); pushSTACK(STACK_(0+2));
  1196. pushSTACK(S(slot_boundp));
  1197. funcall(S(slot_missing),4);
  1198. VALUES_IF(!nullp(value1));
  1199. }
  1200. done:
  1201. skipSTACK(2);
  1202. }
  1203. /* (CLOS:SLOT-MAKUNBOUND instance slot-name) */
  1204. LISPFUNN(slot_makunbound,2) {
  1205. /* stack layout: instance, slot-name. */
  1206. var object clas = class_of(STACK_1); /* determine (CLASS-OF instance) */
  1207. var object slotinfo = /* (GETHASH slot-name (class-slot-location-table class)) */
  1208. gethash(STACK_0,TheClass(clas)->slot_location_table,false);
  1209. if (!eq(slotinfo,nullobj)) { /* found? */
  1210. if (regular_instance_p(slotinfo)) {
  1211. if (!eq(TheSlotDefinition(slotinfo)->slotdef_efm_smuc,L(pslot_makunbound_using_class))) {
  1212. /* Call the effective method of CLOS:SLOT-MAKUNBOUND-USING-CLASS. */
  1213. var object efm = TheSlotDefinition(slotinfo)->slotdef_efm_smuc;
  1214. pushSTACK(clas); pushSTACK(STACK_(1+1)); pushSTACK(slotinfo);
  1215. funcall(efm,3);
  1216. goto done;
  1217. }
  1218. slotinfo = TheSlotDefinition(slotinfo)->slotdef_location;
  1219. }
  1220. var gcv_object_t* slot = ptr_to_slot(STACK_1,slotinfo,STACK_0);
  1221. *slot = unbound;
  1222. } else {
  1223. /* missing slot -> (SLOT-MISSING class instance slot-name 'slot-makunbound) */
  1224. pushSTACK(clas); pushSTACK(STACK_(1+1)); pushSTACK(STACK_(0+2));
  1225. pushSTACK(S(slot_makunbound));
  1226. funcall(S(slot_missing),4);
  1227. }
  1228. done:
  1229. VALUES1(STACK_1); /* instance as value */
  1230. skipSTACK(2);
  1231. }
  1232. /* (CLOS:SLOT-EXISTS-P instance slot-name) */
  1233. LISPFUNNR(slot_exists_p,2) {
  1234. var object clas = class_of(STACK_1); /* determine (CLASS-OF instance) */
  1235. var object slotinfo = /* (GETHASH slot-name (class-slot-location-table class)) */
  1236. gethash(STACK_0,TheClass(clas)->slot_location_table,false);
  1237. VALUES_IF(! eq(slotinfo,nullobj)); skipSTACK(2);
  1238. }
  1239. /* (CLOS:STANDARD-INSTANCE-ACCESS instance location)
  1240. ((SETF CLOS:STANDARD-INSTANCE-ACCESS) new-value instance location)
  1241. Unlike specified in the MOP, these work for non-updated obsolete instances
  1242. as well. */
  1243. /* UP: visits a slot.
  1244. slot_access_up()
  1245. > STACK_1: instance
  1246. > STACK_0: location
  1247. < result: pointer to the slot */
  1248. local gcv_object_t* slot_access_up (void) {
  1249. var object obj = STACK_1;
  1250. /* Preparations like as in class_of. */
  1251. if (instancep(obj)) {
  1252. var object obj_forwarded = obj;
  1253. instance_un_realloc(obj_forwarded);
  1254. if ((record_flags(TheInstance(obj_forwarded)) & instflags_beingupdated_B) == 0) {
  1255. instance_update(obj,obj_forwarded);
  1256. }
  1257. var object slotinfo = STACK_0;
  1258. if (atomp(slotinfo)) {
  1259. /* local slot, slotinfo is index */
  1260. var uintL length = srecord_length(TheInstance(obj_forwarded));
  1261. var uintV index;
  1262. if (posfixnump(slotinfo) && ((index = posfixnum_to_V(slotinfo)) < length)) {
  1263. return &((Srecord)TheInstance(obj_forwarded))->recdata[index];
  1264. } else {
  1265. error_index(length);
  1266. }
  1267. } else if (consp(slotinfo)) {
  1268. /* shared slot, slotinfo is (class-version . index) */
  1269. return &TheSvector(TheClassVersion(Car(slotinfo))->cv_shared_slots)
  1270. ->data[posfixnum_to_V(Cdr(slotinfo))];
  1271. } else {
  1272. /* location already in STACK_0. */
  1273. pushSTACK(TheSubr(subr_self)->name); /* function name */
  1274. error(error_condition,GETTEXT("~S: invalid slot location ~S"));
  1275. }
  1276. } else {
  1277. /* instance already in STACK_1. TYPE-ERROR slot DATUM */
  1278. STACK_0 = S(standard_object); /* TYPE-ERROR slot EXPECTED-TYPE */
  1279. pushSTACK(obj); pushSTACK(TheSubr(subr_self)->name);
  1280. error(type_error,GETTEXT("~S: not a CLOS instance: ~S"));
  1281. }
  1282. }
  1283. /* (CLOS:STANDARD-INSTANCE-ACCESS instance location) */
  1284. LISPFUNNR(standard_instance_access,2) {
  1285. var gcv_object_t* ptr = slot_access_up();
  1286. VALUES1(*ptr); skipSTACK(2);
  1287. }
  1288. /* ((SETF CLOS:STANDARD-INSTANCE-ACCESS) new-value instance location) */
  1289. LISPFUNN(set_standard_instance_access,3) {
  1290. var gcv_object_t* ptr = slot_access_up();
  1291. VALUES1(*ptr = STACK_2); skipSTACK(3);
  1292. }
  1293. /* (SYS::%UNBOUND) */
  1294. LISPFUNNR(punbound,0) { /* not Foldable yet because (const-value (new-const #<unbound>)) is NIL */
  1295. VALUES1(unbound);
  1296. }
  1297. /* update_instance(obj)
  1298. updates a CLOS instance after its class or one of its superclasses has been
  1299. redefined.
  1300. > user_obj: a CLOS instance, possibly a forward pointer
  1301. > obj: the same CLOS instance, not a forward pointer
  1302. < result: the same CLOS instance, not a forward pointer
  1303. can trigger GC */
  1304. global maygc object update_instance (object user_obj, object obj) {
  1305. /* Note about the handling of multiple consecutive class redefinitions:
  1306. When there are multiple class redefinitions before an instance gets to
  1307. be updated, we call UPDATE-INSTANCE-FOR-REDEFINED-CLASS once for each
  1308. redefinition, not once for all changes together.
  1309. Rationale:
  1310. 1. CLHS 4.3.6. says
  1311. "When the class C is redefined, changes are propagated to its
  1312. instances ... Updating such an instance occurs at an
  1313. implementation-dependent time, but no later than the next time
  1314. a slot of that instance is read or written."
  1315. This implies that conceptually, there is an update for each class
  1316. redefinition.
  1317. 2. It's easier for the user to write customization methods for
  1318. UPDATE-INSTANCE-FOR-REDEFINED-CLASS that take into account each
  1319. step separately, rather than arbitrary groupings of consecutive
  1320. steps.
  1321. 3. When in a redefinition, a local slot is discarded, and in a later
  1322. redefinition, a local slot of the same name is added, we would need
  1323. to pass the slot both among the added-slots and among the discarded-
  1324. slots, and it's questionable whether user-defined
  1325. UPDATE-INSTANCE-FOR-REDEFINED-CLASS methods handle this correctly.
  1326. The downside of this way of handling multiple redefinitions is that while
  1327. UPDATE-INSTANCE-FOR-REDEFINED-CLASS is processing, slot accesses to the
  1328. instance being redefined must *not* invoke update_instance (otherwise we
  1329. get an unwanted recursion; this slows down SLOT-VALUE. */
  1330. #if STACKCHECKS || STACKCHECKC
  1331. var gcv_object_t *saved_stack = STACK;
  1332. #endif
  1333. pushSTACK(user_obj);
  1334. {
  1335. var gcv_object_t* top_of_frame = STACK;
  1336. var sp_jmp_buf returner; /* return point */
  1337. finish_entry_frame(UNWIND_PROTECT,returner,, goto clean_up; );
  1338. }
  1339. record_flags_set(TheInstance(obj),instflags_beingupdated_B);
  1340. {do {
  1341. pushSTACK(obj);
  1342. var object cv = TheInstance(obj)->inst_class_version;
  1343. /* We know that the next class is already finalized before
  1344. TheInstance(obj)->inst_class_version is filled. */
  1345. {
  1346. var object newclass = TheClassVersion(TheClassVersion(cv)->cv_next)->cv_class;
  1347. if (!eq(TheClass(newclass)->initialized,fixnum(6)))
  1348. NOTREACHED;
  1349. }
  1350. /* Compute the information needed for the update, if not already done. */
  1351. if (nullp(TheClassVersion(cv)->cv_slotlists_valid_p)) {
  1352. /* Invoke (CLOS::CLASS-VERSION-COMPUTE-SLOTLISTS cv): */
  1353. pushSTACK(cv); funcall(S(class_version_compute_slotlists),1);
  1354. obj = STACK_0;
  1355. cv = TheInstance(obj)->inst_class_version;
  1356. ASSERT(!nullp(TheClassVersion(cv)->cv_slotlists_valid_p));
  1357. }
  1358. pushSTACK(TheClassVersion(cv)->cv_added_slots);
  1359. pushSTACK(TheClassVersion(cv)->cv_discarded_slots);
  1360. /* Fetch the values of the local slots that are discarded. */
  1361. {
  1362. var uintV max_local_slots = posfixnum_to_V(TheClass(TheClassVersion(cv)->cv_class)->instance_size);
  1363. get_space_on_STACK(2*max_local_slots);
  1364. var object plist = TheClassVersion(cv)->cv_discarded_slot_locations;
  1365. var uintL count = 0;
  1366. while (consp(plist)) {
  1367. var object slotname = Car(plist);
  1368. plist = Cdr(plist);
  1369. var object slotinfo = Car(plist);
  1370. plist = Cdr(plist);
  1371. ASSERT(atomp(slotinfo));
  1372. var object value = TheSrecord(obj)->recdata[posfixnum_to_V(slotinfo)];
  1373. if (!eq(value,unbound)) {
  1374. pushSTACK(slotname);
  1375. pushSTACK(value);
  1376. count += 2;
  1377. }
  1378. }
  1379. plist = listof(count);
  1380. pushSTACK(plist);
  1381. }
  1382. obj = STACK_3;
  1383. cv = TheInstance(obj)->inst_class_version;
  1384. /* Fetch the values of the slots that remain local or were shared and
  1385. become local. These values are retained. */
  1386. var uintL kept_slots;
  1387. {
  1388. var object oldclass = TheClassVersion(cv)->cv_class;
  1389. var object newclass = TheClassVersion(TheClassVersion(cv)->cv_next)->cv_class;
  1390. var uintV max_local_slots = posfixnum_to_V(TheClass(newclass)->instance_size);
  1391. get_space_on_STACK(2*max_local_slots);
  1392. var object plist = TheClassVersion(cv)->cv_kept_slot_locations;
  1393. var uintL count = 0;
  1394. while (consp(plist)) {
  1395. var object old_slotinfo = Car(plist);
  1396. plist = Cdr(plist);
  1397. var object new_slotinfo = Car(plist);
  1398. plist = Cdr(plist);
  1399. var object value =
  1400. (atomp(old_slotinfo)
  1401. /* local slot, old_slotinfo is index */
  1402. ? TheSrecord(obj)->recdata[posfixnum_to_V(old_slotinfo)]
  1403. /* shared slot, old_slotinfo is (class . index) */
  1404. : TheSvector(TheClassVersion(Car(old_slotinfo))->cv_shared_slots)
  1405. ->data[posfixnum_to_V(Cdr(old_slotinfo))]);
  1406. if (!eq(value,unbound)) {
  1407. pushSTACK(value);
  1408. pushSTACK(new_slotinfo);
  1409. count++;
  1410. }
  1411. }
  1412. kept_slots = count;
  1413. }
  1414. /* STACK layout: user-obj, UNWIND-PROTECT frame,
  1415. obj, added-slots, discarded-slots, propertylist,
  1416. {old-value, new-slotinfo}*kept_slots.
  1417. ANSI CL 4.3.6.1. Modifying the Structure of Instances */
  1418. {
  1419. var object newclass = TheClassVersion(TheClassVersion(cv)->cv_next)->cv_class;
  1420. /* (CLOS::ALLOCATE-STD-INSTANCE newclass (class-instance-size newclass)) or
  1421. (CLOS::ALLOCATE-FUNCALLABLE-INSTANCE newclass (class-instance-size newclass)): */
  1422. pushSTACK(newclass); pushSTACK(TheClass(newclass)->instance_size);
  1423. if (nullp(TheClass(newclass)->funcallablep))
  1424. C_allocate_std_instance();
  1425. else
  1426. C_allocate_funcallable_instance();
  1427. }
  1428. obj = value1;
  1429. record_flags_set(TheInstance(obj),instflags_beingupdated_B);
  1430. { /* Turn user-obj into a forward-pointer (see the instance_un_realloc
  1431. macro): */
  1432. set_break_sem_1(); /* forbid interrupts */
  1433. var Instance ptr = TheInstance(STACK_(2+4+2*kept_slots));
  1434. record_flags_set(ptr,instflags_forwarded_B);
  1435. ptr->inst_class_version = obj;
  1436. clr_break_sem_1(); /* permit interrupts again */
  1437. }
  1438. ASSERT(Record_flags(STACK_(2+4+2*kept_slots)) & instflags_forwarded_B);
  1439. dotimesL(kept_slots,kept_slots, {
  1440. var object new_slotinfo = popSTACK();
  1441. ASSERT(atomp(new_slotinfo));
  1442. TheSrecord(obj)->recdata[posfixnum_to_V(new_slotinfo)] = popSTACK();
  1443. });
  1444. STACK_3 = STACK_(2+4);
  1445. /* STACK layout: user-obj, UNWIND-PROTECT frame,
  1446. user-obj, added-slots, discarded-slots, propertylist.
  1447. ANSI CL 4.3.6.2. Initializing Newly Added Local Slots */
  1448. funcall(S(update_instance_frc),4);
  1449. /* STACK layout: user-obj, UNWIND-PROTECT frame. */
  1450. obj = STACK_2;
  1451. instance_un_realloc(obj);
  1452. } while (!instance_valid_p(obj));}
  1453. record_flags_clr(TheInstance(obj),instflags_beingupdated_B);
  1454. skipSTACK(1+2); /* unwind UNWIND-PROTECT frame, drop user-obj */
  1455. #if STACKCHECKS || STACKCHECKC
  1456. if (saved_stack != STACK) abort();
  1457. #endif
  1458. return obj;
  1459. clean_up: {
  1460. var restartf_t fun = unwind_protect_to_save.fun;
  1461. var gcv_object_t* arg = unwind_protect_to_save.upto_frame;
  1462. skipSTACK(2); /* unwind UNWIND-PROTECT frame */
  1463. /* Mark the instance update as being terminated. */
  1464. obj = STACK_0;
  1465. instance_un_realloc(obj);
  1466. record_flags_clr(TheInstance(obj),instflags_beingupdated_B);
  1467. fun(arg); /* jump further */
  1468. NOTREACHED;
  1469. }
  1470. }
  1471. /* UP: check keywords, cf. SYSTEM::KEYWORD-TEST
  1472. keyword_test(caller,rest_args_pointer,argcount,valid_keywords);
  1473. > caller: caller (a symbol)
  1474. > rest_args_pointer: pointer to the arguments
  1475. > argcount: number of arguments / 2
  1476. > valid_keywords: list of valid keywords or T if all are valid */
  1477. local void keyword_test (object caller, gcv_object_t* rest_args_pointer,
  1478. uintC argcount, object valid_keywords) {
  1479. if (argcount==0)
  1480. return;
  1481. if (eq(valid_keywords,T))
  1482. return;
  1483. { /* check whether all specified keywords occur in valid_keywords: */
  1484. var gcv_object_t* ptr = rest_args_pointer;
  1485. var uintC count = argcount;
  1486. do {
  1487. var object key = NEXT(ptr);
  1488. var object val = NEXT(ptr);
  1489. if (eq(key,S(Kallow_other_keys))) {
  1490. if (nullp(val)) break; /* need a check */
  1491. else return; /* no check */
  1492. }
  1493. } while(--count);
  1494. ptr = rest_args_pointer;
  1495. count = argcount;
  1496. do {
  1497. var object key = NEXT(ptr);
  1498. var object val = NEXT(ptr);
  1499. if (!symbolp(key))
  1500. error_key_notkw(key,caller);
  1501. if (!eq(key,S(Kallow_other_keys))
  1502. && nullp(memq(key,valid_keywords))) /* not found */
  1503. error_key_badkw(caller,key,val,valid_keywords);
  1504. } while(--count);
  1505. }
  1506. }
  1507. /* UP: find initarg of the slot in the arglist */
  1508. local inline gcv_object_t* slot_in_arglist (const object slot, uintC argcount,
  1509. gcv_object_t* rest_args_pointer) {
  1510. var object l = TheSlotDefinition(slot)->slotdef_initargs;
  1511. var gcv_object_t* ptr = rest_args_pointer;
  1512. var uintC count;
  1513. dotimespC(count,argcount, {
  1514. var object initarg = NEXT(ptr);
  1515. if (!nullp(memq(initarg,l)))
  1516. return ptr;
  1517. (void)NEXT(ptr);
  1518. });
  1519. return NULL;
  1520. }
  1521. /* (CLOS::%SHARED-INITIALIZE instance slot-names &rest initargs)
  1522. instance is an Instance of <standard-object> or <structure-object>,
  1523. initargs is a list of pairs.
  1524. This is the primary method of CLOS:SHARED-INITIALIZE.
  1525. cf. clos.lisp
  1526. (defmethod shared-initialize ((instance standard-object) slot-names &rest initargs)
  1527. (check-initialization-argument-list initargs 'shared-initialize)
  1528. (dolist (slot (class-slots (class-of instance)))
  1529. (let ((slotname (slot-definition-name slot)))
  1530. (multiple-value-bind (init-key init-value foundp)
  1531. (get-properties initargs (slot-definition-initargs slot))
  1532. (declare (ignore init-key))
  1533. (if foundp
  1534. (setf (slot-value instance slotname) init-value)
  1535. (unless (slot-boundp instance slotname)
  1536. (let ((initfunction (slot-definition-initfunction slot)))
  1537. (when initfunction
  1538. (when (or (eq slot-names 'T)
  1539. (member slotname slot-names :test #'eq))
  1540. (setf (slot-value instance slotname)
  1541. (funcall initfunction))))))))))
  1542. instance) */
  1543. LISPFUN(pshared_initialize,seclass_default,2,0,rest,nokey,0,NIL) {
  1544. check_initialization_argument_list(argcount,S(shared_initialize));
  1545. argcount = argcount/2; /* number of Initarg/Value-pairs */
  1546. { /* stack layout: instance, slot-names, argcount Initarg/Value-Pairs. */
  1547. var object instance = Before(rest_args_pointer STACKop 1);
  1548. /* Instance of <standard-class> or <structure-class>: */
  1549. var object clas = class_of(instance); /* instance var is now invalid */
  1550. /* list of all slots (as slot-definitions): */
  1551. var object slots = TheClass(clas)->slots;
  1552. while (consp(slots)) {
  1553. var object slot = Car(slots);
  1554. slots = Cdr(slots);
  1555. /* search if the slot is initialized by the initargs: */
  1556. if (argcount > 0) {
  1557. var gcv_object_t* ptr = slot_in_arglist(slot,argcount,rest_args_pointer);
  1558. if (ptr == NULL)
  1559. goto initarg_not_found;
  1560. value1 = NEXT(ptr);
  1561. goto fill_slot;
  1562. }
  1563. initarg_not_found:
  1564. { /* not found -> test for (slot-boundp instance slotname) first: */
  1565. var object slotinfo = slot;
  1566. if (regular_instance_p(slotinfo)) {
  1567. if (!eq(TheSlotDefinition(slotinfo)->slotdef_efm_sbuc,L(pslot_boundp_using_class))) {
  1568. /* Call (eff-SLOT-BOUNDP-USING-CLASS clas instance slot): */
  1569. var object efm = TheSlotDefinition(slotinfo)->slotdef_efm_sbuc;
  1570. pushSTACK(clas); pushSTACK(slots); pushSTACK(slot);
  1571. pushSTACK(clas); pushSTACK(Before(rest_args_pointer STACKop 1)); pushSTACK(slot);
  1572. funcall(efm,3);
  1573. slot = popSTACK(); slots = popSTACK(); clas = popSTACK();
  1574. if (!nullp(value1))
  1575. goto slot_done;
  1576. goto slot_is_unbound;
  1577. }
  1578. slotinfo = TheSlotDefinition(slotinfo)->slotdef_location;
  1579. }
  1580. if (!eq(*ptr_to_slot(Before(rest_args_pointer STACKop 1),slotinfo,slot),
  1581. unbound))
  1582. goto slot_done;
  1583. }
  1584. slot_is_unbound:
  1585. { /* slot does not have a value yet. Poss. evaluate the initform: */
  1586. var object init = Cdr(TheSlotDefinition(slot)->slotdef_inheritable_initer); /* (slot-definition-initfunction slot) */
  1587. if (nullp(init))
  1588. goto slot_done;
  1589. { /* search slot in slot-names: */
  1590. var object slotnames = Before(rest_args_pointer);
  1591. if (eq(slotnames,T))
  1592. goto eval_init;
  1593. var object slotname = TheSlotDefinition(slot)->slotdef_name;
  1594. if (!nullp(memq(slotname,slotnames)))
  1595. goto eval_init;
  1596. goto slot_done;
  1597. }
  1598. eval_init:
  1599. /* evaluate the initform: */
  1600. if (CONSTANT_INITFUNCTION_P(init)) {
  1601. value1 = TheClosure(init)->other[0];
  1602. } else {
  1603. pushSTACK(clas); pushSTACK(slots); pushSTACK(slot);
  1604. funcall(init,0);
  1605. slot = popSTACK(); slots = popSTACK(); clas = popSTACK();
  1606. }
  1607. }
  1608. fill_slot: {
  1609. /* initialize slot with value1: */
  1610. var object slotinfo = slot;
  1611. if (regular_instance_p(slotinfo)) {
  1612. if (!eq(TheSlotDefinition(slotinfo)->slotdef_efm_ssvuc,L(pset_slot_value_using_class))) {
  1613. /* Call (eff-SET-SLOT-VALUE-USING-CLASS value1 clas instance slot): */
  1614. var object efm = TheSlotDefinition(slotinfo)->slotdef_efm_ssvuc;
  1615. pushSTACK(clas); pushSTACK(slots);
  1616. pushSTACK(value1); pushSTACK(clas); pushSTACK(Before(rest_args_pointer STACKop 1)); pushSTACK(slot);
  1617. funcall(efm,4);
  1618. slots = popSTACK(); clas = popSTACK();
  1619. goto slot_done;
  1620. }
  1621. slotinfo = TheSlotDefinition(slotinfo)->slotdef_location;
  1622. }
  1623. *ptr_to_slot(Before(rest_args_pointer STACKop 1),slotinfo,slot)
  1624. = value1;
  1625. }
  1626. slot_done: ;
  1627. }
  1628. }
  1629. VALUES1(Before(rest_args_pointer STACKop 1)); /* instance as value */
  1630. set_args_end_pointer(rest_args_pointer STACKop 2); /* clean up STACK */
  1631. }
  1632. /* UP: call the non-%SHARED-INITIALIZE init function */
  1633. local inline void call_init_fun (object fun, object last,
  1634. gcv_object_t* rest_args_pointer,
  1635. uintC argcount) {
  1636. /* shift initargs in the stack down by 1, then call fun: */
  1637. if (argcount > 0) {
  1638. var gcv_object_t* ptr = rest_args_pointer;
  1639. var uintC count;
  1640. dotimespC(count,argcount, {
  1641. var object next = Next(ptr); NEXT(ptr) = last;
  1642. last = Next(ptr); NEXT(ptr) = next;
  1643. });
  1644. }
  1645. pushSTACK(last);
  1646. funcall(fun,2*argcount+2);
  1647. }
  1648. /* (CLOS::%REINITIALIZE-INSTANCE instance &rest initargs)
  1649. instance is an Instance of <standard-object> or <structure-object>,
  1650. initargs as list of pairs.
  1651. This is the primary method of CLOS:REINITIALIZE-INSTANCE.
  1652. cf. clos.lisp
  1653. (defmethod reinitialize-instance ((instance standard-object) &rest initargs
  1654. &key &allow-other-keys)
  1655. (check-initialization-argument-list initargs 'reinitialize-instance)
  1656. (let ((h (gethash (class-of instance) *reinitialize-instance-table*)))
  1657. (if h
  1658. (progn
  1659. ; 28.1.9.2. validity of initialization arguments
  1660. (let ((valid-keywords (car h)))
  1661. (sys::keyword-test initargs valid-keywords))
  1662. (if (not (eq (cdr h) #'clos::%shared-initialize))
  1663. ; apply effective method of shared-initialize:
  1664. (apply (cdr h) instance 'NIL initargs)
  1665. ; clos::%shared-initialize with slot-names=NIL can be simplified:
  1666. (progn
  1667. (dolist (slot (class-slots (class-of instance)))
  1668. (let ((slotname (slot-definition-name slot)))
  1669. (multiple-value-bind (init-key init-value foundp)
  1670. (get-properties initargs (slot-definition-initargs slot))
  1671. (declare (ignore init-key))
  1672. (if foundp
  1673. (setf (slot-value instance slotname) init-value)))))
  1674. instance)))
  1675. (apply #'initial-reinitialize-instance instance initargs)))) */
  1676. LISPFUN(preinitialize_instance,seclass_default,1,0,rest,nokey,0,NIL) {
  1677. var object instance = Before(rest_args_pointer);
  1678. /* instance of <standard-class> or <structure-class>: */
  1679. var object clas = class_of(instance); /* instance var is now invalid */
  1680. { /* search (GETHASH class *REINITIALIZE-INSTANCE-TABLE*): */
  1681. var object info =
  1682. gethash(clas,Symbol_value(S(reinitialize_instance_table)),false);
  1683. if (eq(info,nullobj)) {
  1684. /* calculate hash-table-entry freshly. See clos.lisp. */
  1685. funcall(S(initial_reinitialize_instance),argcount+1); return;
  1686. }
  1687. check_initialization_argument_list(argcount,S(reinitialize_instance));
  1688. argcount = argcount/2; /* number of Initarg/Value-pairs */
  1689. keyword_test(S(reinitialize_instance),rest_args_pointer,
  1690. argcount,Car(info));
  1691. /* stack layout: instance, slot-names, argcount Initarg/Value-pairs. */
  1692. var object fun = Cdr(info);
  1693. if (!eq(fun,L(pshared_initialize))) {
  1694. call_init_fun(fun,NIL,rest_args_pointer,argcount);
  1695. return;
  1696. }
  1697. }
  1698. { /* CLOS::%SHARED-INITIALIZE with slot-names=NIL can be simplified:
  1699. list of all slots (as slot-definitions): */
  1700. var object slots = TheClass(clas)->slots;
  1701. while (consp(slots)) {
  1702. var object slot = Car(slots);
  1703. slots = Cdr(slots);
  1704. /* search if the slot is initialized by the initargs: */
  1705. if (argcount > 0) {
  1706. var gcv_object_t* ptr = slot_in_arglist(slot,argcount,rest_args_pointer);
  1707. if (ptr != NULL) {
  1708. var object value = NEXT(ptr);
  1709. /* initialize slot with value: */
  1710. var object slotinfo = slot;
  1711. if (regular_instance_p(slotinfo)) {
  1712. if (!eq(TheSlotDefinition(slotinfo)->slotdef_efm_ssvuc,L(pset_slot_value_using_class))) {
  1713. /* Call (eff-SET-SLOT-VALUE-USING-CLASS value clas instance slot): */
  1714. var object efm = TheSlotDefinition(slotinfo)->slotdef_efm_ssvuc;
  1715. pushSTACK(clas); pushSTACK(slots);
  1716. pushSTACK(value); pushSTACK(clas); pushSTACK(Before(rest_args_pointer)); pushSTACK(slot);
  1717. funcall(efm,4);
  1718. slots = popSTACK(); clas = popSTACK();
  1719. goto slot_done;
  1720. }
  1721. slotinfo = TheSlotDefinition(slotinfo)->slotdef_location;
  1722. }
  1723. *ptr_to_slot(Before(rest_args_pointer),slotinfo,slot) = value;
  1724. slot_done: ;
  1725. }
  1726. }
  1727. }
  1728. }
  1729. VALUES1(Before(rest_args_pointer)); /* instance as value */
  1730. set_args_end_pointer(rest_args_pointer STACKop 1); /* clean up STACK */
  1731. }
  1732. /* (CLOS::%INITIALIZE-INSTANCE instance &rest initargs)
  1733. instance is an Instance of <standard-object> or <structure-object>,
  1734. initargs is a list of pairs.
  1735. This is the primary method of CLOS:INITIALIZE-INSTANCE.
  1736. cf. clos.lisp
  1737. (defmethod initialize-instance ((instance standard-object) &rest initargs
  1738. &key &allow-other-keys)
  1739. (check-initialization-argument-list initargs 'initialize-instance)
  1740. (let ((h (gethash class *make-instance-table*)))
  1741. (if h
  1742. (if (not (eq (svref h 3) #'clos::%shared-initialize))
  1743. ; apply effective method of shared-initialize:
  1744. (apply (svref h 3) instance 'T initargs)
  1745. ; clos::%shared-initialize with slot-names=T can be simplified:
  1746. (progn
  1747. (dolist (slot (class-slots (class-of instance)))
  1748. (let ((slotname (slot-definition-name slot)))
  1749. (multiple-value-bind (init-key init-value foundp)
  1750. (get-properties initargs (slot-definition-initargs slot))
  1751. (declare (ignore init-key))
  1752. (if foundp
  1753. (setf (slot-value instance slotname) init-value)
  1754. (unless (slot-boundp instance slotname)
  1755. (let ((initfunction (slot-definition-initfunction slot)))
  1756. (when initfunction
  1757. (setf (slot-value instance slotname)
  1758. (funcall initfunction)))))))))
  1759. instance))
  1760. (apply #'initial-initialize-instance instance initargs)))) */
  1761. local Values do_initialize_instance (object info,
  1762. gcv_object_t* rest_args_pointer,
  1763. uintC argcount);
  1764. LISPFUN(pinitialize_instance,seclass_default,1,0,rest,nokey,0,NIL) {
  1765. var object instance = Before(rest_args_pointer);
  1766. /* instance of <standard-class> or <structure-class>: */
  1767. var object clas = class_of(instance); /* instance var is not invalid */
  1768. { /* search (GETHASH class *MAKE-INSTANCE-TABLE*): */
  1769. var object info = gethash(clas,Symbol_value(S(make_instance_table)),true);
  1770. if (eq(info,nullobj)) {
  1771. /* calculate hash-table-entry freshly. See clos.lisp. */
  1772. funcall(S(initial_initialize_instance),argcount+1); return;
  1773. }
  1774. check_initialization_argument_list(argcount,S(initialize_instance));
  1775. argcount = argcount/2; /* number of Initarg/Value-pairs */
  1776. return_Values do_initialize_instance(info,rest_args_pointer,argcount);
  1777. }
  1778. }
  1779. local Values do_initialize_instance (object info,
  1780. gcv_object_t* rest_args_pointer,
  1781. uintC argcount) {
  1782. { /* stack layout: instance, argcount Initarg/Value-pairs. */
  1783. var object fun = TheSvector(info)->data[3];
  1784. if (!eq(fun,L(pshared_initialize))) {
  1785. call_init_fun(fun,T,rest_args_pointer,argcount);
  1786. return;
  1787. }
  1788. }
  1789. { /* CLOS::%SHARED-INITIALIZE with slot-names=T can be simplified: */
  1790. var object instance = Before(rest_args_pointer);
  1791. var object clas = class_of(instance); /* instance of <standard-class> or <structure-class> */
  1792. var object slots = TheClass(clas)->slots; /* list of all slots (as slot-definitions) */
  1793. while (consp(slots)) {
  1794. var object slot = Car(slots);
  1795. slots = Cdr(slots);
  1796. /* search if the slot is initialized by the initargs: */
  1797. if (argcount > 0) {
  1798. var gcv_object_t* ptr = slot_in_arglist(slot,argcount,rest_args_pointer);
  1799. if (ptr == NULL)
  1800. goto initarg_not_found;
  1801. value1 = NEXT(ptr);
  1802. goto fill_slot;
  1803. }
  1804. initarg_not_found:
  1805. { /* not found -> first test for (slot-boundp instance slotname): */
  1806. var object slotinfo = slot;
  1807. if (regular_instance_p(slotinfo)) {
  1808. if (!eq(TheSlotDefinition(slotinfo)->slotdef_efm_sbuc,L(pslot_boundp_using_class))) {
  1809. /* Call (eff-SLOT-BOUNDP-USING-CLASS clas instance slot): */
  1810. var object efm = TheSlotDefinition(slotinfo)->slotdef_efm_sbuc;
  1811. pushSTACK(clas); pushSTACK(slots); pushSTACK(slot);
  1812. pushSTACK(clas); pushSTACK(Before(rest_args_pointer)); pushSTACK(slot);
  1813. funcall(efm,3);
  1814. slot = popSTACK(); slots = popSTACK(); clas = popSTACK();
  1815. if (!nullp(value1))
  1816. goto slot_done;
  1817. goto slot_is_unbound;
  1818. }
  1819. slotinfo = TheSlotDefinition(slotinfo)->slotdef_location;
  1820. }
  1821. if (!eq(*ptr_to_slot(Before(rest_args_pointer),slotinfo,slot),unbound))
  1822. goto slot_done;
  1823. }
  1824. slot_is_unbound:
  1825. { /* Slot has no value yet. Evaluate the initform: */
  1826. var object init = Cdr(TheSlotDefinition(slot)->slotdef_inheritable_initer); /* (slot-definition-initfunction slot) */
  1827. if (nullp(init))
  1828. goto slot_done;
  1829. if (CONSTANT_INITFUNCTION_P(init)) {
  1830. value1 = TheClosure(init)->other[0];
  1831. } else {
  1832. pushSTACK(clas); pushSTACK(slots); pushSTACK(slot);
  1833. funcall(init,0);
  1834. slot = popSTACK(); slots = popSTACK(); clas = popSTACK();
  1835. }
  1836. }
  1837. fill_slot: {
  1838. /* initialize slot with value1: */
  1839. var object slotinfo = slot;
  1840. if (regular_instance_p(slotinfo)) {
  1841. if (!eq(TheSlotDefinition(slotinfo)->slotdef_efm_ssvuc,L(pset_slot_value_using_class))) {
  1842. /* Call (eff-SET-SLOT-VALUE-USING-CLASS value1 clas instance slot): */
  1843. var object efm = TheSlotDefinition(slotinfo)->slotdef_efm_ssvuc;
  1844. pushSTACK(clas); pushSTACK(slots);
  1845. pushSTACK(value1); pushSTACK(clas); pushSTACK(Before(rest_args_pointer)); pushSTACK(slot);
  1846. funcall(efm,4);
  1847. slots = popSTACK(); clas = popSTACK();
  1848. goto slot_done;
  1849. }
  1850. slotinfo = TheSlotDefinition(slotinfo)->slotdef_location;
  1851. }
  1852. *ptr_to_slot(Before(rest_args_pointer),slotinfo,slot) = value1;
  1853. }
  1854. slot_done: ;
  1855. }
  1856. }
  1857. VALUES1(Before(rest_args_pointer)); /* instance as value */
  1858. set_args_end_pointer(rest_args_pointer STACKop 1); /* clean up STACK */
  1859. }
  1860. /* (CLOS::%MAKE-INSTANCE class &rest initargs)
  1861. class is an Instance of <standard-class> or <structure-class>,
  1862. initargs is a list (of pairs, hopefully).
  1863. cf. clos.lisp
  1864. (defun %make-instance (class &rest initargs &key &allow-other-keys)
  1865. (check-initialization-argument-list initargs 'make-instance)
  1866. ; take note of 28.1.9.3., 28.1.9.4. default-initargs:
  1867. (dolist (default-initarg (class-default-initargs class))
  1868. (let ((nothing default-initarg))
  1869. (when (eq (getf initargs (car default-initarg) nothing) nothing)
  1870. (setq initargs
  1871. (append initargs
  1872. (list (car default-initarg)
  1873. (funcall (caddr default-initarg))))))))
  1874. (let ((h (gethash class *make-instance-table*)))
  1875. (if h
  1876. (progn
  1877. ; 28.1.9.2. validity of initialization arguments
  1878. (let ((valid-keywords (svref h 0)))
  1879. (sys::keyword-test initargs valid-keywords))
  1880. (let ((instance (apply #'allocate-instance class initargs)))
  1881. (if (not (eq (svref h 2) #'clos::%initialize-instance))
  1882. ; apply effective method of initialize-instance:
  1883. (apply (svref h 2) instance initargs)
  1884. ; clos::%initialize-instance can be simplified (one does not
  1885. ; even have to look it up in *make-instance-table*):
  1886. (if (not (eq (svref h 3) #'clos::%shared-initialize))
  1887. ; apply effective method of shared-initialize:
  1888. (apply (svref h 3) instance 'T initargs)
  1889. ...))))
  1890. (apply #'initial-make-instance class initargs)))) */
  1891. LISPFUN(pmake_instance,seclass_default,1,0,rest,nokey,0,NIL) {
  1892. check_initialization_argument_list(argcount,S(make_instance));
  1893. argcount = argcount/2; /* number of Initarg/Value-pairs */
  1894. /* stack layout: class, argcount Initarg/Value-pairs. */
  1895. { /* add default-initargs: */
  1896. var object clas = Before(rest_args_pointer);
  1897. if (!eq(TheClass(clas)->initialized,fixnum(6))) {
  1898. /* Call (CLOS:FINALIZE-INHERITANCE class). */
  1899. pushSTACK(clas); funcall(S(finalize_inheritance),1);
  1900. clas = Before(rest_args_pointer);
  1901. /* The class must be finalized now, otherwise FINALIZE-INHERITANCE has
  1902. not done its job. */
  1903. ASSERT(eq(TheClass(clas)->initialized,fixnum(6)));
  1904. }
  1905. var object l = TheClass(clas)->default_initargs;
  1906. while (consp(l)) {
  1907. var object default_initarg = Car(l);
  1908. l = Cdr(l);
  1909. var object key = Car(default_initarg);
  1910. /* search key among the initargs so far: */
  1911. if (argcount > 0) {
  1912. var gcv_object_t* ptr = rest_args_pointer;
  1913. var uintC count;
  1914. dotimespC(count,argcount, {
  1915. if (eq(NEXT(ptr),key))
  1916. goto key_found;
  1917. (void)NEXT(ptr);
  1918. });
  1919. }
  1920. /* not found */
  1921. pushSTACK(key); /* Initarg in the stack */
  1922. {
  1923. var object init = Car(Cdr(Cdr(default_initarg)));
  1924. if (CONSTANT_INITFUNCTION_P(init)) {
  1925. pushSTACK(TheClosure(init)->other[0]); /* default in the stack */
  1926. } else {
  1927. pushSTACK(l);
  1928. funcall(init,0);
  1929. l = STACK_0;
  1930. STACK_0 = value1; /* default in the stack */
  1931. }
  1932. }
  1933. argcount++;
  1934. key_found: ;
  1935. }
  1936. }
  1937. { /* search (GETHASH class *MAKE-INSTANCE-TABLE*): */
  1938. var object clas = Before(rest_args_pointer);
  1939. var object info = gethash(clas,Symbol_value(S(make_instance_table)),false);
  1940. if (eq(info,nullobj)) {
  1941. /* calculate hash-table-entry freshly. See clos.lisp. */
  1942. return_Values funcall(S(initial_make_instance),2*argcount+1);
  1943. } else { /* check keywords: */
  1944. keyword_test(S(make_instance),rest_args_pointer,
  1945. argcount,TheSvector(info)->data[0]);
  1946. /* call the effective method of ALLOCATE-INSTANCE: */
  1947. pushSTACK(info);
  1948. {
  1949. var object fun = TheSvector(info)->data[1];
  1950. if (!eq(fun,L(pallocate_instance))) {
  1951. var gcv_object_t* ptr = rest_args_pointer STACKop 1;
  1952. var uintC count;
  1953. dotimespC(count,2*argcount+1, { pushSTACK(NEXT(ptr)); });
  1954. funcall(fun,2*argcount+1);
  1955. pushSTACK(value1); /* save instance */
  1956. var object cls = class_of(value1);
  1957. if (!eq(cls,Before(rest_args_pointer))) {
  1958. /* instance already in STACK_0 */
  1959. pushSTACK(Before(rest_args_pointer));
  1960. pushSTACK(S(allocate_instance));
  1961. error(error_condition,GETTEXT("~S method for ~S returned ~S"));
  1962. }
  1963. value1 = popSTACK(); /* restore instance */
  1964. } else {
  1965. do_allocate_instance(clas);
  1966. }
  1967. }
  1968. info = popSTACK();
  1969. /* call the effective method of INITIALIZE-INSTANCE:
  1970. instance as the 1st argument instead of class: */
  1971. Before(rest_args_pointer) = value1;
  1972. var object fun = TheSvector(info)->data[2];
  1973. /* save the instance in case INITIALIZE-INSTANCE returns junk
  1974. see 7.1.7 "Definitions of Make-Instance and Initialize-Instance"
  1975. http://www.lisp.org/HyperSpec/Body/sec_7-1-7.html */
  1976. pushSTACK(value1);
  1977. if (argcount>0) { /* (rotatef STACK_0 ... STACK_(2*argcount)) */
  1978. var uintC count;
  1979. var gcv_object_t* ptr = &STACK_0;
  1980. dotimespC(count,2*argcount,
  1981. { *ptr = *(ptr STACKop 1); ptr skipSTACKop 1; });
  1982. *ptr = value1;
  1983. }
  1984. rest_args_pointer skipSTACKop -1;
  1985. if (eq(fun,L(pinitialize_instance)))
  1986. /* CLOS::%INITIALIZE-INSTANCE can be simplified
  1987. (do not have to look into *make-instance-table* again): */
  1988. do_initialize_instance(info,rest_args_pointer,argcount);
  1989. else
  1990. funcall(fun,2*argcount+1);
  1991. VALUES1(popSTACK());
  1992. }
  1993. }
  1994. }
  1995. /* (CLOS::%CHANGE-CLASS instance new-class)
  1996. Copy instance, and return the copy.
  1997. Make instance point to a new instance of new-class. */
  1998. LISPFUNN(pchange_class,2) {
  1999. /* Stack layout: instance, new-class. */
  2000. /* Create the new object, to be filled in Lisp: */
  2001. do_allocate_instance(STACK_0);
  2002. STACK_0 = value1;
  2003. /* Stack layout: instance, new-instance. */
  2004. /* Create copy of the old instance: */
  2005. var object clas = class_of(STACK_1); /* Calls instance_update if necessary */
  2006. pushSTACK(clas);
  2007. do_allocate_instance(STACK_0); /* these values are returned */
  2008. /* Stack layout: instance, new-instance, old-class. */
  2009. var object old_instance = STACK_2;
  2010. {
  2011. var object old_instance_forwarded = old_instance;
  2012. instance_un_realloc(old_instance_forwarded);
  2013. copy_mem_o(&TheInstance(value1)->inst_class_version,
  2014. &TheInstance(old_instance_forwarded)->inst_class_version,
  2015. posfixnum_to_V(TheClass(STACK_0)->instance_size));
  2016. }
  2017. { /* Turn instance into a realloc (see the instance_un_realloc macro): */
  2018. set_break_sem_1(); /* forbid interrupts */
  2019. var Instance ptr = TheInstance(old_instance);
  2020. record_flags_set(ptr,instflags_forwarded_B);
  2021. ptr->inst_class_version = STACK_1;
  2022. clr_break_sem_1(); /* permit interrupts again */
  2023. }
  2024. ASSERT(Record_flags(old_instance) & instflags_forwarded_B);
  2025. skipSTACK(3);
  2026. }