PageRenderTime 60ms CodeModel.GetById 22ms RepoModel.GetById 1ms 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

Large files files are truncated, but you can click here to view the full file

  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(sloti

Large files files are truncated, but you can click here to view the full file