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);
2437 GUARD(FIXNUM_P(t2));
2441 GUARD(FIXNUM_P(t2));
2460 GUARD(FIXNUM_P(t2));
2461 fc->argcount = N2I(t2);
2467 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 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. */
2571 cpu_patch_ffi(state, msg);
2572 ffi_call(state, c, nfunc_get_data(msg->method));
2576 defprim :nfunc_call_object
2577 def nfunc_call_object
2579 /* The definition of beauty. Simplicity. To call a native function, there is no work
2580 to be done. The stub contains all the serialization code.
2582 That being said, this might get more complicated when callbacks are supported. */
2583 ffi_call(state, c, nfunc_get_data(msg->recv));
2591 OBJECT t1, t2, t3, t4;
2593 POP(t1, STRING_OR_NIL);
2597 RET(ffi_function_create(state, t1, t2, t3, t4));
2601 defprim :load_library
2609 RET(subtend_load_library(state, c, t1, t2));
2619 int flags = GLOB_NOSORT | GLOB_BRACE;
2628 pat = rbx_string_as_cstr(state, t1);
2629 k = glob(pat, flags, NULL, &gd);
2630 t2 = array_new(state, gd.gl_pathc);
2631 for(j = 0; j < gd.gl_pathc; j++) {
2632 array_set(state, t2, j, string_new(state, gd.gl_pathv[j]));
2648 path = rbx_string_as_cstr(state, t1);
2661 OBJECT t1 = stack_pop();
2662 *((OBJECT*)4) = t1; /* cause a SIGBUS */
2667 defprim :make_weak_ref
2674 RET(object_make_weak_ref(state, t1));
2678 defprim :gc_collect_references
2679 def gc_collect_references
2685 RET(object_memory_collect_references(state, state->om, t1));
2694 /* This is a little contrived so the dup'd task has
2695 it stack setup properly. */
2699 if(TASK_P(msg->recv)) {
2700 t1 = cpu_task_dup(state, c, msg->recv);
2702 t1 = cpu_task_dup(state, c, Qnil);
2705 cpu_stack_set_top(state, c, t1);
2709 defprim :task_set_current
2710 def task_set_current
2717 cpu_task_select(state, c, t1);
2721 defprim :task_associate
2727 GUARD(TASK_P(msg->recv));
2730 RET(cpu_task_associate(state, c, msg->recv, t1));
2734 defprim :task_current
2738 RET(c->current_task);
2746 struct cpu_task *task;
2750 GUARD(TASK_P(msg->recv));
2753 task = (struct cpu_task*)BYTES_OF(msg->recv);
2761 t2 = task->active_context;
2762 if(REFERENCE_P(t2)) methctx_reference(state, t2);
2772 defprim :task_set_debugging
2773 def task_set_debugging
2777 GUARD(TASK_P(msg->recv));
2782 GUARD(t1 == Qnil || CHANNEL_P(t1));
2783 GUARD(t2 == Qnil || CHANNEL_P(t2));
2785 if(msg->recv == c->current_task) {
2786 c->debug_channel = t1;
2787 c->control_channel = t2;
2789 cpu_task_set_debugging(state, msg->recv, t1, t2);
2795 defprim :task_debug_channel
2796 def task_debug_channel
2799 struct cpu_task *task;
2800 GUARD(TASK_P(msg->recv));
2802 task = (struct cpu_task*)BYTES_OF(msg->recv);
2804 RET(task->debug_channel);
2808 defprim :task_control_channel
2809 def task_control_channel
2812 struct cpu_task *task;
2813 GUARD(TASK_P(msg->recv));
2815 task = (struct cpu_task*)BYTES_OF(msg->recv);
2817 RET(task->control_channel);
2821 defprim :task_get_debug_context_change
2822 def task_get_debug_context_change
2825 struct cpu_task *task;
2826 GUARD(TASK_P(msg->recv));
2828 task = (struct cpu_task*)BYTES_OF(msg->recv);
2829 if(TASK_FLAG_P(task, TASK_DEBUG_ON_CTXT_CHANGE)) {
2837 defprim :task_set_debug_context_change
2838 def task_set_debug_context_change
2841 struct cpu_task *task;
2842 GUARD(TASK_P(msg->recv));
2843 OBJECT t1 = stack_pop();
2845 task = (struct cpu_task*)BYTES_OF(msg->recv);
2847 TASK_SET_FLAG(task, TASK_DEBUG_ON_CTXT_CHANGE);
2849 TASK_SET_FLAG(c, TASK_DEBUG_ON_CTXT_CHANGE);
2853 if(TASK_FLAG_P(task, TASK_DEBUG_ON_CTXT_CHANGE)) {
2854 TASK_CLEAR_FLAG(task, TASK_DEBUG_ON_CTXT_CHANGE);
2856 TASK_CLEAR_FLAG(c, TASK_DEBUG_ON_CTXT_CHANGE);
2864 defprim :task_stack_size
2868 struct cpu_task *task;
2869 GUARD(TASK_P(msg->recv));
2871 task = (struct cpu_task*)BYTES_OF(msg->recv);
2872 OBJECT t1 = I2N(task->sp_ptr - task->stack_top);
2878 defprim :task_get_stack_value
2879 def task_get_stack_value
2882 struct cpu_task *task;
2885 GUARD(TASK_P(msg->recv));
2888 task = (struct cpu_task*)BYTES_OF(msg->recv);
2890 GUARD(idx >=0 && idx < (task->sp_ptr - task->stack_top));
2892 t2 = *(task->sp_ptr - idx);
2903 GUARD(TASK_P(msg->recv));
2907 /* The return value */
2910 /* This is conditional because task_select can decide that it's not
2911 not possible to select this task, in which case it handles letting
2912 the user know this on it's own. */
2914 if(cpu_task_select(state, c, msg->recv)) {
2915 cpu_raise_exception(state, c, t1);
2920 defprim :thread_raise
2925 GUARD(THREAD_P(msg->recv));
2929 if(!cpu_thread_alive_p(state, msg->recv)) {
2933 /* The return value */
2936 cpu_thread_schedule(state, c->current_thread);
2937 cpu_thread_force_run(state, c, msg->recv);
2939 methctx_reference(state, c->active_context);
2940 exception_set_context(t1, c->active_context);
2942 cpu_raise_exception(state, c, t1);
2947 defprim :channel_new
2951 RET(cpu_channel_new(state));
2955 defprim :channel_send
2960 GUARD(CHANNEL_P(msg->recv));
2963 RET(cpu_channel_send(state, c, msg->recv, t1));
2967 defprim :channel_receive
2971 GUARD(CHANNEL_P(msg->recv));
2973 cpu_channel_receive(state, c, msg->recv, c->current_thread);
2974 /* Don't touch the stack as we may be in a different task at this
2975 point. The original task's stack is updated when the channel
2976 is written to and the task restored. */
2980 defprim :channel_send_in_microseconds
2981 def channel_send_in_microseconds
2985 OBJECT channel, usec_r, tag;
2988 POP(channel, CHANNEL);
2989 POP(usec_r, INTEGER);
2992 if(FIXNUM_P(usec_r)) {
2993 k = (long)N2I(usec_r);
2995 k = (long)bignum_to_int(state, usec_r);
2998 seconds = k / 1000000.0;
3000 RET(cpu_event_wake_channel(state, c, channel, seconds, tag));
3004 defprim :channel_send_in_seconds
3005 def channel_send_in_seconds
3009 OBJECT channel, seconds_r, tag;
3011 POP(channel, CHANNEL);
3012 POP(seconds_r, FLOAT);
3015 seconds = FLOAT_TO_DOUBLE(seconds_r);
3017 RET(cpu_event_wake_channel(state, c, channel, seconds, tag));
3021 defprim :channel_send_on_readable
3022 def channel_send_on_readable
3025 OBJECT t1, t2, t3, t4;
3033 GUARD(STRING_P(t2) || NIL_P(t2));
3034 GUARD(FIXNUM_P(t3) || NIL_P(t3));
3038 } else if(FIXNUM_P(t1)) {
3044 RET(cpu_event_wait_readable(state, c, t4, j, t2, N2I(t3)));
3048 defprim :channel_send_on_writable
3049 def channel_send_on_writable
3059 RET(cpu_event_wait_writable(state, c, t2, j));
3063 defprim :channel_send_on_signal
3064 def channel_send_on_signal
3072 RET(cpu_event_wait_signal(state, c, t2, N2I(t1)));
3076 defprim :channel_send_on_stopped
3077 def channel_send_on_stopped
3086 RET(cpu_event_wait_child(state, c, t3, N2I(t1), N2I(t2)));
3090 defprim :scheduler_cancel
3091 def scheduler_cancel
3097 RET(cpu_event_cancel_event(state, t1) ? Qtrue : Qfalse);
3105 RET(cpu_thread_new(state, c));
3113 GUARD(THREAD_P(msg->recv));
3115 GUARD(cpu_thread_alive_p(state, msg->recv));
3117 /* So when we're restored, there is a ret val. */
3119 cpu_thread_schedule(state, c->current_thread);
3120 cpu_thread_force_run(state, c, msg->recv);
3124 defprim :thread_schedule
3128 GUARD(THREAD_P(msg->recv));
3130 cpu_thread_schedule(state, msg->recv);
3135 defprim :thread_yield
3139 /* Same reason as thread_run */
3141 cpu_thread_schedule(state, c->current_thread);
3142 THDEBUG("%d: thread yield.\\n", getpid());
3143 cpu_thread_run_best(state, c);
3147 defprim :thread_dequeue
3151 THDEBUG("%d: dequeue thread.\\n", getpid());
3152 cpu_thread_exited(state, c);
3156 defprim :thread_current
3160 RET(c->current_thread);
3164 defprim :object_become
3168 void state_object_become(STATE, cpu c, OBJECT from, OBJECT to);
3173 state_object_become(state, c, t2, t1);
3178 defprim :sampler_activate
3179 def sampler_activate
3185 cpu_sampler_activate(state, N2I(t1));
3190 defprim :sampler_stop
3194 OBJECT t1 = cpu_sampler_disable(state);
3199 defprim :fork_process
3203 native_int k = fork();
3205 RAISE_FROM_ERRNO("Unable to fork");
3216 defprim :replace_process# aka execve().
3228 k = N2I(array_get_total(t2));
3229 argv = ALLOC_N(char*, k + 1);
3230 for(j = 0; j < k; j++) {
3231 t3 = array_get(state, t2, j);
3232 if(!ISA(t3, state->global->string)) {
3233 for(i = 0; i < j; i++) {
3240 tmp = rbx_string_as_cstr(state, t3);
3241 argv[j] = tmp ? strdup(tmp) : NULL;
3246 tmp = rbx_string_as_cstr(state, t1);
3247 file = tmp ? strdup(tmp) : NULL;
3249 cpu_task_disable_preemption(state);
3250 k = execvp(file, argv);
3252 /* If you're here, there was an error. */
3253 cpu_task_configure_preemption(state);
3254 RAISE_FROM_ERRNO("Unable to execute");
3265 RET(object_get_ivar(state, msg->recv, t1));
3276 object_set_ivar(state, msg->recv, t1, t2);
3285 RET(object_get_ivars(state, msg->recv));
3295 GUARD(STRING_P(msg->recv));
3297 RET(string_new(state, crypt(rbx_string_as_cstr(state, msg->recv),
3298 rbx_string_as_cstr(state, t1))));
3313 key = rbx_string_as_cstr(state, t1);
3315 char *value = getenv(key);
3318 t2 = string_new(state, value);
3336 key = rbx_string_as_cstr(state, t1);
3338 /* if t2 is nil, we need to delete the variable
3339 * and return its value.
3342 value = getenv(key);
3345 RET(string_new(state, value));
3350 GUARD(STRING_P(t2));
3351 value = rbx_string_as_cstr(state, t2);
3353 setenv(key, value, 1);
3363 defprim :env_as_hash
3367 char *cur, **total = environ;
3369 OBJECT hash = hash_new(state);
3378 while(*cur && *cur != '=') {
3382 OBJECT key = string_new2(state, name, i);
3383 OBJECT val = string_new(state, cur+1);
3385 hash_set(state, hash, key, val);
3392 defprim :bignum_size
3396 GUARD(BIGNUM_P(msg->recv));
3397 RET(bignum_size(state, msg->recv));
3401 defprim :iseq_compile
3405 GUARD(CMETHOD_P(msg->recv));
3406 cpu_compile_method(state, msg->recv);
3411 defprim :reset_method_cache
3412 def reset_method_cache
3417 cpu_clear_cache_for_method(state, c, t1, TRUE);
3421 defprim :bignum_from_float
3422 def bignum_from_float
3427 RET(bignum_from_double(state, FLOAT_TO_DOUBLE(t1)));
3431 defprim :save_encloser_path
3432 def save_encloser_path
3435 cpu_set_encloser_path(state, c, state->global->object);
3440 defprim :restore_encloser_path
3441 def restore_encloser_path
3444 cpu_push_encloser(state, c);
3455 GUARD(msg->args == 1);
3457 GUARD(FIXNUM_P(t1));
3459 j = N2I(array_get_total(msg->recv));
3465 if(k < 0 || k >= j) {
3466 stack_set_top(Qnil);
3468 k += N2I(array_get_start(msg->recv));
3469 t3 = array_get_tuple(msg->recv);
3470 GUARD(k < NUM_FIELDS(t3));
3472 stack_set_top(tuple_at(state, t3, k));
3483 GUARD(msg->args == 2);
3485 GUARD(FIXNUM_P(t1));
3487 j = N2I(array_get_total(msg->recv));
3494 array_set_total(msg->recv, I2N(k + 1));
3497 k += N2I(array_get_start(msg->recv));
3498 t3 = array_get_tuple(msg->recv);
3499 GUARD(k < NUM_FIELDS(t3));
3501 tuple_put(state, t3, k, stack_top());
3505 defprim :string_append
3510 GUARD(msg->args == 1);
3513 string_append(state, msg->recv, t1);
3522 RET(string_dup(state, msg->recv));
3526 defprim :string_equal
3535 if(msg->recv == t1) {
3538 t2 = string_get_bytes(msg->recv);
3539 t3 = string_get_bytes(t1);
3546 t2 = string_get_data(msg->recv);
3547 t3 = string_get_data(t1);
3549 m = memcmp(BYTEARRAY_ADDRESS(t2), BYTEARRAY_ADDRESS(t3), j < k ? j : k);
3550 RET(m == 0 ? Qtrue : Qfalse);
3556 defprim :object_send
3560 GUARD(msg->args >= 1);
3564 t1 = string_to_sym(state, t1);
3570 /* Send is allowed to call private methods. */
3573 cpu_send(state, c, msg->recv, t1, msg->args - 1, msg->block);
3577 defprim :machine_new
3584 OBJECT ret, ary, str;
3587 environment e = environment_current();
3591 argc = N2I(array_get_total(ary));
3592 argv = ALLOC_N(char*, argc);
3593 for(i = 0; i < argc; i++) {
3594 str = array_get(state, ary, i);
3596 argv[i] = strdup(rbx_string_as_cstr(state, str));
3598 argv[i] = strdup("");
3603 pipes = machine_setup_thread(m, argc, argv);
3605 m->parent_id = current_machine->id;
3607 ret = tuple_new(state, 4);
3608 tuple_put(state, ret, 0, I2N(m->id));
3609 tuple_put(state, ret, 1, io_new(state, pipes[0], "w"));
3610 tuple_put(state, ret, 2, io_new(state, pipes[1], "r"));
3611 tuple_put(state, ret, 3, io_new(state, pipes[2], "r"));
3614 environment_start_thread(e, m);
3620 defprim :machine_join
3626 if(environment_join_machine(environment_current(), N2I(t1))) {
3634 defprim :machine_get_message
3635 def machine_get_message
3638 RET(environment_get_message(environment_current(), current_machine->id));
3642 defprim :machine_send_message
3643 def machine_send_message
3650 environment_send_message(environment_current(), N2I(t1), t2);
3665 dir = opendir(rbx_string_as_cstr(state, t1));
3666 if(!dir) RAISE_FROM_ERRNO("Unable to open directory");
3668 RET(ffi_new_pointer(state, dir));
3681 dir = *DATA_STRUCT(t1, void**);
3683 *DATA_STRUCT(t1, void**) = NULL;
3692 defprim :dir_control
3699 DIR *dir = *DATA_STRUCT(t1, void**);
3706 seekdir(dir, N2I(pos));
3712 RET(I2N(telldir(dir)));
3726 DIR *dir = *DATA_STRUCT(t1, void**);
3732 RET(string_new(state, ent->d_name));
3738 defprim :opt_push_literal
3739 def opt_push_literal
3744 lits = cmethod_get_literals(msg->method);
3745 RET(fast_fetch(lits, 0));
3749 defprim :opt_push_self
3757 defprim :opt_push_ivar
3763 lits = cmethod_get_literals(msg->method);
3764 RET(object_get_ivar(state, msg->recv, fast_fetch(lits, 0)));
3768 defprim :opt_push_my_field
3769 def opt_push_my_field
3774 lits = cmethod_get_literals(msg->method);
3775 RET(NTH_FIELD(msg->recv, N2I(fast_fetch(lits, 0))));
3779 defprim :opt_kind_of
3786 GUARD(CLASS_P(t1) || MODULE_P(t1));
3788 RET(object_kind_of_p(state, msg->recv, t1) ? Qtrue : Qfalse);
3796 GUARD(FLOAT_P(msg->recv));
3797 double a = FLOAT_TO_DOUBLE(msg->recv);
3798 OBJECT t1 = stack_pop();
3800 t1 = float_coerce(state, t1);
3803 RET(float_new(state, a + FLOAT_TO_DOUBLE(t1)));
3811 GUARD(FLOAT_P(msg->recv));
3812 double a = FLOAT_TO_DOUBLE(msg->recv);
3813 OBJECT t1 = stack_pop();
3815 t1 = float_coerce(state, t1);
3818 RET(float_new(state, a - FLOAT_TO_DOUBLE(t1)));
3826 GUARD(FLOAT_P(msg->recv));
3827 double a = FLOAT_TO_DOUBLE(msg->recv);
3828 OBJECT t1 = stack_pop();
3830 t1 = float_coerce(state, t1);
3833 RET(float_new(state, a * FLOAT_TO_DOUBLE(t1)));
3841 GUARD(FLOAT_P(msg->recv));
3842 double a = FLOAT_TO_DOUBLE(msg->recv);
3843 OBJECT t1 = stack_pop();
3845 t1 = float_coerce(state, t1);
3848 RET(float_new(state, a / FLOAT_TO_DOUBLE(t1)));
3852 defprim :float_uminus
3856 GUARD(FLOAT_P(msg->recv));
3857 double a = FLOAT_TO_DOUBLE(msg->recv);
3858 RET(float_new(state, -a));
3862 defprim :float_equal
3866 GUARD(FLOAT_P(msg->recv));
3867 double a = FLOAT_TO_DOUBLE(msg->recv);
3868 OBJECT t1 = stack_pop();
3870 t1 = float_coerce(state, t1);
3873 RET(a == FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
3881 GUARD(FLOAT_P(msg->recv));
3882 OBJECT t1 = stack_pop();
3884 double a = FLOAT_TO_DOUBLE(msg->recv),
3885 b = FLOAT_TO_DOUBLE(t1);
3886 RET(a == b ? Qtrue : Qfalse);
3893 defprim :float_compare
3897 GUARD(FLOAT_P(msg->recv));
3898 double a = FLOAT_TO_DOUBLE(msg->recv);
3899 OBJECT t1 = stack_pop();
3901 t1 = float_coerce(state, t1);
3904 double b = FLOAT_TO_DOUBLE(t1);
3905 RET(float_compare(state, a, b));
3913 GUARD(FLOAT_P(msg->recv));
3914 double a = FLOAT_TO_DOUBLE(msg->recv);
3915 OBJECT t1 = stack_pop();
3917 t1 = float_coerce(state, t1);
3920 RET(a < FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
3928 GUARD(FLOAT_P(msg->recv));
3929 double a = FLOAT_TO_DOUBLE(msg->recv);
3930 OBJECT t1 = stack_pop();
3932 t1 = float_coerce(state, t1);
3935 RET(a <= FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
3943 GUARD(FLOAT_P(msg->recv));
3944 double a = FLOAT_TO_DOUBLE(msg->recv);
3945 OBJECT t1 = stack_pop();
3947 t1 = float_coerce(state, t1);
3950 RET(a > FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
3958 GUARD(FLOAT_P(msg->recv));
3959 double a = FLOAT_TO_DOUBLE(msg->recv);
3960 OBJECT t1 = stack_pop();
3962 t1 = float_coerce(state, t1);
3965 RET(a >= FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
3973 GUARD(FLOAT_P(msg->recv));
3974 double b = FLOAT_TO_DOUBLE(msg->recv);
3976 RAISE("FloatDomainError", b < 0 ? "-Infinity" : "Infinity");
3977 } else if(isnan(b)) {
3980 RET(bignum_from_double(state, float_truncate(b)));
3985 defprim :float_round
3989 GUARD(FLOAT_P(msg->recv));
3990 double value = FLOAT_TO_DOUBLE(msg->recv);
3991 if (value > 0.0) value = floor(value+0.5);
3992 if (value < 0.0) value = ceil(value-0.5);
3993 RET(bignum_from_double(state, value));
3997 defprim :float_divmod
4001 GUARD(FLOAT_P(msg->recv));
4002 double a = FLOAT_TO_DOUBLE(msg->recv);
4003 OBJECT t1 = stack_pop();
4005 t1 = float_coerce(state, t1);
4008 double b = FLOAT_TO_DOUBLE(t1);
4010 RAISE("FloatDomainError", "divide by 0");
4012 double div = floor(a / b);
4013 double mod = fmod(a, b);
4017 OBJECT ary = array_new(state, 2);
4018 array_set(state, ary, 0, bignum_from_double(state, float_truncate(div)));
4019 array_set(state, ary, 1, float_new(state, mod));
4029 GUARD(FLOAT_P(msg->recv));
4030 double a = FLOAT_TO_DOUBLE(msg->recv);
4031 OBJECT t1 = stack_pop();
4033 t1 = float_coerce(state, t1);
4036 RET(float_new(state, pow(a, FLOAT_TO_DOUBLE(t1))));
4040 defprim :float_isnan
4044 GUARD(FLOAT_P(msg->recv));
4045 RET(isnan(FLOAT_TO_DOUBLE(msg->recv)) == 1 ? Qtrue : Qfalse);
4049 defprim :float_isinf
4053 GUARD(FLOAT_P(msg->recv));
4054 double value = FLOAT_TO_DOUBLE(msg->recv);
4055 if(isinf(value) != 0) {
4056 RET(value < 0 ? I2N(-1) : I2N(1));
4067 GUARD(BIGNUM_P(msg->recv));
4068 OBJECT t1 = stack_pop();
4069 if(BIGNUM_P(t1) || FIXNUM_P(t1)) {
4070 RET(bignum_gt(state, msg->recv, t1));
4071 } else if(FLOAT_P(t1)) {
4072 double a = bignum_to_double(state, msg->recv);
4073 RET(a > FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
4084 GUARD(BIGNUM_P(msg->recv));
4085 OBJECT t1 = stack_pop();
4086 if(BIGNUM_P(t1) || FIXNUM_P(t1)) {
4087 RET(bignum_ge(state, msg->recv, t1));
4088 } else if(FLOAT_P(t1)) {
4089 double a = bignum_to_double(state, msg->recv);
4090 RET(a >= FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
4101 GUARD(BIGNUM_P(msg->recv));
4102 OBJECT t1 = stack_pop();
4103 if(BIGNUM_P(t1) || FIXNUM_P(t1)) {
4104 RET(bignum_lt(state, msg->recv, t1));
4105 } else if(FLOAT_P(t1)) {
4106 double a = bignum_to_double(state, msg->recv);
4107 RET(a < FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
4118 GUARD(BIGNUM_P(msg->recv));
4119 OBJECT t1 = stack_pop();
4120 if(BIGNUM_P(t1) || FIXNUM_P(t1)) {
4121 RET(bignum_le(state, msg->recv, t1));
4122 } else if(FLOAT_P(t1)) {
4123 double a = bignum_to_double(state, msg->recv);
4124 RET(a <= FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
4131 defprim :sendsite_create
4137 GUARD(CLASS_P(msg->recv));
4140 ss = send_site_create(state, t1);
4145 defprim :sendsite_set_sender
4146 def sendsite_set_sender
4151 GUARD(SENDSITE_P(msg->recv));
4154 send_site_set_sender(state, msg->recv, cm);
4159 defprim :sendsite_at
4165 GUARD(SENDSITE_P(msg->recv));
4170 RET(SENDSITE(msg->recv)->name);
4172 RET(SENDSITE(msg->recv)->selector);
4174 RET(SENDSITE(msg->recv)->data1);
4176 RET(SENDSITE(msg->recv)->data2);
4178 RET(SENDSITE(msg->recv)->data3);
4180 RET(ffi_new_pointer(state, SENDSITE(msg->recv)->c_data));
4182 RET(I2N(SENDSITE(msg->recv)->hits));
4184 RET(I2N(SENDSITE(msg->recv)->misses));
4186 RET(SENDSITE(msg->recv)->sender);
4193 defprim :selector_clear
4196 GUARD(SELECTOR_P(msg->recv));
4198 selector_clear(state, msg->recv);
4204 defprim :dtrace_fire_ruby_probe
4205 def dtrace_fire_ruby_probe
4215 if (RUBINIUS_RUBY_PROBE_ENABLED()) {
4216 RUBINIUS_RUBY_PROBE(rbx_string_as_cstr(state, t1), rbx_string_as_cstr(state, t2));
4224 defprim :allocate_table
4228 GUARD(CLASS_P(msg->recv));
4231 t1 = lookuptable_new(state);
4232 SET_CLASS(t1, msg->recv);
4237 defprim :lookuptable_store
4238 def lookuptable_store
4241 GUARD(LOOKUPTABLE_P(msg->recv));
4246 RET(lookuptable_store(state, msg->recv, t1, t2));
4250 defprim :lookuptable_fetch
4251 def lookuptable_fetch
4254 GUARD(LOOKUPTABLE_P(msg->recv));
4258 t2 = lookuptable_fetch(state, msg->recv, t1);
4259 RET(t2 == Qundef ? Qnil : t2);
4263 defprim :lookuptable_delete
4264 def lookuptable_delete
4267 GUARD(LOOKUPTABLE_P(msg->recv));
4271 t2 = lookuptable_delete(state, msg->recv, t1);
4272 RET(t2 == Qundef ? Qnil : t2);
4276 defprim :lookuptable_has_key
4277 def lookuptable_has_key
4280 GUARD(LOOKUPTABLE_P(msg->recv));
4284 RET(lookuptable_has_key(state, msg->recv, t1));
4288 defprim :lookuptable_keys
4289 def lookuptable_keys
4292 GUARD(LOOKUPTABLE_P(msg->recv));
4293 RET(lookuptable_keys(state, msg->recv));
4297 defprim :lookuptable_values
4298 def lookuptable_values
4301 GUARD(LOOKUPTABLE_P(msg->recv));
4302 RET(lookuptable_values(state, msg->recv));
4306 defprim :lookuptable_entries
4307 def lookuptable_entries
4310 GUARD(LOOKUPTABLE_P(msg->recv));
4311 RET(lookuptable_entries(state, msg->recv));
4315 defprim :lookuptable_dup
4319 GUARD(LOOKUPTABLE_P(msg->recv));
4320 RET(lookuptable_dup(state, msg->recv));
4324 defprim :allocate_module
4328 GUARD(CLASS_P(msg->recv));
4331 t1 = class_get_instance_fields(msg->recv);
4332 t2 = NEW_OBJECT(msg->recv, N2I(t1));
4333 module_setup_fields(state, t2);
4338 defprim :allocate_hash
4342 GUARD(CLASS_P(msg->recv));
4345 t1 = hash_new(state);
4346 SET_CLASS(t1, msg->recv);
4351 defprim :string_tr_expand
4352 def string_tr_expand
4355 GUARD(STRING_P(msg->recv));
4358 RET(string_tr_expand(state, msg->recv, t1));
4362 defprim :string_template
4366 GUARD(CLASS_P(msg->recv));
4373 t3 = string_new2(state, NULL, k);
4374 SET_CLASS(t3, msg->recv);
4375 t3->IsTainted = msg->recv->IsTainted;
4376 data = rbx_string_as_cstr(state, t3);
4380 memset(data, N2I(t2), k);
4381 } else if(STRING_P(t2)) {
4385 t3->IsTainted |= t2->IsTainted;
4386 bytes = N2I(string_get_bytes(t2));
4387 str = rbx_string_as_cstr(state, t2);
4389 memset(data, str[0], k);
4390 } else if(bytes > 1) {
4394 for(n = i = 0; i < size; i++) {
4395 for(j = 0; j < bytes; j++, n++) {
4399 for(i = n, j = 0; i < k; i++, j++) {
4410 defprim :string_apply_and
4411 def string_apply_and
4414 GUARD(STRING_P(msg->recv));
4416 native_int i, j, k, size;
4420 a = rbx_string_as_cstr(state, msg->recv);
4421 b = rbx_string_as_cstr(state, t1);
4422 j = N2I(string_get_bytes(msg->recv));
4423 k = N2I(string_get_bytes(t1));
4424 size = j < k ? j : k;
4426 for(i = 0; i < size; i++) {
4427 a[i] = a[i] && b[i];
4433 defprim :tuple_template
4437 GUARD(CLASS_P(msg->recv));
4444 t3 = tuple_new(state, k);
4445 for(i = 0; i < k; i++) {
4446 tuple_put(state, t3, i, t2);
4452 defprim :string_copy_from
4453 def string_copy_from
4456 GUARD(STRING_P(msg->recv));
4457 OBJECT t1, t2, t3, t4;
4458 native_int n, start, size, dest;
4470 if(start < 0) { start = 0; }
4471 n = N2I(string_get_bytes(t1));
4472 if(start >= n) { RET(msg->recv); }
4473 if(size > n - start) { size = n - start; }
4475 n = N2I(string_get_bytes(msg->recv));
4476 if(dest < 0) { dest = 0; }
4477 if(dest >= n) { RET(msg->recv); }
4478 if(size > n - dest) { size = n - dest; }
4480 a = rbx_string_as_cstr(state, msg->recv);
4481 b = rbx_string_as_cstr(state, t1);
4482 memcpy(a + dest, b + start, size);
4488 defprim :string_compare_substring
4489 def string_compare_substring
4492 GUARD(STRING_P(msg->recv));
4494 native_int bytes, start, size, cmp;
4504 bytes = N2I(string_get_bytes(t1));
4505 if(start < 0) { start = bytes + start; }
4506 if(start >= bytes || start < 0) { FAIL(); }
4507 if(start + size > bytes) { size = bytes - start; }
4509 bytes = N2I(string_get_bytes(msg->recv));
4510 if(size > bytes) { size = bytes; }
4512 a = rbx_string_as_cstr(state, msg->recv);
4513 b = rbx_string_as_cstr(state, t1);
4514 cmp = memcmp(a, b + start, size);
4517 } else if(cmp > 0) {
4525 defprim :io_close_ng
4531 GUARD(IO_P(msg->recv));
4533 j = io_to_fd(msg->recv);
4536 RAISE("IOError", "instance of IO already closed");
4537 } else if(close(j)) {
4538 RAISE_FROM_ERRNO("Unable to close IO object");
4540 cpu_event_clear(state, j);
4541 io_set_descriptor(msg->recv, I2N(-1));
4548 prim = ShotgunPrimitives.new
4549 prim.generate_select(STDOUT)