More WIN32 porting work for uname(), getpid(), etc.
[cslatevm.git] / src / vm / primitives.c
blobb5b2d655f232beb1e791c081d9b54d624d56ad4c
1 #include "slate.h"
3 // For platform information:
4 #ifndef WIN32
5 #include <sys/utsname.h>
6 #else
7 typedef struct utsname {
8 char sysname[256];
9 char nodename[256];
10 char release[256];
11 char version[256];
12 char machine[256];
15 int uname(struct utsname *un) {
16 DWORD dwVersion = 0;
17 DWORD dwMajorVersion = 0;
18 DWORD dwMinorVersion = 0;
19 DWORD dwBuild = 0;
20 #ifdef WIN32
21 #ifdef WIN64
22 strcpy(un->sysname,"Win64");
23 #else
24 strcpy(un->sysname,"Win32");
25 #endif
26 #endif
27 dwVersion = GetVersion();
28 if (dwVersion < 0x80000000) dwBuild = (DWORD)(HIWORD(dwVersion)); else dwBuild=0;
29 sprintf(un->release, "%d", dwBuild);
30 sprintf(un->version, "%d %d", (DWORD)(LOBYTE(LOWORD(dwVersion))), (DWORD)(HIBYTE(LOWORD(dwVersion))));
31 #ifdef WIN32
32 #ifdef WIN64
33 strcpy(un->machine,"x64");
34 #else
35 strcpy(un->machine,"x86");
36 #endif
37 #endif
38 if(gethostname(un->nodename, 256)!=0) strcpy(un->nodename, "localhost");
39 return 0;
41 #endif
42 struct utsname info;
44 #ifdef WIN32
45 int getpid() {
46 return GetProcessId();
48 #endif
50 //Template for defining Slate primitive signatures. Not a macro because IDEs don't process it:
51 //#define SLATE_PRIM(prim_name) void prim_name(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer)
53 #ifdef SLATE_DAEMONIZE
54 #include <pwd.h>
55 #include <sys/stat.h>
56 #include <signal.h>
57 #endif
59 void prim_fixme(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
60 struct Object* x = args[0];
61 printf("UNIMPLEMENTED PRIMITIVE\n");
62 interpreter_signal_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_TYPE_ERROR_ON), x, NULL, resultStackPointer);
65 #pragma mark Root
67 void prim_isIdenticalTo(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
68 oh->cached.interpreter->stack->elements[resultStackPointer] = (args[0]==args[1])? oh->cached.true_object : oh->cached.false_object;
71 void prim_identity_hash(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
72 /*fix*/
73 /* print_detail(oh, args[0]);
74 print_backtrace(oh);*/
75 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(object_hash(args[0]));
78 void prim_identity_hash_univ(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
79 /*fix*/
80 /* print_detail(oh, args[0]);
81 print_backtrace(oh);*/
82 if (object_is_smallint(args[0])) {
83 oh->cached.interpreter->stack->elements[resultStackPointer] = args[0];
84 } else {
85 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(object_hash(args[0]));
89 /* Root forwardTo: anotherObject */
90 void prim_forward_to(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
91 struct Object* x = args[0];
92 struct Object* y = args[1];
93 oh->cached.interpreter->stack->elements[resultStackPointer] = y;
94 /* since some objects like roleTables store pointers to things like Nil in byte arrays rather than oop arrays,
95 * we must make sure that these special objects do not move.
97 if (x == get_special(oh, SPECIAL_OOP_NIL)
98 || x == get_special(oh, SPECIAL_OOP_TRUE)
99 || x == get_special(oh, SPECIAL_OOP_FALSE)) {
100 printf("Error... you cannot call forwardTo on this special object (did you add a slot to Nil/True/False?)\n");
101 interpreter_signal_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_TYPE_ERROR_ON), x, NULL, resultStackPointer); \
102 return;
105 if (!object_is_smallint(x) && !object_is_smallint(y) && x != y) {
106 heap_forward(oh, x, y);
107 heap_gc(oh);
108 cache_specials(oh);
113 /* Root atSlotNamed: symbol */
114 void prim_at_slot_named(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
115 struct Object* obj;
116 struct Object* name;
117 struct SlotEntry * se;
119 obj = args[0];
120 name = args[1];
122 if (object_is_smallint(obj)) {
123 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_SLOT_NOT_FOUND_NAMED), obj, name, NULL, resultStackPointer);
124 } else {
125 se = slot_table_entry_for_name(oh, obj->map->slotTable, (struct Symbol*)name);
126 if (se == NULL) {
127 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_SLOT_NOT_FOUND_NAMED), obj, name, NULL, resultStackPointer);
128 } else {
129 word_t offset = object_to_smallint(se->offset);
130 oh->cached.interpreter->stack->elements[resultStackPointer] = object_slot_value_at_offset(obj, offset);
135 /* Root atSlotNamed: symbol put: value */
136 void prim_at_slot_named_put(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
137 struct Object* obj=args[0], *val=args[2];
138 struct Object* name = args[1];
139 struct SlotEntry * se;
140 struct Map* map;
142 if (object_is_smallint(obj)) {
143 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_SLOT_NOT_FOUND_NAMED), obj, name, NULL, resultStackPointer);
144 return;
147 if (object_is_immutable(obj)) {
148 interpreter_signal_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_IMMUTABLE), obj, NULL, resultStackPointer);
149 return;
152 map = obj->map;
153 se = slot_table_entry_for_name(oh, map->slotTable, (struct Symbol*)name);
155 if (se == NULL) {
156 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_SLOT_NOT_FOUND_NAMED), obj, name, NULL, resultStackPointer);
157 } else {
158 word_t offset = object_to_smallint(se->offset);
159 oh->cached.interpreter->stack->elements[resultStackPointer] = object_slot_value_at_offset_put(oh, obj, offset, val);
162 /*note: not supporting delegate slots*/
166 void prim_clone(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
167 if (object_is_smallint(args[0])) {
168 oh->cached.interpreter->stack->elements[resultStackPointer] = args[0];
169 } else {
170 oh->cached.interpreter->stack->elements[resultStackPointer] = heap_clone(oh, args[0]);
174 /* Cloneable cloneSettingSlots: slotNamesArray to: valuesArray */
175 void prim_clone_setting_slots(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
176 struct Object *obj = args[0], *slotArray = args[1], *valueArray = args[2], *newObj;
177 word_t i;
179 if (object_is_smallint(obj)) {
180 oh->cached.interpreter->stack->elements[resultStackPointer] = obj;
181 return;
183 newObj = heap_clone(oh, obj);
185 /*fix, check that arrays are same size, and signal errors*/
187 for (i = 0; i < object_array_size(slotArray); i++) {
188 struct Symbol* name = (struct Symbol*)object_array_get_element(slotArray, i);
189 struct SlotEntry* se = slot_table_entry_for_name(oh, obj->map->slotTable, name);
190 if (se == NULL) {
191 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_SLOT_NOT_FOUND_NAMED), obj, (struct Object*)name, NULL, resultStackPointer);
192 } else {
193 /*since the object was just cloned, we aren't expecting a tenured obj to point to a new one*/
194 object_slot_value_at_offset_put(oh, newObj, object_to_smallint(se->offset), object_array_get_element(valueArray, i));
198 oh->cached.interpreter->stack->elements[resultStackPointer] = newObj;
201 void prim_clone_with_slot_valued(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
202 struct Object* obj = args[0], *value = args[2];
203 struct Symbol* name = (struct Symbol*)args[1];
205 if (object_is_smallint(obj)) {
206 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_SLOT_NOT_FOUND_NAMED), obj, (struct Object*)name, NULL, resultStackPointer);
207 } else {
208 oh->cached.interpreter->stack->elements[resultStackPointer] = object_add_slot_named(oh, obj, name, value);
212 void prim_clone_without_slot(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
213 struct Object* obj = args[0];
214 struct Symbol* name = (struct Symbol*)args[1];
216 if (object_is_smallint(obj)) {
217 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_SLOT_NOT_FOUND_NAMED), obj, (struct Object*)name, NULL, resultStackPointer);
218 } else {
219 oh->cached.interpreter->stack->elements[resultStackPointer] = object_remove_slot(oh, obj, name);
223 #pragma mark Map
225 void prim_map(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
226 struct Object* obj;
227 obj = args[0];
229 if (object_is_smallint(obj)) {
230 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
231 } else {
232 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)obj->map;
238 void prim_set_map(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
239 GC_VOLATILE struct Object* obj;
240 GC_VOLATILE struct Map* map;
241 obj = args[0];
242 map = (struct Map*)args[1];
244 if (object_is_smallint(obj) || object_is_immutable(obj)) {
245 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
246 } else {
247 object_change_map(oh, obj, map);
248 heap_store_into(oh, args[0], args[1]);
249 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)map;
254 #pragma mark Method
256 void prim_applyto(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
257 struct Closure *method = (struct Closure*)args[0];
258 struct OopArray* argArray = (struct OopArray*) args[1];
259 struct OopArray* real_opts = NULL;
261 if (opts != NULL && opts->elements[1] != oh->cached.nil) {
262 real_opts = (struct OopArray*) opts->elements[1];
264 interpreter_apply_to_arity_with_optionals(oh, oh->cached.interpreter, method,
265 argArray->elements, array_size(argArray), real_opts, resultStackPointer);
268 void prim_findon(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
269 struct MethodDefinition* def;
270 struct Symbol* selector= (struct Symbol*) args[0];
271 struct OopArray* arguments= (struct OopArray*) args[1];
274 def = method_dispatch_on(oh, selector, arguments->elements, array_size(arguments), NULL);
276 oh->cached.interpreter->stack->elements[resultStackPointer] = (def == NULL ? oh->cached.nil : (struct Object*) def->method);
279 void prim_ensure(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
281 struct Closure* body = (struct Closure*) args[0];
282 struct Object* ensureHandler = args[1];
283 interpreter_apply_to_arity_with_optionals(oh, oh->cached.interpreter, body, NULL, 0, NULL, resultStackPointer);
284 /*the registers are already allocated on the stack so we don't worry about overwriting them*/
285 interpreter_stack_push(oh, oh->cached.interpreter, oh->cached.interpreter->ensureHandlers);
286 interpreter_stack_push(oh, oh->cached.interpreter, ensureHandler);
287 oh->cached.interpreter->ensureHandlers = smallint_to_object(oh->cached.interpreter->stackPointer - 2);
288 #ifdef PRINT_DEBUG_ENSURE
289 printf("ensure handlers at %" PRIdPTR "\n", oh->cached.interpreter->stackPointer - 2);
290 #endif
294 void prim_send_to(struct object_heap* oh, struct Object* args[], word_t n, struct OopArray* optionals, word_t resultStackPointer) {
295 struct Symbol* selector = (struct Symbol*)args[0];
296 struct OopArray* opts, *arguments = (struct OopArray*)args[1];
298 if (optionals == NULL) {
299 opts = NULL;
300 } else {
301 opts = (struct OopArray*)optionals->elements[1];
302 if (opts == (struct OopArray*)oh->cached.nil) opts = NULL;
304 send_to_through_arity_with_optionals(oh, selector, array_elements(arguments), array_elements(arguments), array_size(arguments), opts, resultStackPointer);
307 void prim_send_to_through(struct object_heap* oh, struct Object* args[], word_t n, struct OopArray* optionals, word_t resultStackPointer) {
308 struct Symbol* selector = (struct Symbol*)args[0];
309 struct OopArray* opts, * arguments = (struct OopArray*)args[1], *dispatchers = (struct OopArray*)args[2];
311 if (optionals == NULL) {
312 opts = NULL;
313 } else {
314 opts = (struct OopArray*)optionals->elements[1];
315 if (opts == (struct OopArray*)oh->cached.nil) opts = NULL;
317 /*fix check array sizes are the same*/
318 send_to_through_arity_with_optionals(oh, selector, array_elements(arguments), array_elements(dispatchers), array_size(arguments), opts, resultStackPointer);
321 /* Method asMethod: selector on: rolesArray */
322 void prim_as_method_on(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
323 struct MethodDefinition* def;
324 GC_VOLATILE struct Object *method = args[0], *roles=args[2];
325 struct Symbol *selector = (struct Symbol*)args[1];
326 struct Object* traitsWindow = method->map->delegates->elements[0];
329 if (traitsWindow == get_special(oh, SPECIAL_OOP_CLOSURE_WINDOW)) {
330 GC_VOLATILE struct Closure* closure = (struct Closure*)heap_clone(oh, method);
331 heap_fixed_add(oh, (struct Object*)closure);
332 closure->method = (struct CompiledMethod*)heap_clone(oh, (struct Object*)closure->method);
333 heap_fixed_remove(oh, (struct Object*)closure);
334 heap_store_into(oh, (struct Object*)closure, (struct Object*)closure->method);
335 closure->method->method = closure->method;
336 closure->method->selector = selector;
337 method = (struct Object*)closure;
338 } else {
339 GC_VOLATILE struct CompiledMethod* closure= (struct CompiledMethod*)heap_clone(oh, method);
340 closure->method = closure;
341 closure->selector = selector;
342 method = (struct Object*) closure;
344 def = method_define(oh, method, (struct Symbol*)selector, ((struct OopArray*)roles)->elements, object_array_size(roles));
345 def->slotAccessor = oh->cached.nil;
346 method_flush_cache(oh, selector);
347 #ifdef PRINT_DEBUG_DEFUN
348 if (!oh->quiet) {
349 printf("Defining function '"); print_symbol(selector);
350 printf("' on: ");
351 if (!print_printname(oh, ((struct OopArray*)roles)->elements[0])) printf("NoRole");
353 word_t i;
354 for (i = 1; i < object_array_size(roles); i++) {
355 printf(", ");
356 if (!print_printname(oh, ((struct OopArray*)roles)->elements[i])) printf("NoRole");
359 printf("\n");
361 #endif
363 oh->cached.interpreter->stack->elements[resultStackPointer] = method;
366 /* Method removeFrom: rolesArray */
367 void prim_removefrom(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
369 struct Object *method = args[0], *traitsWindow;
370 struct OopArray* roles = (struct OopArray*)args[1];
371 struct Symbol* selector = (struct Symbol*)oh->cached.nil;
372 struct MethodDefinition* def;
373 word_t i;
375 traitsWindow = method->map->delegates->elements[0];
377 if (traitsWindow == oh->cached.closure_method_window || traitsWindow == oh->cached.compiled_method_window) {
378 selector = ((struct Closure*)method)->method->selector;
379 } else {
380 /*May only remove a CompiledMethod or Closure.*/
381 assert(0);
384 def = method_is_on_arity(oh, method, selector, array_elements(roles), array_size(roles));
385 if (def == NULL) {
386 oh->cached.interpreter->stack->elements[resultStackPointer] = method;
387 return;
390 for (i = 0; i < array_size(roles); i++) {
391 struct Object* role = array_elements(roles)[i];
392 if (!object_is_smallint(role)) {
393 object_remove_role(oh, role, selector, def);
396 method_flush_cache(oh, selector);
397 oh->cached.interpreter->stack->elements[resultStackPointer] = method;
400 void prim_as_accessor(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
401 GC_VOLATILE struct Object *method = args[0], *slot = args[2];
402 struct OopArray *roles = (struct OopArray*)args[3];
403 struct Symbol* selector = (struct Symbol*)args[1];
404 struct Object* traitsWindow = method->map->delegates->elements[0];
405 struct MethodDefinition* def;
407 if (traitsWindow == oh->cached.closure_method_window) {
408 GC_VOLATILE struct Closure* closure = (struct Closure*)heap_clone(oh, method);
409 heap_fixed_add(oh, (struct Object*)closure);
410 closure->method = (struct CompiledMethod*)heap_clone(oh, (struct Object*)closure->method);
411 heap_fixed_remove(oh, (struct Object*)closure);
412 heap_store_into(oh, (struct Object*)closure, (struct Object*)closure->method);
413 closure->method->method = closure->method;
414 closure->method->selector = selector;
415 method = (struct Object*)closure;
416 } else if (traitsWindow == oh->cached.compiled_method_window){
417 GC_VOLATILE struct CompiledMethod* closure = (struct CompiledMethod*)heap_clone(oh, method);
418 closure->method = closure;
419 closure->selector = selector;
420 method = (struct Object*) closure;
423 def = method_define(oh, method, selector, roles->elements, array_size(roles));
424 def->slotAccessor = slot;
425 method_flush_cache(oh, selector);
426 oh->cached.interpreter->stack->elements[resultStackPointer] = method;
428 #ifdef PRINT_DEBUG_DEFUN
429 if (!oh->quiet) {
430 printf("Defining accessor '"); print_symbol(selector);
431 printf("' on: ");
432 if (!print_printname(oh, ((struct OopArray*)roles)->elements[0])) printf("NoRole");
434 word_t i;
435 for (i = 1; i < array_size(roles); i++) {
436 printf(", ");
437 if (!print_printname(oh, ((struct OopArray*)roles)->elements[i])) printf("NoRole");
440 printf("\n");
442 #endif
445 #pragma mark Array
447 void prim_at(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
448 struct Object* array;
449 word_t i;
451 array = args[0];
452 i = object_to_smallint(args[1]);
453 ASSURE_SMALLINT_ARG(1);
454 if (i < object_array_size(array) && i >= 0) {
455 oh->cached.interpreter->stack->elements[resultStackPointer] = ((struct OopArray*)array)->elements[i];
456 } else {
457 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_KEY_NOT_FOUND_ON), args[1], args[0], NULL, resultStackPointer);
461 void prim_at_put(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
462 struct Object *array = args[0], *i = args[1], *val = args[2];
463 word_t index = object_to_smallint(i);
465 ASSURE_SMALLINT_ARG(1);
466 if (object_is_immutable(array)) {
467 interpreter_signal_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_IMMUTABLE), array, NULL, resultStackPointer);
468 return;
471 if (index < object_array_size(array)) {
472 heap_store_into(oh, array, val);
473 oh->cached.interpreter->stack->elements[resultStackPointer] = ((struct OopArray*)array)->elements[index] = val;
474 } else {
475 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_KEY_NOT_FOUND_ON), i, array, NULL, resultStackPointer);
479 void prim_ooparray_newsize(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
480 /*struct Object* array = args[0];*/
481 struct Object* i = args[1];
482 if (object_is_smallint(i)) {
483 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)
484 heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO),
485 object_to_smallint(i));
486 } else {
487 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
491 void prim_size(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
492 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(object_array_size(args[0]));
495 #pragma mark ByteArray
497 void prim_bytearray_newsize(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
498 struct Object* obj, *i;
499 obj = args[0];
500 i = args[1];
502 if (!object_is_smallint(i)) {
503 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
504 return;
507 oh->cached.interpreter->stack->elements[resultStackPointer] =
508 (struct Object*)heap_clone_byte_array_sized(oh, obj, (object_to_smallint(i) < 0) ? 0 : object_to_smallint(i));
511 void prim_bytesize(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
512 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(payload_size(args[0]));
515 void prim_byteat_put(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
516 struct Object* obj= args[0], *i=args[1], *val = args[2];
517 word_t index;
519 index = object_to_smallint(i);
521 ASSURE_SMALLINT_ARG(1);
522 ASSURE_SMALLINT_ARG(2);
524 if (object_is_immutable(obj)) {
525 interpreter_signal_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_IMMUTABLE), obj, NULL, resultStackPointer);
526 return;
529 if (index < byte_array_size((struct ByteArray*)obj)) {
530 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(byte_array_set_element((struct ByteArray*)obj, index, object_to_smallint(val)));
531 } else {
532 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_KEY_NOT_FOUND_ON), i, obj, NULL, resultStackPointer);
537 void prim_byteat(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
538 struct Object* obj, *i;
539 word_t index;
541 obj = args[0];
542 i = args[1];
543 index = object_to_smallint(i);
545 ASSURE_SMALLINT_ARG(1);
547 if (index < byte_array_size((struct ByteArray*)obj)) {
548 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(byte_array_get_element(obj, index));
549 } else {
550 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_KEY_NOT_FOUND_ON), i, obj, NULL, resultStackPointer);
555 #pragma mark File
557 void prim_atEndOf(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
558 word_t handle = object_to_smallint(args[1]);
559 ASSURE_SMALLINT_ARG(1);
560 if (endOfFile(oh, handle)) {
561 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.true_object;
562 } else {
563 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.false_object;
567 void prim_sizeOf(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
568 word_t handle = object_to_smallint(args[1]);
569 word_t retval = sizeOfFile(oh, handle);
570 ASSURE_SMALLINT_ARG(1);
571 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(retval);
574 void prim_flush_output(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
575 /*struct Object *console=args[0];*/
576 fflush(stdout);
577 fflush(stderr);
578 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
581 void prim_handle_for(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
582 word_t handle;
583 struct Object /**file=args[0],*/ *fname=args[1];
585 handle = openFile(oh, (struct ByteArray*)fname, SF_READ|SF_WRITE);
586 if (handle >= 0) {
587 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(handle);
588 } else {
589 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
594 void prim_handleForNew(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
595 word_t handle;
596 struct Object /**file=args[0],*/ *fname=args[1];
598 handle = openFile(oh, (struct ByteArray*)fname, SF_READ|SF_WRITE|SF_CLEAR|SF_CREATE);
599 if (handle >= 0) {
600 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(handle);
601 } else {
602 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
607 void prim_handle_for_input(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
608 word_t handle;
609 struct Object /**file=args[0],*/ *fname=args[1];
611 handle = openFile(oh, (struct ByteArray*)fname, SF_READ);
612 if (handle >= 0) {
613 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(handle);
614 } else {
615 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
620 void prim_closePipe(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
621 word_t handle = object_to_smallint(args[0]);
622 int retval;
624 ASSURE_SMALLINT_ARG(0);
625 #ifdef WIN32
626 retval = closesocket(handle);
627 #else
628 retval = close(handle);
629 #endif
630 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(retval);
634 void prim_readFromPipe(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
635 struct ByteArray* array = (struct ByteArray*) args[0];
636 word_t handle = object_to_smallint(args[1]);
637 word_t start = object_to_smallint(args[2]), end = object_to_smallint(args[3]);
638 ssize_t retval;
640 ASSURE_TYPE_ARG(0, TYPE_BYTE_ARRAY);
641 ASSURE_SMALLINT_ARG(1);
642 ASSURE_SMALLINT_ARG(2);
643 ASSURE_SMALLINT_ARG(3);
645 if (start < 0 || start >= byte_array_size(array)) {
646 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_KEY_NOT_FOUND_ON), args[2], args[0], NULL, resultStackPointer);
647 return;
650 if (end < start || end > byte_array_size(array)) {
651 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_KEY_NOT_FOUND_ON), args[3], args[0], NULL, resultStackPointer);
652 return;
655 retval = recv(handle, byte_array_elements(array)+start, end - start, 0);
658 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(retval);
663 void prim_writeToPipe(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
664 struct ByteArray* array = (struct ByteArray*) args[0];
665 word_t handle = object_to_smallint(args[1]);
666 word_t start = object_to_smallint(args[2]), end = object_to_smallint(args[3]);
667 ssize_t retval;
669 ASSURE_TYPE_ARG(0, TYPE_BYTE_ARRAY);
670 ASSURE_SMALLINT_ARG(1);
671 ASSURE_SMALLINT_ARG(2);
672 ASSURE_SMALLINT_ARG(3);
674 if (start < 0 || start >= byte_array_size(array)) {
675 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_KEY_NOT_FOUND_ON), args[2], args[0], NULL, resultStackPointer);
676 return;
679 if (end < start || end > byte_array_size(array)) {
680 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_KEY_NOT_FOUND_ON), args[3], args[0], NULL, resultStackPointer);
681 return;
684 retval = send(handle, byte_array_elements(array)+start, end - start, 0);
686 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(retval);
690 /*FIXME this is a copy of the last function with only the select call changed*/
691 void prim_selectOnWritePipesFor(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
693 GC_VOLATILE struct OopArray* selectOn = (struct OopArray*) args[0];
694 GC_VOLATILE struct OopArray* readyPipes;
695 word_t waitTime = object_to_smallint(args[1]);
696 int retval, fdCount, maxFD;
697 struct timeval tv;
698 fd_set fdList;
699 maxFD = 0;
701 ASSURE_SMALLINT_ARG(1);
703 if ((fdCount = socket_select_setup(selectOn, &fdList, &maxFD)) < 0) {
704 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
705 return;
709 tv.tv_sec = waitTime / 1000000;
710 tv.tv_usec = waitTime % 1000000;
711 retval = select(maxFD+1, NULL, &fdList, NULL, &tv);
713 if (retval < 0) {
714 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
715 return;
719 readyPipes = heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO), retval);
720 socket_select_find_available(selectOn, &fdList, readyPipes, retval);
722 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)readyPipes;
726 #pragma mark Socket
728 void prim_socketCreate(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
729 word_t domain = object_to_smallint(args[0]);
730 word_t type = object_to_smallint(args[1]);
731 word_t protocol = object_to_smallint(args[2]);
732 word_t ret = socket(socket_lookup_domain(domain), socket_lookup_type(type), socket_lookup_protocol(protocol));
733 int ret2 = 0;
735 ASSURE_SMALLINT_ARG(0);
736 ASSURE_SMALLINT_ARG(1);
737 ASSURE_SMALLINT_ARG(2);
739 if (ret >= 0) {
740 ret2 = socket_set_nonblocking(ret);
741 } else {
742 perror("socket create");
745 if (ret2 < 0) {
746 perror("set nonblocking");
747 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(-1);
748 } else {
749 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(ret);
753 void prim_socketListen(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
754 word_t fd = object_to_smallint(args[0]);
755 word_t size = object_to_smallint(args[1]);
756 word_t ret;
758 ASSURE_SMALLINT_ARG(0);
759 ASSURE_SMALLINT_ARG(1);
761 ret = listen(fd, size);
763 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(ret);
767 void prim_socketAccept(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
768 word_t fd = object_to_smallint(args[0]);
769 word_t ret;
770 struct sockaddr_storage addr;
771 socklen_t len;
772 GC_VOLATILE struct ByteArray* addrArray;
773 GC_VOLATILE struct OopArray* result;
775 ASSURE_SMALLINT_ARG(0);
777 len = sizeof(addr);
778 ret = accept(fd, (struct sockaddr*)&addr, &len);
780 if (ret >= 0) {
781 addrArray = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), sizeof(struct sockaddr_in));
782 } else {
783 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(ret);
784 return;
787 heap_fixed_add(oh, (struct Object*)addrArray);
788 result = heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO), 2);
789 heap_fixed_remove(oh, (struct Object*)addrArray);
791 object_array_set_element(oh, (struct Object*)result, 0, smallint_to_object(ret));
792 object_array_set_element(oh, (struct Object*)result, 1, (struct Object*)addrArray);
794 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)result;
798 void prim_socketBind(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
799 word_t fd = object_to_smallint(args[0]);
800 struct ByteArray* address = (struct ByteArray*) args[1];
801 word_t ret;
803 ASSURE_SMALLINT_ARG(0);
805 ret = bind(fd, (const struct sockaddr*)byte_array_elements(address), (socklen_t)byte_array_size(address));
806 if (ret < 0) perror("bind");
807 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(ret);
810 void prim_socketConnect(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
811 word_t fd = object_to_smallint(args[0]);
812 struct ByteArray* address = (struct ByteArray*) args[1];
813 word_t ret;
815 ASSURE_SMALLINT_ARG(0);
817 ret = connect(fd, (const struct sockaddr*)byte_array_elements(address), (socklen_t)byte_array_size(address));
819 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(ret);
823 void prim_socketGetError(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
824 word_t fd = object_to_smallint(args[0]);
825 word_t ret;
826 int optval;
827 socklen_t optlen;
828 optlen = 4;
829 ASSURE_SMALLINT_ARG(0);
831 ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &optval, (socklen_t*)&optlen);
833 if (ret == 0) {
834 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(optval);
835 } else {
836 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(ret);
841 void prim_getAddrInfo(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
842 struct ByteArray* hostname = (struct ByteArray*)args[1];
843 struct ByteArray* service = (struct ByteArray*)args[2];
844 word_t family = object_to_smallint(args[3]);
845 word_t type = object_to_smallint(args[4]);
846 word_t protocol = object_to_smallint(args[5]);
847 word_t flags = object_to_smallint(args[6]);
848 word_t ret, serviceSize, hostnameSize;
850 ASSURE_TYPE_ARG(1, TYPE_BYTE_ARRAY);
851 ASSURE_SMALLINT_ARG(3);
852 ASSURE_SMALLINT_ARG(4);
853 ASSURE_SMALLINT_ARG(5);
854 ASSURE_SMALLINT_ARG(6);
856 if ((struct Object*)hostname == oh->cached.nil) {
857 hostnameSize = 0;
858 } else {
859 hostnameSize = byte_array_size(hostname)+1;
862 if ((struct Object*)service == oh->cached.nil) {
863 serviceSize = 0;
864 } else {
865 ASSURE_TYPE_ARG(2, TYPE_BYTE_ARRAY);
866 serviceSize = byte_array_size(service)+1;
869 ret = socket_getaddrinfo(oh, hostname, hostnameSize, service, serviceSize, family, type, protocol, flags);
871 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(ret);
875 void prim_getAddrInfoResult(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
876 word_t ticket = object_to_smallint(args[0]);
877 if (ticket >= oh->socketTicketCount || ticket < 0
878 || oh->socketTickets[ticket].inUse == 0 || oh->socketTickets[ticket].finished == 0) {
879 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
880 return;
882 if (oh->socketTickets[ticket].result < 0) {
883 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(socket_return(oh->socketTickets[ticket].result));
884 } else {
885 word_t count, i;
886 struct addrinfo* ai = oh->socketTickets[ticket].addrResult;
887 struct addrinfo* current = ai;
888 GC_VOLATILE struct OopArray* retval;
889 count = 0;
890 while (current != NULL) {
891 current = current->ai_next;
892 count++;
894 current = ai;
895 retval = heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO), count);
896 heap_fixed_add(oh, (struct Object*)retval);
897 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)retval;
898 heap_store_into(oh, (struct Object*)oh->cached.interpreter->stack, (struct Object*)retval);
900 for (i = 0; i < count; i++) {
901 GC_VOLATILE struct OopArray* aResult = heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO), 6);
902 struct ByteArray* aResultAddr;
903 struct ByteArray* aResultCanonName;
904 word_t canonNameLen = (current->ai_canonname == NULL)? 0 : strlen(current->ai_canonname);
905 retval->elements[i] = (struct Object*)aResult;
906 heap_store_into(oh, (struct Object*)retval, retval->elements[i]);
907 aResult->elements[0] = smallint_to_object(current->ai_flags);
908 aResult->elements[1] = smallint_to_object(socket_reverse_lookup_domain(current->ai_family));
909 aResult->elements[2] = smallint_to_object(socket_reverse_lookup_type(current->ai_socktype));
910 aResult->elements[3] = smallint_to_object(socket_reverse_lookup_protocol(current->ai_protocol));
912 aResultAddr = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), current->ai_addrlen);
913 aResult->elements[4] = (struct Object*)aResultAddr;
914 heap_store_into(oh, (struct Object*)aResult, aResult->elements[4]);
915 copy_bytes_into((byte_t*)current->ai_addr, current->ai_addrlen, aResultAddr->elements);
916 if (canonNameLen == 0) {
917 aResult->elements[5] = oh->cached.nil;
918 } else {
919 aResultCanonName = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), canonNameLen);
920 aResult->elements[5] = (struct Object*)aResultCanonName;
921 heap_store_into(oh, (struct Object*)aResult, aResult->elements[5]);
922 copy_bytes_into((byte_t*)current->ai_canonname, canonNameLen, aResultCanonName->elements);
925 current = current->ai_next;
928 heap_fixed_remove(oh, (struct Object*)retval);
934 void prim_freeAddrInfoResult(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
935 word_t ticket = object_to_smallint(args[0]);
936 if (ticket >= oh->socketTicketCount || ticket < 0
937 || oh->socketTickets[ticket].inUse == 0 || oh->socketTickets[ticket].finished == 0) {
938 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.false_object;
939 return;
941 free(oh->socketTickets[ticket].hostname);
942 oh->socketTickets[ticket].hostname = 0;
943 free(oh->socketTickets[ticket].service);
944 oh->socketTickets[ticket].service = 0;
945 freeaddrinfo(oh->socketTickets[ticket].addrResult);
946 oh->socketTickets[ticket].addrResult = 0;
948 oh->socketTickets[ticket].inUse = 0;
949 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.true_object;
953 void prim_socketCreateIP(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
954 word_t domain = object_to_smallint(args[0]);
955 struct Object* address = args[1];
956 word_t port = object_to_smallint(args[2]);
957 /* struct OopArray* options = (struct OopArray*) args[3];*/
958 struct sockaddr_in* sin;
959 struct sockaddr_in6* sin6;
960 struct sockaddr_un* sun;
961 GC_VOLATILE struct ByteArray* ret;
963 ASSURE_SMALLINT_ARG(0);
965 switch (domain) {
967 case SLATE_DOMAIN_LOCAL:
968 #ifdef WIN32
969 #else
970 if (byte_array_size((struct ByteArray*)address) > 100) {
971 ret = (struct ByteArray*)oh->cached.nil;
972 break;
974 ret = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), sizeof(struct sockaddr_un));
975 sun = (struct sockaddr_un*)byte_array_elements(ret);
976 sun->sun_family = socket_lookup_domain(domain);
977 ASSURE_TYPE_ARG(1, TYPE_BYTE_ARRAY);
978 strncpy(sun->sun_path, (char*)byte_array_elements((struct ByteArray*)address), 100);
979 sun->sun_path[byte_array_size((struct ByteArray*)address)] = '\0';
980 #endif
981 break;
983 case SLATE_DOMAIN_IPV4:
984 ASSURE_SMALLINT_ARG(2);
985 if (object_array_size(address) < 4) {
986 ret = (struct ByteArray*)oh->cached.nil;
987 break;
989 ret = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), sizeof(struct sockaddr_in));
990 sin = (struct sockaddr_in*)byte_array_elements(ret);
991 sin->sin_family = socket_lookup_domain(domain);
992 sin->sin_port = htons((uint16_t)port);
993 ASSURE_TYPE_ARG(1, TYPE_OOP_ARRAY);
994 sin->sin_addr.s_addr = htonl(((object_to_smallint(object_array_get_element(address, 0)) & 0xFF) << 24)
995 | ((object_to_smallint(object_array_get_element(address, 1)) & 0xFF) << 16)
996 | ((object_to_smallint(object_array_get_element(address, 2)) & 0xFF) << 8)
997 | (object_to_smallint(object_array_get_element(address, 3)) & 0xFF));
998 break;
1000 /*fixme ipv6*/
1001 case SLATE_DOMAIN_IPV6:
1002 ASSURE_SMALLINT_ARG(2);
1003 if (object_array_size(address) < 16) {
1004 ret = (struct ByteArray*)oh->cached.nil;
1005 break;
1007 ret = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), sizeof(struct sockaddr_in6));
1008 sin6 = (struct sockaddr_in6*)byte_array_elements(ret);
1009 sin6->sin6_family = socket_lookup_domain(domain);
1010 sin6->sin6_port = htons((uint16_t)port);
1011 ASSURE_TYPE_ARG(1, TYPE_OOP_ARRAY);
1013 int i;
1014 for (i = 0; i < 16; i++)
1015 sin6->sin6_addr.s6_addr[i] = object_to_smallint(object_array_get_element(address, i)) & 0xFF;
1017 break;
1019 default:
1020 ret = (struct ByteArray*)oh->cached.nil;
1021 break;
1024 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)ret;
1028 void prim_write_to_starting_at(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1029 struct Object *console=args[0], *n=args[1], *handle=args[2], *seq=args[3], *start=args[4];
1030 byte_t* bytes = &((struct ByteArray*)seq)->elements[0] + object_to_smallint(start);
1031 word_t size = object_to_smallint(n);
1034 ASSURE_SMALLINT_ARG(2);
1035 ASSURE_SMALLINT_ARG(4);
1037 assert(arity == 5 && console != NULL);
1039 oh->cached.interpreter->stack->elements[resultStackPointer] =
1040 smallint_to_object(fwrite(bytes, 1, size, (object_to_smallint(handle) == 0)? stdout : stderr));
1044 void prim_close(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1045 word_t handle = object_to_smallint(args[1]);
1046 ASSURE_SMALLINT_ARG(1);
1048 closeFile(oh, handle);
1049 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1053 void prim_readConsole_from_into_starting_at(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1054 word_t /*handle = object_to_smallint(args[2]),*/ n = object_to_smallint(args[1]), start = object_to_smallint(args[4]);
1055 struct ByteArray* bytes = (struct ByteArray*)args[3];
1056 word_t retval;
1058 ASSURE_SMALLINT_ARG(1);
1059 ASSURE_SMALLINT_ARG(4);
1061 retval = fread((char*)(byte_array_elements(bytes) + start), 1, n, stdin);
1062 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(retval);
1066 void prim_read_from_into_starting_at(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1067 word_t handle = object_to_smallint(args[2]), n = object_to_smallint(args[1]), start = object_to_smallint(args[4]);
1068 struct ByteArray* bytes = (struct ByteArray*)args[3];
1069 word_t retval;
1070 ASSURE_SMALLINT_ARG(1);
1071 ASSURE_SMALLINT_ARG(4);
1072 retval = readFile(oh, handle, n, (char*)(byte_array_elements(bytes) + start));
1073 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(retval);
1076 void prim_write_to_from_starting_at(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1077 word_t handle = object_to_smallint(args[2]), n = object_to_smallint(args[1]), start = object_to_smallint(args[4]);
1078 struct ByteArray* bytes = (struct ByteArray*)args[3];
1079 word_t retval;
1080 ASSURE_SMALLINT_ARG(1);
1081 ASSURE_SMALLINT_ARG(4);
1082 retval = writeFile(oh, handle, n, (char*)(byte_array_elements(bytes) + start));
1083 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(retval);
1086 void prim_reposition_to(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1087 word_t handle = object_to_smallint(args[1]), n = object_to_smallint(args[2]);
1088 word_t retval = seekFile(oh, handle, n);
1089 ASSURE_SMALLINT_ARG(1);
1090 ASSURE_SMALLINT_ARG(2);
1091 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(retval);
1094 void prim_positionOf(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1095 word_t handle = object_to_smallint(args[1]);
1096 word_t retval = tellFile(oh, handle);
1097 ASSURE_SMALLINT_ARG(1);
1098 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(retval);
1101 #pragma mark Directory
1103 void prim_getcwd(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1104 struct ByteArray* buf = (struct ByteArray*)args[1];
1105 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(getCurrentDirectory(buf));
1107 void prim_setcwd(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1108 struct ByteArray* buf = (struct ByteArray*)args[1];
1109 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(setCurrentDirectory(buf));
1112 #pragma mark Platform
1114 void prim_bytesPerWord(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1115 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(sizeof(word_t));
1118 int slate_refresh_systeminfo() {
1119 return !(&info && uname(&info));
1122 void prim_system_name(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1123 GC_VOLATILE struct ByteArray *result;
1124 int resultLength;
1125 if (slate_refresh_systeminfo()) {
1126 resultLength = strlen(info.nodename);
1127 result = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), strlen(info.nodename));
1128 copy_bytes_into((byte_t*)info.nodename, resultLength, result->elements);
1129 } else {
1130 result = (struct ByteArray*)oh->cached.nil;
1132 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)result;
1133 heap_store_into(oh, (struct Object*)oh->cached.interpreter->stack, (struct Object*)result);
1136 void prim_system_release(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1137 GC_VOLATILE struct ByteArray *result;
1138 int resultLength;
1139 if (slate_refresh_systeminfo()) {
1140 resultLength = strlen(info.release);
1141 result = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), strlen(info.release));
1142 copy_bytes_into((byte_t*)info.release, resultLength, result->elements);
1143 } else {
1144 result = (struct ByteArray*)oh->cached.nil;
1146 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)result;
1147 heap_store_into(oh, (struct Object*)oh->cached.interpreter->stack, (struct Object*)result);
1150 void prim_system_version(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1151 GC_VOLATILE struct ByteArray *result;
1152 int resultLength;
1153 if (slate_refresh_systeminfo()) {
1154 resultLength = strlen(info.version);
1155 result = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), strlen(info.version));
1156 copy_bytes_into((byte_t*)info.version, resultLength, result->elements);
1157 } else {
1158 result = (struct ByteArray*)oh->cached.nil;
1160 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)result;
1161 heap_store_into(oh, (struct Object*)oh->cached.interpreter->stack, (struct Object*)result);
1164 void prim_system_platform(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1165 GC_VOLATILE struct ByteArray *result;
1166 int resultLength;
1167 if (slate_refresh_systeminfo()) {
1168 resultLength = strlen(info.sysname);
1169 result = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), strlen(info.sysname));
1170 copy_bytes_into((byte_t*)info.sysname, resultLength, result->elements);
1171 } else {
1172 result = (struct ByteArray*)oh->cached.nil;
1174 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)result;
1175 heap_store_into(oh, (struct Object*)oh->cached.interpreter->stack, (struct Object*)result);
1178 void prim_system_machine(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1179 GC_VOLATILE struct ByteArray *result;
1180 int resultLength;
1181 if (slate_refresh_systeminfo()) {
1182 resultLength = strlen(info.machine);
1183 result = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), strlen(info.machine));
1184 copy_bytes_into((byte_t*)info.machine, resultLength, result->elements);
1185 } else {
1186 result = (struct ByteArray*)oh->cached.nil;
1188 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)result;
1189 heap_store_into(oh, (struct Object*)oh->cached.interpreter->stack, (struct Object*)result);
1192 void prim_environment_removekey(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1193 struct Object *keyString = args[1];
1194 size_t keyLength = payload_size(keyString);
1195 char key[SLATE_FILE_NAME_LENGTH];
1196 memcpy(key, (char*)byte_array_elements((struct ByteArray*)keyString), keyLength);
1197 key[keyLength] = '\0';
1198 #ifdef WIN32
1199 SetEnvironmentVariable(key, "");
1200 #else
1201 unsetenv(key);
1202 #endif
1203 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.true_object;
1206 void prim_environment_atput(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1207 struct Object *keyString = args[1];
1208 struct Object *valueString = args[2];
1209 size_t keyLength = payload_size(keyString);
1210 size_t valueLength = payload_size(valueString);
1211 char key[SLATE_FILE_NAME_LENGTH], value[SLATE_FILE_NAME_LENGTH];
1212 int success;
1213 memcpy(key, (char*)byte_array_elements((struct ByteArray*)keyString), keyLength);
1214 key[keyLength] = '\0';
1215 memcpy(value, (char*)byte_array_elements((struct ByteArray*)valueString), valueLength);
1216 value[valueLength] = '\0';
1217 #ifdef WIN32
1218 success = SetEnvironmentVariable(key, value);
1219 #else
1220 success = setenv(key, value, 1);
1221 #endif
1222 oh->cached.interpreter->stack->elements[resultStackPointer] = (success ? oh->cached.false_object : oh->cached.true_object);
1225 void prim_isLittleEndian(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1226 int x = 1;
1227 char little_endian = *(char*)&x;
1228 oh->cached.interpreter->stack->elements[resultStackPointer] = ((little_endian == 1) ? oh->cached.true_object : oh->cached.false_object);
1231 void prim_system_execute(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1232 struct Object *commandString = args[1];
1233 size_t commandLength = payload_size(commandString);
1234 char command[SLATE_FILE_NAME_LENGTH];
1235 memcpy(command, (char*)byte_array_elements((struct ByteArray*)commandString), commandLength);
1236 command[commandLength] = '\0';
1237 oh->cached.interpreter->stack->elements[resultStackPointer] = (system(command) ? oh->cached.false_object : oh->cached.true_object);
1240 #pragma mark Time
1242 #ifdef WIN32 // gettimeofday() ported to WIN32 for prim_timeSinceEpoch()
1244 #if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
1245 #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64
1246 #else
1247 #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
1248 #endif
1250 struct timezone
1252 int tz_minuteswest; /* minutes W of Greenwich */
1253 int tz_dsttime; /* type of dst correction */
1256 int gettimeofday(struct timeval *tv, struct timezone *tz)
1258 FILETIME ft;
1259 unsigned __int64 tmpres = 0;
1260 static int tzflag = 0;
1262 if (NULL != tv)
1264 GetSystemTimeAsFileTime(&ft);
1266 tmpres |= ft.dwHighDateTime;
1267 tmpres <<= 32;
1268 tmpres |= ft.dwLowDateTime;
1270 tmpres /= 10; /*convert into microseconds*/
1271 /*converting file time to unix epoch*/
1272 tmpres -= DELTA_EPOCH_IN_MICROSECS;
1273 tv->tv_sec = (long)(tmpres / 1000000UL);
1274 tv->tv_usec = (long)(tmpres % 1000000UL);
1277 if (NULL != tz)
1279 if (!tzflag)
1281 _tzset();
1282 tzflag++;
1284 tz->tz_minuteswest = _timezone / 60;
1285 tz->tz_dsttime = _daylight;
1288 return 0;
1291 #endif
1293 void prim_timeSinceEpoch(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1294 int64_t time;
1295 int i;
1296 struct timeval tv;
1297 GC_VOLATILE struct ByteArray* timeArray;
1298 const int arraySize = 8;
1300 timeArray = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), arraySize);
1302 gettimeofday(&tv, NULL);
1303 time = (int64_t)tv.tv_sec * 1000000 + (int64_t)tv.tv_usec;
1305 for (i = 0; i < arraySize; i++) {
1306 timeArray->elements[i] = ((time >> (i * 8)) & 0xFF);
1309 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)timeArray;
1310 heap_store_into(oh, (struct Object*)oh->cached.interpreter->stack, (struct Object*)timeArray);
1313 void prim_addressOf(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1314 struct Object *handle=args[1], *offset=args[2];
1315 struct ByteArray* addressBuffer=(struct ByteArray*) args[3];
1316 ASSURE_SMALLINT_ARG(1);
1317 ASSURE_SMALLINT_ARG(2);
1318 if (object_is_smallint(handle) && object_is_smallint(offset) && byte_array_size(addressBuffer) >= sizeof(word_t)) {
1319 oh->cached.interpreter->stack->elements[resultStackPointer] =
1320 smallint_to_object(addressOfMemory(oh,
1321 (int)object_to_smallint(handle),
1322 (int)object_to_smallint(offset),
1323 byte_array_elements(addressBuffer)));
1324 } else {
1325 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1330 #pragma mark ExternalLibrary
1332 void prim_library_open(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1333 struct Object *libname=args[1], *handle = args[2];
1335 if (openExternalLibrary(oh, (struct ByteArray*)libname, (struct ByteArray*)handle)) {
1336 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.true_object;
1337 } else {
1338 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.false_object;
1343 void prim_library_close(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1344 struct Object *handle=args[1];
1346 if (closeExternalLibrary(oh, (struct ByteArray*) handle)) {
1347 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.true_object;
1348 } else {
1349 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.false_object;
1354 void prim_procAddressOf(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1355 struct Object *handle=args[2], *symname=args[1];
1356 struct ByteArray* addressBuffer=(struct ByteArray*) args[3];
1358 if (lookupExternalLibraryPrimitive(oh, (struct ByteArray*) handle, (struct ByteArray *) symname, addressBuffer)) {
1359 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.true_object;
1360 } else {
1361 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.false_object;
1366 void prim_extlibError(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1367 struct ByteArray* messageBuffer=(struct ByteArray*) args[1];
1369 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(readExternalLibraryError(messageBuffer));
1372 void prim_applyExternal(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1374 oh->cached.interpreter->stack->elements[resultStackPointer] =
1375 applyExternalLibraryPrimitive(oh, (struct ByteArray*)args[1],
1376 (struct OopArray*)args[2],
1377 args[3],
1378 args[4],
1379 (struct OopArray*)args[5]);
1383 #pragma mark MemoryArea
1385 void prim_memory_new(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1386 struct Object *size=args[1];
1387 word_t handle;
1389 if (!object_is_smallint(size)) {
1390 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1391 return;
1394 handle = (word_t)openMemory(oh, object_to_smallint(size));
1395 if (handle >= 0) {
1396 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(handle);
1397 } else {
1398 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1403 void prim_memory_close(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1405 struct Object* handle = args[1];
1406 if (object_is_smallint(handle)) {
1407 closeMemory(oh, object_to_smallint(handle));
1409 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1413 void prim_memory_size(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1415 struct Object* handle = args[1];
1416 if (object_is_smallint(handle)) {
1417 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(sizeOfMemory(oh, object_to_smallint(handle)));
1418 } else {
1419 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1424 void prim_memory_addRef(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1426 struct Object* handle = args[1];
1427 if (object_is_smallint(handle)) {
1428 addRefMemory(oh, object_to_smallint(handle));
1431 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1435 void prim_memory_read(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1437 struct ByteArray* buf = (struct ByteArray*)args[0];
1438 word_t amount = object_to_smallint(args[1]), startingAt = object_to_smallint(args[3]),
1439 handle = object_to_smallint(args[2]);
1441 ASSURE_SMALLINT_ARG(1);
1442 ASSURE_SMALLINT_ARG(2);
1443 ASSURE_SMALLINT_ARG(3);
1445 if (!validMemoryHandle(oh, handle)
1446 || byte_array_size(buf) < amount
1447 || startingAt + amount >= oh->memory_sizes [handle]) {
1448 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(-1);
1449 return;
1452 oh->cached.interpreter->stack->elements[resultStackPointer] =
1453 smallint_to_object(writeMemory(oh, handle, startingAt, amount, byte_array_elements(buf)));
1457 void prim_memory_write(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1459 struct ByteArray* buf = (struct ByteArray*)args[0];
1460 word_t amount = object_to_smallint(args[1]), startingAt = object_to_smallint(args[3]),
1461 handle = object_to_smallint(args[2]);
1463 ASSURE_SMALLINT_ARG(1);
1464 ASSURE_SMALLINT_ARG(2);
1465 ASSURE_SMALLINT_ARG(3);
1467 if (!validMemoryHandle(oh, handle)
1468 || byte_array_size(buf) < amount
1469 || startingAt + amount >= oh->memory_sizes [handle]) {
1470 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(-1);
1471 return;
1474 oh->cached.interpreter->stack->elements[resultStackPointer] =
1475 smallint_to_object(readMemory(oh, handle, startingAt, amount, byte_array_elements(buf)));
1479 void prim_memory_resizeTo(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1481 struct Object* handle = args[1], *size = args[2];
1482 if (object_is_smallint(handle) && object_is_smallint(size)) {
1483 oh->cached.interpreter->stack->elements[resultStackPointer] =
1484 smallint_to_object(resizeMemory(oh, object_to_smallint(handle), object_to_smallint(size)));
1486 } else {
1487 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1492 void prim_smallint_at_slot_named(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1493 struct Object* obj;
1494 struct Object* name;
1495 struct SlotEntry * se;
1496 struct Object * proto;
1498 obj = args[0];
1499 name = args[1];
1500 proto = get_special(oh, SPECIAL_OOP_SMALL_INT_PROTO);
1501 se = slot_table_entry_for_name(oh, proto->map->slotTable, (struct Symbol*)name);
1502 if (se == NULL) {
1503 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_SLOT_NOT_FOUND_NAMED), obj, name, NULL, resultStackPointer);
1504 } else {
1505 word_t offset = object_to_smallint(se->offset);
1506 oh->cached.interpreter->stack->elements[resultStackPointer] = object_slot_value_at_offset(proto, offset);
1512 void prim_frame_pointer_of(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1514 struct Interpreter* i = (struct Interpreter*)args[0];
1515 struct Symbol* selector = (struct Symbol*) args[1];
1516 struct CompiledMethod* method;
1517 word_t frame = i->framePointer;
1521 while (frame > FUNCTION_FRAME_SIZE) {
1522 method = (struct CompiledMethod*) i->stack->elements[frame-3];
1523 method = method->method; /*incase it's a closure and not a compiledmethod*/
1524 if (method->selector == selector) {
1525 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(frame);
1526 return;
1528 frame = object_to_smallint(i->stack->elements[frame-1]);
1531 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1535 #pragma mark Clone/Daemonize System
1537 void prim_cloneSystem(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1538 #ifdef WIN32
1539 #pragma message("TODO WIN32 port forking/cloning the system")
1540 return;
1541 #else
1542 pid_t retval;
1543 int pipes[2];
1544 GC_VOLATILE struct OopArray* array;
1546 /* make two pipes that we can use exclusively in each process to talk to the other */
1547 /*FIXME remap fds for safety*/
1548 if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipes) == -1) {
1549 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1550 return;
1553 retval = fork2();
1555 if (retval == (pid_t)-1) {
1556 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1557 return;
1560 array = heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO), 2);
1561 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)array;
1563 if (!retval) { /* child */
1564 array->elements[0] = oh->cached.false_object;
1565 array->elements[1] = smallint_to_object(pipes[0]);
1566 } else { /* parent */
1567 array->elements[0] = oh->cached.true_object;
1568 array->elements[1] = smallint_to_object(pipes[1]);
1571 #endif
1575 void prim_cloneSystemInProcess(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1576 #ifdef WIN32
1577 #pragma message("TODO WIN32 port cloning/threading a system")
1578 #else
1580 #endif
1584 #ifdef SLATE_DAEMONIZE
1586 /* Change this to whatever your daemon is called */
1587 #define DAEMON_NAME "slatedaemon"
1589 /* Change this to the user under which to run */
1590 #define RUN_AS_USER "root"
1592 static void child_handler(int signum) {
1593 switch(signum) {
1594 case SIGALRM: exit(EXIT_FAILURE); break;
1595 case SIGUSR1: exit(EXIT_SUCCESS); break;
1596 case SIGCHLD: exit(EXIT_FAILURE); break;
1600 void prim_daemonizeSystem(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1601 const char* lock_filename = (char*)byte_array_elements((struct ByteArray*) args[1]);
1602 #ifdef WIN32
1603 #pragma message("TODO WIN32 port daemonizing a system")
1604 #else
1605 pid_t pid, sid, parent;
1606 int lfp = -1;
1608 /* already a daemon */
1609 if (getppid() == 1) return;
1611 /* Create the lock file as the current user */
1612 if (lock_filename && lock_filename[0]) {
1613 lfp = open(lock_filename,O_RDWR|O_CREAT,0640);
1614 if (lfp < 0) {
1615 printf("Unable to create lock file %s, code=%d (%s)",
1616 lock_filename, errno, strerror(errno));
1617 exit(EXIT_FAILURE);
1621 /* Drop user if there is one, and we were run as root */
1622 if (getuid() == 0 || geteuid() == 0) {
1623 struct passwd *pw = getpwnam(RUN_AS_USER);
1624 if (pw) {
1625 if (!oh->quiet)
1626 printf("Setting user to " RUN_AS_USER);
1627 setuid(pw->pw_uid);
1631 /* Trap signals that we expect to receive */
1632 signal(SIGCHLD,child_handler);
1633 signal(SIGUSR1,child_handler);
1634 signal(SIGALRM,child_handler);
1636 /* Fork off the parent process */
1637 pid = fork();
1638 if (pid < 0) {
1639 printf("Unable to fork daemon, code=%d (%s)",
1640 errno, strerror(errno));
1641 exit(EXIT_FAILURE);
1643 /* If we got a good PID, then we can exit the parent process. */
1644 if (pid > 0) {
1646 /* Wait for confirmation from the child via SIGTERM or SIGCHLD, or
1647 for two seconds to elapse (SIGALRM). pause() should not return. */
1648 alarm(2);
1649 pause();
1651 exit(EXIT_FAILURE);
1654 /* At this point we are executing as the child process */
1655 parent = getppid();
1657 /* Cancel certain signals */
1658 signal(SIGCHLD,SIG_DFL); /* A child process dies */
1659 signal(SIGTSTP,SIG_IGN); /* Various TTY signals */
1660 signal(SIGTTOU,SIG_IGN);
1661 signal(SIGTTIN,SIG_IGN);
1662 signal(SIGHUP, SIG_IGN); /* Ignore hangup signal */
1663 signal(SIGTERM,SIG_DFL); /* Die on SIGTERM */
1665 /* Change the file mode mask */
1666 umask(0);
1668 /* Create a new SID for the child process */
1669 sid = setsid();
1670 if (sid < 0) {
1671 printf("Unable to create a new session, code %d (%s)",
1672 errno, strerror(errno));
1673 exit(EXIT_FAILURE);
1676 /* Change the current working directory. This prevents the current
1677 directory from being locked; hence not being able to remove it. */
1678 if ((chdir("/")) < 0) {
1679 printf("Unable to change directory to %s, code %d (%s)",
1680 "/", errno, strerror(errno));
1681 exit(EXIT_FAILURE);
1684 /* Redirect standard files to /dev/null */
1685 freopen("/dev/null", "r", stdin);
1686 freopen("/dev/null", "w", stdout);
1687 freopen("/dev/null", "w", stderr);
1689 /* Tell the parent process that we are A-okay */
1690 kill(parent, SIGUSR1);
1691 #endif
1692 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.true_object;
1695 #endif //SLATE_DAEMONIZE
1697 #pragma mark VM invocation arguments
1699 /*TODO: obsolete*/
1700 void prim_run_args_into(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1701 struct ByteArray* arguments = (struct ByteArray*)args[1];
1702 oh->cached.interpreter->stack->elements[resultStackPointer] =
1703 smallint_to_object(write_args_into(oh, (char*)byte_array_elements(arguments), byte_array_size(arguments)));
1708 void prim_vmArgCount(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1709 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(oh->argcSaved);
1712 void prim_vmArg(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1713 word_t i;
1714 int len;
1715 GC_VOLATILE struct ByteArray* array;
1716 ASSURE_SMALLINT_ARG(1);
1717 i = object_to_smallint(args[1]);
1718 len = strlen(oh->argvSaved[i]);
1720 array = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), len);
1721 copy_bytes_into((byte_t*)oh->argvSaved[i], len, array->elements);
1722 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)array;
1723 heap_store_into(oh, (struct Object*)oh->cached.interpreter->stack, (struct Object*)array);
1726 void prim_environmentVariables(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1727 int i, len;
1728 word_t lenstr;
1729 GC_VOLATILE struct OopArray* array;
1731 len = 0;
1732 while (oh->envp[len]) len++;
1734 array = heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO), len);
1735 heap_fixed_add(oh, (struct Object*)array);
1737 for (i = 0; i < len; i++) {
1738 lenstr = strlen(oh->envp[i]);
1739 array->elements[i] = (struct Object*) heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), lenstr);
1740 copy_bytes_into((byte_t*)oh->envp[i], lenstr, ((struct ByteArray*)array->elements[i])->elements);
1744 heap_fixed_remove(oh, (struct Object*)array);
1746 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)array;
1747 heap_store_into(oh, (struct Object*)oh->cached.interpreter->stack, (struct Object*)array);
1750 void prim_heap_gc(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1751 if (!oh->quiet) {
1752 printf("Collecting garbage...\n");
1754 heap_full_gc(oh);
1757 void prim_save_image(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1758 char nameString [SLATE_FILE_NAME_LENGTH];
1759 struct slate_image_header sih;
1760 struct Object* name = args[1];
1761 size_t nameLength = payload_size(name);
1762 FILE * imageFile;
1764 word_t totalSize, forwardPointerEntryCount;
1765 byte_t* memoryStart;
1766 struct Object *writeObject;
1767 struct ForwardPointerEntry* forwardPointers;
1768 /* do a full gc, allocate a new chunk of memory the size of the young and old combined,
1769 * copy all the non-free objects to the new memory while keeping an array of the position changes,
1770 * go through the memory and fix up the pointers, adjust points to start from 0 instead of memoryStart,
1771 * and write the header and the memory out to disk
1774 /*push true so if it resumes from the save image, it will do init code*/
1775 /*fixme*/
1776 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.true_object;
1778 if (nameLength >= sizeof(nameString)) {
1779 /*interpreter_stack_pop(oh, oh->cached.interpreter);*/
1780 /*push nil*/
1781 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1782 return;
1784 memcpy(nameString, (char*)byte_array_elements((struct ByteArray*)name), nameLength);
1785 nameString[nameLength] = '\0';
1787 imageFile = fopen(nameString, "wb");
1788 if (!imageFile) {
1789 /*interpreter_stack_pop(oh, oh->cached.interpreter);*/
1790 /*push nil*/
1791 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1793 return;
1795 printf("Saving image to %s\n", nameString);
1796 heap_full_gc(oh);
1797 totalSize = oh->memoryOldSize + oh->memoryYoungSize;
1798 forwardPointerEntryCount = ((totalSize / 4) + sizeof(struct ForwardPointerEntry) - 1) / sizeof(struct ForwardPointerEntry);
1799 memoryStart = calloc(1, totalSize);
1800 writeObject = (struct Object*)memoryStart;
1801 forwardPointers = calloc(1, forwardPointerEntryCount * sizeof(struct ForwardPointerEntry));
1802 assert(memoryStart != NULL);
1803 copy_used_objects(oh, &writeObject, oh->memoryOld, oh->memoryOldSize, forwardPointers, forwardPointerEntryCount);
1804 copy_used_objects(oh, &writeObject, oh->memoryYoung, oh->memoryYoungSize, forwardPointers, forwardPointerEntryCount);
1805 totalSize = (byte_t*)writeObject - memoryStart;
1806 adjust_object_fields_with_table(oh, memoryStart, totalSize, forwardPointers, forwardPointerEntryCount);
1807 adjust_oop_pointers_from(oh, 0-(word_t)memoryStart, memoryStart, totalSize);
1808 sih.magic = SLATE_IMAGE_MAGIC;
1809 sih.size = totalSize;
1810 sih.next_hash = heap_new_hash(oh);
1811 sih.special_objects_oop = (byte_t*) (forward_pointer_hash_get(forwardPointers, forwardPointerEntryCount, (struct Object*)oh->special_objects_oop)->toObj) - memoryStart;
1812 sih.current_dispatch_id = oh->current_dispatch_id;
1814 if (fwrite(&sih, sizeof(struct slate_image_header), 1, imageFile) != 1
1815 || fwrite(memoryStart, 1, totalSize, imageFile) != totalSize) {
1816 fprintf(stderr, "Error writing image!\n");
1818 fclose(imageFile);
1819 free(forwardPointers);
1820 free(memoryStart);
1822 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.false_object;
1824 interpreter_stack_pop(oh, oh->cached.interpreter);
1825 interpreter_push_false(oh, oh->cached.interpreter);
1829 void prim_exit(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1830 /* print_stack_types(oh, 128);*/
1831 /* print_backtrace(oh);*/
1832 if (!oh->quiet) {
1833 printf("Slate process %d exiting...\n", getpid());
1835 exit(0);
1838 #pragma mark SmallInteger
1840 void prim_equals(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1841 oh->cached.interpreter->stack->elements[resultStackPointer] = (args[0] == args[1])?oh->cached.true_object:oh->cached.false_object;
1844 void prim_less_than(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1846 ASSURE_SMALLINT_ARG(0);
1847 ASSURE_SMALLINT_ARG(1);
1848 oh->cached.interpreter->stack->elements[resultStackPointer] =
1849 (object_to_smallint(args[0])<object_to_smallint(args[1]))?oh->cached.true_object:oh->cached.false_object;
1852 void prim_bitand(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1853 ASSURE_SMALLINT_ARG(0);
1854 ASSURE_SMALLINT_ARG(1);
1855 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)((word_t)args[0] & (word_t)args[1]);
1857 void prim_bitor(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1858 ASSURE_SMALLINT_ARG(0);
1859 ASSURE_SMALLINT_ARG(1);
1860 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)((word_t)args[0] | (word_t)args[1]);
1862 void prim_bitxor(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1863 ASSURE_SMALLINT_ARG(0);
1864 ASSURE_SMALLINT_ARG(1);
1865 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)(((word_t)args[0] ^ (word_t)args[1])|SMALLINT_MASK);
1867 void prim_bitnot(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1868 ASSURE_SMALLINT_ARG(0);
1869 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)(~((word_t)args[0]) | SMALLINT_MASK);
1872 void prim_smallIntegerMinimum(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1873 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)(((word_t)1<< (sizeof(word_t)*8-1))|1); /*top and smallint bit set*/
1876 void prim_smallIntegerMaximum(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1877 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)LONG_MAX; /*has all bits except the top set*/
1880 void prim_plus(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1881 struct Object* x = args[0];
1882 struct Object* y = args[1];
1883 word_t z = object_to_smallint(x) + object_to_smallint(y);
1886 ASSURE_SMALLINT_ARG(0);
1887 ASSURE_SMALLINT_ARG(1);
1890 if (smallint_fits_object(z)) {
1891 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(z);
1892 } else {
1893 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_ADD_OVERFLOW), x, y, NULL, resultStackPointer);
1897 void prim_exponent(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1898 struct ByteArray* x = (struct ByteArray*)args[0];
1899 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object((*(word_t*)float_part(x) >> FLOAT_EXPONENT_OFFSET) & 0xFF);
1903 void prim_significand(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1904 struct ByteArray* x = (struct ByteArray*)args[0];
1905 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(*(word_t*)float_part(x) & FLOAT_SIGNIFICAND);
1909 void prim_withSignificand_exponent(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1910 /*this is really a bytearray*/
1911 word_t significand = object_to_smallint(args[1]), exponent = object_to_smallint(args[2]);
1912 struct ByteArray* f = heap_new_float(oh);
1913 *((word_t*)float_part(f)) = significand | exponent << FLOAT_EXPONENT_OFFSET;
1915 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)f;
1919 /* SmallInteger bitShift: SmallInteger */
1920 void prim_bitshift(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1921 word_t bits = object_to_smallint(args[0]);
1922 word_t shift = object_to_smallint(args[1]);
1923 word_t z;
1925 ASSURE_SMALLINT_ARG(0);
1926 ASSURE_SMALLINT_ARG(1);
1928 if (shift >= 0) {
1929 if (shift >= __WORDSIZE && bits != 0) {
1930 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_BIT_SHIFT_OVERFLOW), args[0], args[1], NULL, resultStackPointer);
1931 return;
1934 z = bits << shift;
1936 if (!smallint_fits_object(z) || z >> shift != bits) {
1937 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_BIT_SHIFT_OVERFLOW), args[0], args[1], NULL, resultStackPointer);
1938 return;
1941 } else if (shift <= -__WORDSIZE) {
1942 z = bits >> (__WORDSIZE-1);
1943 } else {
1944 z = bits >> -shift;
1947 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(z);
1951 /* SmallInteger - SmallInteger */
1952 void prim_minus(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1953 struct Object* x = args[0];
1954 struct Object* y = args[1];
1955 word_t z = object_to_smallint(x) - object_to_smallint(y);
1957 ASSURE_SMALLINT_ARG(0);
1958 ASSURE_SMALLINT_ARG(1);
1960 if (smallint_fits_object(z)) {
1961 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(z);
1962 } else {
1963 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_SUBTRACT_OVERFLOW), x, y, NULL, resultStackPointer);
1967 /* SmallInteger * SmallInteger */
1968 void prim_times(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1969 word_t x = object_to_smallint(args[0]);
1970 word_t y = object_to_smallint(args[1]);
1971 word_t z = x * y;
1974 ASSURE_SMALLINT_ARG(0);
1975 ASSURE_SMALLINT_ARG(1);
1978 if (y != 0 && (z / y != x || !smallint_fits_object(z))) { /*thanks slava*/
1979 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_MULTIPLY_OVERFLOW), args[0], args[1], NULL, resultStackPointer);
1980 } else {
1981 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(z);
1985 /* SmallInteger quo: SmallInteger */
1986 void prim_quo(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
1987 struct Object* x = args[0];
1988 struct Object* y = args[1];
1990 ASSURE_SMALLINT_ARG(0);
1991 ASSURE_SMALLINT_ARG(1);
1993 if (object_to_smallint(y) == 0) {
1994 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_DIVIDE_BY_ZERO), x, y, NULL, resultStackPointer);
1995 } else {
1996 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(object_to_smallint(x) / object_to_smallint(y));
2000 #pragma mark Float
2002 void prim_float_equals(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
2003 struct ByteArray *x = (struct ByteArray*)args[0], *y = (struct ByteArray*)args[1];
2004 if (*float_part(x) == *float_part(y)) {
2005 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.true_object;
2006 } else {
2007 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.false_object;
2011 void prim_float_less_than(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
2012 struct ByteArray *x = (struct ByteArray*)args[0], *y = (struct ByteArray*)args[1];
2013 if (*float_part(x) < *float_part(y)) {
2014 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.true_object;
2015 } else {
2016 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.false_object;
2020 void prim_float_plus(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
2021 struct ByteArray *x = (struct ByteArray*)args[0], *y = (struct ByteArray*)args[1];
2022 struct ByteArray* z = heap_new_float(oh);
2023 *float_part(z) = *float_part(x) + *float_part(y);
2024 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)z;
2027 void prim_float_minus(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
2028 struct ByteArray *x = (struct ByteArray*)args[0], *y = (struct ByteArray*)args[1];
2029 struct ByteArray* z = heap_new_float(oh);
2030 *float_part(z) = *float_part(x) - *float_part(y);
2031 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)z;
2035 void prim_float_times(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
2036 struct ByteArray *x = (struct ByteArray*)args[0], *y = (struct ByteArray*)args[1];
2037 struct ByteArray* z = heap_new_float(oh);
2038 *float_part(z) = *float_part(x) * *float_part(y);
2039 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)z;
2042 void prim_float_divide(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
2043 struct ByteArray *x = (struct ByteArray*)args[0], *y = (struct ByteArray*)args[1];
2044 struct ByteArray* z = heap_new_float(oh);
2045 *float_part(z) = *float_part(x) / *float_part(y);
2046 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)z;
2049 void prim_float_raisedTo(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
2050 struct ByteArray *x = (struct ByteArray*)args[0], *y = (struct ByteArray*)args[1];
2051 struct ByteArray* z = heap_new_float(oh);
2052 *float_part(z) = pow(*float_part(x), *float_part(y));
2053 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)z;
2056 void prim_float_ln(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
2057 struct ByteArray *x = (struct ByteArray*)args[0];
2058 struct ByteArray* z = heap_new_float(oh);
2059 *float_part(z) = log(*float_part(x));
2060 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)z;
2063 void prim_float_exp(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
2064 struct ByteArray *x = (struct ByteArray*)args[0];
2065 struct ByteArray* z = heap_new_float(oh);
2066 *float_part(z) = exp(*float_part(x));
2067 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)z;
2070 void prim_float_sin(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
2071 struct ByteArray *x = (struct ByteArray*)args[0];
2072 struct ByteArray* z = heap_new_float(oh);
2073 *float_part(z) = sin(*float_part(x));
2074 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)z;
2078 void (*primitives[]) (struct object_heap* oh, struct Object* args[], word_t n, struct OopArray* opts, word_t resultStackPointer) = {
2080 /*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,
2081 /*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,
2082 /*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,
2083 /*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,
2084 /*40-9*/ prim_bitxor, prim_bitnot, prim_bitshift, prim_plus, prim_minus, prim_times, prim_quo, prim_fixme, prim_fixme, prim_frame_pointer_of,
2085 /*50-9*/ prim_fixme, prim_fixme, prim_fixme, prim_heap_gc, prim_bytesPerWord, prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme,
2086 /*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,
2087 /*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,
2088 /*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,
2089 /*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,
2090 /*00-9*/ prim_fixme, prim_fixme, prim_fixme, prim_memory_new, prim_memory_close, prim_memory_addRef, prim_memory_write, prim_memory_read, prim_memory_size, prim_memory_resizeTo,
2091 /*10-9*/ prim_addressOf, prim_library_open, prim_library_close, prim_procAddressOf, prim_extlibError, prim_applyExternal, prim_timeSinceEpoch, prim_cloneSystem, prim_readFromPipe, prim_writeToPipe,
2092 /*20-9*/ prim_selectOnReadPipesFor, prim_selectOnWritePipesFor, prim_closePipe, prim_socketCreate, prim_socketListen, prim_socketAccept, prim_socketBind, prim_socketConnect, prim_socketCreateIP, prim_smallIntegerMinimum,
2093 /*30-9*/ prim_smallIntegerMaximum, prim_socketGetError, prim_getAddrInfo, prim_getAddrInfoResult, prim_freeAddrInfoResult, prim_vmArgCount, prim_vmArg, prim_environmentVariables, prim_environment_atput, prim_environment_removekey,
2094 /*40-9*/ prim_isLittleEndian, prim_system_name, prim_system_release, prim_system_version, prim_system_platform, prim_system_machine, prim_system_execute, prim_fixme, prim_fixme, prim_fixme,
2095 /*50-9*/ prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme,