Fixed remaining usage of MAX_OPTS/MAX_ARGS in the VM.
[cslatevm.git] / src / vm / primitives.cpp
blobaf29d98c04f22e842732fb38fd9fe79b41d62c17
1 #include "slate.hpp"
4 //Template for defining Slate primitive signatures. Not a macro because IDEs don't process it:
5 //#define SLATE_PRIM(prim_name) void prim_name(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer)
7 #ifdef SLATE_DAEMONIZE
8 #include <pwd.h>
9 #include <sys/stat.h>
10 #include <signal.h>
11 #endif
13 void prim_fixme(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
14 struct Object* x = args[0];
15 printf("UNIMPLEMENTED PRIMITIVE\n");
16 interpreter_signal_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_TYPE_ERROR_ON), x, NULL, 0, resultStackPointer);
19 #pragma mark Root
21 void prim_isIdenticalTo(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
22 oh->cached.interpreter->stack->elements[resultStackPointer] = (args[0]==args[1])? oh->cached.true_object : oh->cached.false_object;
25 void prim_identity_hash(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
26 /*fix*/
27 /* print_detail(oh, args[0]);
28 print_backtrace(oh);*/
29 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(object_hash(args[0]));
32 void prim_identity_hash_univ(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
33 /*fix*/
34 /* print_detail(oh, args[0]);
35 print_backtrace(oh);*/
36 if (object_is_smallint(args[0])) {
37 oh->cached.interpreter->stack->elements[resultStackPointer] = args[0];
38 } else {
39 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(object_hash(args[0]));
43 /* Root forwardTo: anotherObject */
44 void prim_forward_to(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
45 struct Object* x = args[0];
46 struct Object* y = args[1];
47 oh->cached.interpreter->stack->elements[resultStackPointer] = y;
48 /* since some objects like roleTables store pointers to things like Nil in byte arrays rather than oop arrays,
49 * we must make sure that these special objects do not move.
51 if (x == get_special(oh, SPECIAL_OOP_NIL)
52 || x == get_special(oh, SPECIAL_OOP_TRUE)
53 || x == get_special(oh, SPECIAL_OOP_FALSE)) {
54 printf("Error... you cannot call forwardTo on this special object (did you add a slot to Nil/True/False?)\n");
55 interpreter_signal_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_TYPE_ERROR_ON), x, NULL, 0, resultStackPointer); \
56 return;
59 if (!object_is_smallint(x) && !object_is_smallint(y) && x != y) {
60 heap_unpin_object(oh, x);
61 heap_forward(oh, x, y);
62 /*heap_gc(oh);*/ /* unnecessary waste of time for one object? */
63 //cache_specials(oh);
68 /* Root atSlotNamed: symbol */
69 void prim_at_slot_named(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
70 struct Object* obj;
71 struct Object* name;
72 struct SlotEntry * se;
74 obj = args[0];
75 name = args[1];
77 if (object_is_smallint(obj)) {
78 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_SLOT_NOT_FOUND_NAMED), obj, name, NULL, 0, resultStackPointer);
79 } else {
80 se = slot_table_entry_for_name(oh, obj->map->slotTable, (struct Symbol*)name);
81 if (se == NULL) {
82 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_SLOT_NOT_FOUND_NAMED), obj, name, NULL, 0, resultStackPointer);
83 } else {
84 word_t offset = object_to_smallint(se->offset);
85 oh->cached.interpreter->stack->elements[resultStackPointer] = object_slot_value_at_offset(obj, offset);
90 /* Root atSlotNamed: symbol put: value */
91 void prim_at_slot_named_put(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
92 struct Object* obj=args[0], *val=args[2];
93 struct Object* name = args[1];
94 struct SlotEntry * se;
95 struct Map* map;
97 if (object_is_smallint(obj)) {
98 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_SLOT_NOT_FOUND_NAMED), obj, name, NULL, 0, resultStackPointer);
99 return;
102 if (object_is_immutable(obj)) {
103 interpreter_signal_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_IMMUTABLE), obj, NULL, 0, resultStackPointer);
104 return;
107 map = obj->map;
108 se = slot_table_entry_for_name(oh, map->slotTable, (struct Symbol*)name);
110 if (se == NULL) {
111 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_SLOT_NOT_FOUND_NAMED), obj, name, NULL, 0, resultStackPointer);
112 } else {
113 word_t offset = object_to_smallint(se->offset);
114 oh->cached.interpreter->stack->elements[resultStackPointer] = object_slot_value_at_offset_put(oh, obj, offset, val);
117 /*note: not supporting delegate slots*/
121 void prim_clone(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
122 if (object_is_smallint(args[0])) {
123 oh->cached.interpreter->stack->elements[resultStackPointer] = args[0];
124 } else {
125 oh->cached.interpreter->stack->elements[resultStackPointer] = heap_clone(oh, args[0]);
129 /* Cloneable cloneSettingSlots: slotNamesArray to: valuesArray */
130 void prim_clone_setting_slots(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
131 Pinned<struct Object> obj(oh, args[0]), slotArray(oh, args[1]), valueArray(oh, args[2]), newObj(oh);
132 word_t i;
134 if (object_is_smallint(obj)) {
135 oh->cached.interpreter->stack->elements[resultStackPointer] = obj;
136 return;
138 newObj = heap_clone(oh, obj);
140 /*fix, check that arrays are same size, and signal errors*/
142 for (i = 0; i < object_array_size(slotArray); i++) {
143 struct Symbol* name = (struct Symbol*)object_array_get_element(slotArray, i);
144 struct SlotEntry* se = slot_table_entry_for_name(oh, obj->map->slotTable, name);
145 if (se == NULL) {
146 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_SLOT_NOT_FOUND_NAMED), obj, (struct Object*)name, NULL, 0, resultStackPointer);
147 } else {
148 /*since the object was just cloned, we aren't expecting a tenured obj to point to a new one*/
149 object_slot_value_at_offset_put(oh, newObj, object_to_smallint(se->offset), object_array_get_element(valueArray, i));
153 oh->cached.interpreter->stack->elements[resultStackPointer] = newObj;
156 void prim_clone_with_slot_valued(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
157 Pinned<struct Object> obj(oh, args[0]), value(oh, args[2]);
158 Pinned<struct Symbol> name(oh, (struct Symbol*)args[1]);
160 if (object_is_smallint(obj)) {
161 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_SLOT_NOT_FOUND_NAMED), obj, (struct Object*)name, NULL, 0, resultStackPointer);
162 } else {
163 oh->cached.interpreter->stack->elements[resultStackPointer] = object_add_slot_named(oh, obj, name, value);
167 void prim_clone_without_slot(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
168 Pinned<struct Object> obj(oh, args[0]);
169 Pinned<struct Symbol> name(oh, (struct Symbol*)args[1]);
171 if (object_is_smallint(obj)) {
172 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_SLOT_NOT_FOUND_NAMED), obj, (struct Object*)name, NULL, 0, resultStackPointer);
173 } else {
174 oh->cached.interpreter->stack->elements[resultStackPointer] = object_remove_slot(oh, obj, name);
178 #pragma mark Map
180 void prim_map(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
181 struct Object* obj;
182 obj = args[0];
184 if (object_is_smallint(obj)) {
185 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
186 } else {
187 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)obj->map;
193 void prim_set_map(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
194 Pinned<struct Object> obj(oh);
195 Pinned<struct Map> map(oh);
196 obj = args[0];
197 map = (struct Map*)args[1];
199 if (object_is_smallint(obj) || object_is_immutable(obj)) {
200 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
201 } else {
202 object_change_map(oh, obj, map);
203 heap_store_into(oh, args[0], args[1]);
204 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)map;
209 #pragma mark Method
211 void prim_applyto(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
212 Pinned<struct Closure> method(oh);
213 Pinned<struct OopArray> argArray(oh);
215 method = (struct Closure*)args[0];
216 argArray = (struct OopArray*) args[1];
218 struct Object* optsArray[MAX_OPTS];
219 word_t optsArrayCount = 0, k = 0;
222 if (optCount == 2 && opts[1] != oh->cached.nil) { /* {&optionals:. someOopArray} */
223 optsArrayCount = object_array_size(opts[1]);
224 assert(optsArrayCount <= MAX_OPTS);
225 for (k = 0; k < optsArrayCount; k++) {
226 optsArray[k] = ((struct OopArray*)opts[1])->elements[k];
227 heap_pin_object(oh, optsArray[k]);
231 interpreter_apply_to_arity_with_optionals(oh, oh->cached.interpreter, method,
232 argArray->elements, array_size(argArray), optsArray, optsArrayCount, resultStackPointer);
234 if (optCount == 2 && opts[1] != oh->cached.nil) {
235 HEAP_UNPIN_ARGS(k, optsArray);
240 // this runs the interpreter in the special oop
241 void prim_interrupt(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
243 oh->interrupt_flag = 1;
248 void prim_initializeThreadOn(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
249 Pinned<struct Closure> method(oh);
250 Pinned<struct Interpreter> i(oh);
251 Pinned<struct OopArray> newStack(oh);
252 word_t newStackSize;
254 newStackSize = 16;
255 newStack = heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO), newStackSize);
256 i = (struct Interpreter*)args[0];
257 method = (struct Closure*)args[1];
259 i->stack = newStack;
260 i->stackSize = newStackSize;
261 i->framePointer = 0;
262 i->stackPointer = 0;
263 i->ensureHandlers = smallint_to_object(0);
264 i->codePointer = 0;
266 interpreter_apply_to_arity_with_optionals(oh, i, method, NULL, 0, NULL, 0, 0);
269 void prim_findon(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
270 struct MethodDefinition* def;
271 Pinned<struct Symbol> selector(oh);
272 Pinned<struct OopArray> arguments(oh);
274 selector = (struct Symbol*) args[0];
275 arguments = (struct OopArray*) args[1];
277 def = method_dispatch_on(oh, selector, arguments->elements, array_size(arguments), NULL);
279 oh->cached.interpreter->stack->elements[resultStackPointer] = (def == NULL ? oh->cached.nil : (struct Object*) def->method);
282 void prim_ensure(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
284 Pinned<struct Closure> body(oh);
285 Pinned<struct Object> ensureHandler(oh);
287 body = (struct Closure*) args[0];
288 ensureHandler = args[1];
290 interpreter_apply_to_arity_with_optionals(oh, oh->cached.interpreter, body, NULL, 0, NULL, 0, resultStackPointer);
291 /*the registers are already allocated on the stack so we don't worry about overwriting them*/
292 interpreter_stack_push(oh, oh->cached.interpreter, oh->cached.interpreter->ensureHandlers);
293 interpreter_stack_push(oh, oh->cached.interpreter, ensureHandler);
294 oh->cached.interpreter->ensureHandlers = smallint_to_object(oh->cached.interpreter->stackPointer - 2);
295 #ifdef PRINT_DEBUG_ENSURE
296 printf("ensure handlers at %" PRIdPTR "\n", oh->cached.interpreter->stackPointer - 2);
297 #endif
301 void prim_send_to(struct object_heap* oh, struct Object* args[], word_t n, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
302 Pinned<struct Symbol> selector(oh,(struct Symbol*)args[0]);
303 Pinned<struct OopArray> arguments(oh, (struct OopArray*)args[1]);
305 struct Object* optsArray[MAX_OPTS];
306 word_t optsArrayCount = 0, k = 0;
308 if (optCount == 2 && opts[1] != oh->cached.nil) {/* {&optionals:. someOopArray} */
309 optsArrayCount = object_array_size(opts[1]);
310 assert(optsArrayCount <= MAX_OPTS);
311 for (k = 0; k < optsArrayCount; k++) {
312 optsArray[k] = ((struct OopArray*)opts[1])->elements[k];
313 heap_pin_object(oh, optsArray[k]);
317 send_to_through_arity_with_optionals(oh, selector, array_elements(arguments), array_elements(arguments), array_size(arguments), optsArray, optsArrayCount, resultStackPointer);
319 if (optCount == 2 && opts[1] != oh->cached.nil) {
320 HEAP_UNPIN_ARGS(k, optsArray);
325 void prim_send_to_through(struct object_heap* oh, struct Object* args[], word_t n, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
326 Pinned<struct Symbol> selector(oh, (struct Symbol*)args[0]);
327 Pinned<struct OopArray> arguments(oh, (struct OopArray*)args[1]), dispatchers(oh, (struct OopArray*)args[2]);
329 struct Object* optsArray[MAX_OPTS];
330 word_t optsArrayCount = 0, k = 0;
332 if (optCount == 2 && opts[1] != oh->cached.nil) { /* {&optionals:. someOopArray} */
333 optsArrayCount = object_array_size(opts[1]);
334 assert(optsArrayCount <= MAX_OPTS);
335 for (k = 0; k < optsArrayCount; k++) {
336 optsArray[k] = ((struct OopArray*)opts[1])->elements[k];
337 heap_pin_object(oh, optsArray[k]);
341 send_to_through_arity_with_optionals(oh, selector, array_elements(arguments), array_elements(dispatchers), array_size(arguments), optsArray, optsArrayCount, resultStackPointer);
343 if (optCount == 2 && opts[1] != oh->cached.nil) {
344 HEAP_UNPIN_ARGS(k, optsArray);
348 /* Method asMethod: selector on: rolesArray */
349 void prim_as_method_on(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
350 Pinned<struct MethodDefinition> def(oh);
351 Pinned<struct Object> method(oh);
352 Pinned<struct Object> roles(oh);
353 method = args[0];
354 roles = args[2];
355 Pinned<struct Symbol> selector(oh);
356 selector = (struct Symbol*)args[1];
357 Pinned<struct Object> traitsWindow(oh);
358 traitsWindow = method->map->delegates->elements[0];
359 Pinned<struct Object> closure(oh);
360 std::vector<Pinned<struct Object> > pinnedRoles(object_array_size(roles), Pinned<struct Object>(oh));
361 for (int i = 0; i < object_array_size(roles); i++) {
362 pinnedRoles[i] = ((struct OopArray*)roles)->elements[i];
365 if (traitsWindow == get_special(oh, SPECIAL_OOP_CLOSURE_WINDOW)) {
366 closure = heap_clone(oh, method);
367 ((struct Closure*)closure)->method = (struct CompiledMethod*)heap_clone(oh, (struct Object*)((struct Closure*)closure)->method);
368 heap_store_into(oh, (struct Object*)closure, (struct Object*)((struct Closure*)closure)->method);
369 ((struct Closure*)closure)->method->method = ((struct Closure*)closure)->method;
370 ((struct Closure*)closure)->method->selector = selector;
371 method = (struct Object*)closure;
372 } else {
374 closure = heap_clone(oh, method);
375 ((struct CompiledMethod*)closure)->method = closure;
376 ((struct CompiledMethod*)closure)->selector = selector;
377 method = (struct Object*) closure;
379 def = method_define(oh, method, (struct Symbol*)selector, ((struct OopArray*)roles)->elements, object_array_size(roles));
380 def->slotAccessor = oh->cached.nil;
381 method_flush_cache(oh, selector);
382 #ifdef PRINT_DEBUG_DEFUN
383 if (!oh->quiet) {
384 printf("Defining function '"); print_symbol(selector);
385 printf("' on: ");
386 if (!print_printname(oh, ((struct OopArray*)roles)->elements[0])) printf("NoRole");
388 word_t i;
389 for (i = 1; i < object_array_size(roles); i++) {
390 printf(", ");
391 if (!print_printname(oh, ((struct OopArray*)roles)->elements[i])) printf("NoRole");
394 printf("\n");
396 #endif
398 oh->cached.interpreter->stack->elements[resultStackPointer] = method;
401 /* Method removeFrom: rolesArray */
402 void prim_removefrom(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
404 Pinned<struct Object> method(oh, args[0]), traitsWindow(oh);
405 Pinned<struct OopArray> roles(oh, (struct OopArray*)args[1]);
406 Pinned<struct Symbol> selector(oh);
407 selector = (struct Symbol*)oh->cached.nil;
408 Pinned<struct MethodDefinition> def(oh);
409 word_t i;
411 traitsWindow = method->map->delegates->elements[0];
413 if (traitsWindow == oh->cached.closure_method_window || traitsWindow == oh->cached.compiled_method_window) {
414 selector = ((struct Closure*)method)->method->selector;
415 } else {
416 /*May only remove a CompiledMethod or Closure.*/
417 assert(0);
420 def = method_is_on_arity(oh, method, selector, array_elements(roles), array_size(roles));
421 if ((struct Object*)def == NULL) {
422 oh->cached.interpreter->stack->elements[resultStackPointer] = method;
423 return;
426 for (i = 0; i < array_size(roles); i++) {
427 struct Object* role = array_elements(roles)[i];
428 if (!object_is_smallint(role)) {
429 object_remove_role(oh, role, selector, def);
432 method_flush_cache(oh, selector);
433 oh->cached.interpreter->stack->elements[resultStackPointer] = method;
436 void prim_as_accessor(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
437 Pinned<struct Object> method(oh);
438 method = args[0];
439 Pinned<struct Object> slot(oh);
440 slot = args[2];
441 Pinned<struct OopArray> roles(oh);
442 roles = (struct OopArray*)args[3];
443 Pinned<struct Symbol> selector(oh);
444 selector = (struct Symbol*)args[1];
445 Pinned<struct Object> traitsWindow(oh, method->map->delegates->elements[0]);
446 struct MethodDefinition* def;
447 Pinned<struct Object> closure(oh);
448 std::vector<Pinned<struct Object> > pinnedRoles(object_array_size(roles), Pinned<struct Object>(oh));
449 for (int i = 0; i < object_array_size(roles); i++) {
450 pinnedRoles[i] = roles->elements[i];
453 if (traitsWindow == oh->cached.closure_method_window) {
454 closure = heap_clone(oh, method);
455 ((struct Closure*)closure)->method = (struct CompiledMethod*)heap_clone(oh, (struct Object*)((struct Closure*)closure)->method);
456 heap_store_into(oh, (struct Object*)closure, (struct Object*)((struct Closure*)closure)->method);
457 ((struct Closure*)closure)->method->method = ((struct Closure*)closure)->method;
458 ((struct Closure*)closure)->method->selector = selector;
459 method = (struct Object*)closure;
460 } else if (traitsWindow == oh->cached.compiled_method_window){
461 closure = heap_clone(oh, method);
462 ((struct CompiledMethod*)closure)->method = closure;
463 ((struct CompiledMethod*)closure)->selector = selector;
464 method = (struct Object*) closure;
467 def = method_define(oh, method, selector, roles->elements, array_size(roles));
468 def->slotAccessor = slot;
469 method_flush_cache(oh, selector);
470 oh->cached.interpreter->stack->elements[resultStackPointer] = method;
472 #ifdef PRINT_DEBUG_DEFUN
473 if (!oh->quiet) {
474 printf("Defining accessor '"); print_symbol(selector);
475 printf("' on: ");
476 if (!print_printname(oh, ((struct OopArray*)roles)->elements[0])) printf("NoRole");
478 word_t i;
479 for (i = 1; i < array_size(roles); i++) {
480 printf(", ");
481 if (!print_printname(oh, ((struct OopArray*)roles)->elements[i])) printf("NoRole");
484 printf("\n");
486 #endif
489 #pragma mark Array
491 void prim_at(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
492 struct Object* array;
493 word_t i;
495 array = args[0];
496 i = object_to_smallint(args[1]);
497 ASSURE_SMALLINT_ARG(1);
498 if (i < object_array_size(array) && i >= 0) {
499 oh->cached.interpreter->stack->elements[resultStackPointer] = ((struct OopArray*)array)->elements[i];
500 } else {
501 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_KEY_NOT_FOUND_ON), args[1], args[0], NULL, 0, resultStackPointer);
505 void prim_at_put(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
506 struct Object *array = args[0], *i = args[1], *val = args[2];
507 word_t index = object_to_smallint(i);
509 ASSURE_SMALLINT_ARG(1);
510 if (object_is_immutable(array)) {
511 interpreter_signal_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_IMMUTABLE), array, NULL, 0, resultStackPointer);
512 return;
515 if (index < object_array_size(array)) {
516 heap_store_into(oh, array, val);
517 oh->cached.interpreter->stack->elements[resultStackPointer] = ((struct OopArray*)array)->elements[index] = val;
518 } else {
519 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_KEY_NOT_FOUND_ON), i, array, NULL, 0, resultStackPointer);
523 void prim_ooparray_newsize(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
524 /*struct Object* array = args[0];*/
525 struct Object* i = args[1];
526 if (object_is_smallint(i)) {
527 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)
528 heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO),
529 object_to_smallint(i));
530 } else {
531 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
535 void prim_size(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
536 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(object_array_size(args[0]));
539 #pragma mark ByteArray
541 void prim_bytearray_newsize(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
542 struct Object* obj, *i;
543 obj = args[0];
544 i = args[1];
546 if (!object_is_smallint(i)) {
547 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
548 return;
551 oh->cached.interpreter->stack->elements[resultStackPointer] =
552 (struct Object*)heap_clone_byte_array_sized(oh, obj, (object_to_smallint(i) < 0) ? 0 : object_to_smallint(i));
555 void prim_bytesize(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
556 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(payload_size(args[0]));
559 void prim_byteat_put(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
560 struct Object* obj= args[0], *i=args[1], *val = args[2];
561 word_t index;
563 index = object_to_smallint(i);
565 ASSURE_SMALLINT_ARG(1);
566 ASSURE_SMALLINT_ARG(2);
568 if (object_is_immutable(obj)) {
569 interpreter_signal_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_IMMUTABLE), obj, NULL, 0, resultStackPointer);
570 return;
573 if (index < byte_array_size((struct ByteArray*)obj)) {
574 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(byte_array_set_element((struct ByteArray*)obj, index, object_to_smallint(val)));
575 } else {
576 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_KEY_NOT_FOUND_ON), i, obj, NULL, 0, resultStackPointer);
581 void prim_byteat(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
582 struct Object* obj, *i;
583 word_t index;
585 obj = args[0];
586 i = args[1];
587 index = object_to_smallint(i);
589 ASSURE_SMALLINT_ARG(1);
591 if (index < byte_array_size((struct ByteArray*)obj)) {
592 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(byte_array_get_element(obj, index));
593 } else {
594 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_KEY_NOT_FOUND_ON), i, obj, NULL, 0, resultStackPointer);
599 #pragma mark File
601 void prim_atEndOf(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
602 word_t handle = object_to_smallint(args[1]);
603 ASSURE_SMALLINT_ARG(1);
604 if (file_isatend(oh, handle)) {
605 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.true_object;
606 } else {
607 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.false_object;
611 void prim_sizeOf(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
612 word_t handle = object_to_smallint(args[1]);
613 word_t retval = file_sizeof(oh, handle);
614 ASSURE_SMALLINT_ARG(1);
615 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(retval);
618 void prim_flush_output(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
619 /*struct Object *console=args[0];*/
620 fflush(stdout);
621 fflush(stderr);
622 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
625 void prim_handle_for(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
626 word_t handle;
627 struct Object /**file=args[0],*/ *fname=args[1];
629 handle = file_open(oh, (struct ByteArray*)fname, SF_READ|SF_WRITE);
630 if (handle >= 0) {
631 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(handle);
632 } else {
633 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
638 void prim_handleForNew(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
639 word_t handle;
640 struct Object /**file=args[0],*/ *fname=args[1];
642 handle = file_open(oh, (struct ByteArray*)fname, SF_READ|SF_WRITE|SF_CLEAR|SF_CREATE);
643 if (handle >= 0) {
644 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(handle);
645 } else {
646 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
651 void prim_handle_for_input(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
652 word_t handle;
653 struct Object /**file=args[0],*/ *fname=args[1];
655 handle = file_open(oh, (struct ByteArray*)fname, SF_READ);
656 if (handle >= 0) {
657 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(handle);
658 } else {
659 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
664 void prim_closePipe(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
665 word_t handle = object_to_smallint(args[0]);
666 int retval;
668 ASSURE_SMALLINT_ARG(0);
669 #ifdef WIN32
670 retval = closesocket(handle);
671 #else
672 retval = close(handle);
673 #endif
674 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(retval);
678 void prim_readFromPipe(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
679 struct ByteArray* array = (struct ByteArray*) args[0];
680 word_t handle = object_to_smallint(args[1]);
681 word_t start = object_to_smallint(args[2]), end = object_to_smallint(args[3]);
682 ssize_t retval;
684 ASSURE_TYPE_ARG(0, TYPE_BYTE_ARRAY);
685 ASSURE_SMALLINT_ARG(1);
686 ASSURE_SMALLINT_ARG(2);
687 ASSURE_SMALLINT_ARG(3);
689 if (start < 0 || start >= byte_array_size(array)) {
690 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_KEY_NOT_FOUND_ON), args[2], args[0], NULL, 0, resultStackPointer);
691 return;
694 if (end < start || end > byte_array_size(array)) {
695 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_KEY_NOT_FOUND_ON), args[3], args[0], NULL, 0, resultStackPointer);
696 return;
699 retval = recv(handle, byte_array_elements(array)+start, end - start, 0);
702 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(retval);
707 void prim_writeToPipe(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
708 struct ByteArray* array = (struct ByteArray*) args[0];
709 word_t handle = object_to_smallint(args[1]);
710 word_t start = object_to_smallint(args[2]), end = object_to_smallint(args[3]);
711 ssize_t retval;
713 ASSURE_TYPE_ARG(0, TYPE_BYTE_ARRAY);
714 ASSURE_SMALLINT_ARG(1);
715 ASSURE_SMALLINT_ARG(2);
716 ASSURE_SMALLINT_ARG(3);
718 if (start < 0 || start >= byte_array_size(array)) {
719 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_KEY_NOT_FOUND_ON), args[2], args[0], NULL, 0, resultStackPointer);
720 return;
723 if (end < start || end > byte_array_size(array)) {
724 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_KEY_NOT_FOUND_ON), args[3], args[0], NULL, 0, resultStackPointer);
725 return;
728 retval = send(handle, byte_array_elements(array)+start, end - start, 0);
730 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(retval);
734 /*FIXME this is a copy of the last function with only the select call changed*/
735 void prim_selectOnWritePipesFor(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
737 Pinned<struct OopArray> selectOn(oh);
738 selectOn = (struct OopArray*) args[0];
739 Pinned<struct OopArray> readyPipes(oh);
740 word_t waitTime = object_to_smallint(args[1]);
741 int retval, fdCount, maxFD;
742 struct timeval tv;
743 fd_set fdList;
744 maxFD = 0;
746 ASSURE_SMALLINT_ARG(1);
748 if ((fdCount = socket_select_setup(selectOn, &fdList, &maxFD)) < 0) {
749 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
750 return;
754 tv.tv_sec = waitTime / 1000000;
755 tv.tv_usec = waitTime % 1000000;
756 retval = select(maxFD+1, NULL, &fdList, NULL, &tv);
758 if (retval < 0) {
759 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
760 return;
764 readyPipes = heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO), retval);
765 socket_select_find_available(selectOn, &fdList, readyPipes, retval);
767 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)readyPipes;
771 #pragma mark Socket
773 void prim_socketCreate(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
774 word_t domain = object_to_smallint(args[0]);
775 word_t type = object_to_smallint(args[1]);
776 word_t protocol = object_to_smallint(args[2]);
777 word_t ret = socket(socket_lookup_domain(domain), socket_lookup_type(type), socket_lookup_protocol(protocol));
778 int ret2 = 0;
780 ASSURE_SMALLINT_ARG(0);
781 ASSURE_SMALLINT_ARG(1);
782 ASSURE_SMALLINT_ARG(2);
784 if (ret >= 0) {
785 ret2 = socket_set_nonblocking(ret);
786 } else {
787 perror("socket create");
790 if (ret2 < 0) {
791 perror("set nonblocking");
792 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(-1);
793 } else {
794 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(ret);
798 void prim_socketListen(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
799 word_t fd = object_to_smallint(args[0]);
800 word_t size = object_to_smallint(args[1]);
801 word_t ret;
803 ASSURE_SMALLINT_ARG(0);
804 ASSURE_SMALLINT_ARG(1);
806 ret = listen(fd, size);
808 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(ret);
812 void prim_socketAccept(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
813 word_t fd = object_to_smallint(args[0]);
814 word_t ret;
815 struct sockaddr_storage addr;
816 socklen_t len;
817 Pinned<struct ByteArray> addrArray(oh);
818 Pinned<struct OopArray> result(oh);
820 ASSURE_SMALLINT_ARG(0);
822 len = sizeof(addr);
823 ret = accept(fd, (struct sockaddr*)&addr, &len);
825 if (ret >= 0) {
826 addrArray = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), sizeof(struct sockaddr_in));
827 } else {
828 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(ret);
829 return;
832 result = heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO), 2);
834 object_array_set_element(oh, (struct Object*)result, 0, smallint_to_object(ret));
835 object_array_set_element(oh, (struct Object*)result, 1, (struct Object*)addrArray);
837 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)result;
841 void prim_socketBind(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
842 word_t fd = object_to_smallint(args[0]);
843 struct ByteArray* address = (struct ByteArray*) args[1];
844 word_t ret;
846 ASSURE_SMALLINT_ARG(0);
848 ret = bind(fd, (const struct sockaddr*)byte_array_elements(address), (socklen_t)byte_array_size(address));
849 if (ret < 0) perror("bind");
850 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(ret);
853 void prim_socketConnect(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
854 word_t fd = object_to_smallint(args[0]);
855 struct ByteArray* address = (struct ByteArray*) args[1];
856 word_t ret;
858 ASSURE_SMALLINT_ARG(0);
860 ret = connect(fd, (const struct sockaddr*)byte_array_elements(address), (socklen_t)byte_array_size(address));
862 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(ret);
866 void prim_socketGetError(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
867 word_t fd = object_to_smallint(args[0]);
868 word_t ret;
869 int optval;
870 socklen_t optlen;
871 optlen = 4;
872 ASSURE_SMALLINT_ARG(0);
874 ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &optval, (socklen_t*)&optlen);
876 if (ret == 0) {
877 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(optval);
878 } else {
879 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(ret);
884 void prim_getAddrInfo(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
885 struct ByteArray* hostname = (struct ByteArray*)args[1];
886 struct ByteArray* service = (struct ByteArray*)args[2];
887 word_t family = object_to_smallint(args[3]);
888 word_t type = object_to_smallint(args[4]);
889 word_t protocol = object_to_smallint(args[5]);
890 word_t flags = object_to_smallint(args[6]);
891 word_t ret, serviceSize, hostnameSize;
893 ASSURE_TYPE_ARG(1, TYPE_BYTE_ARRAY);
894 ASSURE_SMALLINT_ARG(3);
895 ASSURE_SMALLINT_ARG(4);
896 ASSURE_SMALLINT_ARG(5);
897 ASSURE_SMALLINT_ARG(6);
899 if ((struct Object*)hostname == oh->cached.nil) {
900 hostnameSize = 0;
901 } else {
902 hostnameSize = byte_array_size(hostname)+1;
905 if ((struct Object*)service == oh->cached.nil) {
906 serviceSize = 0;
907 } else {
908 ASSURE_TYPE_ARG(2, TYPE_BYTE_ARRAY);
909 serviceSize = byte_array_size(service)+1;
912 ret = socket_getaddrinfo(oh, hostname, hostnameSize, service, serviceSize, family, type, protocol, flags);
914 oh->cached.interpreter->stack->elements[resultStackPointer] = SOCKET_RETURN(ret);
918 void prim_getAddrInfoResult(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
919 word_t ticket = object_to_smallint(args[0]);
920 if (ticket >= oh->socketTicketCount || ticket < 0
921 || oh->socketTickets[ticket].inUse == 0 || oh->socketTickets[ticket].finished == 0) {
922 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
923 return;
925 if (oh->socketTickets[ticket].result < 0) {
926 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(socket_return(oh->socketTickets[ticket].result));
927 } else {
928 word_t count, i;
929 struct addrinfo* ai = oh->socketTickets[ticket].addrResult;
930 struct addrinfo* current = ai;
931 Pinned<struct OopArray> retval(oh);
932 Pinned<struct OopArray> aResult(oh);
933 count = 0;
934 while (current != NULL) {
935 current = current->ai_next;
936 count++;
938 current = ai;
939 retval = heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO), count);
940 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)retval;
941 heap_store_into(oh, (struct Object*)oh->cached.interpreter->stack, (struct Object*)retval);
943 for (i = 0; i < count; i++) {
944 aResult = heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO), 6);
945 struct ByteArray* aResultAddr;
946 struct ByteArray* aResultCanonName;
947 word_t canonNameLen = (current->ai_canonname == NULL)? 0 : strlen(current->ai_canonname);
948 retval->elements[i] = (struct Object*)aResult;
949 heap_store_into(oh, (struct Object*)retval, retval->elements[i]);
950 aResult->elements[0] = smallint_to_object(current->ai_flags);
951 aResult->elements[1] = smallint_to_object(socket_reverse_lookup_domain(current->ai_family));
952 aResult->elements[2] = smallint_to_object(socket_reverse_lookup_type(current->ai_socktype));
953 aResult->elements[3] = smallint_to_object(socket_reverse_lookup_protocol(current->ai_protocol));
955 aResultAddr = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), current->ai_addrlen);
956 aResult->elements[4] = (struct Object*)aResultAddr;
957 heap_store_into(oh, (struct Object*)aResult, aResult->elements[4]);
958 copy_bytes_into((byte_t*)current->ai_addr, current->ai_addrlen, aResultAddr->elements);
959 if (canonNameLen == 0) {
960 aResult->elements[5] = oh->cached.nil;
961 } else {
962 aResultCanonName = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), canonNameLen);
963 aResult->elements[5] = (struct Object*)aResultCanonName;
964 heap_store_into(oh, (struct Object*)aResult, aResult->elements[5]);
965 copy_bytes_into((byte_t*)current->ai_canonname, canonNameLen, aResultCanonName->elements);
968 current = current->ai_next;
974 void prim_freeAddrInfoResult(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
975 word_t ticket = object_to_smallint(args[0]);
976 if (ticket >= oh->socketTicketCount || ticket < 0
977 || oh->socketTickets[ticket].inUse == 0 || oh->socketTickets[ticket].finished == 0) {
978 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.false_object;
979 return;
981 free(oh->socketTickets[ticket].hostname);
982 oh->socketTickets[ticket].hostname = 0;
983 free(oh->socketTickets[ticket].service);
984 oh->socketTickets[ticket].service = 0;
985 freeaddrinfo(oh->socketTickets[ticket].addrResult);
986 oh->socketTickets[ticket].addrResult = 0;
988 oh->socketTickets[ticket].inUse = 0;
989 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.true_object;
993 void prim_socketCreateIP(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
994 word_t domain = object_to_smallint(args[0]);
995 struct Object* address = args[1];
996 word_t port = object_to_smallint(args[2]);
997 /* struct OopArray* options = (struct OopArray*) args[3];*/
998 struct sockaddr_in* sin;
999 struct sockaddr_in6* sin6;
1000 struct sockaddr_un* sun;
1001 Pinned<struct ByteArray> ret(oh);
1003 ASSURE_SMALLINT_ARG(0);
1005 switch (domain) {
1007 case SLATE_DOMAIN_LOCAL:
1008 #ifdef WIN32
1009 #else
1010 if (byte_array_size((struct ByteArray*)address) > 100) {
1011 ret = (struct ByteArray*)oh->cached.nil;
1012 break;
1014 ret = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), sizeof(struct sockaddr_un));
1015 sun = (struct sockaddr_un*)byte_array_elements(ret);
1016 sun->sun_family = socket_lookup_domain(domain);
1017 ASSURE_TYPE_ARG(1, TYPE_BYTE_ARRAY);
1018 strncpy(sun->sun_path, (char*)byte_array_elements((struct ByteArray*)address), 100);
1019 sun->sun_path[byte_array_size((struct ByteArray*)address)] = '\0';
1020 #endif
1021 break;
1023 case SLATE_DOMAIN_IPV4:
1024 ASSURE_SMALLINT_ARG(2);
1025 if (object_array_size(address) < 4) {
1026 ret = (struct ByteArray*)oh->cached.nil;
1027 break;
1029 ret = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), sizeof(struct sockaddr_in));
1030 sin = (struct sockaddr_in*)byte_array_elements(ret);
1031 sin->sin_family = socket_lookup_domain(domain);
1032 sin->sin_port = htons((uint16_t)port);
1033 ASSURE_TYPE_ARG(1, TYPE_OOP_ARRAY);
1034 sin->sin_addr.s_addr = htonl(((object_to_smallint(object_array_get_element(address, 0)) & 0xFF) << 24)
1035 | ((object_to_smallint(object_array_get_element(address, 1)) & 0xFF) << 16)
1036 | ((object_to_smallint(object_array_get_element(address, 2)) & 0xFF) << 8)
1037 | (object_to_smallint(object_array_get_element(address, 3)) & 0xFF));
1038 break;
1040 /*fixme ipv6*/
1041 case SLATE_DOMAIN_IPV6:
1042 ASSURE_SMALLINT_ARG(2);
1043 if (object_array_size(address) < 16) {
1044 ret = (struct ByteArray*)oh->cached.nil;
1045 break;
1047 ret = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), sizeof(struct sockaddr_in6));
1048 sin6 = (struct sockaddr_in6*)byte_array_elements(ret);
1049 sin6->sin6_family = socket_lookup_domain(domain);
1050 sin6->sin6_port = htons((uint16_t)port);
1051 ASSURE_TYPE_ARG(1, TYPE_OOP_ARRAY);
1053 int i;
1054 for (i = 0; i < 16; i++)
1055 sin6->sin6_addr.s6_addr[i] = object_to_smallint(object_array_get_element(address, i)) & 0xFF;
1057 break;
1059 default:
1060 ret = (struct ByteArray*)oh->cached.nil;
1061 break;
1064 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)ret;
1068 void prim_write_to_starting_at(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1069 struct Object *console=args[0], *n=args[1], *handle=args[2], *seq=args[3], *start=args[4];
1070 byte_t* bytes = &((struct ByteArray*)seq)->elements[0] + object_to_smallint(start);
1071 word_t size = object_to_smallint(n);
1074 ASSURE_SMALLINT_ARG(2);
1075 ASSURE_SMALLINT_ARG(4);
1077 assert(arity == 5 && console != NULL);
1079 oh->cached.interpreter->stack->elements[resultStackPointer] =
1080 smallint_to_object(fwrite(bytes, 1, size, (object_to_smallint(handle) == 0)? stdout : stderr));
1084 void prim_close(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1085 word_t handle = object_to_smallint(args[1]);
1086 ASSURE_SMALLINT_ARG(1);
1088 file_close(oh, handle);
1089 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1093 void prim_file_delete(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1094 char filename[SLATE_FILE_NAME_LENGTH];
1095 word_t len;
1096 len = extractCString((struct ByteArray*)args[1], (byte_t*)filename, sizeof(filename));
1097 oh->cached.interpreter->stack->elements[resultStackPointer] = ((file_delete(oh, filename)) ? oh->cached.true_object : oh->cached.false_object);
1100 void prim_file_touch(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1101 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.false_object;
1104 void prim_file_rename_to(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1105 char src[SLATE_FILE_NAME_LENGTH], dest[SLATE_FILE_NAME_LENGTH];
1106 word_t srcLen, destLen;
1107 srcLen = extractCString((struct ByteArray*)args[1], (byte_t*)src, sizeof(src));
1108 destLen = extractCString((struct ByteArray*)args[2], (byte_t*)dest, sizeof(dest));
1109 oh->cached.interpreter->stack->elements[resultStackPointer] = ((file_rename_to(oh, src, dest)) ? oh->cached.true_object : oh->cached.false_object);
1112 void prim_file_information(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1113 char filename[SLATE_FILE_NAME_LENGTH];
1114 word_t len;
1115 len = extractCString((struct ByteArray*)args[1], (byte_t*)filename, sizeof(filename));
1116 oh->cached.interpreter->stack->elements[resultStackPointer] = file_information(oh, filename);
1117 heap_store_into(oh, (struct Object*)oh->cached.interpreter->stack, oh->cached.interpreter->stack->elements[resultStackPointer]);
1120 void prim_dir_make(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1121 char filename[SLATE_FILE_NAME_LENGTH];
1122 word_t len;
1123 len = extractCString((struct ByteArray*)args[1], (byte_t*)filename, sizeof(filename));
1124 oh->cached.interpreter->stack->elements[resultStackPointer] = ((dir_make(oh, filename)) ? oh->cached.true_object : oh->cached.false_object);
1127 void prim_dir_rename_to(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1128 char src[SLATE_FILE_NAME_LENGTH], dest[SLATE_FILE_NAME_LENGTH];
1129 word_t srcLen, destLen;
1130 srcLen = extractCString((struct ByteArray*)args[1], (byte_t*)src, sizeof(src));
1131 destLen = extractCString((struct ByteArray*)args[2], (byte_t*)dest, sizeof(dest));
1132 oh->cached.interpreter->stack->elements[resultStackPointer] = ((dir_rename_to(oh, src, dest)) ? oh->cached.true_object : oh->cached.false_object);
1135 void prim_dir_delete(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1136 char filename[SLATE_FILE_NAME_LENGTH];
1137 word_t len;
1138 len = extractCString((struct ByteArray*)args[1], (byte_t*)filename, sizeof(filename));
1139 oh->cached.interpreter->stack->elements[resultStackPointer] = ((dir_delete(oh, filename)) ? oh->cached.true_object : oh->cached.false_object);
1143 void prim_readConsole_from_into_starting_at(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1144 word_t /*handle = object_to_smallint(args[2]),*/ n = object_to_smallint(args[1]), start = object_to_smallint(args[4]);
1145 struct ByteArray* bytes = (struct ByteArray*)args[3];
1146 word_t retval;
1148 ASSURE_SMALLINT_ARG(1);
1149 ASSURE_SMALLINT_ARG(4);
1151 retval = fread((char*)(byte_array_elements(bytes) + start), 1, n, stdin);
1152 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(retval);
1156 void prim_read_from_into_starting_at(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1157 word_t handle = object_to_smallint(args[2]), n = object_to_smallint(args[1]), start = object_to_smallint(args[4]);
1158 struct ByteArray* bytes = (struct ByteArray*)args[3];
1159 word_t retval;
1160 ASSURE_SMALLINT_ARG(1);
1161 ASSURE_SMALLINT_ARG(4);
1162 retval = file_read(oh, handle, n, (char*)(byte_array_elements(bytes) + start));
1163 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(retval);
1166 void prim_write_to_from_starting_at(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1167 word_t handle = object_to_smallint(args[2]), n = object_to_smallint(args[1]), start = object_to_smallint(args[4]);
1168 struct ByteArray* bytes = (struct ByteArray*)args[3];
1169 word_t retval;
1170 ASSURE_SMALLINT_ARG(1);
1171 ASSURE_SMALLINT_ARG(4);
1172 retval = file_write(oh, handle, n, (char*)(byte_array_elements(bytes) + start));
1173 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(retval);
1176 void prim_reposition_to(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1177 word_t handle = object_to_smallint(args[1]), n = object_to_smallint(args[2]);
1178 word_t retval = file_seek(oh, handle, n);
1179 ASSURE_SMALLINT_ARG(1);
1180 ASSURE_SMALLINT_ARG(2);
1181 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(retval);
1184 void prim_positionOf(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1185 word_t handle = object_to_smallint(args[1]);
1186 word_t retval = file_tell(oh, handle);
1187 ASSURE_SMALLINT_ARG(1);
1188 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(retval);
1191 #pragma mark Directory
1193 void prim_dir_open(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1194 struct ByteArray* buf = (struct ByteArray*)args[1];
1195 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(dir_open(oh, buf));
1198 void prim_dir_close(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1199 word_t handle = object_to_smallint(args[1]);
1200 ASSURE_SMALLINT_ARG(1);
1202 dir_close(oh, handle);
1203 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1206 void prim_dir_read(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1207 word_t handle = object_to_smallint(args[1]);
1208 struct ByteArray* buf = (struct ByteArray*)args[2];
1209 word_t retval;
1211 ASSURE_SMALLINT_ARG(1);
1213 retval = dir_read(oh, handle, buf);
1215 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(retval);
1218 void prim_dir_getcwd(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1219 struct ByteArray* buf = (struct ByteArray*)args[1];
1220 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(dir_getcwd(buf));
1223 void prim_dir_setcwd(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1224 struct ByteArray* buf = (struct ByteArray*)args[1];
1225 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(dir_setcwd(buf));
1228 #pragma mark Platform
1230 void prim_bytesPerWord(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1231 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(sizeof(word_t));
1234 int slate_refresh_systeminfo(struct object_heap* oh) {
1235 return !(uname(&oh->platform_info));
1238 void prim_system_name(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1239 struct ByteArray* result;
1240 int resultLength;
1241 if (slate_refresh_systeminfo(oh)) {
1242 resultLength = strlen(oh->platform_info.nodename);
1243 result = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), strlen(oh->platform_info.nodename));
1244 copy_bytes_into((byte_t*)oh->platform_info.nodename, resultLength, result->elements);
1245 } else {
1246 result = (struct ByteArray*)oh->cached.nil;
1248 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)result;
1249 heap_store_into(oh, (struct Object*)oh->cached.interpreter->stack, (struct Object*)result);
1252 void prim_system_release(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1253 struct ByteArray *result;
1254 int resultLength;
1255 if (slate_refresh_systeminfo(oh)) {
1256 resultLength = strlen(oh->platform_info.release);
1257 result = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), strlen(oh->platform_info.release));
1258 copy_bytes_into((byte_t*)oh->platform_info.release, resultLength, result->elements);
1259 } else {
1260 result = (struct ByteArray*)oh->cached.nil;
1262 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)result;
1263 heap_store_into(oh, (struct Object*)oh->cached.interpreter->stack, (struct Object*)result);
1266 void prim_system_version(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1267 struct ByteArray *result;
1268 int resultLength;
1269 if (slate_refresh_systeminfo(oh)) {
1270 resultLength = strlen(oh->platform_info.version);
1271 result = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), strlen(oh->platform_info.version));
1272 copy_bytes_into((byte_t*)oh->platform_info.version, resultLength, result->elements);
1273 } else {
1274 result = (struct ByteArray*)oh->cached.nil;
1276 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)result;
1277 heap_store_into(oh, (struct Object*)oh->cached.interpreter->stack, (struct Object*)result);
1280 void prim_system_platform(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1281 struct ByteArray *result;
1282 int resultLength;
1283 if (slate_refresh_systeminfo(oh)) {
1284 resultLength = strlen(oh->platform_info.sysname);
1285 result = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), strlen(oh->platform_info.sysname));
1286 copy_bytes_into((byte_t*)oh->platform_info.sysname, resultLength, result->elements);
1287 } else {
1288 result = (struct ByteArray*)oh->cached.nil;
1290 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)result;
1291 heap_store_into(oh, (struct Object*)oh->cached.interpreter->stack, (struct Object*)result);
1294 void prim_system_machine(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1295 struct ByteArray *result;
1296 int resultLength;
1297 if (slate_refresh_systeminfo(oh)) {
1298 resultLength = strlen(oh->platform_info.machine);
1299 result = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), strlen(oh->platform_info.machine));
1300 copy_bytes_into((byte_t*)oh->platform_info.machine, resultLength, result->elements);
1301 } else {
1302 result = (struct ByteArray*)oh->cached.nil;
1304 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)result;
1305 heap_store_into(oh, (struct Object*)oh->cached.interpreter->stack, (struct Object*)result);
1308 void prim_environment_removekey(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1309 struct Object *keyString = args[1];
1310 size_t keyLength = payload_size(keyString);
1311 char key[SLATE_FILE_NAME_LENGTH];
1312 memcpy(key, (char*)byte_array_elements((struct ByteArray*)keyString), keyLength);
1313 key[keyLength] = '\0';
1314 #ifdef WIN32
1315 SetEnvironmentVariable(key, "");
1316 #else
1317 unsetenv(key);
1318 #endif
1319 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.true_object;
1322 void prim_environment_atput(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1323 struct Object *keyString = args[1];
1324 struct Object *valueString = args[2];
1325 size_t keyLength = payload_size(keyString);
1326 size_t valueLength = payload_size(valueString);
1327 char key[SLATE_FILE_NAME_LENGTH], value[SLATE_FILE_NAME_LENGTH];
1328 int success;
1329 memcpy(key, (char*)byte_array_elements((struct ByteArray*)keyString), keyLength);
1330 key[keyLength] = '\0';
1331 memcpy(value, (char*)byte_array_elements((struct ByteArray*)valueString), valueLength);
1332 value[valueLength] = '\0';
1333 #ifdef WIN32
1334 success = SetEnvironmentVariable(key, value);
1335 #else
1336 success = setenv(key, value, 1);
1337 #endif
1338 oh->cached.interpreter->stack->elements[resultStackPointer] = (success ? oh->cached.false_object : oh->cached.true_object);
1341 void prim_isLittleEndian(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1342 int x = 1;
1343 char little_endian = *(char*)&x;
1344 oh->cached.interpreter->stack->elements[resultStackPointer] = ((little_endian == 1) ? oh->cached.true_object : oh->cached.false_object);
1347 void prim_system_execute(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1348 struct Object *commandString = args[1];
1349 size_t commandLength = payload_size(commandString);
1350 char command[SLATE_FILE_NAME_LENGTH];
1351 memcpy(command, (char*)byte_array_elements((struct ByteArray*)commandString), commandLength);
1352 command[commandLength] = '\0';
1353 oh->cached.interpreter->stack->elements[resultStackPointer] = (system(command) ? oh->cached.false_object : oh->cached.true_object);
1356 #pragma mark Time
1358 #ifdef WIN32 // gettimeofday() ported to WIN32 for prim_timeSinceEpoch()
1360 #if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
1361 #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64
1362 #else
1363 #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
1364 #endif
1366 struct timezone
1368 int tz_minuteswest; /* minutes W of Greenwich */
1369 int tz_dsttime; /* type of dst correction */
1372 int gettimeofday(struct timeval *tv, struct timezone *tz)
1374 FILETIME ft;
1375 unsigned __int64 tmpres = 0;
1376 static int tzflag = 0;
1378 if (NULL != tv)
1380 GetSystemTimeAsFileTime(&ft);
1382 tmpres |= ft.dwHighDateTime;
1383 tmpres <<= 32;
1384 tmpres |= ft.dwLowDateTime;
1386 tmpres /= 10; /*convert into microseconds*/
1387 /*converting file time to unix epoch*/
1388 tmpres -= DELTA_EPOCH_IN_MICROSECS;
1389 tv->tv_sec = (long)(tmpres / 1000000UL);
1390 tv->tv_usec = (long)(tmpres % 1000000UL);
1393 if (NULL != tz)
1395 if (!tzflag)
1397 _tzset();
1398 tzflag++;
1400 tz->tz_minuteswest = _timezone / 60;
1401 tz->tz_dsttime = _daylight;
1404 return 0;
1407 #endif
1409 void prim_timeSinceEpoch(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1410 int64_t time;
1411 int i;
1412 struct ByteArray* timeArray;
1413 const int arraySize = 8;
1415 timeArray = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), arraySize);
1417 time = getTickCount();
1419 for (i = 0; i < arraySize; i++) {
1420 timeArray->elements[i] = ((time >> (i * 8)) & 0xFF);
1423 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)timeArray;
1424 heap_store_into(oh, (struct Object*)oh->cached.interpreter->stack, (struct Object*)timeArray);
1427 void prim_addressOf(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1428 struct Object *handle=args[1], *offset=args[2];
1429 struct ByteArray* addressBuffer=(struct ByteArray*) args[3];
1430 ASSURE_SMALLINT_ARG(1);
1431 ASSURE_SMALLINT_ARG(2);
1432 if (object_is_smallint(handle) && object_is_smallint(offset) && (unsigned)byte_array_size(addressBuffer) >= sizeof(word_t)) {
1433 oh->cached.interpreter->stack->elements[resultStackPointer] =
1434 smallint_to_object(memarea_addressof(oh,
1435 (int)object_to_smallint(handle),
1436 (int)object_to_smallint(offset),
1437 byte_array_elements(addressBuffer)));
1438 } else {
1439 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1444 #pragma mark ExternalLibrary
1446 void prim_library_open(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1447 struct Object *libname=args[1], *handle = args[2];
1449 if (openExternalLibrary(oh, (struct ByteArray*)libname, (struct ByteArray*)handle)) {
1450 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.true_object;
1451 } else {
1452 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.false_object;
1457 void prim_library_close(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1458 struct Object *handle=args[1];
1460 if (closeExternalLibrary(oh, (struct ByteArray*) handle)) {
1461 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.true_object;
1462 } else {
1463 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.false_object;
1468 void prim_procAddressOf(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1469 struct Object *handle=args[2], *symname=args[1];
1470 struct ByteArray* addressBuffer=(struct ByteArray*) args[3];
1472 if (lookupExternalLibraryPrimitive(oh, (struct ByteArray*) handle, (struct ByteArray *) symname, addressBuffer)) {
1473 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.true_object;
1474 } else {
1475 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.false_object;
1480 void prim_extlibError(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1481 struct ByteArray* messageBuffer=(struct ByteArray*) args[1];
1483 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(readExternalLibraryError(messageBuffer));
1486 void prim_applyExternal(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1488 oh->cached.interpreter->stack->elements[resultStackPointer] =
1489 applyExternalLibraryPrimitive(oh, (struct ByteArray*)args[1],
1490 (struct OopArray*)args[2],
1491 args[3],
1492 args[4],
1493 (struct OopArray*)args[5]);
1497 #pragma mark MemoryArea
1499 void prim_memory_new(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1500 struct Object *size=args[1];
1501 word_t handle;
1503 if (!object_is_smallint(size)) {
1504 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1505 return;
1508 handle = (word_t)memarea_open(oh, object_to_smallint(size));
1509 if (handle >= 0) {
1510 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(handle);
1511 } else {
1512 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1517 void prim_memory_close(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1519 struct Object* handle = args[1];
1520 if (object_is_smallint(handle)) {
1521 memarea_close(oh, object_to_smallint(handle));
1523 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1527 void prim_memory_size(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1529 struct Object* handle = args[1];
1530 if (object_is_smallint(handle)) {
1531 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(memarea_sizeof(oh, object_to_smallint(handle)));
1532 } else {
1533 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1538 void prim_memory_addRef(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1540 struct Object* handle = args[1];
1541 if (object_is_smallint(handle)) {
1542 memarea_addref(oh, object_to_smallint(handle));
1545 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1549 void prim_memory_read(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1551 struct ByteArray* buf = (struct ByteArray*)args[0];
1552 word_t amount = object_to_smallint(args[1]), startingAt = object_to_smallint(args[3]),
1553 handle = object_to_smallint(args[2]);
1555 ASSURE_SMALLINT_ARG(1);
1556 ASSURE_SMALLINT_ARG(2);
1557 ASSURE_SMALLINT_ARG(3);
1559 if (!memarea_handle_isvalid(oh, handle)
1560 || byte_array_size(buf) < amount
1561 || startingAt + amount >= oh->memory_sizes [handle]) {
1562 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(-1);
1563 return;
1566 oh->cached.interpreter->stack->elements[resultStackPointer] =
1567 smallint_to_object(memarea_write(oh, handle, startingAt, amount, byte_array_elements(buf)));
1571 void prim_memory_write(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1573 struct ByteArray* buf = (struct ByteArray*)args[0];
1574 word_t amount = object_to_smallint(args[1]), startingAt = object_to_smallint(args[3]),
1575 handle = object_to_smallint(args[2]);
1577 ASSURE_SMALLINT_ARG(1);
1578 ASSURE_SMALLINT_ARG(2);
1579 ASSURE_SMALLINT_ARG(3);
1581 if (!memarea_handle_isvalid(oh, handle)
1582 || byte_array_size(buf) < amount
1583 || startingAt + amount >= oh->memory_sizes [handle]) {
1584 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(-1);
1585 return;
1588 oh->cached.interpreter->stack->elements[resultStackPointer] =
1589 smallint_to_object(memarea_read(oh, handle, startingAt, amount, byte_array_elements(buf)));
1593 void prim_memory_resizeTo(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1595 struct Object* handle = args[1], *size = args[2];
1596 if (object_is_smallint(handle) && object_is_smallint(size)) {
1597 oh->cached.interpreter->stack->elements[resultStackPointer] =
1598 smallint_to_object(memarea_resize(oh, object_to_smallint(handle), object_to_smallint(size)));
1600 } else {
1601 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1606 void prim_smallint_at_slot_named(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1607 struct Object* obj;
1608 struct Object* name;
1609 struct SlotEntry * se;
1610 struct Object * proto;
1612 obj = args[0];
1613 name = args[1];
1614 proto = get_special(oh, SPECIAL_OOP_SMALL_INT_PROTO);
1615 se = slot_table_entry_for_name(oh, proto->map->slotTable, (struct Symbol*)name);
1616 if (se == NULL) {
1617 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_SLOT_NOT_FOUND_NAMED), obj, name, NULL, 0, resultStackPointer);
1618 } else {
1619 word_t offset = object_to_smallint(se->offset);
1620 oh->cached.interpreter->stack->elements[resultStackPointer] = object_slot_value_at_offset(proto, offset);
1626 void prim_frame_pointer_of(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1628 struct Interpreter* i = (struct Interpreter*)args[0];
1629 struct Symbol* selector = (struct Symbol*) args[1];
1630 struct CompiledMethod* method;
1631 word_t frame = i->framePointer;
1635 while (frame > FUNCTION_FRAME_SIZE) {
1636 method = (struct CompiledMethod*) i->stack->elements[frame - FRAME_OFFSET_METHOD];
1637 method = method->method; /*incase it's a closure and not a compiledmethod*/
1638 if (method->selector == selector) {
1639 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(frame);
1640 return;
1642 frame = object_to_smallint(i->stack->elements[frame - FRAME_OFFSET_PREVIOUS_FRAME_POINTER]);
1645 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1649 #pragma mark Clone/Daemonize System
1651 void prim_cloneSystem(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1652 #ifdef WIN32
1653 #pragma message("TODO WIN32 port forking/cloning the system")
1654 return;
1655 #else
1656 pid_t retval;
1657 int pipes[2];
1658 struct OopArray* array;
1660 /* make two pipes that we can use exclusively in each process to talk to the other */
1661 /*FIXME remap fds for safety*/
1662 if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipes) == -1) {
1663 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1664 return;
1667 retval = fork2();
1669 if (retval == (pid_t)-1) {
1670 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1671 return;
1674 array = heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO), 2);
1675 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)array;
1677 if (!retval) { /* child */
1678 array->elements[0] = oh->cached.false_object;
1679 array->elements[1] = smallint_to_object(pipes[0]);
1680 } else { /* parent */
1681 array->elements[0] = oh->cached.true_object;
1682 array->elements[1] = smallint_to_object(pipes[1]);
1685 #endif
1689 void prim_cloneSystemInProcess(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1690 #ifdef WIN32
1691 #pragma message("TODO WIN32 port cloning/threading a system")
1692 #else
1694 #endif
1698 #ifdef SLATE_DAEMONIZE
1700 /* Change this to whatever your daemon is called */
1701 #define DAEMON_NAME "slatedaemon"
1703 /* Change this to the user under which to run */
1704 #define RUN_AS_USER "root"
1706 static void child_handler(int signum) {
1707 switch(signum) {
1708 case SIGALRM: exit(EXIT_FAILURE); break;
1709 case SIGUSR1: exit(EXIT_SUCCESS); break;
1710 case SIGCHLD: exit(EXIT_FAILURE); break;
1714 void prim_daemonizeSystem(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1715 const char* lock_filename = (char*)byte_array_elements((struct ByteArray*) args[1]);
1716 #ifdef WIN32
1717 #pragma message("TODO WIN32 port daemonizing a system")
1718 #else
1719 pid_t pid, sid, parent;
1720 int lfp = -1;
1722 /* already a daemon */
1723 if (getppid() == 1) return;
1725 /* Create the lock file as the current user */
1726 if (lock_filename && lock_filename[0]) {
1727 lfp = open(lock_filename,O_RDWR|O_CREAT,0640);
1728 if (lfp < 0) {
1729 printf("Unable to create lock file %s, code=%d (%s)",
1730 lock_filename, errno, strerror(errno));
1731 exit(EXIT_FAILURE);
1735 /* Drop user if there is one, and we were run as root */
1736 if (getuid() == 0 || geteuid() == 0) {
1737 struct passwd *pw = getpwnam(RUN_AS_USER);
1738 if (pw) {
1739 if (!oh->quiet)
1740 printf("Setting user to " RUN_AS_USER);
1741 setuid(pw->pw_uid);
1745 /* Trap signals that we expect to receive */
1746 signal(SIGCHLD,child_handler);
1747 signal(SIGUSR1,child_handler);
1748 signal(SIGALRM,child_handler);
1750 /* Fork off the parent process */
1751 pid = fork();
1752 if (pid < 0) {
1753 printf("Unable to fork daemon, code=%d (%s)",
1754 errno, strerror(errno));
1755 exit(EXIT_FAILURE);
1757 /* If we got a good PID, then we can exit the parent process. */
1758 if (pid > 0) {
1760 /* Wait for confirmation from the child via SIGTERM or SIGCHLD, or
1761 for two seconds to elapse (SIGALRM). pause() should not return. */
1762 alarm(2);
1763 pause();
1765 exit(EXIT_FAILURE);
1768 /* At this point we are executing as the child process */
1769 parent = getppid();
1771 /* Cancel certain signals */
1772 signal(SIGCHLD,SIG_DFL); /* A child process dies */
1773 signal(SIGTSTP,SIG_IGN); /* Various TTY signals */
1774 signal(SIGTTOU,SIG_IGN);
1775 signal(SIGTTIN,SIG_IGN);
1776 signal(SIGHUP, SIG_IGN); /* Ignore hangup signal */
1777 signal(SIGTERM,SIG_DFL); /* Die on SIGTERM */
1779 /* Change the file mode mask */
1780 umask(0);
1782 /* Create a new SID for the child process */
1783 sid = setsid();
1784 if (sid < 0) {
1785 printf("Unable to create a new session, code %d (%s)",
1786 errno, strerror(errno));
1787 exit(EXIT_FAILURE);
1790 /* Change the current working directory. This prevents the current
1791 directory from being locked; hence not being able to remove it. */
1792 if ((chdir("/")) < 0) {
1793 printf("Unable to change directory to %s, code %d (%s)",
1794 "/", errno, strerror(errno));
1795 exit(EXIT_FAILURE);
1798 /* Redirect standard files to /dev/null */
1799 freopen("/dev/null", "r", stdin);
1800 freopen("/dev/null", "w", stdout);
1801 freopen("/dev/null", "w", stderr);
1803 /* Tell the parent process that we are A-okay */
1804 kill(parent, SIGUSR1);
1805 #endif
1806 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.true_object;
1809 #endif //SLATE_DAEMONIZE
1811 #pragma mark VM invocation arguments
1813 /*TODO: obsolete*/
1814 void prim_run_args_into(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1815 struct ByteArray* arguments = (struct ByteArray*)args[1];
1816 oh->cached.interpreter->stack->elements[resultStackPointer] =
1817 smallint_to_object(write_args_into(oh, (char*)byte_array_elements(arguments), byte_array_size(arguments)));
1822 void prim_vmArgCount(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1823 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(oh->argcSaved);
1826 void prim_vmArg(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1827 word_t i;
1828 int len;
1829 struct ByteArray* array;
1830 ASSURE_SMALLINT_ARG(1);
1831 i = object_to_smallint(args[1]);
1833 if (i >= 0 && i < oh->argcSaved) {
1834 len = strlen(oh->argvSaved[i]);
1835 array = heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), len);
1836 copy_bytes_into((byte_t*)oh->argvSaved[i], len, array->elements);
1837 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)array;
1838 heap_store_into(oh, (struct Object*)oh->cached.interpreter->stack, (struct Object*)array);
1839 } else {
1840 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1844 void prim_environmentVariables(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1845 int i, len;
1846 word_t lenstr;
1847 Pinned<struct OopArray> array(oh);
1849 len = 0;
1850 while (oh->envp[len]) len++;
1852 array = heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO), len);
1854 for (i = 0; i < len; i++) {
1855 lenstr = strlen(oh->envp[i]);
1856 array->elements[i] = (struct Object*) heap_clone_byte_array_sized(oh, get_special(oh, SPECIAL_OOP_BYTE_ARRAY_PROTO), lenstr);
1857 copy_bytes_into((byte_t*)oh->envp[i], lenstr, ((struct ByteArray*)array->elements[i])->elements);
1858 heap_store_into(oh, (struct Object*) array, (struct Object*) array->elements[i]);
1861 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)array;
1862 heap_store_into(oh, (struct Object*)oh->cached.interpreter->stack, (struct Object*)array);
1866 void prim_startProfiling(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1867 if (oh->currentlyProfiling) {
1868 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.false_object;
1869 return;
1872 profiler_start(oh);
1873 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.true_object;
1876 void prim_stopProfiling(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1877 Pinned<struct OopArray> array(oh);
1878 std::vector<Pinned<struct OopArray> > pinnedArrays;
1879 std::vector<Pinned<struct Object> > pinnedMethods;
1880 word_t k;
1881 if (!oh->currentlyProfiling) {
1882 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.false_object;
1883 return;
1886 /*we don't use heap_store_into below because everything is pinned and should be in the young obj area*/
1888 // gc before we allocate so we know how many profiledmethods to keep
1889 heap_full_gc(oh);
1891 /*method, callcount, selftime, childCounts, childTimes*/
1892 array = heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO),
1893 oh->profiledMethods.size()*5);
1896 #ifdef GC_BUG_CHECK
1897 for (std::set<struct Object*>::iterator i = oh->profiledMethods.begin();
1898 i != oh->profiledMethods.end();
1899 i++) {
1900 assert(object_hash(*i) < ID_HASH_RESERVED);
1902 #endif
1905 //pin all the methods so the next time we iterate over things aren't deleted from the list
1906 // while iterating
1907 for (std::set<struct Object*>::iterator i = oh->profiledMethods.begin();
1908 i != oh->profiledMethods.end();
1909 i++) {
1910 Pinned<struct Object> m(oh, *i);
1911 pinnedMethods.push_back(m);
1914 // methods are pinned... we don't have to worry about redirecting things anymore after they're freed?
1915 profiler_stop(oh);
1918 k = 0;
1919 for (std::set<struct Object*>::iterator i = oh->profiledMethods.begin();
1920 i != oh->profiledMethods.end();
1921 i++) {
1922 struct Object* method = *i;
1923 int m = 0;
1924 Pinned<struct OopArray> childCounts(oh, heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO),
1925 oh->profilerChildCallCount[method].size()*2));
1926 Pinned<struct OopArray> childTimes(oh, heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO),
1927 oh->profilerChildCallTime[method].size()*2));
1929 m = 0;
1930 for (std::map<struct Object*,word_t>::iterator cci = oh->profilerChildCallCount[method].begin();
1931 cci != oh->profilerChildCallCount[method].end();
1932 cci++) {
1933 #ifdef GC_BUG_CHECK
1934 assert_good_object(oh, (*cci).first);
1935 #endif
1936 childCounts->elements[m++] = (*cci).first;
1937 childCounts->elements[m++] = smallint_to_object((*cci).second);
1939 m = 0;
1940 for (std::map<struct Object*,word_t>::iterator cti = oh->profilerChildCallTime[method].begin();
1941 cti != oh->profilerChildCallTime[method].end();
1942 cti++) {
1943 #ifdef GC_BUG_CHECK
1944 assert_good_object(oh, (*cti).first);
1945 #endif
1946 childTimes->elements[m++] = (*cti).first;
1947 childTimes->elements[m++] = smallint_to_object((*cti).second);
1950 pinnedArrays.push_back(childCounts);
1951 pinnedArrays.push_back(childTimes);
1953 #ifdef GC_BUG_CHECK
1954 assert_good_object(oh, method);
1955 assert_good_object(oh, childCounts);
1956 assert_good_object(oh, childTimes);
1957 #endif
1959 array->elements[k++] = method;
1960 array->elements[k++] = smallint_to_object(oh->profilerCallCounts[method]);
1961 array->elements[k++] = smallint_to_object(oh->profilerSelfTime[method]);
1962 array->elements[k++] = childCounts;
1963 array->elements[k++] = childTimes;
1966 oh->profiledMethods.clear();
1967 pinnedArrays.clear();
1968 pinnedMethods.clear();
1970 oh->cached.interpreter->stack->elements[resultStackPointer] = array;
1971 heap_store_into(oh, (struct Object*)oh->cached.interpreter->stack, (struct Object*)array);
1972 //this is probably a mess, we should do a full gc so we don't crash
1973 heap_full_gc(oh);
1977 void prim_profilerStatistics(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1978 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
1983 void prim_heap_gc(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1984 if (!oh->quiet) {
1985 printf("Collecting garbage...\n");
1987 heap_full_gc(oh);
1990 void prim_save_image(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1991 char nameString [SLATE_FILE_NAME_LENGTH];
1992 struct slate_image_header sih;
1993 struct Object* name = args[1];
1994 size_t nameLength = payload_size(name);
1995 FILE * imageFile;
1997 word_t totalSize, forwardPointerEntryCount;
1998 byte_t* memoryStart;
1999 struct Object *writeObject;
2000 struct ForwardPointerEntry* forwardPointers;
2001 /* do a full gc, allocate a new chunk of memory the size of the young and old combined,
2002 * copy all the non-free objects to the new memory while keeping an array of the position changes,
2003 * go through the memory and fix up the pointers, adjust points to start from 0 instead of memoryStart,
2004 * and write the header and the memory out to disk
2007 /*push true so if it resumes from the save image, it will do init code*/
2008 /*fixme*/
2009 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.true_object;
2011 if (nameLength >= sizeof(nameString)) {
2012 /*interpreter_stack_pop(oh, oh->cached.interpreter);*/
2013 /*push nil*/
2014 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
2015 return;
2017 memcpy(nameString, (char*)byte_array_elements((struct ByteArray*)name), nameLength);
2018 nameString[nameLength] = '\0';
2020 imageFile = fopen(nameString, "wb");
2021 if (!imageFile) {
2022 /*interpreter_stack_pop(oh, oh->cached.interpreter);*/
2023 /*push nil*/
2024 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
2026 return;
2028 printf("Saving image to %s\n", nameString);
2029 heap_full_gc(oh);
2030 totalSize = oh->memoryOldSize + oh->memoryYoungSize;
2031 forwardPointerEntryCount = ((totalSize / 4) + sizeof(struct ForwardPointerEntry) - 1) / sizeof(struct ForwardPointerEntry);
2032 memoryStart = (byte_t*)calloc(1, totalSize);
2033 writeObject = (struct Object*)memoryStart;
2034 forwardPointers = (struct ForwardPointerEntry*)calloc(1, forwardPointerEntryCount * sizeof(struct ForwardPointerEntry));
2035 assert(memoryStart != NULL);
2036 copy_used_objects(oh, &writeObject, oh->memoryOld, oh->memoryOldSize, forwardPointers, forwardPointerEntryCount);
2037 copy_used_objects(oh, &writeObject, oh->memoryYoung, oh->memoryYoungSize, forwardPointers, forwardPointerEntryCount);
2038 totalSize = (byte_t*)writeObject - memoryStart;
2039 adjust_object_fields_with_table(oh, memoryStart, totalSize, forwardPointers, forwardPointerEntryCount);
2040 adjust_oop_pointers_from(oh, 0-(word_t)memoryStart, memoryStart, totalSize);
2041 sih.magic = SLATE_IMAGE_MAGIC;
2042 sih.size = totalSize;
2043 sih.next_hash = heap_new_hash(oh);
2044 sih.special_objects_oop = (byte_t*) (forward_pointer_hash_get(forwardPointers, forwardPointerEntryCount, (struct Object*)oh->special_objects_oop)->toObj) - memoryStart;
2045 sih.current_dispatch_id = oh->current_dispatch_id;
2047 if (fwrite(&sih, sizeof(struct slate_image_header), 1, imageFile) != 1
2048 || fwrite(memoryStart, 1, totalSize, imageFile) != (size_t)totalSize) {
2049 fprintf(stderr, "Error writing image!\n");
2051 fclose(imageFile);
2052 free(forwardPointers);
2053 free(memoryStart);
2055 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.false_object;
2057 interpreter_stack_pop(oh, oh->cached.interpreter);
2058 interpreter_push_false(oh, oh->cached.interpreter);
2062 void prim_exit(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
2063 /* print_stack_types(oh, 128);*/
2064 /* print_backtrace(oh);*/
2065 ASSURE_SMALLINT_ARG(1);
2066 if (!oh->quiet) {
2067 printf("Slate process %d exiting...\n", getpid());
2069 exit(object_to_smallint(args[1]));
2072 #pragma mark SmallInteger
2074 void prim_equals(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
2075 oh->cached.interpreter->stack->elements[resultStackPointer] = (args[0] == args[1])?oh->cached.true_object:oh->cached.false_object;
2078 void prim_less_than(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
2080 ASSURE_SMALLINT_ARG(0);
2081 ASSURE_SMALLINT_ARG(1);
2082 oh->cached.interpreter->stack->elements[resultStackPointer] =
2083 (object_to_smallint(args[0])<object_to_smallint(args[1]))?oh->cached.true_object:oh->cached.false_object;
2086 void prim_bitand(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
2087 ASSURE_SMALLINT_ARG(0);
2088 ASSURE_SMALLINT_ARG(1);
2089 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)((word_t)args[0] & (word_t)args[1]);
2091 void prim_bitor(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
2092 ASSURE_SMALLINT_ARG(0);
2093 ASSURE_SMALLINT_ARG(1);
2094 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)((word_t)args[0] | (word_t)args[1]);
2096 void prim_bitxor(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
2097 ASSURE_SMALLINT_ARG(0);
2098 ASSURE_SMALLINT_ARG(1);
2099 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)(((word_t)args[0] ^ (word_t)args[1])|SMALLINT_MASK);
2101 void prim_bitnot(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
2102 ASSURE_SMALLINT_ARG(0);
2103 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)(~((word_t)args[0]) | SMALLINT_MASK);
2106 void prim_smallIntegerMinimum(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
2107 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)(((word_t)1<< (sizeof(word_t)*8-1))|1); /*top and smallint bit set*/
2110 void prim_smallIntegerMaximum(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
2111 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)LONG_MAX; /*has all bits except the top set*/
2114 void prim_plus(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
2115 struct Object* x = args[0];
2116 struct Object* y = args[1];
2117 word_t z = object_to_smallint(x) + object_to_smallint(y);
2120 ASSURE_SMALLINT_ARG(0);
2121 ASSURE_SMALLINT_ARG(1);
2124 if (smallint_fits_object(z)) {
2125 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(z);
2126 } else {
2127 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_ADD_OVERFLOW), x, y, NULL, 0, resultStackPointer);
2131 void prim_exponent(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
2132 struct ByteArray* x = (struct ByteArray*)args[0];
2133 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object((*(word_t*)float_part(x) >> FLOAT_EXPONENT_OFFSET) & 0xFF);
2137 void prim_significand(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
2138 struct ByteArray* x = (struct ByteArray*)args[0];
2139 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(*(word_t*)float_part(x) & FLOAT_SIGNIFICAND);
2143 void prim_withSignificand_exponent(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
2144 /*this is really a bytearray*/
2145 word_t significand = object_to_smallint(args[1]), exponent = object_to_smallint(args[2]);
2146 struct ByteArray* f = heap_new_float(oh);
2147 *((word_t*)float_part(f)) = significand | exponent << FLOAT_EXPONENT_OFFSET;
2149 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)f;
2153 /* SmallInteger bitShift: SmallInteger */
2154 void prim_bitshift(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
2155 word_t bits = object_to_smallint(args[0]);
2156 word_t shift = object_to_smallint(args[1]);
2157 word_t z;
2159 ASSURE_SMALLINT_ARG(0);
2160 ASSURE_SMALLINT_ARG(1);
2162 if (shift >= 0) {
2163 if (shift >= __WORDSIZE && bits != 0) {
2164 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_BIT_SHIFT_OVERFLOW), args[0], args[1], NULL, 0, resultStackPointer);
2165 return;
2168 z = bits << shift;
2170 if (!smallint_fits_object(z) || z >> shift != bits) {
2171 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_BIT_SHIFT_OVERFLOW), args[0], args[1], NULL, 0, resultStackPointer);
2172 return;
2175 } else if (shift <= -__WORDSIZE) {
2176 z = bits >> (__WORDSIZE-1);
2177 } else {
2178 z = bits >> -shift;
2181 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(z);
2185 /* SmallInteger - SmallInteger */
2186 void prim_minus(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
2187 struct Object* x = args[0];
2188 struct Object* y = args[1];
2189 word_t z = object_to_smallint(x) - object_to_smallint(y);
2191 ASSURE_SMALLINT_ARG(0);
2192 ASSURE_SMALLINT_ARG(1);
2194 if (smallint_fits_object(z)) {
2195 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(z);
2196 } else {
2197 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_SUBTRACT_OVERFLOW), x, y, NULL, 0, resultStackPointer);
2201 /* SmallInteger * SmallInteger */
2202 void prim_times(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
2203 word_t x = object_to_smallint(args[0]);
2204 word_t y = object_to_smallint(args[1]);
2205 word_t z = x * y;
2208 ASSURE_SMALLINT_ARG(0);
2209 ASSURE_SMALLINT_ARG(1);
2212 if (y != 0 && (z / y != x || !smallint_fits_object(z))) { /*thanks slava*/
2213 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_MULTIPLY_OVERFLOW), args[0], args[1], NULL, 0, resultStackPointer);
2214 } else {
2215 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(z);
2219 /* SmallInteger quo: SmallInteger */
2220 void prim_quo(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
2221 struct Object* x = args[0];
2222 struct Object* y = args[1];
2224 ASSURE_SMALLINT_ARG(0);
2225 ASSURE_SMALLINT_ARG(1);
2227 if (object_to_smallint(y) == 0) {
2228 interpreter_signal_with_with(oh, oh->cached.interpreter, get_special(oh, SPECIAL_OOP_DIVIDE_BY_ZERO), x, y, NULL, 0, resultStackPointer);
2229 } else {
2230 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object(object_to_smallint(x) / object_to_smallint(y));
2234 #pragma mark Float
2236 void prim_float_equals(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
2237 struct ByteArray *x = (struct ByteArray*)args[0], *y = (struct ByteArray*)args[1];
2238 if (*float_part(x) == *float_part(y)) {
2239 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.true_object;
2240 } else {
2241 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.false_object;
2245 void prim_float_less_than(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
2246 struct ByteArray *x = (struct ByteArray*)args[0], *y = (struct ByteArray*)args[1];
2247 if (*float_part(x) < *float_part(y)) {
2248 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.true_object;
2249 } else {
2250 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.false_object;
2254 void prim_float_plus(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
2255 struct ByteArray *x = (struct ByteArray*)args[0], *y = (struct ByteArray*)args[1];
2256 struct ByteArray* z = heap_new_float(oh);
2257 *float_part(z) = *float_part(x) + *float_part(y);
2258 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)z;
2261 void prim_float_minus(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
2262 struct ByteArray *x = (struct ByteArray*)args[0], *y = (struct ByteArray*)args[1];
2263 struct ByteArray* z = heap_new_float(oh);
2264 *float_part(z) = *float_part(x) - *float_part(y);
2265 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)z;
2269 void prim_float_times(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
2270 struct ByteArray *x = (struct ByteArray*)args[0], *y = (struct ByteArray*)args[1];
2271 struct ByteArray* z = heap_new_float(oh);
2272 *float_part(z) = *float_part(x) * *float_part(y);
2273 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)z;
2276 void prim_float_divide(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
2277 struct ByteArray *x = (struct ByteArray*)args[0], *y = (struct ByteArray*)args[1];
2278 struct ByteArray* z = heap_new_float(oh);
2279 *float_part(z) = *float_part(x) / *float_part(y);
2280 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)z;
2283 void prim_float_raisedTo(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
2284 struct ByteArray *x = (struct ByteArray*)args[0], *y = (struct ByteArray*)args[1];
2285 struct ByteArray* z = heap_new_float(oh);
2286 *float_part(z) = pow(*float_part(x), *float_part(y));
2287 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)z;
2290 void prim_float_ln(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
2291 struct ByteArray *x = (struct ByteArray*)args[0];
2292 struct ByteArray* z = heap_new_float(oh);
2293 *float_part(z) = log(*float_part(x));
2294 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)z;
2297 void prim_float_exp(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
2298 struct ByteArray *x = (struct ByteArray*)args[0];
2299 struct ByteArray* z = heap_new_float(oh);
2300 *float_part(z) = exp(*float_part(x));
2301 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)z;
2304 void prim_float_sin(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
2305 struct ByteArray *x = (struct ByteArray*)args[0];
2306 struct ByteArray* z = heap_new_float(oh);
2307 *float_part(z) = sin(*float_part(x));
2308 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)z;
2311 void prim_objectPointerAddress(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
2312 oh->cached.interpreter->stack->elements[resultStackPointer] = smallint_to_object((word_t)args[1]);
2315 void (*primitives[]) (struct object_heap* oh, struct Object* args[], word_t n, struct Object* opts[], word_t optCount, word_t resultStackPointer) = {
2317 /*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,
2318 /*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,
2319 /*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,
2320 /*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,
2321 /*40-9*/ prim_bitxor, prim_bitnot, prim_bitshift, prim_plus, prim_minus, prim_times, prim_quo, prim_interrupt, prim_initializeThreadOn, prim_frame_pointer_of,
2322 /*50-9*/ prim_fixme, prim_fixme, prim_fixme, prim_heap_gc, prim_bytesPerWord, prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme,
2323 /*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,
2324 /*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_dir_open,
2325 /*80-9*/ prim_dir_close, prim_dir_read, prim_dir_getcwd, prim_dir_setcwd, prim_significand, prim_exponent, prim_withSignificand_exponent, prim_float_equals, prim_float_less_than, prim_float_plus,
2326 /*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,
2327 /*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,
2328 /*10-9*/ prim_addressOf, prim_library_open, prim_library_close, prim_procAddressOf, prim_extlibError, prim_applyExternal, prim_timeSinceEpoch, prim_cloneSystem, prim_readFromPipe, prim_writeToPipe,
2329 /*20-9*/ prim_selectOnReadPipesFor, prim_selectOnWritePipesFor, prim_closePipe, prim_socketCreate, prim_socketListen, prim_socketAccept, prim_socketBind, prim_socketConnect, prim_socketCreateIP, prim_smallIntegerMinimum,
2330 /*30-9*/ prim_smallIntegerMaximum, prim_socketGetError, prim_getAddrInfo, prim_getAddrInfoResult, prim_freeAddrInfoResult, prim_vmArgCount, prim_vmArg, prim_environmentVariables, prim_environment_atput, prim_environment_removekey,
2331 /*40-9*/ prim_isLittleEndian, prim_system_name, prim_system_release, prim_system_version, prim_system_platform, prim_system_machine, prim_system_execute, prim_startProfiling, prim_stopProfiling, prim_profilerStatistics,
2332 /*50-9*/ prim_file_delete, prim_file_touch, prim_file_rename_to, prim_file_information, prim_dir_make, prim_dir_rename_to, prim_dir_delete, prim_objectPointerAddress, prim_fixme, prim_fixme,
2333 /*60-9*/ prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme,
2334 /*70-9*/ prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme, prim_fixme,