Standardized VM primitive type signatures enough to be macro-izable, but not actually...
[cslatevm.git] / src / vm / primitives.c
blob6d779fb3abf2f37b10035c9938ed235751dbfc4f
1 #include "slate.h"
3 //Template for defining Slate primitive signatures. Not a macro because IDEs don't process it:
4 //#define SLATE_PRIM(prim_name) void prim_name(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer)
6 #ifdef SLATE_DAEMONIZE
7 #include <pwd.h>
8 #include <sys/stat.h>
9 #include <signal.h>
10 #endif
12 void prim_fixme(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
14 printf("unimplemented primitive... dying\n");
15 assert(0);
20 void prim_closePipe(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
21 word_t handle = object_to_smallint(args[0]);
22 int retval;
24 ASSURE_SMALLINT_ARG(0);
25 #ifdef WIN32
26 retval = closesocket(handle);
27 #else
28 retval = close(handle);
29 #endif
30 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(retval);
34 void prim_readFromPipe(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
35 struct ByteArray* array = (struct ByteArray*) args[0];
36 word_t handle = object_to_smallint(args[1]);
37 word_t start = object_to_smallint(args[2]), end = object_to_smallint(args[3]);
38 ssize_t retval;
40 ASSURE_TYPE_ARG(0, TYPE_BYTE_ARRAY);
41 ASSURE_SMALLINT_ARG(1);
42 ASSURE_SMALLINT_ARG(2);
43 ASSURE_SMALLINT_ARG(3);
45 if (start < 0 || start >= byte_array_size(array)) {
46 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_KEY_NOT_FOUND_ON), args[2], args[0], NULL, resultStackPointer);
47 return;
50 if (end < start || end > byte_array_size(array)) {
51 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_KEY_NOT_FOUND_ON), args[3], args[0], NULL, resultStackPointer);
52 return;
55 retval = recv(handle, byte_array_elements(array)+start, end - start, 0);
58 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(retval);
63 void prim_writeToPipe(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
64 struct ByteArray* array = (struct ByteArray*) args[0];
65 word_t handle = object_to_smallint(args[1]);
66 word_t start = object_to_smallint(args[2]), end = object_to_smallint(args[3]);
67 ssize_t retval;
69 ASSURE_TYPE_ARG(0, TYPE_BYTE_ARRAY);
70 ASSURE_SMALLINT_ARG(1);
71 ASSURE_SMALLINT_ARG(2);
72 ASSURE_SMALLINT_ARG(3);
74 if (start < 0 || start >= byte_array_size(array)) {
75 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_KEY_NOT_FOUND_ON), args[2], args[0], NULL, resultStackPointer);
76 return;
79 if (end < start || end > byte_array_size(array)) {
80 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_KEY_NOT_FOUND_ON), args[3], args[0], NULL, resultStackPointer);
81 return;
84 retval = send(handle, byte_array_elements(array)+start, end - start, 0);
86 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(retval);
90 /*FIXME this is a copy of the last function with only the select call changed*/
91 void prim_selectOnWritePipesFor(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
93 GC_VOLATILE struct OopArray* selectOn = (struct OopArray*) args[0];
94 GC_VOLATILE struct OopArray* readyPipes;
95 word_t waitTime = object_to_smallint(args[1]);
96 int retval, fdCount, maxFD;
97 struct timeval tv;
98 fd_set fdList;
99 maxFD = 0;
101 ASSURE_SMALLINT_ARG(1);
103 if ((fdCount = socket_select_setup(selectOn, &fdList, &maxFD)) < 0) {
104 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
105 return;
109 tv.tv_sec = waitTime / 1000000;
110 tv.tv_usec = waitTime % 1000000;
111 retval = select(maxFD+1, NULL, &fdList, NULL, &tv);
113 if (retval < 0) {
114 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
115 return;
119 readyPipes = heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO), retval);
120 socket_select_find_available(selectOn, &fdList, readyPipes, retval);
122 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)readyPipes;
126 void prim_cloneSystem(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
127 #ifdef WIN32
128 #pragma message("TODO WIN32 port forking/cloning the system")
129 return;
130 #else
131 pid_t retval;
132 int pipes[2];
133 GC_VOLATILE struct OopArray* array;
135 /* make two pipes that we can use exclusively in each process to talk to the other */
136 /*FIXME remap fds for safety*/
137 if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipes) == -1) {
138 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
139 return;
142 retval = fork2();
144 if (retval == (pid_t)-1) {
145 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
146 return;
149 array = heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO), 2);
150 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)array;
152 if (!retval) { /* child */
153 array->elements[0] = oh->cached.false_object;
154 array->elements[1] = smallint_to_object(pipes[0]);
155 } else { /* parent */
156 array->elements[0] = oh->cached.true_object;
157 array->elements[1] = smallint_to_object(pipes[1]);
160 #endif
164 void prim_cloneSystemInProcess(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
165 #ifdef WIN32
166 #pragma message("TODO WIN32 port cloning/threading a system")
167 #else
169 #endif
173 #ifdef SLATE_DAEMONIZE
175 /* Change this to whatever your daemon is called */
176 #define DAEMON_NAME "slatedaemon"
178 /* Change this to the user under which to run */
179 #define RUN_AS_USER "root"
181 static void child_handler(int signum) {
182 switch(signum) {
183 case SIGALRM: exit(EXIT_FAILURE); break;
184 case SIGUSR1: exit(EXIT_SUCCESS); break;
185 case SIGCHLD: exit(EXIT_FAILURE); break;
189 void prim_daemonizeSystem(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
190 const char* lock_filename = (char*)byte_array_elements((struct ByteArray*) args[1]);
191 #ifdef WIN32
192 #pragma message("TODO WIN32 port daemonizing a system")
193 #else
194 pid_t pid, sid, parent;
195 int lfp = -1;
197 /* already a daemon */
198 if (getppid() == 1) return;
200 /* Create the lock file as the current user */
201 if (lock_filename && lock_filename[0]) {
202 lfp = open(lock_filename,O_RDWR|O_CREAT,0640);
203 if (lfp < 0) {
204 printf("Unable to create lock file %s, code=%d (%s)",
205 lock_filename, errno, strerror(errno));
206 exit(EXIT_FAILURE);
210 /* Drop user if there is one, and we were run as root */
211 if (getuid() == 0 || geteuid() == 0) {
212 struct passwd *pw = getpwnam(RUN_AS_USER);
213 if (pw) {
214 if (!oh->quiet)
215 printf("Setting user to " RUN_AS_USER);
216 setuid(pw->pw_uid);
220 /* Trap signals that we expect to receive */
221 signal(SIGCHLD,child_handler);
222 signal(SIGUSR1,child_handler);
223 signal(SIGALRM,child_handler);
225 /* Fork off the parent process */
226 pid = fork();
227 if (pid < 0) {
228 printf("Unable to fork daemon, code=%d (%s)",
229 errno, strerror(errno));
230 exit(EXIT_FAILURE);
232 /* If we got a good PID, then we can exit the parent process. */
233 if (pid > 0) {
235 /* Wait for confirmation from the child via SIGTERM or SIGCHLD, or
236 for two seconds to elapse (SIGALRM). pause() should not return. */
237 alarm(2);
238 pause();
240 exit(EXIT_FAILURE);
243 /* At this point we are executing as the child process */
244 parent = getppid();
246 /* Cancel certain signals */
247 signal(SIGCHLD,SIG_DFL); /* A child process dies */
248 signal(SIGTSTP,SIG_IGN); /* Various TTY signals */
249 signal(SIGTTOU,SIG_IGN);
250 signal(SIGTTIN,SIG_IGN);
251 signal(SIGHUP, SIG_IGN); /* Ignore hangup signal */
252 signal(SIGTERM,SIG_DFL); /* Die on SIGTERM */
254 /* Change the file mode mask */
255 umask(0);
257 /* Create a new SID for the child process */
258 sid = setsid();
259 if (sid < 0) {
260 printf("Unable to create a new session, code %d (%s)",
261 errno, strerror(errno));
262 exit(EXIT_FAILURE);
265 /* Change the current working directory. This prevents the current
266 directory from being locked; hence not being able to remove it. */
267 if ((chdir("/")) < 0) {
268 printf("Unable to change directory to %s, code %d (%s)",
269 "/", errno, strerror(errno));
270 exit(EXIT_FAILURE);
273 /* Redirect standard files to /dev/null */
274 freopen("/dev/null", "r", stdin);
275 freopen("/dev/null", "w", stdout);
276 freopen("/dev/null", "w", stderr);
278 /* Tell the parent process that we are A-okay */
279 kill(parent, SIGUSR1);
280 #endif
281 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.true_object;
284 #endif //SLATE_DAEMONIZE
286 void prim_socketCreate(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
287 word_t domain = object_to_smallint(args[0]);
288 word_t type = object_to_smallint(args[1]);
289 word_t protocol = object_to_smallint(args[2]);
290 word_t ret = socket(socket_lookup_domain(domain), socket_lookup_type(type), socket_lookup_protocol(protocol));
291 int ret2 = 0;
293 ASSURE_SMALLINT_ARG(0);
294 ASSURE_SMALLINT_ARG(1);
295 ASSURE_SMALLINT_ARG(2);
297 if (ret >= 0) {
298 ret2 = socket_set_nonblocking(ret);
299 } else {
300 perror("socket create");
303 if (ret2 < 0) {
304 perror("set nonblocking");
305 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(-1);
306 } else {
307 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(ret);
311 void prim_socketListen(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
312 word_t fd = object_to_smallint(args[0]);
313 word_t size = object_to_smallint(args[1]);
314 word_t ret;
316 ASSURE_SMALLINT_ARG(0);
317 ASSURE_SMALLINT_ARG(1);
319 ret = listen(fd, size);
321 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(ret);
325 void prim_socketAccept(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
326 word_t fd = object_to_smallint(args[0]);
327 word_t ret;
328 struct sockaddr_storage addr;
329 socklen_t len;
330 GC_VOLATILE struct ByteArray* addrArray;
331 GC_VOLATILE struct OopArray* result;
333 ASSURE_SMALLINT_ARG(0);
335 len = sizeof(addr);
336 ret = accept(fd, (struct sockaddr*)&addr, &len);
338 if (ret >= 0) {
339 addrArray = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), sizeof(struct sockaddr_in));
340 } else {
341 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(ret);
342 return;
345 heap_fixed_add(oh, (struct Object*)addrArray);
346 result = heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO), 2);
347 heap_fixed_remove(oh, (struct Object*)addrArray);
349 object_array_set_element(oh, (struct Object*)result, 0, smallint_to_object(ret));
350 object_array_set_element(oh, (struct Object*)result, 1, (struct Object*)addrArray);
352 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)result;
356 void prim_socketBind(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
357 word_t fd = object_to_smallint(args[0]);
358 struct ByteArray* address = (struct ByteArray*) args[1];
359 word_t ret;
361 ASSURE_SMALLINT_ARG(0);
363 ret = bind(fd, (const struct sockaddr*)byte_array_elements(address), (socklen_t)byte_array_size(address));
364 if (ret < 0) perror("bind");
365 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(ret);
368 void prim_socketConnect(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
369 word_t fd = object_to_smallint(args[0]);
370 struct ByteArray* address = (struct ByteArray*) args[1];
371 word_t ret;
373 ASSURE_SMALLINT_ARG(0);
375 ret = connect(fd, (const struct sockaddr*)byte_array_elements(address), (socklen_t)byte_array_size(address));
377 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(ret);
381 void prim_socketGetError(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
382 word_t fd = object_to_smallint(args[0]);
383 word_t ret;
384 int optval;
385 socklen_t optlen;
386 optlen = 4;
387 ASSURE_SMALLINT_ARG(0);
389 ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &optval, (socklen_t*)&optlen);
391 if (ret == 0) {
392 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(optval);
393 } else {
394 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(ret);
399 void prim_getAddrInfo(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
400 struct ByteArray* hostname = (struct ByteArray*)args[1];
401 struct ByteArray* service = (struct ByteArray*)args[2];
402 word_t family = object_to_smallint(args[3]);
403 word_t type = object_to_smallint(args[4]);
404 word_t protocol = object_to_smallint(args[5]);
405 word_t flags = object_to_smallint(args[6]);
406 word_t ret, serviceSize, hostnameSize;
408 ASSURE_TYPE_ARG(1, TYPE_BYTE_ARRAY);
409 ASSURE_SMALLINT_ARG(3);
410 ASSURE_SMALLINT_ARG(4);
411 ASSURE_SMALLINT_ARG(5);
412 ASSURE_SMALLINT_ARG(6);
414 if ((struct Object*)hostname == oh->cached.nil) {
415 hostnameSize = 0;
416 } else {
417 hostnameSize = byte_array_size(hostname)+1;
420 if ((struct Object*)service == oh->cached.nil) {
421 serviceSize = 0;
422 } else {
423 ASSURE_TYPE_ARG(2, TYPE_BYTE_ARRAY);
424 serviceSize = byte_array_size(service)+1;
427 ret = socket_getaddrinfo(oh, hostname, hostnameSize, service, serviceSize, family, type, protocol, flags);
429 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(ret);
434 void prim_getAddrInfoResult(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
435 word_t ticket = object_to_smallint(args[0]);
436 if (ticket >= oh->socketTicketCount || ticket < 0
437 || oh->socketTickets[ticket].inUse == 0 || oh->socketTickets[ticket].finished == 0) {
438 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
439 return;
441 if (oh->socketTickets[ticket].result < 0) {
442 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(socket_return(oh->socketTickets[ticket].result));
443 } else {
444 word_t count, i;
445 struct addrinfo* ai = oh->socketTickets[ticket].addrResult;
446 struct addrinfo* current = ai;
447 GC_VOLATILE struct OopArray* retval;
448 count = 0;
449 while (current != NULL) {
450 current = current->ai_next;
451 count++;
453 current = ai;
454 retval = heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO), count);
455 heap_fixed_add(oh, (struct Object*)retval);
456 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)retval;
457 heap_store_into(oh, (struct Object*)oh->cached.interpreter->stack, (struct Object*)retval);
459 for (i = 0; i < count; i++) {
460 GC_VOLATILE struct OopArray* aResult = heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO), 6);
461 struct ByteArray* aResultAddr;
462 struct ByteArray* aResultCanonName;
463 word_t canonNameLen = (current->ai_canonname == NULL)? 0 : strlen(current->ai_canonname);
464 retval->elements[i] = (struct Object*)aResult;
465 heap_store_into(oh, (struct Object*)retval, retval->elements[i]);
466 aResult->elements[0] = smallint_to_object(current->ai_flags);
467 aResult->elements[1] = smallint_to_object(socket_reverse_lookup_domain(current->ai_family));
468 aResult->elements[2] = smallint_to_object(socket_reverse_lookup_type(current->ai_socktype));
469 aResult->elements[3] = smallint_to_object(socket_reverse_lookup_protocol(current->ai_protocol));
471 aResultAddr = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), current->ai_addrlen);
472 aResult->elements[4] = (struct Object*)aResultAddr;
473 heap_store_into(oh, (struct Object*)aResult, aResult->elements[4]);
474 copy_bytes_into((byte_t*)current->ai_addr, current->ai_addrlen, aResultAddr->elements);
475 if (canonNameLen == 0) {
476 aResult->elements[5] = oh->cached.nil;
477 } else {
478 aResultCanonName = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), canonNameLen);
479 aResult->elements[5] = (struct Object*)aResultCanonName;
480 heap_store_into(oh, (struct Object*)aResult, aResult->elements[5]);
481 copy_bytes_into((byte_t*)current->ai_canonname, canonNameLen, aResultCanonName->elements);
484 current = current->ai_next;
487 heap_fixed_remove(oh, (struct Object*)retval);
493 void prim_freeAddrInfoResult(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
494 word_t ticket = object_to_smallint(args[0]);
495 if (ticket >= oh->socketTicketCount || ticket < 0
496 || oh->socketTickets[ticket].inUse == 0 || oh->socketTickets[ticket].finished == 0) {
497 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.false_object;
498 return;
500 free(oh->socketTickets[ticket].hostname);
501 oh->socketTickets[ticket].hostname = 0;
502 free(oh->socketTickets[ticket].service);
503 oh->socketTickets[ticket].service = 0;
504 freeaddrinfo(oh->socketTickets[ticket].addrResult);
505 oh->socketTickets[ticket].addrResult = 0;
507 oh->socketTickets[ticket].inUse = 0;
508 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.true_object;
512 void prim_socketCreateIP(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
513 word_t domain = object_to_smallint(args[0]);
514 struct Object* address = args[1];
515 word_t port = object_to_smallint(args[2]);
516 /* struct OopArray* options = (struct OopArray*) args[3];*/
517 struct sockaddr_in* sin;
518 struct sockaddr_in6* sin6;
519 struct sockaddr_un* sun;
520 GC_VOLATILE struct ByteArray* ret;
522 ASSURE_SMALLINT_ARG(0);
524 switch (domain) {
526 case SLATE_DOMAIN_LOCAL:
527 #ifdef WIN32
528 #else
529 if (byte_array_size((struct ByteArray*)address) > 100) {
530 ret = (struct ByteArray*)oh->cached.nil;
531 break;
533 ret = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), sizeof(struct sockaddr_un));
534 sun = (struct sockaddr_un*)byte_array_elements(ret);
535 sun->sun_family = socket_lookup_domain(domain);
536 ASSURE_TYPE_ARG(1, TYPE_BYTE_ARRAY);
537 strncpy(sun->sun_path, (char*)byte_array_elements((struct ByteArray*)address), 100);
538 sun->sun_path[byte_array_size((struct ByteArray*)address)] = '\0';
539 #endif
540 break;
542 case SLATE_DOMAIN_IPV4:
543 ASSURE_SMALLINT_ARG(2);
544 if (object_array_size(address) < 4) {
545 ret = (struct ByteArray*)oh->cached.nil;
546 break;
548 ret = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), sizeof(struct sockaddr_in));
549 sin = (struct sockaddr_in*)byte_array_elements(ret);
550 sin->sin_family = socket_lookup_domain(domain);
551 sin->sin_port = htons((uint16_t)port);
552 ASSURE_TYPE_ARG(1, TYPE_OOP_ARRAY);
553 sin->sin_addr.s_addr = htonl(((object_to_smallint(object_array_get_element(address, 0)) & 0xFF) << 24)
554 | ((object_to_smallint(object_array_get_element(address, 1)) & 0xFF) << 16)
555 | ((object_to_smallint(object_array_get_element(address, 2)) & 0xFF) << 8)
556 | (object_to_smallint(object_array_get_element(address, 3)) & 0xFF));
557 break;
559 /*fixme ipv6*/
560 case SLATE_DOMAIN_IPV6:
561 ASSURE_SMALLINT_ARG(2);
562 if (object_array_size(address) < 16) {
563 ret = (struct ByteArray*)oh->cached.nil;
564 break;
566 ret = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), sizeof(struct sockaddr_in6));
567 sin6 = (struct sockaddr_in6*)byte_array_elements(ret);
568 sin6->sin6_family = socket_lookup_domain(domain);
569 sin6->sin6_port = htons((uint16_t)port);
570 ASSURE_TYPE_ARG(1, TYPE_OOP_ARRAY);
572 int i;
573 for (i = 0; i < 16; i++)
574 sin6->sin6_addr.s6_addr[i] = object_to_smallint(object_array_get_element(address, i)) & 0xFF;
576 break;
578 default:
579 ret = (struct ByteArray*)oh->cached.nil;
580 break;
583 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)ret;
587 void prim_write_to_starting_at(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
588 struct Object *console=args[0], *n=args[1], *handle=args[2], *seq=args[3], *start=args[4];
589 byte_t* bytes = &((struct ByteArray*)seq)->elements[0] + object_to_smallint(start);
590 word_t size = object_to_smallint(n);
593 ASSURE_SMALLINT_ARG(2);
594 ASSURE_SMALLINT_ARG(4);
596 assert(arity == 5 && console != NULL);
598 oh->cached.interpreter->stack->elements[resultStackPointer] =
599 smallint_to_object(fwrite(bytes, 1, size, (object_to_smallint(handle) == 0)? stdout : stderr));
603 void prim_close(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
604 word_t handle = object_to_smallint(args[1]);
605 ASSURE_SMALLINT_ARG(1);
607 closeFile(oh, handle);
608 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
612 void prim_readConsole_from_into_starting_at(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
613 word_t /*handle = object_to_smallint(args[2]),*/ n = object_to_smallint(args[1]), start = object_to_smallint(args[4]);
614 struct ByteArray* bytes = (struct ByteArray*)args[3];
615 word_t retval;
617 ASSURE_SMALLINT_ARG(1);
618 ASSURE_SMALLINT_ARG(4);
620 retval = fread((char*)(byte_array_elements(bytes) + start), 1, n, stdin);
621 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(retval);
625 void prim_read_from_into_starting_at(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
626 word_t handle = object_to_smallint(args[2]), n = object_to_smallint(args[1]), start = object_to_smallint(args[4]);
627 struct ByteArray* bytes = (struct ByteArray*)args[3];
628 word_t retval;
629 ASSURE_SMALLINT_ARG(1);
630 ASSURE_SMALLINT_ARG(4);
631 retval = readFile(oh, handle, n, (char*)(byte_array_elements(bytes) + start));
632 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(retval);
635 void prim_write_to_from_starting_at(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
636 word_t handle = object_to_smallint(args[2]), n = object_to_smallint(args[1]), start = object_to_smallint(args[4]);
637 struct ByteArray* bytes = (struct ByteArray*)args[3];
638 word_t retval;
639 ASSURE_SMALLINT_ARG(1);
640 ASSURE_SMALLINT_ARG(4);
641 retval = writeFile(oh, handle, n, (char*)(byte_array_elements(bytes) + start));
642 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(retval);
646 void prim_reposition_to(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
647 word_t handle = object_to_smallint(args[1]), n = object_to_smallint(args[2]);
648 word_t retval = seekFile(oh, handle, n);
649 ASSURE_SMALLINT_ARG(1);
650 ASSURE_SMALLINT_ARG(2);
651 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(retval);
654 void prim_positionOf(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
655 word_t handle = object_to_smallint(args[1]);
656 word_t retval = tellFile(oh, handle);
657 ASSURE_SMALLINT_ARG(1);
658 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(retval);
661 void prim_bytesPerWord(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
662 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(sizeof(word_t));
665 void prim_timeSinceEpoch(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
666 word_t time;
667 struct timeval tv;
668 #ifdef WIN32
669 #pragma message("TODO WIN32 time-since-epoch")
670 time = 0;
671 #else
672 gettimeofday(&tv, NULL);
673 time = (word_t)tv.tv_sec * 1000000 + (word_t)tv.tv_usec;
674 #endif
675 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(time);
678 void prim_atEndOf(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
679 word_t handle = object_to_smallint(args[1]);
680 ASSURE_SMALLINT_ARG(1);
681 if (endOfFile(oh, handle)) {
682 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.true_object;
683 } else {
684 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.false_object;
688 void prim_sizeOf(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
689 word_t handle = object_to_smallint(args[1]);
690 word_t retval = sizeOfFile(oh, handle);
691 ASSURE_SMALLINT_ARG(1);
692 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(retval);
697 void prim_flush_output(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
698 /*struct Object *console=args[0];*/
699 fflush(stdout);
700 fflush(stderr);
701 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
704 void prim_handle_for(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
705 word_t handle;
706 struct Object /**file=args[0],*/ *fname=args[1];
708 handle = openFile(oh, (struct ByteArray*)fname, SF_READ|SF_WRITE);
709 if (handle >= 0) {
710 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(handle);
711 } else {
712 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
717 void prim_handleForNew(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
718 word_t handle;
719 struct Object /**file=args[0],*/ *fname=args[1];
721 handle = openFile(oh, (struct ByteArray*)fname, SF_READ|SF_WRITE|SF_CLEAR|SF_CREATE);
722 if (handle >= 0) {
723 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(handle);
724 } else {
725 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
731 void prim_handle_for_input(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
732 word_t handle;
733 struct Object /**file=args[0],*/ *fname=args[1];
735 handle = openFile(oh, (struct ByteArray*)fname, SF_READ);
736 if (handle >= 0) {
737 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(handle);
738 } else {
739 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
745 void prim_addressOf(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
746 struct Object *handle=args[1], *offset=args[2];
747 struct ByteArray* addressBuffer=(struct ByteArray*) args[3];
748 ASSURE_SMALLINT_ARG(1);
749 ASSURE_SMALLINT_ARG(2);
750 if (object_is_smallint(handle) && object_is_smallint(offset) && byte_array_size(addressBuffer) >= sizeof(word_t)) {
751 oh->cached.interpreter->stack->elements[resultStackPointer] =
752 smallint_to_object(addressOfMemory(oh,
753 (int)object_to_smallint(handle),
754 (int)object_to_smallint(offset),
755 byte_array_elements(addressBuffer)));
756 } else {
757 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
762 void prim_loadLibrary(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
763 struct Object *libname=args[1], *handle = args[2];
765 if (openExternalLibrary(oh, (struct ByteArray*)libname, (struct ByteArray*)handle)) {
766 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.true_object;
767 } else {
768 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.false_object;
773 void prim_closeLibrary(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
774 struct Object *handle=args[1];
776 if (closeExternalLibrary(oh, (struct ByteArray*) handle)) {
777 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.true_object;
778 } else {
779 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.false_object;
785 void prim_procAddressOf(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
786 struct Object *handle=args[2], *symname=args[1];
787 struct ByteArray* addressBuffer=(struct ByteArray*) args[3];
789 if (lookupExternalLibraryPrimitive(oh, (struct ByteArray*) handle, (struct ByteArray *) symname, addressBuffer)) {
790 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.true_object;
791 } else {
792 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.false_object;
797 void prim_extlibError(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
798 struct ByteArray* messageBuffer=(struct ByteArray*) args[1];
800 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(readExternalLibraryError(messageBuffer));
804 void prim_applyExternal(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
806 oh->cached.interpreter->stack->elements[resultStackPointer] =
807 applyExternalLibraryPrimitive(oh, (struct ByteArray*)args[1],
808 (struct OopArray*)args[2],
809 args[3],
810 args[4],
811 (struct OopArray*)args[5]);
815 void prim_newFixedArea(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
816 struct Object *size=args[1];
817 word_t handle;
819 if (!object_is_smallint(size)) {
820 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
821 return;
824 handle = (word_t)openMemory(oh, object_to_smallint(size));
825 if (handle >= 0) {
826 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(handle);
827 } else {
828 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
833 void prim_closeFixedArea(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
835 struct Object* handle = args[1];
836 if (object_is_smallint(handle)) {
837 closeMemory(oh, object_to_smallint(handle));
839 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
843 void prim_fixedAreaSize(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
845 struct Object* handle = args[1];
846 if (object_is_smallint(handle)) {
847 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(sizeOfMemory(oh, object_to_smallint(handle)));
848 } else {
849 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
854 void prim_fixedAreaAddRef(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
856 struct Object* handle = args[1];
857 if (object_is_smallint(handle)) {
858 addRefMemory(oh, object_to_smallint(handle));
861 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
865 void prim_fixedReadFromStarting(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
867 struct ByteArray* buf = (struct ByteArray*)args[0];
868 word_t amount = object_to_smallint(args[1]), startingAt = object_to_smallint(args[3]),
869 handle = object_to_smallint(args[2]);
871 ASSURE_SMALLINT_ARG(1);
872 ASSURE_SMALLINT_ARG(2);
873 ASSURE_SMALLINT_ARG(3);
875 if (!validMemoryHandle(oh, handle)
876 || byte_array_size(buf) < amount
877 || startingAt + amount >= oh->memory_sizes [handle]) {
878 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(-1);
879 return;
882 oh->cached.interpreter->stack->elements[resultStackPointer] =
883 smallint_to_object(writeMemory(oh, handle, startingAt, amount, byte_array_elements(buf)));
887 void prim_fixedWriteFromStarting(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
889 struct ByteArray* buf = (struct ByteArray*)args[0];
890 word_t amount = object_to_smallint(args[1]), startingAt = object_to_smallint(args[3]),
891 handle = object_to_smallint(args[2]);
893 ASSURE_SMALLINT_ARG(1);
894 ASSURE_SMALLINT_ARG(2);
895 ASSURE_SMALLINT_ARG(3);
897 if (!validMemoryHandle(oh, handle)
898 || byte_array_size(buf) < amount
899 || startingAt + amount >= oh->memory_sizes [handle]) {
900 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(-1);
901 return;
904 oh->cached.interpreter->stack->elements[resultStackPointer] =
905 smallint_to_object(readMemory(oh, handle, startingAt, amount, byte_array_elements(buf)));
910 void prim_fixedAreaResize(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
912 struct Object* handle = args[1], *size = args[2];
913 if (object_is_smallint(handle) && object_is_smallint(size)) {
914 oh->cached.interpreter->stack->elements[resultStackPointer] =
915 smallint_to_object(resizeMemory(oh, object_to_smallint(handle), object_to_smallint(size)));
917 } else {
918 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
923 void prim_smallint_at_slot_named(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
924 struct Object* obj;
925 struct Object* name;
926 struct SlotEntry * se;
927 struct Object * proto;
929 obj = args[0];
930 name = args[1];
931 proto = get_special(oh, SPECIAL_OOP_SMALL_INT_PROTO);
932 se = slot_table_entry_for_name(oh, proto->map->slotTable, (struct Symbol*)name);
933 if (se == NULL) {
934 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_SLOT_NOT_FOUND_NAMED), obj, name, NULL, resultStackPointer);
935 } else {
936 word_t offset = object_to_smallint(se->offset);
937 oh->cached.interpreter->stack->elements[resultStackPointer] = object_slot_value_at_offset(proto, offset);
945 void prim_bytesize(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
946 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(payload_size(args[0]));
949 void prim_findon(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
950 struct MethodDefinition* def;
951 struct Symbol* selector= (struct Symbol*) args[0];
952 struct OopArray* arguments= (struct OopArray*) args[1];
955 def = method_dispatch_on(oh, selector, arguments->elements, array_size(arguments), NULL);
957 oh->cached.interpreter->stack->elements[resultStackPointer] = (def == NULL ? oh->cached.nil : (struct Object*) def->method);
962 void prim_ensure(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
964 struct Closure* body = (struct Closure*) args[0];
965 struct Object* ensureHandler = args[1];
966 interpreter_apply_to_arity_with_optionals(oh, oh->cached.interpreter, body, NULL, 0, NULL, resultStackPointer);
967 /*the registers are already allocated on the stack so we don't worry about overwriting them*/
968 interpreter_stack_push(oh, oh->cached.interpreter, oh->cached.interpreter->ensureHandlers);
969 interpreter_stack_push(oh, oh->cached.interpreter, ensureHandler);
970 oh->cached.interpreter->ensureHandlers = smallint_to_object(oh->cached.interpreter->stackPointer - 2);
971 #ifdef PRINT_DEBUG_ENSURE
972 printf("ensure handlers at %" PRIdPTR "\n", oh->cached.interpreter->stackPointer - 2);
973 #endif
978 void prim_frame_pointer_of(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
980 struct Interpreter* i = (struct Interpreter*)args[0];
981 struct Symbol* selector = (struct Symbol*) args[1];
982 struct CompiledMethod* method;
983 word_t frame = i->framePointer;
987 while (frame > FUNCTION_FRAME_SIZE) {
988 method = (struct CompiledMethod*) i->stack->elements[frame-3];
989 method = method->method; /*incase it's a closure and not a compiledmethod*/
990 if (method->selector == selector) {
991 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(frame);
992 return;
994 frame = object_to_smallint(i->stack->elements[frame-1]);
997 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1002 void prim_bytearray_newsize(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1003 struct Object* obj, *i;
1004 obj = args[0];
1005 i = args[1];
1007 if (!object_is_smallint(i)) {
1008 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1009 return;
1012 oh->cached.interpreter->stack->elements[resultStackPointer] =
1013 (struct Object*)heap_clone_byte_array_sized(oh, obj, (object_to_smallint(i) < 0) ? 0 : object_to_smallint(i));
1017 void prim_byteat_put(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1018 struct Object* obj= args[0], *i=args[1], *val = args[2];
1019 word_t index;
1021 index = object_to_smallint(i);
1023 ASSURE_SMALLINT_ARG(1);
1024 ASSURE_SMALLINT_ARG(2);
1026 if (object_is_immutable(obj)) {
1027 interpreter_signal_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_IMMUTABLE), obj, NULL, resultStackPointer);
1028 return;
1031 if (index < byte_array_size((struct ByteArray*)obj)) {
1032 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(byte_array_set_element((struct ByteArray*)obj, index, object_to_smallint(val)));
1033 } else {
1034 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_KEY_NOT_FOUND_ON), i, obj, NULL, resultStackPointer);
1040 void prim_byteat(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1041 struct Object* obj, *i;
1042 word_t index;
1044 obj = args[0];
1045 i = args[1];
1046 index = object_to_smallint(i);
1048 ASSURE_SMALLINT_ARG(1);
1050 if (index < byte_array_size((struct ByteArray*)obj)) {
1051 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(byte_array_get_element(obj, index));
1052 } else {
1053 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_KEY_NOT_FOUND_ON), i, obj, NULL, resultStackPointer);
1059 void prim_map(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1060 struct Object* obj;
1061 obj = args[0];
1063 if (object_is_smallint(obj)) {
1064 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1065 } else {
1066 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)obj->map;
1072 void prim_set_map(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1073 GC_VOLATILE struct Object* obj;
1074 GC_VOLATILE struct Map* map;
1075 obj = args[0];
1076 map = (struct Map*)args[1];
1078 if (object_is_smallint(obj) || object_is_immutable(obj)) {
1079 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1080 } else {
1081 object_change_map(oh, obj, map);
1082 heap_store_into(oh, args[0], args[1]);
1083 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)map;
1088 /*obsolete*/
1089 void prim_run_args_into(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1090 struct ByteArray* arguments = (struct ByteArray*)args[1];
1091 oh->cached.interpreter->stack->elements[resultStackPointer] =
1092 smallint_to_object(write_args_into(oh, (char*)byte_array_elements(arguments), byte_array_size(arguments)));
1097 void prim_vmArgCount(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1098 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(oh->argcSaved);
1101 void prim_vmArg(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1102 word_t i;
1103 int len;
1104 GC_VOLATILE struct ByteArray* array;
1105 ASSURE_SMALLINT_ARG(1);
1106 i = object_to_smallint(args[1]);
1107 len = strlen(oh->argvSaved[i]);
1109 array = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), len);
1110 copy_bytes_into((byte_t*)oh->argvSaved[i], len, array->elements);
1111 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)array;
1112 heap_store_into(oh, (struct Object*)oh->cached.interpreter->stack, (struct Object*)array);
1116 void prim_environmentVariables(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1117 int i, len;
1118 word_t lenstr;
1119 GC_VOLATILE struct OopArray* array;
1121 len = 0;
1122 while (oh->envp[len]) len++;
1124 array = heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO), len);
1125 heap_fixed_add(oh, (struct Object*)array);
1127 for (i = 0; i < len; i++) {
1128 lenstr = strlen(oh->envp[i]);
1129 array->elements[i] = (struct Object*) heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), lenstr);
1130 copy_bytes_into((byte_t*)oh->envp[i], lenstr, ((struct ByteArray*)array->elements[i])->elements);
1134 heap_fixed_remove(oh, (struct Object*)array);
1136 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)array;
1137 heap_store_into(oh, (struct Object*)oh->cached.interpreter->stack, (struct Object*)array);
1141 void prim_exit(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1142 /* print_stack_types(oh, 128);*/
1143 /* print_backtrace(oh);*/
1144 if (!oh->quiet) {
1145 printf("Slate process %d exiting...\n", getpid());
1147 exit(0);
1150 void prim_isIdenticalTo(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1151 oh->cached.interpreter->stack->elements[resultStackPointer] = (args[0]==args[1])? oh->cached.true_object : oh->cached.false_object;
1154 void prim_identity_hash(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1155 /*fix*/
1156 /* print_detail(oh, args[0]);
1157 print_backtrace(oh);*/
1158 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(object_hash(args[0]));
1161 void prim_identity_hash_univ(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1162 /*fix*/
1163 /* print_detail(oh, args[0]);
1164 print_backtrace(oh);*/
1165 if (object_is_smallint(args[0])) {
1166 oh->cached.interpreter->stack->elements[resultStackPointer] = args[0];
1167 } else {
1168 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(object_hash(args[0]));
1173 void prim_clone(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1174 if (object_is_smallint(args[0])) {
1175 oh->cached.interpreter->stack->elements[resultStackPointer] = args[0];
1176 } else {
1177 oh->cached.interpreter->stack->elements[resultStackPointer] = heap_clone(oh, args[0]);
1181 void prim_applyto(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1182 struct Closure *method = (struct Closure*)args[0];
1183 struct OopArray* argArray = (struct OopArray*) args[1];
1184 struct OopArray* real_opts = NULL;
1186 if (opts != NULL && opts->elements[1] != oh->cached.nil) {
1187 real_opts = (struct OopArray*) opts->elements[1];
1189 interpreter_apply_to_arity_with_optionals(oh, oh->cached.interpreter, method,
1190 argArray->elements, array_size(argArray), real_opts, resultStackPointer);
1196 void prim_at(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1197 struct Object* array;
1198 word_t i;
1200 array = args[0];
1201 i = object_to_smallint(args[1]);
1202 ASSURE_SMALLINT_ARG(1);
1203 if (i < object_array_size(array) && i >= 0) {
1204 oh->cached.interpreter->stack->elements[resultStackPointer] = ((struct OopArray*)array)->elements[i];
1205 } else {
1206 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_KEY_NOT_FOUND_ON), args[1], args[0], NULL, resultStackPointer);
1214 void prim_at_put(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1215 struct Object *array = args[0], *i = args[1], *val = args[2];
1216 word_t index = object_to_smallint(i);
1218 ASSURE_SMALLINT_ARG(1);
1219 if (object_is_immutable(array)) {
1220 interpreter_signal_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_IMMUTABLE), array, NULL, resultStackPointer);
1221 return;
1224 if (index < object_array_size(array)) {
1225 heap_store_into(oh, array, val);
1226 oh->cached.interpreter->stack->elements[resultStackPointer] = ((struct OopArray*)array)->elements[index] = val;
1227 } else {
1228 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_KEY_NOT_FOUND_ON), i, array, NULL, resultStackPointer);
1233 void prim_ooparray_newsize(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1234 /*struct Object* array = args[0];*/
1235 struct Object* i = args[1];
1236 if (object_is_smallint(i)) {
1237 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)
1238 heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO),
1239 object_to_smallint(i));
1240 } else {
1241 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1246 void prim_equals(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1247 oh->cached.interpreter->stack->elements[resultStackPointer] = (args[0] == args[1])?oh->cached.true_object:oh->cached.false_object;
1250 void prim_less_than(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1252 ASSURE_SMALLINT_ARG(0);
1253 ASSURE_SMALLINT_ARG(1);
1254 oh->cached.interpreter->stack->elements[resultStackPointer] =
1255 (object_to_smallint(args[0])<object_to_smallint(args[1]))?oh->cached.true_object:oh->cached.false_object;
1259 void prim_size(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1260 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(object_array_size(args[0]));
1263 void prim_bitand(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1264 ASSURE_SMALLINT_ARG(0);
1265 ASSURE_SMALLINT_ARG(1);
1266 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)((word_t)args[0] & (word_t)args[1]);
1268 void prim_bitor(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1269 ASSURE_SMALLINT_ARG(0);
1270 ASSURE_SMALLINT_ARG(1);
1271 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)((word_t)args[0] | (word_t)args[1]);
1273 void prim_bitxor(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1274 ASSURE_SMALLINT_ARG(0);
1275 ASSURE_SMALLINT_ARG(1);
1276 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)(((word_t)args[0] ^ (word_t)args[1])|SMALLINT_MASK);
1278 void prim_bitnot(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1279 ASSURE_SMALLINT_ARG(0);
1280 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)(~((word_t)args[0]) | SMALLINT_MASK);
1283 void prim_smallIntegerMinimum(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1284 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)(((word_t)1<< (sizeof(word_t)*8-1))|1); /*top and smallint bit set*/
1287 void prim_smallIntegerMaximum(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1288 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)LONG_MAX; /*has all bits except the top set*/
1291 void prim_plus(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1292 struct Object* x = args[0];
1293 struct Object* y = args[1];
1294 word_t z = object_to_smallint(x) + object_to_smallint(y);
1297 ASSURE_SMALLINT_ARG(0);
1298 ASSURE_SMALLINT_ARG(1);
1301 if (smallint_fits_object(z)) {
1302 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(z);
1303 } else {
1304 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_ADD_OVERFLOW), x, y, NULL, resultStackPointer);
1308 void prim_removefrom(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1310 struct Object *method = args[0], *traitsWindow;
1311 struct OopArray* roles = (struct OopArray*)args[1];
1312 struct Symbol* selector = (struct Symbol*)oh->cached.nil;
1313 struct MethodDefinition* def;
1314 word_t i;
1316 traitsWindow = method->map->delegates->elements[0];
1318 if (traitsWindow == oh->cached.closure_method_window || traitsWindow == oh->cached.compiled_method_window) {
1319 selector = ((struct Closure*)method)->method->selector;
1320 } else {
1321 /*May only remove a CompiledMethod or Closure.*/
1322 assert(0);
1325 def = method_is_on_arity(oh, method, selector, array_elements(roles), array_size(roles));
1326 if (def == NULL) {
1327 oh->cached.interpreter->stack->elements[resultStackPointer] = method;
1328 return;
1331 for (i = 0; i < array_size(roles); i++) {
1332 struct Object* role = array_elements(roles)[i];
1333 if (!object_is_smallint(role)) {
1334 object_remove_role(oh, role, selector, def);
1338 method_flush_cache(oh, selector);
1339 oh->cached.interpreter->stack->elements[resultStackPointer] = method;
1344 void prim_exponent(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1345 struct ByteArray* x = (struct ByteArray*)args[0];
1346 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object((*(word_t*)float_part(x) >> FLOAT_EXPONENT_OFFSET) & 0xFF);
1350 void prim_significand(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1351 struct ByteArray* x = (struct ByteArray*)args[0];
1352 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(*(word_t*)float_part(x) & FLOAT_SIGNIFICAND);
1356 void prim_getcwd(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1357 struct ByteArray* buf = (struct ByteArray*)args[1];
1358 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(getCurrentDirectory(buf));
1360 void prim_setcwd(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1361 struct ByteArray* buf = (struct ByteArray*)args[1];
1362 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(setCurrentDirectory(buf));
1366 void prim_float_equals(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1367 struct ByteArray *x = (struct ByteArray*)args[0], *y = (struct ByteArray*)args[1];
1368 if (*float_part(x) == *float_part(y)) {
1369 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.true_object;
1370 } else {
1371 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.false_object;
1375 void prim_float_less_than(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1376 struct ByteArray *x = (struct ByteArray*)args[0], *y = (struct ByteArray*)args[1];
1377 if (*float_part(x) < *float_part(y)) {
1378 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.true_object;
1379 } else {
1380 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.false_object;
1384 void prim_float_plus(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1385 struct ByteArray *x = (struct ByteArray*)args[0], *y = (struct ByteArray*)args[1];
1386 struct ByteArray* z = heap_new_float(oh);
1387 *float_part(z) = *float_part(x) + *float_part(y);
1388 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)z;
1391 void prim_float_minus(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1392 struct ByteArray *x = (struct ByteArray*)args[0], *y = (struct ByteArray*)args[1];
1393 struct ByteArray* z = heap_new_float(oh);
1394 *float_part(z) = *float_part(x) - *float_part(y);
1395 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)z;
1399 void prim_float_times(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1400 struct ByteArray *x = (struct ByteArray*)args[0], *y = (struct ByteArray*)args[1];
1401 struct ByteArray* z = heap_new_float(oh);
1402 *float_part(z) = *float_part(x) * *float_part(y);
1403 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)z;
1406 void prim_float_divide(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1407 struct ByteArray *x = (struct ByteArray*)args[0], *y = (struct ByteArray*)args[1];
1408 struct ByteArray* z = heap_new_float(oh);
1409 *float_part(z) = *float_part(x) / *float_part(y);
1410 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)z;
1413 void prim_float_raisedTo(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1414 struct ByteArray *x = (struct ByteArray*)args[0], *y = (struct ByteArray*)args[1];
1415 struct ByteArray* z = heap_new_float(oh);
1416 *float_part(z) = pow(*float_part(x), *float_part(y));
1417 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)z;
1420 void prim_float_ln(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1421 struct ByteArray *x = (struct ByteArray*)args[0];
1422 struct ByteArray* z = heap_new_float(oh);
1423 *float_part(z) = log(*float_part(x));
1424 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)z;
1427 void prim_float_exp(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1428 struct ByteArray *x = (struct ByteArray*)args[0];
1429 struct ByteArray* z = heap_new_float(oh);
1430 *float_part(z) = exp(*float_part(x));
1431 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)z;
1434 void prim_float_sin(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1435 struct ByteArray *x = (struct ByteArray*)args[0];
1436 struct ByteArray* z = heap_new_float(oh);
1437 *float_part(z) = sin(*float_part(x));
1438 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)z;
1441 void prim_withSignificand_exponent(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1442 /*this is really a bytearray*/
1443 word_t significand = object_to_smallint(args[1]), exponent = object_to_smallint(args[2]);
1444 struct ByteArray* f = heap_new_float(oh);
1445 *((word_t*)float_part(f)) = significand | exponent << FLOAT_EXPONENT_OFFSET;
1447 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)f;
1451 void prim_bitshift(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1452 word_t bits = object_to_smallint(args[0]);
1453 word_t shift = object_to_smallint(args[1]);
1454 word_t z;
1456 ASSURE_SMALLINT_ARG(0);
1457 ASSURE_SMALLINT_ARG(1);
1459 if (shift >= 0) {
1460 if (shift >= __WORDSIZE && bits != 0) {
1461 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_BIT_SHIFT_OVERFLOW), args[0], args[1], NULL, resultStackPointer);
1462 return;
1465 z = bits << shift;
1467 if (!smallint_fits_object(z) || z >> shift != bits) {
1468 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_BIT_SHIFT_OVERFLOW), args[0], args[1], NULL, resultStackPointer);
1469 return;
1472 } else if (shift <= -__WORDSIZE) {
1473 z = bits >> (__WORDSIZE-1);
1474 } else {
1475 z = bits >> -shift;
1478 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(z);
1483 void prim_minus(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1484 struct Object* x = args[0];
1485 struct Object* y = args[1];
1486 word_t z = object_to_smallint(x) - object_to_smallint(y);
1488 ASSURE_SMALLINT_ARG(0);
1489 ASSURE_SMALLINT_ARG(1);
1491 if (smallint_fits_object(z)) {
1492 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(z);
1493 } else {
1494 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_SUBTRACT_OVERFLOW), x, y, NULL, resultStackPointer);
1499 void prim_times(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1500 word_t x = object_to_smallint(args[0]);
1501 word_t y = object_to_smallint(args[1]);
1502 word_t z = x * y;
1505 ASSURE_SMALLINT_ARG(0);
1506 ASSURE_SMALLINT_ARG(1);
1509 if (y != 0 && (z / y != x || !smallint_fits_object(z))) { /*thanks slava*/
1510 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_MULTIPLY_OVERFLOW), args[0], args[1], NULL, resultStackPointer);
1511 } else {
1512 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(z);
1516 void prim_quo(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1517 struct Object* x = args[0];
1518 struct Object* y = args[1];
1520 ASSURE_SMALLINT_ARG(0);
1521 ASSURE_SMALLINT_ARG(1);
1523 if (object_to_smallint(y) == 0) {
1524 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_DIVIDE_BY_ZERO), x, y, NULL, resultStackPointer);
1525 } else {
1526 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(object_to_smallint(x) / object_to_smallint(y));
1531 void prim_forward_to(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1532 struct Object* x = args[0];
1533 struct Object* y = args[1];
1534 oh->cached.interpreter->stack->elements[resultStackPointer] = y;
1535 /* since some objects like roleTables store pointers to things like Nil in byte arrays rather than oop arrays,
1536 * we must make sure that these special objects do not move.
1538 if (x == get_special(oh, SPECIAL_OOP_NIL)
1539 || x == get_special(oh, SPECIAL_OOP_TRUE)
1540 || x == get_special(oh, SPECIAL_OOP_FALSE)) {
1541 printf("Error... you cannot call forwardTo on this special object (did you add a slot to Nil/True/False?)\n");
1542 interpreter_signal_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_TYPE_ERROR_ON), x, NULL, resultStackPointer); \
1543 return;
1546 if (!object_is_smallint(x) && !object_is_smallint(y) && x != y) {
1547 heap_forward(oh, x, y);
1548 heap_gc(oh);
1549 cache_specials(oh);
1555 void prim_clone_setting_slots(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1556 struct Object *obj = args[0], *slotArray = args[1], *valueArray = args[2], *newObj;
1557 word_t i;
1559 if (object_is_smallint(obj)) {
1560 oh->cached.interpreter->stack->elements[resultStackPointer] = obj;
1561 return;
1563 newObj = heap_clone(oh, obj);
1565 /*fix, check that arrays are same size, and signal errors*/
1567 for (i = 0; i < object_array_size(slotArray); i++) {
1568 struct Symbol* name = (struct Symbol*)object_array_get_element(slotArray, i);
1569 struct SlotEntry* se = slot_table_entry_for_name(oh, obj->map->slotTable, name);
1570 if (se == NULL) {
1571 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_SLOT_NOT_FOUND_NAMED), obj, (struct Object*)name, NULL, resultStackPointer);
1572 } else {
1573 /*since the object was just cloned, we aren't expecting a tenured obj to point to a new one*/
1574 object_slot_value_at_offset_put(oh, newObj, object_to_smallint(se->offset), object_array_get_element(valueArray, i));
1578 oh->cached.interpreter->stack->elements[resultStackPointer] = newObj;
1583 void prim_as_method_on(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1584 struct MethodDefinition* def;
1585 GC_VOLATILE struct Object *method = args[0], *roles=args[2];
1586 struct Symbol *selector = (struct Symbol*)args[1];
1587 struct Object* traitsWindow = method->map->delegates->elements[0];
1590 if (traitsWindow == get_special(oh, SPECIAL_OOP_CLOSURE_WINDOW)) {
1591 GC_VOLATILE struct Closure* closure = (struct Closure*)heap_clone(oh, method);
1592 heap_fixed_add(oh, (struct Object*)closure);
1593 closure->method = (struct CompiledMethod*)heap_clone(oh, (struct Object*)closure->method);
1594 heap_fixed_remove(oh, (struct Object*)closure);
1595 heap_store_into(oh, (struct Object*)closure, (struct Object*)closure->method);
1596 closure->method->method = closure->method;
1597 closure->method->selector = selector;
1598 method = (struct Object*)closure;
1599 } else {
1600 GC_VOLATILE struct CompiledMethod* closure= (struct CompiledMethod*)heap_clone(oh, method);
1601 closure->method = closure;
1602 closure->selector = selector;
1603 method = (struct Object*) closure;
1605 def = method_define(oh, method, (struct Symbol*)selector, ((struct OopArray*)roles)->elements, object_array_size(roles));
1606 def->slotAccessor = oh->cached.nil;
1607 method_flush_cache(oh, selector);
1608 #ifdef PRINT_DEBUG_DEFUN
1609 if (!oh->quiet) {
1610 printf("Defining function '"); print_symbol(selector);
1611 printf("' on: ");
1612 if (!print_printname(oh, ((struct OopArray*)roles)->elements[0])) printf("NoRole");
1614 word_t i;
1615 for (i = 1; i < object_array_size(roles); i++) {
1616 printf(", ");
1617 if (!print_printname(oh, ((struct OopArray*)roles)->elements[i])) printf("NoRole");
1620 printf("\n");
1622 #endif
1624 oh->cached.interpreter->stack->elements[resultStackPointer] = method;
1628 void prim_at_slot_named(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1629 struct Object* obj;
1630 struct Object* name;
1631 struct SlotEntry * se;
1633 obj = args[0];
1634 name = args[1];
1636 if (object_is_smallint(obj)) {
1637 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_SLOT_NOT_FOUND_NAMED), obj, name, NULL, resultStackPointer);
1638 } else {
1639 se = slot_table_entry_for_name(oh, obj->map->slotTable, (struct Symbol*)name);
1640 if (se == NULL) {
1641 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_SLOT_NOT_FOUND_NAMED), obj, name, NULL, resultStackPointer);
1642 } else {
1643 word_t offset = object_to_smallint(se->offset);
1644 oh->cached.interpreter->stack->elements[resultStackPointer] = object_slot_value_at_offset(obj, offset);
1652 void prim_at_slot_named_put(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1653 struct Object* obj=args[0], *val=args[2];
1654 struct Object* name = args[1];
1655 struct SlotEntry * se;
1656 struct Map* map;
1658 if (object_is_smallint(obj)) {
1659 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_SLOT_NOT_FOUND_NAMED), obj, name, NULL, resultStackPointer);
1660 return;
1663 if (object_is_immutable(obj)) {
1664 interpreter_signal_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_IMMUTABLE), obj, NULL, resultStackPointer);
1665 return;
1668 map = obj->map;
1669 se = slot_table_entry_for_name(oh, map->slotTable, (struct Symbol*)name);
1671 if (se == NULL) {
1672 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_SLOT_NOT_FOUND_NAMED), obj, name, NULL, resultStackPointer);
1673 } else {
1674 word_t offset = object_to_smallint(se->offset);
1675 oh->cached.interpreter->stack->elements[resultStackPointer] = object_slot_value_at_offset_put(oh, obj, offset, val);
1678 /*note: not supporting delegate slots*/
1685 void prim_clone_with_slot_valued(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1686 struct Object* obj = args[0], *value = args[2];
1687 struct Symbol* name = (struct Symbol*)args[1];
1689 if (object_is_smallint(obj)) {
1690 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_SLOT_NOT_FOUND_NAMED), obj, (struct Object*)name, NULL, resultStackPointer);
1691 } else {
1692 oh->cached.interpreter->stack->elements[resultStackPointer] = object_add_slot_named(oh, obj, name, value);
1696 void prim_clone_without_slot(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1697 struct Object* obj = args[0];
1698 struct Symbol* name = (struct Symbol*)args[1];
1700 if (object_is_smallint(obj)) {
1701 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_SLOT_NOT_FOUND_NAMED), obj, (struct Object*)name, NULL, resultStackPointer);
1702 } else {
1703 oh->cached.interpreter->stack->elements[resultStackPointer] = object_remove_slot(oh, obj, name);
1709 void prim_send_to(struct object_heap* oh, struct Object* args[], word_t n, struct OopArray* optionals, word_t resultStackPointer) {
1710 struct Symbol* selector = (struct Symbol*)args[0];
1711 struct OopArray* opts, *arguments = (struct OopArray*)args[1];
1713 if (optionals == NULL) {
1714 opts = NULL;
1715 } else {
1716 opts = (struct OopArray*)optionals->elements[1];
1717 if (opts == (struct OopArray*)oh->cached.nil) opts = NULL;
1719 send_to_through_arity_with_optionals(oh, selector, array_elements(arguments), array_elements(arguments), array_size(arguments), opts, resultStackPointer);
1722 void prim_send_to_through(struct object_heap* oh, struct Object* args[], word_t n, struct OopArray* optionals, word_t resultStackPointer) {
1723 struct Symbol* selector = (struct Symbol*)args[0];
1724 struct OopArray* opts, * arguments = (struct OopArray*)args[1], *dispatchers = (struct OopArray*)args[2];
1726 if (optionals == NULL) {
1727 opts = NULL;
1728 } else {
1729 opts = (struct OopArray*)optionals->elements[1];
1730 if (opts == (struct OopArray*)oh->cached.nil) opts = NULL;
1732 /*fix check array sizes are the same*/
1733 send_to_through_arity_with_optionals(oh, selector, array_elements(arguments), array_elements(dispatchers), array_size(arguments), opts, resultStackPointer);
1739 void prim_as_accessor(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1740 GC_VOLATILE struct Object *method = args[0], *slot = args[2];
1741 struct OopArray *roles = (struct OopArray*)args[3];
1742 struct Symbol* selector = (struct Symbol*)args[1];
1743 struct Object* traitsWindow = method->map->delegates->elements[0];
1744 struct MethodDefinition* def;
1746 if (traitsWindow == oh->cached.closure_method_window) {
1747 GC_VOLATILE struct Closure* closure = (struct Closure*)heap_clone(oh, method);
1748 heap_fixed_add(oh, (struct Object*)closure);
1749 closure->method = (struct CompiledMethod*)heap_clone(oh, (struct Object*)closure->method);
1750 heap_fixed_remove(oh, (struct Object*)closure);
1751 heap_store_into(oh, (struct Object*)closure, (struct Object*)closure->method);
1752 closure->method->method = closure->method;
1753 closure->method->selector = selector;
1754 method = (struct Object*)closure;
1755 } else if (traitsWindow == oh->cached.compiled_method_window){
1756 GC_VOLATILE struct CompiledMethod* closure = (struct CompiledMethod*)heap_clone(oh, method);
1757 closure->method = closure;
1758 closure->selector = selector;
1759 method = (struct Object*) closure;
1762 def = method_define(oh, method, selector, roles->elements, array_size(roles));
1763 def->slotAccessor = slot;
1764 method_flush_cache(oh, selector);
1765 oh->cached.interpreter->stack->elements[resultStackPointer] = method;
1767 #ifdef PRINT_DEBUG_DEFUN
1768 if (!oh->quiet) {
1769 printf("Defining accessor '"); print_symbol(selector);
1770 printf("' on: ");
1771 if (!print_printname(oh, ((struct OopArray*)roles)->elements[0])) printf("NoRole");
1773 word_t i;
1774 for (i = 1; i < array_size(roles); i++) {
1775 printf(", ");
1776 if (!print_printname(oh, ((struct OopArray*)roles)->elements[i])) printf("NoRole");
1779 printf("\n");
1781 #endif
1787 void prim_save_image(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1788 char nameString [SLATE_FILE_NAME_LENGTH];
1789 struct slate_image_header sih;
1790 struct Object* name = args[1];
1791 size_t nameLength = payload_size(name);
1792 FILE * imageFile;
1794 word_t totalSize, forwardPointerEntryCount;
1795 byte_t* memoryStart;
1796 struct Object *writeObject;
1797 struct ForwardPointerEntry* forwardPointers;
1798 /* do a full gc, allocate a new chunk of memory the size of the young and old combined,
1799 * copy all the non-free objects to the new memory while keeping an array of the position changes,
1800 * go through the memory and fix up the pointers, adjust points to start from 0 instead of memoryStart,
1801 * and write the header and the memory out to disk
1804 /*push true so if it resumes from the save image, it will do init code*/
1805 /*fixme*/
1806 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.true_object;
1808 if (nameLength >= sizeof(nameString)) {
1809 /*interpreter_stack_pop(oh, oh->cached.interpreter);*/
1810 /*push nil*/
1811 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1812 return;
1814 memcpy(nameString, (char*)byte_array_elements((struct ByteArray*)name), nameLength);
1815 nameString[nameLength] = '\0';
1817 imageFile = fopen(nameString, "wb");
1818 if (!imageFile) {
1819 /*interpreter_stack_pop(oh, oh->cached.interpreter);*/
1820 /*push nil*/
1821 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1823 return;
1825 printf("Saving image to %s\n", nameString);
1826 heap_full_gc(oh);
1827 totalSize = oh->memoryOldSize + oh->memoryYoungSize;
1828 forwardPointerEntryCount = ((totalSize / 4) + sizeof(struct ForwardPointerEntry) - 1) / sizeof(struct ForwardPointerEntry);
1829 memoryStart = calloc(1, totalSize);
1830 writeObject = (struct Object*)memoryStart;
1831 forwardPointers = calloc(1, forwardPointerEntryCount * sizeof(struct ForwardPointerEntry));
1832 assert(memoryStart != NULL);
1833 copy_used_objects(oh, &writeObject, oh->memoryOld, oh->memoryOldSize, forwardPointers, forwardPointerEntryCount);
1834 copy_used_objects(oh, &writeObject, oh->memoryYoung, oh->memoryYoungSize, forwardPointers, forwardPointerEntryCount);
1835 totalSize = (byte_t*)writeObject - memoryStart;
1836 adjust_object_fields_with_table(oh, memoryStart, totalSize, forwardPointers, forwardPointerEntryCount);
1837 adjust_oop_pointers_from(oh, 0-(word_t)memoryStart, memoryStart, totalSize);
1838 sih.magic = SLATE_IMAGE_MAGIC;
1839 sih.size = totalSize;
1840 sih.next_hash = heap_new_hash(oh);
1841 sih.special_objects_oop = (byte_t*) (forward_pointer_hash_get(forwardPointers, forwardPointerEntryCount, (struct Object*)oh->special_objects_oop)->toObj) - memoryStart;
1842 sih.current_dispatch_id = oh->current_dispatch_id;
1844 if (fwrite(&sih, sizeof(struct slate_image_header), 1, imageFile) != 1
1845 || fwrite(memoryStart, 1, totalSize, imageFile) != totalSize) {
1846 fprintf(stderr, "Error writing image!\n");
1848 fclose(imageFile);
1849 free(forwardPointers);
1850 free(memoryStart);
1852 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.false_object;
1854 interpreter_stack_pop(oh, oh->cached.interpreter);
1855 interpreter_push_false(oh, oh->cached.interpreter);
1863 void (*primitives[]) (struct object_heap* oh, struct Object* args[], word_t n, struct OopArray* opts, word_t resultStackPointer) = {
1865 /*0-9*/ prim_as_method_on, prim_as_accessor, prim_map, prim_set_map, prim_fixme, prim_removefrom, prim_clone, prim_clone_setting_slots, prim_clone_with_slot_valued, prim_fixme,
1866 /*10-9*/ prim_fixme, prim_fixme, prim_clone_without_slot, prim_at_slot_named, prim_smallint_at_slot_named, prim_at_slot_named_put, prim_forward_to, prim_bytearray_newsize, prim_bytesize, prim_byteat,
1867 /*20-9*/ prim_byteat_put, prim_ooparray_newsize, prim_size, prim_at, prim_at_put, prim_ensure, prim_applyto, prim_send_to, prim_send_to_through, prim_findon,
1868 /*30-9*/ prim_fixme, prim_run_args_into, prim_exit, prim_isIdenticalTo, prim_identity_hash, prim_identity_hash_univ, prim_equals, prim_less_than, prim_bitor, prim_bitand,
1869 /*40-9*/ prim_bitxor, prim_bitnot, prim_bitshift, prim_plus, prim_minus, prim_times, prim_quo, prim_fixme, prim_fixme, prim_frame_pointer_of,
1870 /*50-9*/ prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_bytesPerWord, prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme,
1871 /*60-9*/ prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_readConsole_from_into_starting_at, prim_write_to_starting_at, prim_flush_output, prim_handle_for, prim_handle_for_input, prim_fixme,
1872 /*70-9*/ prim_handleForNew, prim_close, prim_read_from_into_starting_at, prim_write_to_from_starting_at, prim_reposition_to, prim_positionOf, prim_atEndOf, prim_sizeOf, prim_save_image, prim_fixme,
1873 /*80-9*/ prim_fixme, prim_fixme, prim_getcwd, prim_setcwd, prim_significand, prim_exponent, prim_withSignificand_exponent, prim_float_equals, prim_float_less_than, prim_float_plus,
1874 /*90-9*/ prim_float_minus, prim_float_times, prim_float_divide, prim_float_raisedTo, prim_float_ln, prim_float_exp, prim_float_sin, prim_fixme, prim_fixme, prim_fixme,
1875 /*00-9*/ prim_fixme, prim_fixme, prim_fixme, prim_newFixedArea, prim_closeFixedArea, prim_fixedAreaAddRef, prim_fixedWriteFromStarting, prim_fixedReadFromStarting, prim_fixedAreaSize, prim_fixedAreaResize,
1876 /*10-9*/ prim_addressOf, prim_loadLibrary, prim_closeLibrary, prim_procAddressOf, prim_extlibError, prim_applyExternal, prim_timeSinceEpoch, prim_cloneSystem, prim_readFromPipe, prim_writeToPipe,
1877 /*20-9*/ prim_selectOnReadPipesFor, prim_selectOnWritePipesFor, prim_closePipe, prim_socketCreate, prim_socketListen, prim_socketAccept, prim_socketBind, prim_socketConnect, prim_socketCreateIP, prim_smallIntegerMinimum,
1878 /*30-9*/ prim_smallIntegerMaximum, prim_socketGetError, prim_getAddrInfo, prim_getAddrInfoResult, prim_freeAddrInfoResult, prim_vmArgCount, prim_vmArg, prim_environmentVariables, prim_fixme, prim_fixme,
1879 /*40-9*/ prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme,
1880 /*50-9*/ prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme,