1 class ShotgunPrimitives
4 def self.defprim(symbol)
8 def generate_select(fd, op="prim")
9 primitives = @@primitives
11 File.open("primitive_implementation.gen", "w") do |f|
12 primitives.each do |prim_name|
13 f.puts "int cpu_primitive_#{prim_name}(STATE, cpu c, const struct message *msg) {"
14 f.puts send(prim_name)
18 f.puts "\nprim_func cpu_lookup_primitive(int index) {"
19 f.puts " static prim_func funcs[] = { NULL, "
21 primitives.each do |prim_name|
22 f.puts " cpu_primitive_#{prim_name},"
26 f.puts " return funcs[index];"
29 f.puts "OBJECT cpu_populate_prim_names(STATE) {"
30 f.puts "OBJECT tbl = lookuptable_new(state);"
31 primitives.each_with_index do |prim_name,i|
32 f.puts "lookuptable_store(state, tbl, I2N(#{i+1}), SYM(\"#{prim_name}\"));"
33 f.puts "lookuptable_store(state, tbl, SYM(\"#{prim_name}\"), I2N(#{i+1}));"
38 fd.puts "switch(#{op}) {"
39 fd.puts " // NOOP is 0 and signifies a method with no primitive"
40 primitives.each_with_index do |prim_name,i|
41 fd.puts "case #{i+1}: { // #{prim_name}"
42 fd.puts " cpu_patch_primitive(state, msg, cpu_primitive_#{prim_name}, #{i+1});"
43 fd.puts " _ret = cpu_primitive_#{prim_name}(state, c, msg);"
48 fd.puts ' printf("Error: Primitive index out of range for this VM (%d)\n", prim);'
49 fd.puts " sassert(0);"
53 File.open("primitive_indexes.h", "w") do |f|
54 primitives.each_with_index do |prim_name,i|
55 f.puts "#define CPU_PRIMITIVE_#{prim_name.to_s.upcase} #{i+1}"
59 File.open("primitive_util.h", "w") do |f|
60 size = primitives.size
61 f.puts "struct prim2index { const char *name; int index; };"
63 f.puts "static int calc_primitive_index(STATE, OBJECT str) {"
64 f.puts " static struct prim2index pi[] = {"
66 primitives.each_with_index do |prim_name,i|
67 f.puts %Q! { "#{prim_name}", #{i+1} },!
70 f.puts " { NULL, 0 } };"
71 f.puts <<-CODE.gsub(/^\s{6}/,'')
73 char *target = rbx_string_as_cstr(state, str);
74 for(i = 0; pi[i].name; i++) {
75 if(!strcmp(target, pi[i].name)) return pi[i].index;
78 printf("Unknown primitive %s\\n", target);
92 GUARD(FIXNUM_P(msg->recv));
93 OBJECT t1 = stack_pop();
95 RET(fixnum_add(state, msg->recv, t1));
96 } else if(BIGNUM_P(t1)) {
97 RET(bignum_add(state, t1, msg->recv));
98 } else if(FLOAT_P(t1)) {
99 OBJECT t2 = float_coerce(state, msg->recv);
100 RET(float_new(state, FLOAT_TO_DOUBLE(t2) + FLOAT_TO_DOUBLE(t1)));
111 GUARD(BIGNUM_P(msg->recv));
112 OBJECT t1 = stack_pop();
113 if(BIGNUM_P(t1) || FIXNUM_P(t1)) {
114 RET(bignum_add(state, msg->recv, t1));
115 } else if(FLOAT_P(t1)) {
116 double a = bignum_to_double(state, msg->recv);
117 RET(float_new(state, a + FLOAT_TO_DOUBLE(t1)));
128 GUARD(FIXNUM_P(msg->recv));
129 OBJECT t1 = stack_pop();
131 RET(fixnum_sub(state, msg->recv, t1));
132 } else if(BIGNUM_P(t1)) {
133 OBJECT res = bignum_sub(state, t1, msg->recv);
135 res = I2N(-N2I(res));
137 res = bignum_neg(state, res);
140 } else if(FLOAT_P(t1)) {
141 OBJECT t2 = float_coerce(state, msg->recv);
142 RET(float_new(state, FLOAT_TO_DOUBLE(t2) - FLOAT_TO_DOUBLE(t1)));
153 GUARD(BIGNUM_P(msg->recv));
154 OBJECT t1 = stack_pop();
155 if(BIGNUM_P(t1) || FIXNUM_P(t1)) {
156 RET(bignum_sub(state, msg->recv, t1));
157 } else if(FLOAT_P(t1)) {
158 double a = bignum_to_double(state, msg->recv);
159 RET(float_new(state, a - FLOAT_TO_DOUBLE(t1)));
170 GUARD(FIXNUM_P(msg->recv));
171 OBJECT t1 = stack_pop();
173 RET(fixnum_mul(state, msg->recv, t1));
174 } else if(BIGNUM_P(t1)) {
175 RET(bignum_mul(state, t1, msg->recv));
176 } else if(FLOAT_P(t1)) {
177 OBJECT t2 = float_coerce(state, msg->recv);
178 RET(float_new(state, FLOAT_TO_DOUBLE(t2) * FLOAT_TO_DOUBLE(t1)));
189 RET(I2N(sizeof(native_int)));
197 GUARD(BIGNUM_P(msg->recv));
198 OBJECT t1 = stack_pop();
199 if(BIGNUM_P(t1) || FIXNUM_P(t1)) {
200 RET(bignum_mul(state, msg->recv, t1));
201 } else if(FLOAT_P(t1)) {
202 double a = bignum_to_double(state, msg->recv);
203 RET(float_new(state, a * FLOAT_TO_DOUBLE(t1)));
214 GUARD(FIXNUM_P(msg->recv));
215 OBJECT t1 = stack_pop();
218 GUARD(N2I(t1) != 0) // no divide by zero
219 RET(I2N(fixnum_div(state, msg->recv, t1, &mod)));
220 } else if(BIGNUM_P(t1)) {
221 GUARD(!bignum_is_zero(state, t1));
222 RET(bignum_div(state, bignum_new(state, N2I(msg->recv)), t1, NULL));
223 } else if(FLOAT_P(t1)) {
224 OBJECT t2 = float_coerce(state, msg->recv);
225 RET(float_new(state, FLOAT_TO_DOUBLE(t2) / FLOAT_TO_DOUBLE(t1)));
236 GUARD(BIGNUM_P(msg->recv));
237 OBJECT t1 = stack_pop();
239 GUARD(!bignum_is_zero(state, t1));
240 RET(bignum_div(state, msg->recv, t1, NULL));
241 } else if(FIXNUM_P(t1)) {
242 GUARD(N2I(t1) != 0) // no divide by zero
243 RET(bignum_div(state, msg->recv, t1, NULL));
244 } else if(FLOAT_P(t1)) {
245 double a = bignum_to_double(state, msg->recv);
246 RET(float_new(state, a / FLOAT_TO_DOUBLE(t1)));
259 GUARD(BIGNUM_P(msg->recv));
262 RET(bignum_mod(state, msg->recv, t1));
270 GUARD(FIXNUM_P(msg->recv));
271 OBJECT t1 = stack_pop();
274 RET(msg->recv == t1 ? Qtrue : Qfalse);
275 } else if(BIGNUM_P(t1)) {
276 RET(bignum_equal(state, t1, msg->recv));
277 } else if(FLOAT_P(t1)) {
278 OBJECT t2 = float_coerce(state, msg->recv);
279 RET(FLOAT_TO_DOUBLE(t1) == FLOAT_TO_DOUBLE(t2) ? Qtrue : Qfalse);
286 defprim :object_equal
293 if(msg->recv == t1) {
301 defprim :bignum_equal
305 GUARD(BIGNUM_P(msg->recv));
306 OBJECT t1 = stack_pop();
307 if(BIGNUM_P(t1) || FIXNUM_P(t1)) {
308 RET(bignum_equal(state, msg->recv, t1));
309 } else if(FLOAT_P(t1)) {
310 double a = bignum_to_double(state, msg->recv);
311 RET(a == FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
322 GUARD(FIXNUM_P(msg->recv));
323 OBJECT t1 = stack_pop();
326 if(msg->recv == t1) {
329 native_int j = N2I(msg->recv);
330 native_int k = N2I(t1);
337 /* We shouldn't be here! */
341 } else if(BIGNUM_P(t1)) {
342 OBJECT t2 = bignum_new(state, N2I(msg->recv));
343 RET(bignum_compare(state, t2, t1));
344 } else if(FLOAT_P(t1)) {
345 OBJECT t2 = float_coerce(state, msg->recv);
346 RET(float_compare(state, FLOAT_TO_DOUBLE(t2), FLOAT_TO_DOUBLE(t1)));
357 GUARD(FIXNUM_P(msg->recv));
358 OBJECT t2 = stack_pop();
361 native_int j = N2I(msg->recv);
362 native_int k = N2I(t2);
363 RET(j < k ? Qtrue : Qfalse);
364 } else if(BIGNUM_P(t2)) {
365 RET(bignum_ge(state, t2, msg->recv));
366 } else if(FLOAT_P(t2)) {
367 OBJECT t1 = float_coerce(state, msg->recv);
368 RET(FLOAT_TO_DOUBLE(t1) < FLOAT_TO_DOUBLE(t2) ? Qtrue : Qfalse);
379 GUARD(FIXNUM_P(msg->recv));
380 OBJECT t2 = stack_pop();
383 native_int j = N2I(msg->recv);
384 native_int k = N2I(t2);
385 RET(j <= k ? Qtrue : Qfalse);
386 } else if(BIGNUM_P(t2)) {
387 RET(bignum_gt(state, t2, msg->recv));
388 } else if(FLOAT_P(t2)) {
389 OBJECT t1 = float_coerce(state, msg->recv);
390 RET(FLOAT_TO_DOUBLE(t1) <= FLOAT_TO_DOUBLE(t2) ? Qtrue : Qfalse);
401 GUARD(FIXNUM_P(msg->recv));
402 OBJECT t2 = stack_pop();
405 native_int j = N2I(msg->recv);
406 native_int k = N2I(t2);
407 RET(j > k ? Qtrue : Qfalse);
408 } else if(BIGNUM_P(t2)) {
409 RET(bignum_le(state, t2, msg->recv));
410 } else if(FLOAT_P(t2)) {
411 OBJECT t1 = float_coerce(state, msg->recv);
412 RET(FLOAT_TO_DOUBLE(t1) > FLOAT_TO_DOUBLE(t2) ? Qtrue : Qfalse);
423 GUARD(FIXNUM_P(msg->recv));
424 OBJECT t2 = stack_pop();
427 native_int j = N2I(msg->recv);
428 native_int k = N2I(t2);
429 RET(j >= k ? Qtrue : Qfalse);
430 } else if(BIGNUM_P(t2)) {
431 RET(bignum_lt(state, t2, msg->recv));
432 } else if(FLOAT_P(t2)) {
433 OBJECT t1 = float_coerce(state, msg->recv);
434 RET(FLOAT_TO_DOUBLE(t1) >= FLOAT_TO_DOUBLE(t2) ? Qtrue : Qfalse);
448 GUARD(INDEXED(msg->recv));
451 native_int j = N2I(t1);
453 GUARD(j >= 0 && j < NUM_FIELDS(msg->recv));
455 RET(NTH_FIELD(msg->recv, j));
465 GUARD(INDEXED(msg->recv));
468 t2 = stack_pop(); // We do not care about the type
469 native_int j = N2I(t1);
470 GUARD(j >= 0 && j < NUM_FIELDS(msg->recv));
472 SET_FIELD(msg->recv, j, t2);
481 GUARD(REFERENCE_P(msg->recv));
483 RET(I2N(NUM_FIELDS(msg->recv)));
493 GUARD(CLASS_P(msg->recv));
495 t1 = class_get_instance_fields(msg->recv);
497 t2 = NEW_OBJECT(msg->recv, N2I(t1));
502 defprim :allocate_count
508 GUARD(CLASS_P(msg->recv));
511 t2 = NEW_OBJECT(msg->recv, N2I(t1));
516 defprim :allocate_bytes
522 GUARD(CLASS_P(msg->recv));
526 t2 = bytearray_new(state, N2I(t1));
527 t2->klass = msg->recv;
541 GUARD(IO_P(msg->recv));
543 POP(t1, INTEGER); /* offset */
544 POP(t2, FIXNUM); /* whence */
546 j = io_to_fd(msg->recv);
549 position = lseek(j, N2I(t1), N2I(t2));
551 position = lseek(j, bignum_to_ll(state, t1), N2I(t2));
554 if (position == -1) {
555 RAISE_FROM_ERRNO("Unable to seek");
567 // pop true off the stack to conform to the "all primitives have a msg->recv rule"
568 GUARD( TRUE_P(msg->recv) )
570 if( RTEST(cpu_current_block(state, c)) ) {
581 GUARD(BLOCKENV_P(msg->recv));
583 blokenv_call(state, c, msg->recv, msg->args);
593 GUARD(IO_P(msg->recv));
596 native_int j = io_to_fd(msg->recv);
597 char *buf = rbx_string_as_cstr(state, t1);
598 native_int k = N2I(string_get_bytes(t1));
600 k = write(j, buf, k);
602 RAISE_FROM_ERRNO("Unable to write");
607 t2 = bignum_new(state, k);
621 GUARD(IO_P(msg->recv));
625 t2 = string_new2(state, NULL, N2I(t1));
626 j = io_to_fd(msg->recv);
627 k = read(j, rbx_string_as_cstr(state, t2), N2I(t1));
630 } else if(k != N2I(t1)) {
631 t3 = string_new2(state, NULL, k);
632 memcpy(rbx_string_as_cstr(state, t3), rbx_string_as_cstr(state, t2), k);
653 io_wrap(state, t1, fds[0], "r");
654 io_wrap(state, t2, fds[1], "w");
673 _path = rbx_string_as_cstr(state, t1);
677 fd = open(_path, mode, perm);
690 GUARD(IO_P(msg->recv));
693 /* MRI does a ton more with reopen, but I don't yet understand why.
694 This seems perfectly acceptable currently. */
696 k = io_to_fd(msg->recv);
699 /* Probably needs an fflush here. */
700 if(dup2(j, k) == -1) {
701 RAISE_FROM_ERRNO("Unable to reopen IO object");
709 defprim :io_operation
716 GUARD(IO_P(msg->recv));
719 j = io_to_fd(msg->recv);
732 RET(string_new(state, ttyname(j)));
749 name = rbx_string_as_cstr(state, t1);
750 if(unlink(name) == 0) {
753 /* TODO translate errno into an exception. */
759 defprim :gettimeofday
766 /* don't fill in the 2nd argument here. getting the timezone here
767 * this way is not portable and broken anyway.
769 gettimeofday(&tv, NULL);
771 /* update Time::TIMEVAL_FIELDS when changing order of fields */
772 t1 = array_new(state, 2);
773 array_set(state, t1, 0, ML2N(tv.tv_sec));
774 array_set(state, t1, 1, ML2N(tv.tv_usec));
786 GUARD(REFERENCE_P(msg->recv));
792 char str[MAX_STRFTIME_OUTPUT+1];
795 tm.tm_sec = N2I(array_get(state, t1, 0));
796 tm.tm_min = N2I(array_get(state, t1, 1));
797 tm.tm_hour = N2I(array_get(state, t1, 2));
798 tm.tm_mday = N2I(array_get(state, t1, 3));
799 tm.tm_mon = N2I(array_get(state, t1, 4));
800 tm.tm_year = N2I(array_get(state, t1, 5));
801 tm.tm_wday = N2I(array_get(state, t1, 6));
802 tm.tm_yday = N2I(array_get(state, t1, 7));
803 tm.tm_isdst = N2I(array_get(state, t1, 8));
805 #ifdef HAVE_STRUCT_TM_TM_GMTOFF
806 tm.tm_gmtoff = N2I(array_get(state, t1, 9));
809 #ifdef HAVE_STRUCT_TM_TM_ZONE
810 tm.tm_zone = rbx_string_as_cstr(state, array_get(state, t1, 10));
813 format = rbx_string_as_cstr(state, t2);
815 out = strftime(str, MAX_STRFTIME_OUTPUT-1, format, &tm);
817 str[MAX_STRFTIME_OUTPUT] = '\\0';
818 t3 = string_new2(state, str, out);
831 GUARD(REFERENCE_P(msg->recv));
839 seconds = bignum_to_ll(state, t1);
843 tm = gmtime(&seconds);
845 tm = localtime(&seconds);
848 /* update Time::TM_FIELDS when changing order of fields */
849 t3 = array_new(state, 2);
850 array_set(state, t3, 0, I2N(tm->tm_sec));
851 array_set(state, t3, 1, I2N(tm->tm_min));
852 array_set(state, t3, 2, I2N(tm->tm_hour));
853 array_set(state, t3, 3, I2N(tm->tm_mday));
854 array_set(state, t3, 4, I2N(tm->tm_mon));
855 array_set(state, t3, 5, I2N(tm->tm_year));
856 array_set(state, t3, 6, I2N(tm->tm_wday));
857 array_set(state, t3, 7, I2N(tm->tm_yday));
858 array_set(state, t3, 8, I2N(tm->tm_isdst));
860 #ifdef HAVE_STRUCT_TM_TM_GMTOFF
861 array_set(state, t3, 9, I2N(tm->tm_gmtoff));
863 array_set(state, t3, 9, Qnil);
866 #ifdef HAVE_STRUCT_TM_TM_ZONE
867 array_set(state, t3, 10, string_new(state, tm->tm_zone));
869 array_set(state, t3, 10, Qnil);
882 char *old_tz, old_tz_buf[128];
883 OBJECT t1, t2, t3, t4, t5, t6, t7, t8, t9, ret;
887 GUARD(REFERENCE_P(msg->recv));
900 GUARD(tm.tm_sec >= 0 && tm.tm_sec <= 60);
903 GUARD(tm.tm_min >= 0 && tm.tm_min <= 60);
905 tm.tm_hour = N2I(t3);
906 GUARD(tm.tm_hour >= 0 && tm.tm_hour <= 24);
908 tm.tm_mday = N2I(t4);
909 GUARD(tm.tm_mday >= 1 && tm.tm_mday <= 31);
911 tm.tm_mon = N2I(t5) - 1;
912 GUARD(tm.tm_mon >= 0 && tm.tm_mon <= 11);
914 tm.tm_year = N2I(t6) - 1900;
916 /* In theory, we'd set the tm_isdst field to N2I(t8).
917 * But since that will break on at least FreeBSD,
918 * and I don't see the point of filling in that flag at all,
919 * we're telling the system here to figure the DST stuff
925 old_tz = getenv("TZ");
927 /* We need to save old_tz to our own buffer here, because e.g.
928 * FreeBSD's setenv() will manipulate that string directly.
931 strncpy(old_tz_buf, old_tz, sizeof(old_tz_buf));
932 old_tz_buf[sizeof(old_tz_buf) - 1] = 0;
938 seconds = mktime(&tm);
942 setenv("TZ", old_tz_buf, 1);
948 ret = array_new(state, 2);
949 array_set(state, ret, 0, ML2N(seconds));
950 array_set(state, ret, 1, t7);
961 static const char digitmap[] = "0123456789abcdefghijklmnopqrstuvwxyz";
963 char *b = buf + sizeof(buf);
966 GUARD(FIXNUM_P(msg->recv));
971 GUARD( j >= 2 && j <= 36 );
973 /* Algorithm taken from 1.8.4 rb_fix2str */
975 RET(string_new(state, "0"));
984 *--b = digitmap[(int)(k % j)];
989 RET(string_new(state, b));
999 GUARD(BIGNUM_P(msg->recv));
1002 RET(bignum_to_s(state, msg->recv, t1));
1006 defprim :logical_class
1010 /* msg->recv is ANY object because object_class knows all. */
1011 RET(object_class(state, msg->recv));
1019 RET(UI2N(object_get_id(state, msg->recv)));
1028 GUARD(HASH_P(msg->recv));
1031 t2 = stack_pop(); // some type of object
1032 t3 = stack_pop(); // some type of object can we do an object guard?
1034 hash_add(state, msg->recv, N2I(t1), t2, t3);
1044 GUARD(HASH_P(msg->recv));
1048 t3 = hash_find_entry(state, msg->recv, N2I(t1));
1053 defprim :hash_redistribute
1054 def hash_redistribute
1057 GUARD(HASH_P(msg->recv));
1059 if(hash_redistribute_p(msg->recv)) {
1060 hash_redistribute(state, msg->recv);
1066 defprim :hash_object
1071 /* msg->recv is ANY object because object_class knows all. */
1072 t1 = UI2N(object_hash_int(state, msg->recv));
1077 defprim :hash_delete
1082 GUARD(HASH_P(msg->recv));
1086 t2 = hash_delete(state, msg->recv, N2I(t1));
1091 defprim :hash_value_set
1095 GUARD(REFERENCE_P(msg->recv));
1102 defprim :symbol_index
1106 GUARD(SYMBOL_P(msg->recv));
1108 RET(I2N(symbol_to_index(state, msg->recv)));
1112 defprim :symbol_lookup
1116 GUARD(STRING_P(msg->recv));
1117 GUARD(N2I(string_get_bytes(msg->recv)) > 0);
1118 RET(string_to_sym(state, msg->recv));
1129 GUARD(REFERENCE_P(msg->recv));
1135 native_int start = N2I(t2);
1136 native_int dest = N2I(t3);
1137 for(k = start, j = dest;
1138 k < NUM_FIELDS(t1) && j < NUM_FIELDS(msg->recv);
1140 SET_FIELD(msg->recv, j, NTH_FIELD(t1, k));
1143 object_copy_nongc_flags(msg->recv, t1);
1149 defprim :bytes_dup_into
1156 GUARD(REFERENCE_P(msg->recv));
1160 GUARD(_object_stores_bytes(msg->recv));
1161 GUARD(_object_stores_bytes(t1));
1163 k = bytearray_bytes(state, msg->recv);
1164 j = bytearray_bytes(state, t1);
1166 if(j < k) { k = j; }
1168 memcpy(bytearray_byte_address(state, t1),
1169 bytearray_byte_address(state, msg->recv), k);
1182 if(REFERENCE_P(msg->recv)) {
1183 j = NUM_FIELDS(msg->recv);
1184 t2 = NEW_OBJECT(object_class(state, msg->recv), j);
1185 if(msg->recv->StoresBytes) {
1186 memcpy(object_byte_start(state, t2),
1187 object_byte_start(state, msg->recv), SIZE_OF_BODY(msg->recv));
1188 t2->StoresBytes = 1;
1190 for(k = 0; k < j; k++) {
1191 SET_FIELD(t2, k, NTH_FIELD(msg->recv, k));
1195 if (object_tainted_p(state, msg->recv)) {
1196 object_set_tainted(state, t2);
1200 object_copy_ivars(state, msg->recv, t2);
1201 cpu_perform_hook(state, c, t2, state->global->sym_init_copy, msg->recv);
1209 defprim :object_clone
1216 GUARD(REFERENCE_P(msg->recv));
1218 j = NUM_FIELDS(msg->recv);
1219 t2 = NEW_OBJECT(object_class(state, msg->recv), j);
1220 if(msg->recv->StoresBytes) {
1221 memcpy(object_byte_start(state, t2),
1222 object_byte_start(state, msg->recv), SIZE_OF_BODY(msg->recv));
1223 t2->StoresBytes = 1;
1225 for(k = 0; k < j; k++) {
1226 SET_FIELD(t2, k, NTH_FIELD(msg->recv, k));
1230 if (object_tainted_p(state, msg->recv)) {
1231 object_set_tainted(state, t2);
1235 object_copy_ivars(state, msg->recv, t2);
1236 object_copy_metaclass(state, msg->recv, t2);
1237 cpu_perform_hook(state, c, t2, state->global->sym_init_copy, msg->recv);
1243 defprim :fastctx_dup
1247 GUARD(RISA(msg->recv, fastctx));
1249 RET(methctx_dup(state, msg->recv));
1253 defprim :tuple_shifted
1260 GUARD(TUPLE_P(msg->recv));
1267 t2 = tuple_new(state, NUM_FIELDS(msg->recv) + j);
1268 object_copy_fields_shifted(state, msg->recv, t2, j);
1282 GUARD( object_stores_bytes_p(state, msg->recv) )
1283 POP(t1, FIXNUM); /* index */
1285 unsigned char *indexed;
1287 k = bytearray_bytes(state, msg->recv);
1289 GUARD( j >= 0 && j < k );
1290 indexed = (unsigned char*)bytearray_byte_address(state, msg->recv);
1293 RET(UI2N(*indexed));
1304 GUARD( object_stores_bytes_p(state, msg->recv) )
1305 POP(t1, FIXNUM); /* index */
1306 POP(t2, FIXNUM); /* value */
1308 unsigned char *indexed;
1310 k = bytearray_bytes(state, msg->recv);
1312 GUARD( j >= 0 && j < k );
1314 indexed = (unsigned char*)bytearray_byte_address(state, msg->recv);
1316 t2 = UI2N(*indexed = N2I(t2));
1322 defprim :fetch_bytes
1329 GUARD( object_stores_bytes_p(state, msg->recv) )
1333 char *source, *dest;
1337 m = bytearray_bytes(state, msg->recv);
1343 GUARD( j >= 0 && j <= m );
1345 t3 = bytearray_new(state, k+1);
1346 source = (char*)bytearray_byte_address(state, msg->recv);
1347 dest = (char*)bytearray_byte_address(state, t3);
1349 memcpy(dest, source, k);
1361 char *data, *source, *dest;
1362 native_int total, offset, start, count;
1364 GUARD(object_stores_bytes_p(state, msg->recv));
1374 total = bytearray_bytes(state, msg->recv);
1376 GUARD(start + count + offset < total);
1380 data = (char*)bytearray_byte_address(state, msg->recv);
1387 memmove((void*)dest, (void*)source, count);
1393 defprim :compare_bytes
1399 native_int len, a, b, n, cmp;
1401 GUARD(object_stores_bytes_p(state, msg->recv));
1403 GUARD(object_stores_bytes_p(state, t1));
1406 a = N2I(t2); /* max bytes to compare in self */
1407 b = N2I(t3); /* max bytes to compare in t1 */
1409 j = bytearray_bytes(state, msg->recv);
1410 k = bytearray_bytes(state, t1);
1414 /* regardless of the user's request,
1415 * don't compare more bytes than there are
1417 len = m < n ? m : n;
1419 cmp = memcmp(bytearray_byte_address(state, msg->recv),
1420 bytearray_byte_address(state, t1), len);
1422 /* check against m and n, to allow a, b to be non-symmetric with j, k */
1432 RET(cmp < 0 ? I2N(-1) : I2N(1));
1437 defprim :bytearray_size
1442 GUARD( object_stores_bytes_p(state, msg->recv) )
1444 j = bytearray_bytes(state, msg->recv);
1459 char *path = rbx_string_as_cstr(state, t1);
1460 t2 = cpu_unmarshal_file(state, path, N2I(t2));
1466 defprim :activate_as_script
1467 def activate_as_script
1470 GUARD(CMETHOD_P(msg->recv));
1472 cpu_run_script(state, c, msg->recv);
1477 defprim :process_exit
1486 cpu_show_lookup_time(state);
1489 if(state->gc_stats) {
1490 printf("[GC M %6dK total]\\n", state->om->ms->allocated_bytes / 1024);
1493 if(current_machine->sub) {
1494 environment_exit_machine();
1501 defprim :micro_sleep
1511 ts.tv_sec = j / 1000000;
1512 ts.tv_nsec = (j % 1000000) * 1000;
1514 if(!nanosleep(&ts, NULL)) {
1524 defprim :activate_context
1525 def activate_context
1529 if(block_context_p(state, msg->recv)) {
1530 t1 = blokctx_home(state, msg->recv);
1535 cpu_activate_context(state, c, msg->recv, t1, 0);
1539 defprim :context_sender
1544 GUARD(CTX_P(msg->recv));
1546 t1 = FASTCTX(msg->recv)->sender;
1549 methctx_reference(state, t1);
1556 defprim :string_to_sexp
1564 GUARD(STRING_P(msg->recv));
1570 contents = cstr2bstr(rbx_string_as_cstr(state, msg->recv));
1571 name = rbx_string_as_cstr(state, t1);
1572 t1 = syd_compile_string(state, name, contents, N2I(t2), RTEST(t3));
1579 defprim :file_to_sexp
1587 POP(t1, STRING); /* The filename */
1590 name = rbx_string_as_cstr(state, t1);
1591 file = fopen(name, "r");
1596 t1 = syd_compile_file(state, name, file, 1, RTEST(t2));
1603 defprim :terminal_raw
1611 if(NULL == state->termios) {
1612 if(!isatty(STDOUT_FILENO)) {
1616 /* HACK: this memory is never freed */
1617 state->termios = ALLOC(struct termios);
1619 if(NULL == state->termios) {
1623 err = tcgetattr(STDOUT_FILENO, state->termios);
1625 if(err == -1) { /* TODO: handle errno */
1626 XFREE(state->termios);
1631 err = tcgetattr(STDOUT_FILENO, &ts);
1633 if(err == -1) { /* TODO: handle errno */
1637 ts.c_lflag &= ~ICANON; /* -icanon */
1638 ts.c_lflag &= ~ISIG; /* -isig */
1639 ts.c_lflag &= ~ECHO; /* -echo */
1640 ts.c_cc[VMIN] = 1; /* min 1 */
1642 err = tcsetattr(STDOUT_FILENO, TCSANOW, &ts);
1644 if(err == -1) { /* TODO: handle errno */
1648 t3 = tuple_new2(state, 4,
1649 I2N(ts.c_cc[VERASE]), I2N(ts.c_cc[VKILL]),
1650 I2N(ts.c_cc[VQUIT]), I2N(ts.c_cc[VINTR])
1657 defprim :terminal_normal
1661 if(NULL == state->termios) {
1663 } else if (isatty(STDOUT_FILENO)) {
1666 err = tcsetattr(STDOUT_FILENO, TCSANOW, state->termios);
1686 GUARD(CLASS_P(msg->recv));
1689 t3 = regexp_new(state, t1, t2, err_buf);
1692 RAISE("RegexpError", err_buf);
1694 t3->klass = msg->recv; /* Subclasses */
1701 defprim :regexp_match
1706 GUARD(REGEXP_P(msg->recv));
1710 RET(regexp_match(state, msg->recv, t1));
1714 defprim :regexp_match_start
1715 def regexp_match_start
1719 GUARD(REGEXP_P(msg->recv));
1724 RET(regexp_match_start(state, msg->recv, t1, t2));
1728 defprim :regexp_search_region
1729 def regexp_search_region
1732 OBJECT t1, t2, t3, t4, t5;
1733 GUARD(REGEXP_P(msg->recv));
1740 t5 = regexp_search_region(state, msg->recv, t1, t2, t3, t4);
1746 defprim :regexp_options
1750 GUARD(REGEXP_P(msg->recv));
1752 RET(regexp_options(state, msg->recv));
1760 OBJECT t1 = stack_pop();
1762 state->om->collect_now = OMCollectYoung;
1764 state->om->collect_now = OMCollectYoung | OMCollectMature;
1774 OBJECT t1 = NTH_FIELD(msg->method, 4);
1775 RET(object_get_ivar(state, msg->recv, t1));
1785 t1 = NTH_FIELD(msg->method, 4);
1787 object_set_ivar(state, msg->recv, t1, t2);
1793 # field 4: method to call
1794 # field 5: object to call method on
1795 # field 6: whether or not we need to retain 'msg->recv'
1796 defprim :dispatch_as_method
1797 def dispatch_as_method
1800 int args = msg->args;
1802 t1 = NTH_FIELD(msg->method, 4);
1803 t2 = NTH_FIELD(msg->method, 5);
1804 t3 = NTH_FIELD(msg->method, 6);
1807 stack_push(msg->recv);
1811 cpu_send(state, c, t2, t1, args, Qnil);
1820 GUARD(INDEXED(msg->recv));
1822 j = N2I(NTH_FIELD(msg->method, 4));
1823 SET_FIELD(msg->recv, j, stack_pop());
1825 RET(NTH_FIELD(msg->recv, j));
1834 GUARD(INDEXED(msg->recv));
1836 j = N2I(NTH_FIELD(msg->method, 4));
1837 RET(NTH_FIELD(msg->recv, j));
1841 defprim :fixnum_modulo
1847 GUARD(FIXNUM_P(msg->recv));
1850 GUARD(N2I(t1) != 0) // no divide by zero
1852 fixnum_div(state, msg->recv, t1, &mod);
1857 defprim :marshal_object
1865 RET(cpu_marshal(state, t1, N2I(t2)));
1869 defprim :unmarshal_object
1870 def unmarshal_object
1876 t3 = cpu_unmarshal(state,
1877 (uint8_t*)rbx_string_as_cstr(state, t1),
1878 N2I(string_get_bytes(t1)),
1884 defprim :marshal_to_file
1895 _path = rbx_string_as_cstr(state, t2);
1896 RET(cpu_marshal_to_file(state, t1, _path, N2I(t3)));
1900 defprim :unmarshal_from_file
1901 def unmarshal_from_file
1910 _path = rbx_string_as_cstr(state, t1);
1911 RET(cpu_unmarshal_file(state, _path, N2I(t2)));
1919 GUARD(FIXNUM_P(msg->recv));
1920 OBJECT t1 = stack_pop();
1921 native_int j, k = 0;
1926 } else if(BIGNUM_P(t1)) {
1927 RET(bignum_and(state, bignum_new(state, N2I(msg->recv)), t1));
1928 } else if(FLOAT_P(t1)) {
1929 double a = FLOAT_TO_DOUBLE(t1);
1930 if(float_bounded_p(a)) {
1931 k = (native_int)float_truncate(a);
1946 GUARD(FIXNUM_P(msg->recv));
1947 OBJECT t1 = stack_pop();
1948 native_int j, k = 0;
1953 } else if(BIGNUM_P(t1)) {
1954 RET(bignum_or(state, bignum_new(state, N2I(msg->recv)), t1));
1955 } else if(FLOAT_P(t1)) {
1956 double a = FLOAT_TO_DOUBLE(t1);
1957 if(float_bounded_p(a)) {
1958 k = (native_int)float_truncate(a);
1973 GUARD(FIXNUM_P(msg->recv));
1974 OBJECT t1 = stack_pop();
1975 native_int j, k = 0;
1980 } else if(BIGNUM_P(t1)) {
1981 RET(bignum_xor(state, bignum_new(state, N2I(msg->recv)), t1));
1982 } else if(FLOAT_P(t1)) {
1983 double a = FLOAT_TO_DOUBLE(t1);
1984 if(float_bounded_p(a)) {
1985 k = (native_int)float_truncate(a);
1996 defprim :fixnum_invert
2001 GUARD(FIXNUM_P(msg->recv));
2013 GUARD(FIXNUM_P(msg->recv));
2020 defprim :fixnum_right_shift
2021 def fixnum_right_shift
2025 native_int value, width;
2027 GUARD(FIXNUM_P(msg->recv));
2030 value = N2I(msg->recv);
2034 if (width >= sizeof(value)*8-1) {
2050 defprim :fixnum_left_shift
2051 def fixnum_left_shift
2055 native_int value, width;
2057 GUARD(FIXNUM_P(msg->recv));
2060 value = N2I(msg->recv);
2075 RET(bignum_new(state, N2I(t1)));
2079 defprim :bignum_to_float
2083 GUARD(BIGNUM_P(msg->recv));
2085 RET(float_new(state, bignum_to_double(state, msg->recv)));
2093 GUARD(BIGNUM_P(msg->recv));
2094 OBJECT t1 = stack_pop();
2096 RET(bignum_and(state, msg->recv, t1));
2097 } else if(FLOAT_P(t1)) {
2098 RET(bignum_and(state, msg->recv,
2099 bignum_from_double(state, FLOAT_TO_DOUBLE(t1))));
2110 GUARD(BIGNUM_P(msg->recv));
2111 OBJECT t1 = stack_pop();
2113 RET(bignum_or(state, msg->recv, t1));
2114 } else if(FLOAT_P(t1)) {
2115 RET(bignum_or(state, msg->recv,
2116 bignum_from_double(state, FLOAT_TO_DOUBLE(t1))));
2127 GUARD(BIGNUM_P(msg->recv));
2128 OBJECT t1 = stack_pop();
2130 RET(bignum_xor(state, msg->recv, t1));
2131 } else if(FLOAT_P(t1)) {
2132 RET(bignum_xor(state, msg->recv,
2133 bignum_from_double(state, FLOAT_TO_DOUBLE(t1))));
2144 GUARD(BIGNUM_P(msg->recv));
2146 RET(bignum_neg(state, msg->recv));
2150 defprim :bignum_invert
2154 GUARD(BIGNUM_P(msg->recv));
2156 RET(bignum_invert(state, msg->recv));
2160 defprim :numeric_coerce
2166 GUARD(INTEGER_P(msg->recv));
2169 t3 = array_new(state, 2);
2170 if(BIGNUM_P(msg->recv)) {
2172 array_set(state, t3, 0, t1);
2174 array_set(state, t3, 0, bignum_new(state, N2I(t1)));
2176 array_set(state, t3, 1, msg->recv);
2179 array_set(state, t3, 0, t1);
2180 array_set(state, t3, 1, bignum_new(state, N2I(msg->recv)));
2182 array_set(state, t3, 0, t1);
2183 array_set(state, t3, 1, msg->recv);
2190 defprim :bignum_compare
2194 GUARD(BIGNUM_P(msg->recv));
2195 OBJECT t1 = stack_pop();
2196 if(BIGNUM_P(t1) || FIXNUM_P(t1)) {
2197 RET(bignum_compare(state, msg->recv, t1));
2198 } else if(FLOAT_P(t1)) {
2199 double f = bignum_to_double(state, msg->recv);
2200 RET(float_compare(state, f, FLOAT_TO_DOUBLE(t1)));
2207 defprim :fixnum_to_f
2211 GUARD(FIXNUM_P(msg->recv));
2213 RET(float_new(state, FIXNUM_TO_DOUBLE(msg->recv)));
2217 defprim :string_to_f
2221 GUARD(STRING_P(msg->recv));
2223 RET(float_new(state, string_to_double(state, msg->recv)));
2227 defprim :fixnum_divmod
2232 GUARD(FIXNUM_P(msg->recv));
2235 GUARD( N2I(t1) != 0 ) // no divide by zero
2236 RET(fixnum_divmod(state, msg->recv, t1));
2240 defprim :bignum_left_shift
2241 def bignum_left_shift
2245 GUARD(BIGNUM_P(msg->recv));
2249 RET(bignum_left_shift(state, msg->recv, t1));
2253 defprim :bignum_right_shift
2254 def bignum_right_shift
2258 GUARD(BIGNUM_P(msg->recv));
2262 RET(bignum_right_shift(state, msg->recv, t1));
2266 defprim :find_method
2272 t1 = exported_cpu_find_method(state, c, msg->recv, t1, &t2);
2273 t3 = tuple_new(state, 2);
2275 tuple_put(state, t3, 0, t2);
2276 tuple_put(state, t3, 1, t1);
2282 defprim :bignum_divmod
2288 GUARD(BIGNUM_P(msg->recv));
2291 // no divide by zero
2293 GUARD(N2I(t1) != 0);
2294 } else if(BIGNUM_P(t1)) {
2295 GUARD(!bignum_is_zero(state, t1));
2300 RET(bignum_divmod(state, msg->recv, t1));
2304 defprim :object_taint
2308 GUARD(REFERENCE_P(msg->recv));
2309 object_set_tainted(state, msg->recv);
2314 defprim :object_tainted_p
2315 def object_tainted_p
2318 GUARD(REFERENCE_P(msg->recv));
2319 RET(object_tainted_p(state, msg->recv) ? Qtrue : Qfalse);
2323 defprim :object_untaint
2327 GUARD(REFERENCE_P(msg->recv));
2328 object_set_untainted(state, msg->recv);
2333 defprim :object_freeze
2337 GUARD(REFERENCE_P(msg->recv));
2338 object_set_frozen(state, msg->recv);
2343 defprim :object_frozen_p
2347 GUARD(REFERENCE_P(msg->recv));
2348 RET(object_frozen_p(state, msg->recv) ? Qtrue : Qfalse);
2352 defprim :fastctx_get_field
2353 def fastctx_get_field
2357 struct fast_context *fc;
2360 GUARD(CTX_P(msg->recv));
2363 fc = FASTCTX(msg->recv);
2368 if(!NIL_P(fc->sender)) {
2369 methctx_reference(state, fc->sender);
2395 RET(I2N(fc->argcount));
2401 RET(fc->method_module);
2404 RET(I2N(fc->flags));
2415 defprim :fastctx_set_field
2416 def fastctx_set_field
2420 struct fast_context *fc;
2423 GUARD(CTX_P(msg->recv));
2429 fc = FASTCTX(msg->recv);
2434 SET_STRUCT_FIELD(msg->recv, fc->sender, t2);
2437 GUARD(FIXNUM_P(t2));
2441 GUARD(FIXNUM_P(t2));
2445 SET_STRUCT_FIELD(msg->recv, fc->block, t2);
2448 SET_STRUCT_FIELD(msg->recv, fc->method, t2);
2451 SET_STRUCT_FIELD(msg->recv, fc->literals, t2);
2454 SET_STRUCT_FIELD(msg->recv, fc->self, t2);
2457 SET_STRUCT_FIELD(msg->recv, fc->locals, t2);
2460 GUARD(FIXNUM_P(t2));
2461 fc->argcount = N2I(t2);
2464 SET_STRUCT_FIELD(msg->recv, fc->name, t2);
2467 SET_STRUCT_FIELD(msg->recv, fc->method_module, t2);
2472 } else if(FIXNUM_P(t2)) {
2473 fc->flags |= N2I(t2);
2484 defprim :fastctx_reload_method
2485 def fastctx_reload_method
2488 struct fast_context *fc;
2489 GUARD(CTX_P(msg->recv));
2491 fc = FASTCTX(msg->recv);
2492 if(fc->method->obj_type == CMethodType) {
2493 fc->custom_iseq = Qnil;
2494 fc->data = BYTEARRAY_ADDRESS(cmethod_get_compiled(fc->method));
2501 defprim :fastctx_set_iseq
2502 def fastctx_set_iseq
2505 struct fast_context *fc;
2509 GUARD(CTX_P(msg->recv));
2511 fc = FASTCTX(msg->recv);
2512 GUARD(fc->method->obj_type == CMethodType);
2515 target_size = (BYTEARRAY_SIZE(t1) / sizeof(uint32_t)) * sizeof(uintptr_t);
2517 target_size = BYTEARRAY_SIZE(t1);
2520 ba = bytearray_new(state, target_size);
2521 cpu_compile_instructions(state, t1, ba);
2522 SET_STRUCT_FIELD(msg->recv, fc->custom_iseq, ba);
2523 fc->data = BYTEARRAY_ADDRESS(ba);
2534 OBJECT t1 = tuple_new(state, 7);
2535 tuple_put(state, t1, 0, I2N(state->cache_hits));
2536 tuple_put(state, t1, 1, I2N(state->cache_misses));
2537 tuple_put(state, t1, 2, I2N(state->cache_used));
2538 tuple_put(state, t1, 3, I2N(state->cache_collisions));
2539 tuple_put(state, t1, 4, I2N(state->cache_inline_hit));
2540 tuple_put(state, t1, 5, I2N(state->cache_inline_stale));
2541 tuple_put(state, t1, 6, I2N(state->cache_inline_const_hit));
2549 defprim :nmethod_call
2555 cpu_save_registers(state, c, msg->args);
2556 t1 = nmc_new(state, msg->method, c->active_context, msg->recv, msg->name, msg->block, msg->args);
2558 ARITY(nmethod_get_args(msg->method));
2560 nmc_activate(state, c, t1, Qnil, FALSE);
2567 /* The definition of beauty. Simplicity. To call a native function, there is no work
2568 to be done. The stub contains all the serialization code.
2570 That being said, this might get more complicated when callbacks are supported. */
2573 cpu_patch_ffi(state, msg);
2575 ptr = nfunc_get_data(msg->method);
2576 ARITY(ffi_get_arg_count(ptr));
2577 ffi_call(state, c, ptr);
2581 defprim :nfunc_call_object
2582 def nfunc_call_object
2584 /* The definition of beauty. Simplicity. To call a native function, there is no work
2585 to be done. The stub contains all the serialization code.
2587 That being said, this might get more complicated when callbacks are supported. */
2588 OBJECT ptr = nfunc_get_data(msg->recv);
2590 ARITY(ffi_get_arg_count(ptr));
2591 ffi_call(state, c, ptr);
2599 OBJECT t1, t2, t3, t4;
2601 POP(t1, STRING_OR_NIL);
2605 RET(ffi_function_create(state, t1, t2, t3, t4));
2609 defprim :load_library
2617 OBJECT ret = subtend_load_library(state, c, t1, t2);
2618 if(ret != Qtrue) RET(ret);
2628 int flags = GLOB_NOSORT | GLOB_BRACE;
2637 pat = rbx_string_as_cstr(state, t1);
2638 k = glob(pat, flags, NULL, &gd);
2639 t2 = array_new(state, gd.gl_pathc);
2640 for(j = 0; j < gd.gl_pathc; j++) {
2641 array_set(state, t2, j, string_new(state, gd.gl_pathv[j]));
2657 path = rbx_string_as_cstr(state, t1);
2670 OBJECT t1 = stack_pop();
2671 *((OBJECT*)4) = t1; /* cause a SIGBUS */
2676 defprim :make_weak_ref
2683 RET(object_make_weak_ref(state, t1));
2687 defprim :gc_collect_references
2688 def gc_collect_references
2694 RET(object_memory_collect_references(state, state->om, t1));
2703 /* This is a little contrived so the dup'd task has
2704 it stack setup properly. */
2708 if(TASK_P(msg->recv)) {
2709 t1 = cpu_task_dup(state, c, msg->recv);
2711 t1 = cpu_task_dup(state, c, Qnil);
2714 cpu_stack_set_top(state, c, t1);
2718 defprim :task_set_current
2719 def task_set_current
2726 cpu_task_select(state, c, t1);
2730 defprim :task_associate
2736 GUARD(TASK_P(msg->recv));
2739 RET(cpu_task_associate(state, c, msg->recv, t1));
2743 defprim :task_current
2747 RET(c->current_task);
2755 struct cpu_task *task;
2759 GUARD(TASK_P(msg->recv));
2762 task = (struct cpu_task*)BYTES_OF(msg->recv);
2770 t2 = task->active_context;
2771 if(REFERENCE_P(t2)) methctx_reference(state, t2);
2781 defprim :task_set_debugging
2782 def task_set_debugging
2786 GUARD(TASK_P(msg->recv));
2791 GUARD(t1 == Qnil || CHANNEL_P(t1));
2792 GUARD(t2 == Qnil || CHANNEL_P(t2));
2794 if(msg->recv == c->current_task) {
2795 c->debug_channel = t1;
2796 c->control_channel = t2;
2798 cpu_task_set_debugging(state, msg->recv, t1, t2);
2804 defprim :task_debug_channel
2805 def task_debug_channel
2808 struct cpu_task *task;
2809 GUARD(TASK_P(msg->recv));
2811 task = (struct cpu_task*)BYTES_OF(msg->recv);
2813 RET(task->debug_channel);
2817 defprim :task_control_channel
2818 def task_control_channel
2821 struct cpu_task *task;
2822 GUARD(TASK_P(msg->recv));
2824 task = (struct cpu_task*)BYTES_OF(msg->recv);
2826 RET(task->control_channel);
2830 defprim :task_get_debug_context_change
2831 def task_get_debug_context_change
2834 struct cpu_task *task;
2835 GUARD(TASK_P(msg->recv));
2837 task = (struct cpu_task*)BYTES_OF(msg->recv);
2838 if(TASK_FLAG_P(task, TASK_DEBUG_ON_CTXT_CHANGE)) {
2846 defprim :task_set_debug_context_change
2847 def task_set_debug_context_change
2850 struct cpu_task *task;
2851 GUARD(TASK_P(msg->recv));
2852 OBJECT t1 = stack_pop();
2854 task = (struct cpu_task*)BYTES_OF(msg->recv);
2856 TASK_SET_FLAG(task, TASK_DEBUG_ON_CTXT_CHANGE);
2858 TASK_SET_FLAG(c, TASK_DEBUG_ON_CTXT_CHANGE);
2862 if(TASK_FLAG_P(task, TASK_DEBUG_ON_CTXT_CHANGE)) {
2863 TASK_CLEAR_FLAG(task, TASK_DEBUG_ON_CTXT_CHANGE);
2865 TASK_CLEAR_FLAG(c, TASK_DEBUG_ON_CTXT_CHANGE);
2873 defprim :task_stack_size
2877 struct cpu_task *task;
2878 GUARD(TASK_P(msg->recv));
2880 task = (struct cpu_task*)BYTES_OF(msg->recv);
2881 OBJECT t1 = I2N(task->sp_ptr - task->stack_top);
2887 defprim :task_get_stack_value
2888 def task_get_stack_value
2891 struct cpu_task *task;
2894 GUARD(TASK_P(msg->recv));
2897 task = (struct cpu_task*)BYTES_OF(msg->recv);
2899 GUARD(idx >=0 && idx < (task->sp_ptr - task->stack_top));
2901 t2 = *(task->sp_ptr - idx);
2912 GUARD(TASK_P(msg->recv));
2916 /* The return value */
2919 /* This is conditional because task_select can decide that it's not
2920 not possible to select this task, in which case it handles letting
2921 the user know this on it's own. */
2923 if(cpu_task_select(state, c, msg->recv)) {
2924 cpu_raise_exception(state, c, t1);
2929 defprim :thread_raise
2934 GUARD(THREAD_P(msg->recv));
2938 if(!cpu_thread_alive_p(state, msg->recv)) {
2942 /* The return value */
2945 cpu_thread_schedule(state, c->current_thread);
2946 cpu_thread_force_run(state, c, msg->recv);
2948 methctx_reference(state, c->active_context);
2949 exception_set_context(t1, c->active_context);
2951 cpu_raise_exception(state, c, t1);
2956 defprim :channel_new
2960 RET(cpu_channel_new(state));
2964 defprim :channel_send
2969 GUARD(CHANNEL_P(msg->recv));
2972 RET(cpu_channel_send(state, c, msg->recv, t1));
2976 defprim :channel_receive
2980 GUARD(CHANNEL_P(msg->recv));
2982 cpu_channel_receive(state, c, msg->recv, c->current_thread);
2983 /* Don't touch the stack as we may be in a different task at this
2984 point. The original task's stack is updated when the channel
2985 is written to and the task restored. */
2989 defprim :channel_send_in_microseconds
2990 def channel_send_in_microseconds
2994 OBJECT channel, usec_r, tag;
2997 POP(channel, CHANNEL);
2998 POP(usec_r, INTEGER);
3001 if(FIXNUM_P(usec_r)) {
3002 k = (long)N2I(usec_r);
3004 k = (long)bignum_to_int(state, usec_r);
3007 seconds = k / 1000000.0;
3009 RET(cpu_event_wake_channel(state, c, channel, seconds, tag));
3013 defprim :channel_send_in_seconds
3014 def channel_send_in_seconds
3018 OBJECT channel, seconds_r, tag;
3020 POP(channel, CHANNEL);
3021 POP(seconds_r, FLOAT);
3024 seconds = FLOAT_TO_DOUBLE(seconds_r);
3026 RET(cpu_event_wake_channel(state, c, channel, seconds, tag));
3030 defprim :channel_send_on_readable
3031 def channel_send_on_readable
3034 OBJECT t1, t2, t3, t4;
3042 GUARD(STRING_P(t2) || NIL_P(t2));
3043 GUARD(FIXNUM_P(t3) || NIL_P(t3));
3047 } else if(FIXNUM_P(t1)) {
3053 RET(cpu_event_wait_readable(state, c, t4, j, t2, N2I(t3)));
3057 defprim :channel_send_on_writable
3058 def channel_send_on_writable
3068 RET(cpu_event_wait_writable(state, c, t2, j));
3072 defprim :channel_send_on_signal
3073 def channel_send_on_signal
3081 RET(cpu_event_wait_signal(state, c, t2, N2I(t1)));
3085 defprim :channel_send_on_stopped
3086 def channel_send_on_stopped
3095 RET(cpu_event_wait_child(state, c, t3, N2I(t1), N2I(t2)));
3099 defprim :scheduler_cancel
3100 def scheduler_cancel
3106 RET(cpu_event_cancel_event(state, t1) ? Qtrue : Qfalse);
3114 RET(cpu_thread_new(state, c));
3122 GUARD(THREAD_P(msg->recv));
3124 GUARD(cpu_thread_alive_p(state, msg->recv));
3126 /* So when we're restored, there is a ret val. */
3128 cpu_thread_schedule(state, c->current_thread);
3129 cpu_thread_force_run(state, c, msg->recv);
3133 defprim :thread_schedule
3137 GUARD(THREAD_P(msg->recv));
3139 cpu_thread_schedule(state, msg->recv);
3144 defprim :thread_yield
3148 /* Same reason as thread_run */
3150 cpu_thread_schedule(state, c->current_thread);
3151 THDEBUG("%d: thread yield.\\n", getpid());
3152 cpu_thread_run_best(state, c);
3156 defprim :thread_dequeue
3160 THDEBUG("%d: dequeue thread.\\n", getpid());
3161 cpu_thread_exited(state, c);
3165 defprim :thread_current
3169 RET(c->current_thread);
3173 defprim :object_become
3177 void state_object_become(STATE, cpu c, OBJECT from, OBJECT to);
3182 state_object_become(state, c, t2, t1);
3187 defprim :sampler_activate
3188 def sampler_activate
3194 cpu_sampler_activate(state, N2I(t1), environment_current_machine());
3199 defprim :sampler_stop
3203 OBJECT t1 = cpu_sampler_disable(state, environment_current_machine());
3208 defprim :fork_process
3212 native_int k = fork();
3214 RAISE_FROM_ERRNO("Unable to fork");
3225 defprim :replace_process# aka execve().
3237 k = N2I(array_get_total(t2));
3238 argv = ALLOC_N(char*, k + 1);
3239 for(j = 0; j < k; j++) {
3240 t3 = array_get(state, t2, j);
3241 if(!ISA(t3, state->global->string)) {
3242 for(i = 0; i < j; i++) {
3249 tmp = rbx_string_as_cstr(state, t3);
3250 argv[j] = tmp ? strdup(tmp) : NULL;
3255 tmp = rbx_string_as_cstr(state, t1);
3256 file = tmp ? strdup(tmp) : NULL;
3258 cpu_task_disable_preemption(state);
3259 k = execvp(file, argv);
3261 /* If you're here, there was an error. */
3262 cpu_task_configure_preemption(state);
3263 RAISE_FROM_ERRNO("Unable to execute");
3274 RET(object_get_ivar(state, msg->recv, t1));
3285 object_set_ivar(state, msg->recv, t1, t2);
3294 RET(object_get_ivars(state, msg->recv));
3304 GUARD(STRING_P(msg->recv));
3306 RET(string_new(state, crypt(rbx_string_as_cstr(state, msg->recv),
3307 rbx_string_as_cstr(state, t1))));
3322 key = rbx_string_as_cstr(state, t1);
3324 char *value = getenv(key);
3327 t2 = string_new(state, value);
3345 key = rbx_string_as_cstr(state, t1);
3347 /* if t2 is nil, we need to delete the variable
3348 * and return its value.
3351 value = getenv(key);
3354 RET(string_new(state, value));
3359 GUARD(STRING_P(t2));
3360 value = rbx_string_as_cstr(state, t2);
3362 setenv(key, value, 1);
3372 defprim :env_as_hash
3376 char *cur, **total = environ;
3378 OBJECT hash = hash_new(state);
3387 while(*cur && *cur != '=') {
3391 OBJECT key = string_new2(state, name, i);
3392 OBJECT val = string_new(state, cur+1);
3394 hash_set(state, hash, key, val);
3401 defprim :bignum_size
3405 GUARD(BIGNUM_P(msg->recv));
3406 RET(bignum_size(state, msg->recv));
3410 defprim :iseq_compile
3414 GUARD(CMETHOD_P(msg->recv));
3415 cpu_compile_method(state, msg->recv);
3420 defprim :reset_method_cache
3421 def reset_method_cache
3426 cpu_clear_cache_for_method(state, c, t1, TRUE);
3430 defprim :bignum_from_float
3431 def bignum_from_float
3436 RET(bignum_from_double(state, FLOAT_TO_DOUBLE(t1)));
3440 defprim :save_encloser_path
3441 def save_encloser_path
3444 cpu_set_encloser_path(state, c, state->global->object);
3449 defprim :restore_encloser_path
3450 def restore_encloser_path
3453 cpu_push_encloser(state, c);
3464 GUARD(msg->args == 1);
3466 GUARD(FIXNUM_P(t1));
3468 j = N2I(array_get_total(msg->recv));
3474 if(k < 0 || k >= j) {
3475 stack_set_top(Qnil);
3477 k += N2I(array_get_start(msg->recv));
3478 t3 = array_get_tuple(msg->recv);
3479 GUARD(k < NUM_FIELDS(t3));
3481 stack_set_top(tuple_at(state, t3, k));
3492 GUARD(msg->args == 2);
3494 GUARD(FIXNUM_P(t1));
3496 j = N2I(array_get_total(msg->recv));
3503 array_set_total(msg->recv, I2N(k + 1));
3506 k += N2I(array_get_start(msg->recv));
3507 t3 = array_get_tuple(msg->recv);
3508 GUARD(k < NUM_FIELDS(t3));
3510 tuple_put(state, t3, k, stack_top());
3514 defprim :string_append
3519 GUARD(msg->args == 1);
3522 string_append(state, msg->recv, t1);
3531 RET(string_dup(state, msg->recv));
3535 defprim :string_equal
3544 if(msg->recv == t1) {
3547 t2 = string_get_bytes(msg->recv);
3548 t3 = string_get_bytes(t1);
3555 t2 = string_get_data(msg->recv);
3556 t3 = string_get_data(t1);
3558 m = memcmp(BYTEARRAY_ADDRESS(t2), BYTEARRAY_ADDRESS(t3), j < k ? j : k);
3559 RET(m == 0 ? Qtrue : Qfalse);
3565 defprim :object_send
3569 GUARD(msg->args >= 1);
3573 t1 = string_to_sym(state, t1);
3579 /* Send is allowed to call private methods. */
3582 cpu_send(state, c, msg->recv, t1, msg->args - 1, msg->block);
3586 defprim :machine_new
3593 OBJECT ret, ary, str;
3596 environment e = environment_current();
3600 argc = N2I(array_get_total(ary));
3601 argv = ALLOC_N(char*, argc);
3602 for(i = 0; i < argc; i++) {
3603 str = array_get(state, ary, i);
3605 argv[i] = strdup(rbx_string_as_cstr(state, str));
3607 argv[i] = strdup("");
3612 pipes = machine_setup_thread(m, argc, argv);
3614 m->parent_id = current_machine->id;
3616 ret = tuple_new(state, 4);
3617 tuple_put(state, ret, 0, I2N(m->id));
3618 tuple_put(state, ret, 1, io_new(state, pipes[0], "w"));
3619 tuple_put(state, ret, 2, io_new(state, pipes[1], "r"));
3620 tuple_put(state, ret, 3, io_new(state, pipes[2], "r"));
3623 environment_start_thread(e, m);
3629 defprim :machine_join
3635 if(environment_join_machine(environment_current(), N2I(t1))) {
3643 defprim :machine_get_message
3644 def machine_get_message
3647 RET(environment_get_message(environment_current(), current_machine->id));
3651 defprim :machine_send_message
3652 def machine_send_message
3659 environment_send_message(environment_current(), N2I(t1), t2);
3674 dir = opendir(rbx_string_as_cstr(state, t1));
3675 if(!dir) RAISE_FROM_ERRNO("Unable to open directory");
3677 RET(ffi_new_pointer(state, dir));
3690 dir = *DATA_STRUCT(t1, void**);
3692 *DATA_STRUCT(t1, void**) = NULL;
3701 defprim :dir_control
3708 DIR *dir = *DATA_STRUCT(t1, void**);
3715 seekdir(dir, N2I(pos));
3721 RET(I2N(telldir(dir)));
3735 DIR *dir = *DATA_STRUCT(t1, void**);
3741 RET(string_new(state, ent->d_name));
3747 defprim :opt_push_literal
3748 def opt_push_literal
3753 lits = cmethod_get_literals(msg->method);
3754 RET(fast_fetch(lits, 0));
3758 defprim :opt_push_self
3766 defprim :opt_push_ivar
3772 lits = cmethod_get_literals(msg->method);
3773 RET(object_get_ivar(state, msg->recv, fast_fetch(lits, 0)));
3777 defprim :opt_push_my_field
3778 def opt_push_my_field
3783 lits = cmethod_get_literals(msg->method);
3784 RET(NTH_FIELD(msg->recv, N2I(fast_fetch(lits, 0))));
3788 defprim :opt_kind_of
3795 GUARD(CLASS_P(t1) || MODULE_P(t1));
3797 RET(object_kind_of_p(state, msg->recv, t1) ? Qtrue : Qfalse);
3805 GUARD(FLOAT_P(msg->recv));
3806 double a = FLOAT_TO_DOUBLE(msg->recv);
3807 OBJECT t1 = stack_pop();
3809 t1 = float_coerce(state, t1);
3812 RET(float_new(state, a + FLOAT_TO_DOUBLE(t1)));
3820 GUARD(FLOAT_P(msg->recv));
3821 double a = FLOAT_TO_DOUBLE(msg->recv);
3822 OBJECT t1 = stack_pop();
3824 t1 = float_coerce(state, t1);
3827 RET(float_new(state, a - FLOAT_TO_DOUBLE(t1)));
3835 GUARD(FLOAT_P(msg->recv));
3836 double a = FLOAT_TO_DOUBLE(msg->recv);
3837 OBJECT t1 = stack_pop();
3839 t1 = float_coerce(state, t1);
3842 RET(float_new(state, a * FLOAT_TO_DOUBLE(t1)));
3850 GUARD(FLOAT_P(msg->recv));
3851 double a = FLOAT_TO_DOUBLE(msg->recv);
3852 OBJECT t1 = stack_pop();
3854 t1 = float_coerce(state, t1);
3857 RET(float_new(state, a / FLOAT_TO_DOUBLE(t1)));
3861 defprim :float_uminus
3865 GUARD(FLOAT_P(msg->recv));
3866 double a = FLOAT_TO_DOUBLE(msg->recv);
3867 RET(float_new(state, -a));
3871 defprim :float_equal
3875 GUARD(FLOAT_P(msg->recv));
3876 double a = FLOAT_TO_DOUBLE(msg->recv);
3877 OBJECT t1 = stack_pop();
3879 t1 = float_coerce(state, t1);
3882 RET(a == FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
3890 GUARD(FLOAT_P(msg->recv));
3891 OBJECT t1 = stack_pop();
3893 double a = FLOAT_TO_DOUBLE(msg->recv),
3894 b = FLOAT_TO_DOUBLE(t1);
3895 RET(a == b ? Qtrue : Qfalse);
3902 defprim :float_compare
3906 GUARD(FLOAT_P(msg->recv));
3907 double a = FLOAT_TO_DOUBLE(msg->recv);
3908 OBJECT t1 = stack_pop();
3910 t1 = float_coerce(state, t1);
3913 double b = FLOAT_TO_DOUBLE(t1);
3914 RET(float_compare(state, a, b));
3922 GUARD(FLOAT_P(msg->recv));
3923 double a = FLOAT_TO_DOUBLE(msg->recv);
3924 OBJECT t1 = stack_pop();
3926 t1 = float_coerce(state, t1);
3929 RET(a < FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
3937 GUARD(FLOAT_P(msg->recv));
3938 double a = FLOAT_TO_DOUBLE(msg->recv);
3939 OBJECT t1 = stack_pop();
3941 t1 = float_coerce(state, t1);
3944 RET(a <= FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
3952 GUARD(FLOAT_P(msg->recv));
3953 double a = FLOAT_TO_DOUBLE(msg->recv);
3954 OBJECT t1 = stack_pop();
3956 t1 = float_coerce(state, t1);
3959 RET(a > FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
3967 GUARD(FLOAT_P(msg->recv));
3968 double a = FLOAT_TO_DOUBLE(msg->recv);
3969 OBJECT t1 = stack_pop();
3971 t1 = float_coerce(state, t1);
3974 RET(a >= FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
3982 GUARD(FLOAT_P(msg->recv));
3983 double b = FLOAT_TO_DOUBLE(msg->recv);
3985 RAISE("FloatDomainError", b < 0 ? "-Infinity" : "Infinity");
3986 } else if(isnan(b)) {
3989 RET(bignum_from_double(state, float_truncate(b)));
3994 defprim :float_round
3998 GUARD(FLOAT_P(msg->recv));
3999 double value = FLOAT_TO_DOUBLE(msg->recv);
4000 if (value > 0.0) value = floor(value+0.5);
4001 if (value < 0.0) value = ceil(value-0.5);
4002 RET(bignum_from_double(state, value));
4006 defprim :float_divmod
4010 GUARD(FLOAT_P(msg->recv));
4011 double a = FLOAT_TO_DOUBLE(msg->recv);
4012 OBJECT t1 = stack_pop();
4014 t1 = float_coerce(state, t1);
4017 double b = FLOAT_TO_DOUBLE(t1);
4019 RAISE("FloatDomainError", "divide by 0");
4021 double div = floor(a / b);
4022 double mod = fmod(a, b);
4026 OBJECT ary = array_new(state, 2);
4027 array_set(state, ary, 0, bignum_from_double(state, float_truncate(div)));
4028 array_set(state, ary, 1, float_new(state, mod));
4038 GUARD(FLOAT_P(msg->recv));
4039 double a = FLOAT_TO_DOUBLE(msg->recv);
4040 OBJECT t1 = stack_pop();
4042 t1 = float_coerce(state, t1);
4045 RET(float_new(state, pow(a, FLOAT_TO_DOUBLE(t1))));
4049 defprim :float_isnan
4053 GUARD(FLOAT_P(msg->recv));
4054 RET(isnan(FLOAT_TO_DOUBLE(msg->recv)) == 1 ? Qtrue : Qfalse);
4058 defprim :float_isinf
4062 GUARD(FLOAT_P(msg->recv));
4063 double value = FLOAT_TO_DOUBLE(msg->recv);
4064 if(isinf(value) != 0) {
4065 RET(value < 0 ? I2N(-1) : I2N(1));
4076 GUARD(BIGNUM_P(msg->recv));
4077 OBJECT t1 = stack_pop();
4078 if(BIGNUM_P(t1) || FIXNUM_P(t1)) {
4079 RET(bignum_gt(state, msg->recv, t1));
4080 } else if(FLOAT_P(t1)) {
4081 double a = bignum_to_double(state, msg->recv);
4082 RET(a > FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
4093 GUARD(BIGNUM_P(msg->recv));
4094 OBJECT t1 = stack_pop();
4095 if(BIGNUM_P(t1) || FIXNUM_P(t1)) {
4096 RET(bignum_ge(state, msg->recv, t1));
4097 } else if(FLOAT_P(t1)) {
4098 double a = bignum_to_double(state, msg->recv);
4099 RET(a >= FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
4110 GUARD(BIGNUM_P(msg->recv));
4111 OBJECT t1 = stack_pop();
4112 if(BIGNUM_P(t1) || FIXNUM_P(t1)) {
4113 RET(bignum_lt(state, msg->recv, t1));
4114 } else if(FLOAT_P(t1)) {
4115 double a = bignum_to_double(state, msg->recv);
4116 RET(a < FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
4127 GUARD(BIGNUM_P(msg->recv));
4128 OBJECT t1 = stack_pop();
4129 if(BIGNUM_P(t1) || FIXNUM_P(t1)) {
4130 RET(bignum_le(state, msg->recv, t1));
4131 } else if(FLOAT_P(t1)) {
4132 double a = bignum_to_double(state, msg->recv);
4133 RET(a <= FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
4140 defprim :sendsite_create
4146 GUARD(CLASS_P(msg->recv));
4149 ss = send_site_create(state, t1);
4154 defprim :sendsite_set_sender
4155 def sendsite_set_sender
4160 GUARD(SENDSITE_P(msg->recv));
4163 send_site_set_sender(state, msg->recv, cm);
4168 defprim :sendsite_at
4174 GUARD(SENDSITE_P(msg->recv));
4179 RET(SENDSITE(msg->recv)->name);
4181 RET(SENDSITE(msg->recv)->selector);
4183 RET(SENDSITE(msg->recv)->data1);
4185 RET(SENDSITE(msg->recv)->data2);
4187 RET(SENDSITE(msg->recv)->data3);
4189 RET(ffi_new_pointer(state, SENDSITE(msg->recv)->c_data));
4191 RET(I2N(SENDSITE(msg->recv)->hits));
4193 RET(I2N(SENDSITE(msg->recv)->misses));
4195 RET(SENDSITE(msg->recv)->sender);
4202 defprim :selector_clear
4205 GUARD(SELECTOR_P(msg->recv));
4207 selector_clear(state, msg->recv);
4213 defprim :dtrace_fire_ruby_probe
4214 def dtrace_fire_ruby_probe
4224 if (RUBINIUS_RUBY_PROBE_ENABLED()) {
4225 RUBINIUS_RUBY_PROBE(rbx_string_as_cstr(state, t1), rbx_string_as_cstr(state, t2));
4233 defprim :allocate_table
4237 GUARD(CLASS_P(msg->recv));
4240 t1 = lookuptable_new(state);
4241 SET_CLASS(t1, msg->recv);
4246 defprim :lookuptable_store
4247 def lookuptable_store
4250 GUARD(LOOKUPTABLE_P(msg->recv));
4255 RET(lookuptable_store(state, msg->recv, t1, t2));
4259 defprim :lookuptable_fetch
4260 def lookuptable_fetch
4263 GUARD(LOOKUPTABLE_P(msg->recv));
4267 t2 = lookuptable_fetch(state, msg->recv, t1);
4268 RET(t2 == Qundef ? Qnil : t2);
4272 defprim :lookuptable_delete
4273 def lookuptable_delete
4276 GUARD(LOOKUPTABLE_P(msg->recv));
4280 t2 = lookuptable_delete(state, msg->recv, t1);
4281 RET(t2 == Qundef ? Qnil : t2);
4285 defprim :lookuptable_has_key
4286 def lookuptable_has_key
4289 GUARD(LOOKUPTABLE_P(msg->recv));
4293 RET(lookuptable_has_key(state, msg->recv, t1));
4297 defprim :lookuptable_keys
4298 def lookuptable_keys
4301 GUARD(LOOKUPTABLE_P(msg->recv));
4302 RET(lookuptable_keys(state, msg->recv));
4306 defprim :lookuptable_values
4307 def lookuptable_values
4310 GUARD(LOOKUPTABLE_P(msg->recv));
4311 RET(lookuptable_values(state, msg->recv));
4315 defprim :lookuptable_entries
4316 def lookuptable_entries
4319 GUARD(LOOKUPTABLE_P(msg->recv));
4320 RET(lookuptable_entries(state, msg->recv));
4324 defprim :lookuptable_dup
4328 GUARD(LOOKUPTABLE_P(msg->recv));
4329 RET(lookuptable_dup(state, msg->recv));
4333 defprim :allocate_module
4337 GUARD(CLASS_P(msg->recv));
4340 t1 = class_get_instance_fields(msg->recv);
4341 t2 = NEW_OBJECT(msg->recv, N2I(t1));
4342 module_setup_fields(state, t2);
4347 defprim :allocate_hash
4351 GUARD(CLASS_P(msg->recv));
4354 t1 = hash_new(state);
4355 SET_CLASS(t1, msg->recv);
4360 defprim :string_tr_expand
4361 def string_tr_expand
4364 GUARD(STRING_P(msg->recv));
4367 RET(string_tr_expand(state, msg->recv, t1));
4371 defprim :string_template
4375 GUARD(CLASS_P(msg->recv));
4382 t3 = string_new2(state, NULL, k);
4383 SET_CLASS(t3, msg->recv);
4384 t3->IsTainted = msg->recv->IsTainted;
4385 data = rbx_string_as_cstr(state, t3);
4389 memset(data, N2I(t2), k);
4390 } else if(STRING_P(t2)) {
4394 t3->IsTainted |= t2->IsTainted;
4395 bytes = N2I(string_get_bytes(t2));
4396 str = rbx_string_as_cstr(state, t2);
4398 memset(data, str[0], k);
4399 } else if(bytes > 1) {
4403 for(n = i = 0; i < size; i++) {
4404 for(j = 0; j < bytes; j++, n++) {
4408 for(i = n, j = 0; i < k; i++, j++) {
4419 defprim :string_apply_and
4420 def string_apply_and
4423 GUARD(STRING_P(msg->recv));
4425 native_int i, j, k, size;
4429 a = rbx_string_as_cstr(state, msg->recv);
4430 b = rbx_string_as_cstr(state, t1);
4431 j = N2I(string_get_bytes(msg->recv));
4432 k = N2I(string_get_bytes(t1));
4433 size = j < k ? j : k;
4435 for(i = 0; i < size; i++) {
4436 a[i] = a[i] && b[i];
4442 defprim :tuple_template
4446 GUARD(CLASS_P(msg->recv));
4453 t3 = tuple_new(state, k);
4454 for(i = 0; i < k; i++) {
4455 tuple_put(state, t3, i, t2);
4461 defprim :string_copy_from
4462 def string_copy_from
4465 GUARD(STRING_P(msg->recv));
4466 OBJECT t1, t2, t3, t4;
4467 native_int n, start, size, dest;
4479 if(start < 0) { start = 0; }
4480 n = N2I(string_get_bytes(t1));
4481 if(start >= n) { RET(msg->recv); }
4482 if(size > n - start) { size = n - start; }
4484 n = N2I(string_get_bytes(msg->recv));
4485 if(dest < 0) { dest = 0; }
4486 if(dest >= n) { RET(msg->recv); }
4487 if(size > n - dest) { size = n - dest; }
4489 a = rbx_string_as_cstr(state, msg->recv);
4490 b = rbx_string_as_cstr(state, t1);
4491 memcpy(a + dest, b + start, size);
4497 defprim :string_compare_substring
4498 def string_compare_substring
4501 GUARD(STRING_P(msg->recv));
4503 native_int bytes, start, size, cmp;
4513 bytes = N2I(string_get_bytes(t1));
4514 if(start < 0) { start = bytes + start; }
4515 if(start >= bytes || start < 0) { FAIL(); }
4516 if(start + size > bytes) { size = bytes - start; }
4518 bytes = N2I(string_get_bytes(msg->recv));
4519 if(size > bytes) { size = bytes; }
4521 a = rbx_string_as_cstr(state, msg->recv);
4522 b = rbx_string_as_cstr(state, t1);
4523 cmp = memcmp(a, b + start, size);
4526 } else if(cmp > 0) {
4534 defprim :io_close_ng
4540 GUARD(IO_P(msg->recv));
4542 j = io_to_fd(msg->recv);
4545 RAISE("IOError", "instance of IO already closed");
4546 } else if(close(j)) {
4547 RAISE_FROM_ERRNO("Unable to close IO object");
4549 cpu_event_clear(state, j);
4550 io_set_descriptor(msg->recv, I2N(-1));
4557 prim = ShotgunPrimitives.new
4558 prim.generate_select(STDOUT)