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)
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
);
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
) {
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
) {
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];
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
); \
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? */
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
) {
72 struct SlotEntry
* se
;
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
);
80 se
= slot_table_entry_for_name(oh
, obj
->map
->slotTable
, (struct Symbol
*)name
);
82 interpreter_signal_with_with(oh
, oh
->cached
.interpreter
, get_special(oh
, SPECIAL_OOP_SLOT_NOT_FOUND_NAMED
), obj
, name
, NULL
, 0, resultStackPointer
);
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
;
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
);
102 if (object_is_immutable(obj
)) {
103 interpreter_signal_with(oh
, oh
->cached
.interpreter
, get_special(oh
, SPECIAL_OOP_IMMUTABLE
), obj
, NULL
, 0, resultStackPointer
);
108 se
= slot_table_entry_for_name(oh
, map
->slotTable
, (struct Symbol
*)name
);
111 interpreter_signal_with_with(oh
, oh
->cached
.interpreter
, get_special(oh
, SPECIAL_OOP_SLOT_NOT_FOUND_NAMED
), obj
, name
, NULL
, 0, resultStackPointer
);
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];
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
);
134 if (object_is_smallint(obj
)) {
135 oh
->cached
.interpreter
->stack
->elements
[resultStackPointer
] = obj
;
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
);
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
);
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
);
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
);
174 oh
->cached
.interpreter
->stack
->elements
[resultStackPointer
] = object_remove_slot(oh
, obj
, name
);
180 void prim_map(struct object_heap
* oh
, struct Object
* args
[], word_t arity
, struct Object
* opts
[], word_t optCount
, word_t resultStackPointer
) {
184 if (object_is_smallint(obj
)) {
185 oh
->cached
.interpreter
->stack
->elements
[resultStackPointer
] = oh
->cached
.nil
;
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
);
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
;
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
;
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
);
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];
260 i
->stackSize
= newStackSize
;
263 i
->ensureHandlers
= smallint_to_object(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);
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
);
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
;
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
384 printf("Defining function '"); print_symbol(selector
);
386 if (!print_printname(oh
, ((struct OopArray
*)roles
)->elements
[0])) printf("NoRole");
389 for (i
= 1; i
< object_array_size(roles
); i
++) {
391 if (!print_printname(oh
, ((struct OopArray
*)roles
)->elements
[i
])) printf("NoRole");
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
);
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
;
416 /*May only remove a CompiledMethod or Closure.*/
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
;
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
);
439 Pinned
<struct Object
> slot(oh
);
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
474 printf("Defining accessor '"); print_symbol(selector
);
476 if (!print_printname(oh
, ((struct OopArray
*)roles
)->elements
[0])) printf("NoRole");
479 for (i
= 1; i
< array_size(roles
); i
++) {
481 if (!print_printname(oh
, ((struct OopArray
*)roles
)->elements
[i
])) printf("NoRole");
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
;
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
];
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
);
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
;
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
));
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
;
546 if (!object_is_smallint(i
)) {
547 oh
->cached
.interpreter
->stack
->elements
[resultStackPointer
] = oh
->cached
.nil
;
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];
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
);
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
)));
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
;
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
));
594 interpreter_signal_with_with(oh
, oh
->cached
.interpreter
, get_special(oh
, SPECIAL_OOP_KEY_NOT_FOUND_ON
), i
, obj
, NULL
, 0, resultStackPointer
);
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
;
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];*/
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
) {
627 struct Object
/**file=args[0],*/ *fname
=args
[1];
629 handle
= file_open(oh
, (struct ByteArray
*)fname
, SF_READ
|SF_WRITE
);
631 oh
->cached
.interpreter
->stack
->elements
[resultStackPointer
] = smallint_to_object(handle
);
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
) {
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
);
644 oh
->cached
.interpreter
->stack
->elements
[resultStackPointer
] = smallint_to_object(handle
);
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
) {
653 struct Object
/**file=args[0],*/ *fname
=args
[1];
655 handle
= file_open(oh
, (struct ByteArray
*)fname
, SF_READ
);
657 oh
->cached
.interpreter
->stack
->elements
[resultStackPointer
] = smallint_to_object(handle
);
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]);
668 ASSURE_SMALLINT_ARG(0);
670 retval
= closesocket(handle
);
672 retval
= close(handle
);
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]);
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
);
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
);
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]);
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
);
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
);
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
;
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
;
754 tv
.tv_sec
= waitTime
/ 1000000;
755 tv
.tv_usec
= waitTime
% 1000000;
756 retval
= select(maxFD
+1, NULL
, &fdList
, NULL
, &tv
);
759 oh
->cached
.interpreter
->stack
->elements
[resultStackPointer
] = oh
->cached
.nil
;
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
;
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
));
780 ASSURE_SMALLINT_ARG(0);
781 ASSURE_SMALLINT_ARG(1);
782 ASSURE_SMALLINT_ARG(2);
785 ret2
= socket_set_nonblocking(ret
);
787 perror("socket create");
791 perror("set nonblocking");
792 oh
->cached
.interpreter
->stack
->elements
[resultStackPointer
] = SOCKET_RETURN(-1);
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]);
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]);
815 struct sockaddr_storage addr
;
817 Pinned
<struct ByteArray
> addrArray(oh
);
818 Pinned
<struct OopArray
> result(oh
);
820 ASSURE_SMALLINT_ARG(0);
823 ret
= accept(fd
, (struct sockaddr
*)&addr
, &len
);
826 addrArray
= heap_clone_byte_array_sized(oh
, get_special(oh
, SPECIAL_OOP_BYTE_ARRAY_PROTO
), sizeof(struct sockaddr_in
));
828 oh
->cached
.interpreter
->stack
->elements
[resultStackPointer
] = SOCKET_RETURN(ret
);
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];
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];
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]);
872 ASSURE_SMALLINT_ARG(0);
874 ret
= getsockopt(fd
, SOL_SOCKET
, SO_ERROR
, &optval
, (socklen_t
*)&optlen
);
877 oh
->cached
.interpreter
->stack
->elements
[resultStackPointer
] = SOCKET_RETURN(optval
);
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
) {
902 hostnameSize
= byte_array_size(hostname
)+1;
905 if ((struct Object
*)service
== oh
->cached
.nil
) {
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
;
925 if (oh
->socketTickets
[ticket
].result
< 0) {
926 oh
->cached
.interpreter
->stack
->elements
[resultStackPointer
] = smallint_to_object(socket_return(oh
->socketTickets
[ticket
].result
));
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
);
934 while (current
!= NULL
) {
935 current
= current
->ai_next
;
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
;
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
;
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);
1007 case SLATE_DOMAIN_LOCAL
:
1010 if (byte_array_size((struct ByteArray
*)address
) > 100) {
1011 ret
= (struct ByteArray
*)oh
->cached
.nil
;
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';
1023 case SLATE_DOMAIN_IPV4
:
1024 ASSURE_SMALLINT_ARG(2);
1025 if (object_array_size(address
) < 4) {
1026 ret
= (struct ByteArray
*)oh
->cached
.nil
;
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));
1041 case SLATE_DOMAIN_IPV6
:
1042 ASSURE_SMALLINT_ARG(2);
1043 if (object_array_size(address
) < 16) {
1044 ret
= (struct ByteArray
*)oh
->cached
.nil
;
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
);
1054 for (i
= 0; i
< 16; i
++)
1055 sin6
->sin6_addr
.s6_addr
[i
] = object_to_smallint(object_array_get_element(address
, i
)) & 0xFF;
1060 ret
= (struct ByteArray
*)oh
->cached
.nil
;
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
];
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
];
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
];
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
];
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];
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];
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];
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];
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
;
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
);
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
;
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
);
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
;
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
);
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
;
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
);
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
;
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
);
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';
1315 SetEnvironmentVariable(key
, "");
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
];
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';
1334 success
= SetEnvironmentVariable(key
, value
);
1336 success
= setenv(key
, value
, 1);
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
) {
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
);
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
1363 #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
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
)
1375 unsigned __int64 tmpres
= 0;
1376 static int tzflag
= 0;
1380 GetSystemTimeAsFileTime(&ft
);
1382 tmpres
|= ft
.dwHighDateTime
;
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);
1400 tz
->tz_minuteswest
= _timezone
/ 60;
1401 tz
->tz_dsttime
= _daylight
;
1409 void prim_timeSinceEpoch(struct object_heap
* oh
, struct Object
* args
[], word_t arity
, struct Object
* opts
[], word_t optCount
, word_t resultStackPointer
) {
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
)));
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
;
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
;
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
;
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],
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];
1503 if (!object_is_smallint(size
)) {
1504 oh
->cached
.interpreter
->stack
->elements
[resultStackPointer
] = oh
->cached
.nil
;
1508 handle
= (word_t
)memarea_open(oh
, object_to_smallint(size
));
1510 oh
->cached
.interpreter
->stack
->elements
[resultStackPointer
] = smallint_to_object(handle
);
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
)));
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);
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);
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
)));
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
) {
1608 struct Object
* name
;
1609 struct SlotEntry
* se
;
1610 struct Object
* proto
;
1614 proto
= get_special(oh
, SPECIAL_OOP_SMALL_INT_PROTO
);
1615 se
= slot_table_entry_for_name(oh
, proto
->map
->slotTable
, (struct Symbol
*)name
);
1617 interpreter_signal_with_with(oh
, oh
->cached
.interpreter
, get_special(oh
, SPECIAL_OOP_SLOT_NOT_FOUND_NAMED
), obj
, name
, NULL
, 0, resultStackPointer
);
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
);
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
) {
1653 #pragma message("TODO WIN32 port forking/cloning the system")
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
;
1669 if (retval
== (pid_t
)-1) {
1670 oh
->cached
.interpreter
->stack
->elements
[resultStackPointer
] = oh
->cached
.nil
;
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]);
1689 void prim_cloneSystemInProcess(struct object_heap* oh, struct Object* args[], word_t arity, struct Object* opts[], word_t optCount, word_t resultStackPointer) {
1691 #pragma message("TODO WIN32 port cloning/threading a system")
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
) {
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]);
1717 #pragma message("TODO WIN32 port daemonizing a system")
1719 pid_t pid
, sid
, parent
;
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);
1729 printf("Unable to create lock file %s, code=%d (%s)",
1730 lock_filename
, errno
, strerror(errno
));
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
);
1740 printf("Setting user to " RUN_AS_USER
);
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 */
1753 printf("Unable to fork daemon, code=%d (%s)",
1754 errno
, strerror(errno
));
1757 /* If we got a good PID, then we can exit the parent process. */
1760 /* Wait for confirmation from the child via SIGTERM or SIGCHLD, or
1761 for two seconds to elapse (SIGALRM). pause() should not return. */
1768 /* At this point we are executing as the child process */
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 */
1782 /* Create a new SID for the child process */
1785 printf("Unable to create a new session, code %d (%s)",
1786 errno
, strerror(errno
));
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
));
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
);
1806 oh
->cached
.interpreter
->stack
->elements
[resultStackPointer
] = oh
->cached
.true_object
;
1809 #endif //SLATE_DAEMONIZE
1811 #pragma mark VM invocation arguments
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
) {
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
);
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
) {
1847 Pinned
<struct OopArray
> array(oh
);
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
;
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
;
1881 if (!oh
->currentlyProfiling
) {
1882 oh
->cached
.interpreter
->stack
->elements
[resultStackPointer
] = oh
->cached
.false_object
;
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
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);
1897 for (std::set
<struct Object
*>::iterator i
= oh
->profiledMethods
.begin();
1898 i
!= oh
->profiledMethods
.end();
1900 assert(object_hash(*i
) < ID_HASH_RESERVED
);
1905 //pin all the methods so the next time we iterate over things aren't deleted from the list
1907 for (std::set
<struct Object
*>::iterator i
= oh
->profiledMethods
.begin();
1908 i
!= oh
->profiledMethods
.end();
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?
1919 for (std::set
<struct Object
*>::iterator i
= oh
->profiledMethods
.begin();
1920 i
!= oh
->profiledMethods
.end();
1922 struct Object
* method
= *i
;
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));
1930 for (std::map
<struct Object
*,word_t
>::iterator cci
= oh
->profilerChildCallCount
[method
].begin();
1931 cci
!= oh
->profilerChildCallCount
[method
].end();
1934 assert_good_object(oh
, (*cci
).first
);
1936 childCounts
->elements
[m
++] = (*cci
).first
;
1937 childCounts
->elements
[m
++] = smallint_to_object((*cci
).second
);
1940 for (std::map
<struct Object
*,word_t
>::iterator cti
= oh
->profilerChildCallTime
[method
].begin();
1941 cti
!= oh
->profilerChildCallTime
[method
].end();
1944 assert_good_object(oh
, (*cti
).first
);
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
);
1954 assert_good_object(oh
, method
);
1955 assert_good_object(oh
, childCounts
);
1956 assert_good_object(oh
, childTimes
);
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
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
) {
1985 printf("Collecting garbage...\n");
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
);
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*/
2009 oh
->cached
.interpreter
->stack
->elements
[resultStackPointer
] = oh
->cached
.true_object
;
2011 if (nameLength
>= sizeof(nameString
)) {
2012 /*interpreter_stack_pop(oh, oh->cached.interpreter);*/
2014 oh
->cached
.interpreter
->stack
->elements
[resultStackPointer
] = oh
->cached
.nil
;
2017 memcpy(nameString
, (char*)byte_array_elements((struct ByteArray
*)name
), nameLength
);
2018 nameString
[nameLength
] = '\0';
2020 imageFile
= fopen(nameString
, "wb");
2022 /*interpreter_stack_pop(oh, oh->cached.interpreter);*/
2024 oh
->cached
.interpreter
->stack
->elements
[resultStackPointer
] = oh
->cached
.nil
;
2028 printf("Saving image to %s\n", nameString
);
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");
2052 free(forwardPointers
);
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);
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
);
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]);
2159 ASSURE_SMALLINT_ARG(0);
2160 ASSURE_SMALLINT_ARG(1);
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
);
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
);
2175 } else if (shift
<= -__WORDSIZE
) {
2176 z
= bits
>> (__WORDSIZE
-1);
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
);
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]);
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
);
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
);
2230 oh
->cached
.interpreter
->stack
->elements
[resultStackPointer
] = smallint_to_object(object_to_smallint(x
) / object_to_smallint(y
));
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
;
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
;
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
,