Change soft-fail to use the config, rather than env
[rbx.git] / shotgun / lib / primitives.rb
blob461dfcf3f8a7d0d653afa1045c01d0f0722aa11b
1 class ShotgunPrimitives
2   @@primitives = []
4   def self.defprim(symbol)
5     @@primitives << symbol
6   end
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)
15         f.puts "  DONE();\n}"
16       end
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},"
23       end
25       f.puts "  };"
26       f.puts "  return funcs[index];"
27       f.puts "}"
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}));"
34       end
35       f.puts "return tbl;}"
36     end
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);"
44       fd.puts "  break;\n}"
45     end
47     fd.puts "default:"
48     fd.puts '  printf("Error: Primitive index out of range for this VM (%d)\n", prim);'
49     fd.puts "  sassert(0);"
50     fd.puts "}"
51     fd.puts
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}"
56       end
57     end
59     File.open("primitive_util.h", "w") do |f|
60       size = primitives.size
61       f.puts "struct prim2index { const char *name; int index; };"
62       f.puts
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} },!
68       end
70       f.puts "    { NULL, 0 } };"
71       f.puts <<-CODE.gsub(/^\s{6}/,'')
72         int i;
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;
76         }
78         printf("Unknown primitive %s\\n", target);
80         return -1;
81       }
82       CODE
84     end
86   end
88   defprim :add
89   def add
90     <<-CODE
91     ARITY(1);
92     GUARD(FIXNUM_P(msg->recv));
93     OBJECT t1 = stack_pop();
94     if(FIXNUM_P(t1)) {
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)));
101     } else {
102       FAIL();
103     }
104     CODE
105   end
107   defprim :bignum_add
108   def bignum_add
109     <<-CODE
110     ARITY(1);
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)));
118     } else {
119       FAIL();
120     }
121     CODE
122   end
124   defprim :sub
125   def sub
126     <<-CODE
127     ARITY(1);
128     GUARD(FIXNUM_P(msg->recv));
129     OBJECT t1 = stack_pop();
130     if(FIXNUM_P(t1)) {
131       RET(fixnum_sub(state, msg->recv, t1));
132     } else if(BIGNUM_P(t1)) {
133       OBJECT res = bignum_sub(state, t1, msg->recv);
134       if(FIXNUM_P(res)) {
135         res = I2N(-N2I(res));
136       } else {
137         res = bignum_neg(state, res);
138       }
139       RET(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)));
143     } else {
144       FAIL();
145     }
146     CODE
147   end
149   defprim :bignum_sub
150   def bignum_sub
151     <<-CODE
152     ARITY(1);
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)));
160     } else {
161       FAIL();
162     }
163     CODE
164   end
166   defprim :fixnum_mul
167   def fixnum_mul
168     <<-CODE
169     ARITY(1);
170     GUARD(FIXNUM_P(msg->recv));
171     OBJECT t1 = stack_pop();
172     if(FIXNUM_P(t1)) {
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)));
179     } else {
180       FAIL();
181     }
182     CODE
183   end
185   defprim :fixnum_size
186   def fixnum_size
187     <<-CODE
188     ARITY(0);
189     RET(I2N(sizeof(native_int)));
190     CODE
191   end
193   defprim :bignum_mul
194   def bignum_mul
195     <<-CODE
196     ARITY(1);
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)));
204     } else {
205       FAIL();
206     }
207     CODE
208   end
210   defprim :fixnum_div
211   def fixnum_div
212     <<-CODE
213     ARITY(1);
214     GUARD(FIXNUM_P(msg->recv));
215     OBJECT t1 = stack_pop();
216     if(FIXNUM_P(t1)) {
217       native_int mod;
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)));
226     } else {
227       FAIL();
228     }
229     CODE
230   end
232   defprim :bignum_div
233   def bignum_div
234     <<-CODE
235     ARITY(1);
236     GUARD(BIGNUM_P(msg->recv));
237     OBJECT t1 = stack_pop();
238     if(BIGNUM_P(t1)) {
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)));
247     } else {
248       FAIL();
249     }
250     CODE
251   end
253   defprim :bignum_mod
254   def bignum_mod
255     <<-CODE
256     ARITY(1);
257     OBJECT t1;
259     GUARD(BIGNUM_P(msg->recv));
260     POP(t1, INTEGER);
262     RET(bignum_mod(state, msg->recv, t1));
263     CODE
264   end
266   defprim :equal
267   def equal
268     <<-CODE
269     ARITY(1);
270     GUARD(FIXNUM_P(msg->recv));
271     OBJECT t1 = stack_pop();
273     if(FIXNUM_P(t1)) {
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);
280     } else {
281       FAIL();
282     }
283     CODE
284   end
286   defprim :object_equal
287   def object_equal
288     <<-CODE
289     ARITY(1);
290     OBJECT t1;
291     t1 = stack_pop();
293     if(msg->recv == t1) {
294       RET(Qtrue);
295     } else {
296       RET(Qfalse);
297     }
298     CODE
299   end
301   defprim :bignum_equal
302   def bignum_equal
303     <<-CODE
304     ARITY(1);
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);
312     } else {
313       FAIL();
314     }
315     CODE
316   end
318   defprim :compare
319   def compare
320     <<-CODE
321     ARITY(1);
322     GUARD(FIXNUM_P(msg->recv));
323     OBJECT t1 = stack_pop();
325     if(FIXNUM_P(t1)) {
326       if(msg->recv == t1) {
327         RET(I2N(0));
328       } else {
329         native_int j = N2I(msg->recv);
330         native_int k = N2I(t1);
332         if (j < k) {
333           RET(I2N(-1));
334         } else if (j > k) {
335           RET(I2N(1));
336         } else {
337           /* We shouldn't be here! */
338           FAIL();
339         }
340       }
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)));
347     } else {
348       FAIL();
349     }
350     CODE
351   end
353   defprim :fixnum_lt
354   def fixnum_lt
355     <<-CODE
356     ARITY(1);
357     GUARD(FIXNUM_P(msg->recv));
358     OBJECT t2 = stack_pop();
360     if(FIXNUM_P(t2)) {
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);
369     } else {
370       FAIL();
371     }
372     CODE
373   end
375   defprim :fixnum_le
376   def fixnum_le
377     <<-CODE
378     ARITY(1);
379     GUARD(FIXNUM_P(msg->recv));
380     OBJECT t2 = stack_pop();
382     if(FIXNUM_P(t2)) {
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);
391     } else {
392       FAIL();
393     }
394     CODE
395   end
397   defprim :fixnum_gt
398   def fixnum_gt
399     <<-CODE
400     ARITY(1);
401     GUARD(FIXNUM_P(msg->recv));
402     OBJECT t2 = stack_pop();
404     if(FIXNUM_P(t2)) {
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);
413     } else {
414       FAIL();
415     }
416     CODE
417   end
419   defprim :fixnum_ge
420   def fixnum_ge
421     <<-CODE
422     ARITY(1);
423     GUARD(FIXNUM_P(msg->recv));
424     OBJECT t2 = stack_pop();
426     if(FIXNUM_P(t2)) {
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);
435     } else {
436       FAIL();
437     }
438     CODE
439   end
442   defprim :at
443   def at
444     <<-CODE
445     ARITY(1);
446     OBJECT t1;
448     GUARD(INDEXED(msg->recv));
449     POP(t1, FIXNUM);
451     native_int j = N2I(t1);
453     GUARD(j >= 0 && j < NUM_FIELDS(msg->recv));
455     RET(NTH_FIELD(msg->recv, j));
456     CODE
457   end
459   defprim :put
460   def put
461     <<-CODE
462     ARITY(2);
463     OBJECT t1, t2;
465     GUARD(INDEXED(msg->recv));
466     POP(t1, FIXNUM);
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);
473     RET(t2);
474     CODE
475   end
477   defprim :fields
478   def fields
479     <<-CODE
480     ARITY(0);
481     GUARD(REFERENCE_P(msg->recv));
483     RET(I2N(NUM_FIELDS(msg->recv)));
484     CODE
485   end
487   defprim :allocate
488   def allocate
489     <<-CODE
490     ARITY(0);
491     OBJECT t1, t2;
493     GUARD(CLASS_P(msg->recv));
495     t1 = class_get_instance_fields(msg->recv);
497     t2 = NEW_OBJECT(msg->recv, N2I(t1));
498     RET(t2);
499     CODE
500   end
502   defprim :allocate_count
503   def allocate_count
504     <<-CODE
505     ARITY(1);
506     OBJECT t1, t2;
508     GUARD(CLASS_P(msg->recv));
509     POP(t1, FIXNUM);
511     t2 = NEW_OBJECT(msg->recv, N2I(t1));
512     RET(t2);
513     CODE
514   end
516   defprim :allocate_bytes
517   def allocate_bytes
518     <<-CODE
519     ARITY(1);
520     OBJECT t1, t2;
522     GUARD(CLASS_P(msg->recv));
524     POP(t1, FIXNUM);
526     t2 = bytearray_new(state, N2I(t1));
527     t2->klass = msg->recv;
529     RET(t2);
530     CODE
531   end
533   defprim :io_seek
534   def io_seek
535     <<-CODE
536       ARITY(2);
537       OBJECT t1, t2;
538       native_int j;
539       off_t position;
541       GUARD(IO_P(msg->recv));
543       POP(t1, INTEGER); /* offset */
544       POP(t2, FIXNUM); /* whence */
546       j = io_to_fd(msg->recv);
548       if (FIXNUM_P(t1)) {
549         position = lseek(j, N2I(t1), N2I(t2));
550       } else {
551         position = lseek(j, bignum_to_ll(state, t1), N2I(t2));
552       }
554       if (position == -1) {
555         RAISE_FROM_ERRNO("Unable to seek");
556         return TRUE;
557       } else {
558         RET(I2N(position));
559       }
560     CODE
561   end
563   defprim :block_given
564   def block_given
565     <<-CODE
566     ARITY(0)
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)) ) {
571       RET(Qtrue);
572     } else {
573       RET(Qfalse);
574     }
575     CODE
576   end
578   defprim :block_call
579   def block_call
580     <<-CODE
581     GUARD(BLOCKENV_P(msg->recv));
583     blokenv_call(state, c, msg->recv, msg->args);
584     CODE
585   end
587   defprim :io_write
588   def io_write
589     <<-CODE
590     ARITY(1);
591     OBJECT t1, t2;
593     GUARD(IO_P(msg->recv));
594     POP(t1, STRING);
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);
601     if (k == -1) {
602       RAISE_FROM_ERRNO("Unable to write");
603     }
605     t2 = I2N(k);
606     if(k != N2I(t2)) {
607       t2 = bignum_new(state, k);
608     }
610     RET(t2);
611     CODE
612   end
614   defprim :io_read
615   def io_read
616     <<-CODE
617     ARITY(1);
618     OBJECT t1, t2, t3;
619     native_int j, k;
621     GUARD(IO_P(msg->recv));
623     POP(t1, FIXNUM);
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));
628     if(k == 0) {
629       t2 = Qnil;
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);
633       t2 = t3;
634     }
636     RET(t2);
637     CODE
638   end
640   defprim :create_pipe
641   def create_pipe
642     <<-CODE
643     ARITY(2);
644     OBJECT t1, t2;
645     int j;
646     int fds[2];
648     POP(t1, IO);
649     POP(t2, IO);
651     j = pipe(fds);
652     if(!j) {
653       io_wrap(state, t1, fds[0], "r");
654       io_wrap(state, t2, fds[1], "w");
655     }
657     RET(I2N(j));
658     CODE
659   end
661   defprim :io_open
662   def io_open
663     <<-CODE
664     ARITY(3);
665     int fd, mode, perm;
666     char *_path;
667     OBJECT t1, t2, t3;
669     POP(t1, STRING);
670     POP(t2, FIXNUM);
671     POP(t3, FIXNUM);
673     _path = rbx_string_as_cstr(state, t1);
674     mode = N2I(t2);
675     perm = N2I(t3);
677     fd = open(_path, mode, perm);
679     RET(I2N(fd));
680     CODE
681   end
683   defprim :io_reopen
684   def io_reopen
685     <<-CODE
686     ARITY(1);
687     OBJECT t1;
688     native_int j, k;
690     GUARD(IO_P(msg->recv));
691     POP(t1, IO);
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);
697     j = io_to_fd(t1);
699     /* Probably needs an fflush here. */
700     if(dup2(j, k) == -1) {
701       RAISE_FROM_ERRNO("Unable to reopen IO object");
702     } else {
703       RET(Qtrue);
704     }
706     CODE
707   end
709   defprim :io_operation
710   def io_operation
711     <<-CODE
712     ARITY(1);
713     OBJECT t1;
714     native_int k, j;
716     GUARD(IO_P(msg->recv));
717     POP(t1, FIXNUM);
719     j = io_to_fd(msg->recv);
720     GUARD(j >= 0);
722     k = N2I(t1);
723     switch(k) {
724       case 0:
725         if(isatty(j)) {
726           RET(Qtrue);
727         } else {
728           RET(Qfalse);
729         }
730         break;
731       case 1:
732         RET(string_new(state, ttyname(j)));
733         break;
734       default:
735         RET(Qnil);
736     }
737     CODE
738   end
740   defprim :file_unlink
741   def file_unlink
742     <<-CODE
743     ARITY(1);
744     OBJECT t1;
745     char *name;
747     POP(t1, STRING);
749     name = rbx_string_as_cstr(state, t1);
750     if(unlink(name) == 0) {
751       RET(Qtrue);
752     } else {
753       /* TODO translate errno into an exception. */
754       RET(Qfalse);
755     }
756     CODE
757   end
759   defprim :gettimeofday
760   def gettimeofday
761     <<-CODE
762     ARITY(0);
763     OBJECT t1;
764     struct timeval tv;
766     /* don't fill in the 2nd argument here. getting the timezone here
767      * this way is not portable and broken anyway.
768      */
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));
776     RET(t1);
777     CODE
778   end
780   defprim :strftime
781   def strftime
782     <<-CODE
783     ARITY(2);
784     OBJECT t1, t2, t3;
786     GUARD(REFERENCE_P(msg->recv));
787     POP(t1, ARRAY);
788     POP(t2, STRING);
790     struct tm tm;
791     char *format = NULL;
792     char str[MAX_STRFTIME_OUTPUT+1];
793     size_t out;
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));
807 #endif
809 #ifdef HAVE_STRUCT_TM_TM_ZONE
810     tm.tm_zone = rbx_string_as_cstr(state, array_get(state, t1, 10));
811 #endif
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);
819     RET(t3);
820     CODE
821   end
823   defprim :time_switch
824   def time_switch
825     <<-CODE
826     ARITY(2);
827     time_t seconds;
828     struct tm *tm;
829     OBJECT t1, t2, t3;
831     GUARD(REFERENCE_P(msg->recv));
833     POP(t1, INTEGER);
834     t2 = stack_pop();
836     if(FIXNUM_P(t1)) {
837       seconds = N2I(t1);
838     } else {
839       seconds = bignum_to_ll(state, t1);
840     }
842     if(t2 == Qtrue) {
843       tm = gmtime(&seconds);
844     } else {
845       tm = localtime(&seconds);
846     }
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));
862 #else
863     array_set(state, t3, 9, Qnil);
864 #endif
866 #ifdef HAVE_STRUCT_TM_TM_ZONE
867     array_set(state, t3, 10, string_new(state, tm->tm_zone));
868 #else
869     array_set(state, t3, 10, Qnil);
870 #endif
872     RET(t3);
873     CODE
874   end
876   defprim :mktime
877   def mktime
878     <<-CODE
879     ARITY(9);
880     time_t seconds;
881     struct tm tm;
882     char *old_tz, old_tz_buf[128];
883     OBJECT t1, t2, t3, t4, t5, t6, t7, t8, t9, ret;
885     old_tz = NULL;
887     GUARD(REFERENCE_P(msg->recv));
889     POP(t1, FIXNUM);
890     POP(t2, FIXNUM);
891     POP(t3, FIXNUM);
892     POP(t4, FIXNUM);
893     POP(t5, FIXNUM);
894     POP(t6, FIXNUM);
895     POP(t7, FIXNUM);
896     POP(t8, FIXNUM);
897     t9 = stack_pop();
899     tm.tm_sec = N2I(t1);
900     GUARD(tm.tm_sec >= 0 && tm.tm_sec <= 60);
902     tm.tm_min = N2I(t2);
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
920      * out itmsg->recv.
921      */
922     tm.tm_isdst = -1;
924     if(t9 == Qtrue) {
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.
929        */
930       if(old_tz) {
931         strncpy(old_tz_buf, old_tz, sizeof(old_tz_buf));
932         old_tz_buf[sizeof(old_tz_buf) - 1] = 0;
933       }
935       setenv("TZ", "", 1);
936     }
938     seconds = mktime(&tm);
940     if(t9 == Qtrue) {
941       if(old_tz) {
942         setenv("TZ", old_tz_buf, 1);
943       } else {
944         unsetenv("TZ");
945       }
946     }
948     ret = array_new(state, 2);
949     array_set(state, ret, 0, ML2N(seconds));
950     array_set(state, ret, 1, t7);
952     RET(ret);
953     CODE
954   end
956   defprim :fixnum_to_s
957   def fixnum_to_s
958     <<-CODE
959     ARITY(1);
960     OBJECT t1;
961     static const char digitmap[] = "0123456789abcdefghijklmnopqrstuvwxyz";
962     char buf[100];
963     char *b = buf + sizeof(buf);
964     native_int j, k, m;
966     GUARD(FIXNUM_P(msg->recv));
967     POP(t1, FIXNUM);
969     j = N2I(t1);
970     k = N2I(msg->recv);
971     GUARD( j >= 2 && j <= 36 );
973     /* Algorithm taken from 1.8.4 rb_fix2str */
974     if(k == 0) {
975       RET(string_new(state, "0"));
976     } else {
977       m = 0;
978       if(k < 0) {
979         k = -k;
980         m = 1;
981       }
982       *--b = '\\0';
983       do {
984         *--b = digitmap[(int)(k % j)];
985       } while(k /= j);
986       if(m) {
987         *--b = '-';
988       }
989       RET(string_new(state, b));
990     }
991     CODE
992   end
994   defprim :bignum_to_s
995   def bignum_to_s
996     <<-CODE
997     ARITY(1);
998     OBJECT t1;
999     GUARD(BIGNUM_P(msg->recv));
1000     POP(t1, FIXNUM);
1002     RET(bignum_to_s(state, msg->recv, t1));
1003     CODE
1004   end
1006   defprim :logical_class
1007   def logical_class
1008     <<-CODE
1009     ARITY(0);
1010     /* msg->recv is ANY object because object_class knows all. */
1011     RET(object_class(state, msg->recv));
1012     CODE
1013   end
1015   defprim :object_id
1016   def object_id
1017     <<-CODE
1018     ARITY(0);
1019     RET(UI2N(object_get_id(state, msg->recv)));
1020     CODE
1021   end
1023   defprim :hash_set
1024   def hash_set
1025     <<-CODE
1026     ARITY(3);
1027     OBJECT t1, t2, t3;
1028     GUARD(HASH_P(msg->recv));
1030     POP(t1, FIXNUM);
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);
1035     RET(t3);
1036     CODE
1037   end
1039   defprim :hash_get
1040   def hash_get
1041     <<-CODE
1042     ARITY(2);
1043     OBJECT t1, t2, t3;
1044     GUARD(HASH_P(msg->recv));
1046     POP(t1, FIXNUM);
1047     t2 = stack_pop();
1048     t3 = hash_find_entry(state, msg->recv, N2I(t1));
1049     RET(t3);
1050     CODE
1051   end
1053   defprim :hash_redistribute
1054   def hash_redistribute
1055     <<-CODE
1056     ARITY(0);
1057     GUARD(HASH_P(msg->recv));
1059     if(hash_redistribute_p(msg->recv)) {
1060       hash_redistribute(state, msg->recv);
1061     }
1062     RET(msg->recv);
1063     CODE
1064   end
1066   defprim :hash_object
1067   def hash_object
1068     <<-CODE
1069     ARITY(0);
1070     OBJECT t1;
1071     /* msg->recv is ANY object because object_class knows all. */
1072     t1 = UI2N(object_hash_int(state, msg->recv));
1073     RET(t1);
1074     CODE
1075   end
1077   defprim :hash_delete
1078   def hash_delete
1079     <<-CODE
1080     ARITY(1);
1081     OBJECT t1, t2;
1082     GUARD(HASH_P(msg->recv));
1084     POP(t1, FIXNUM);
1086     t2 = hash_delete(state, msg->recv, N2I(t1));
1087     RET(t2);
1088     CODE
1089   end
1091   defprim :hash_value_set
1092   def hash_value_set
1093     <<-CODE
1094     OBJECT t1;
1095     GUARD(REFERENCE_P(msg->recv));
1097     POP(t1, NUMERIC);
1098     abort();
1099     CODE
1100   end
1102   defprim :symbol_index
1103   def symbol_index
1104     <<-CODE
1105     ARITY(0);
1106     GUARD(SYMBOL_P(msg->recv));
1108     RET(I2N(symbol_to_index(state, msg->recv)));
1109     CODE
1110   end
1112   defprim :symbol_lookup
1113   def symbol_lookup
1114     <<-CODE
1115     ARITY(0);
1116     GUARD(STRING_P(msg->recv));
1117     GUARD(N2I(string_get_bytes(msg->recv)) > 0);
1118     RET(string_to_sym(state, msg->recv));
1119     CODE
1120   end
1122   defprim :dup_into
1123   def dup_into
1124     <<-CODE
1125     ARITY(3);
1126     OBJECT t1, t2, t3;
1127     native_int k, j;
1129     GUARD(REFERENCE_P(msg->recv));
1131     POP(t1, REFERENCE);
1132     POP(t2, FIXNUM);
1133     POP(t3, FIXNUM);
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);
1139         k++, j++) {
1140       SET_FIELD(msg->recv, j, NTH_FIELD(t1, k));
1141     }
1143     object_copy_nongc_flags(msg->recv, t1);
1145     RET(t1);
1146     CODE
1147   end
1149   defprim :bytes_dup_into
1150   def bytes_dup_into
1151     <<-CODE
1152     ARITY(1);
1153     OBJECT t1;
1154     native_int k, j;
1156     GUARD(REFERENCE_P(msg->recv));
1158     POP(t1,   REFERENCE);
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);
1171     RET(t1);
1172     CODE
1173   end
1175   defprim :object_dup
1176   def object_dup
1177     <<-CODE
1178     ARITY(0);
1179     OBJECT t2;
1180     native_int j, 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;
1189       } else {
1190         for(k = 0; k < j; k++) {
1191           SET_FIELD(t2, k, NTH_FIELD(msg->recv, k));
1192         }
1193       }
1195       if (object_tainted_p(state, msg->recv)) {
1196         object_set_tainted(state, t2);
1197       }
1199       stack_push(t2);
1200       object_copy_ivars(state, msg->recv, t2);
1201       cpu_perform_hook(state, c, t2, state->global->sym_init_copy, msg->recv);
1202       DONE();
1203     } else {
1204       RET(msg->recv);
1205     }
1206     CODE
1207   end
1209   defprim :object_clone
1210   def object_clone
1211     <<-CODE
1212     ARITY(0);
1213     native_int k, j;
1214     OBJECT t2;
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;
1224     } else {
1225       for(k = 0; k < j; k++) {
1226         SET_FIELD(t2, k, NTH_FIELD(msg->recv, k));
1227       }
1228     }
1230     if (object_tainted_p(state, msg->recv)) {
1231       object_set_tainted(state, t2);
1232     }
1234     stack_push(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);
1238     DONE();
1239     CODE
1240   end
1243   defprim :fastctx_dup
1244   def fastctx_dup
1245     <<-CODE
1246     ARITY(0);
1247     GUARD(RISA(msg->recv, fastctx));
1249     RET(methctx_dup(state, msg->recv));
1250     CODE
1251   end
1253   defprim :tuple_shifted
1254   def tuple_shifted
1255     <<-CODE
1256     ARITY(1);
1257     OBJECT t1, t2;
1258     native_int j;
1260     GUARD(TUPLE_P(msg->recv));
1261     POP(t1, FIXNUM);
1263     j = N2I(t1);
1264     if(!j) {
1265       t2 = msg->recv;
1266     } else {
1267       t2 = tuple_new(state, NUM_FIELDS(msg->recv) + j);
1268       object_copy_fields_shifted(state, msg->recv, t2, j);
1269     }
1271     RET(t2);
1272     CODE
1273   end
1275   defprim :get_byte
1276   def get_byte
1277     <<-CODE
1278     ARITY(1);
1279     OBJECT t1;
1280     native_int j, k;
1282     GUARD( object_stores_bytes_p(state, msg->recv) )
1283     POP(t1, FIXNUM); /* index */
1285     unsigned char *indexed;
1286     j = N2I(t1);
1287     k = bytearray_bytes(state, msg->recv);
1289     GUARD( j >= 0 && j < k );
1290     indexed = (unsigned char*)bytearray_byte_address(state, msg->recv);
1291     indexed += j;
1293     RET(UI2N(*indexed));
1294     CODE
1295   end
1297   defprim :set_byte
1298   def set_byte
1299     <<-CODE
1300     ARITY(2);
1301     OBJECT t1, t2;
1302     native_int j, k;
1304     GUARD( object_stores_bytes_p(state, msg->recv) )
1305     POP(t1, FIXNUM); /* index */
1306     POP(t2, FIXNUM); /* value */
1308     unsigned char *indexed;
1309     j = N2I(t1);
1310     k = bytearray_bytes(state, msg->recv);
1312     GUARD( j >= 0 && j < k );
1314     indexed = (unsigned char*)bytearray_byte_address(state, msg->recv);
1315     indexed += j;
1316     t2 = UI2N(*indexed = N2I(t2));
1318     RET(t2);
1319     CODE
1320   end
1322   defprim :fetch_bytes
1323   def fetch_bytes
1324     <<-CODE
1325     ARITY(2);
1326     OBJECT t1, t2, t3;
1327     native_int j, k, m;
1329     GUARD( object_stores_bytes_p(state, msg->recv) )
1330     POP(t1, FIXNUM);
1331     POP(t2, FIXNUM);
1333     char *source, *dest;
1334     native_int num;
1335     j = N2I(t1);
1336     k = N2I(t2);
1337     m = bytearray_bytes(state, msg->recv);
1339     num = abs(j - k);
1341     GUARD( m >= num );
1342     GUARD( k >= 0 );
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);
1348     source += j;
1349     memcpy(dest, source, k);
1350     dest[k] = 0;
1352     RET(t3);
1353     CODE
1354   end
1356   defprim :move_bytes
1357   def move_bytes
1358     <<-CODE
1359     ARITY(3);
1360     OBJECT t1, t2, t3;
1361     char *data, *source, *dest;
1362     native_int total, offset, start, count;
1364     GUARD(object_stores_bytes_p(state, msg->recv));
1366     POP(t1, FIXNUM);
1367     POP(t2, FIXNUM);
1368     POP(t3, FIXNUM);
1370     start  = N2I(t1);
1371     count  = N2I(t2);
1372     offset = N2I(t3);
1374     total = bytearray_bytes(state, msg->recv);
1376     GUARD(start + count + offset < total);
1377     GUARD(offset >= 0);
1378     GUARD(count >= 0);
1380     data = (char*)bytearray_byte_address(state, msg->recv);
1381     source = data;
1382     dest = data;
1384     source += start;
1385     dest += offset;
1387     memmove((void*)dest, (void*)source, count);
1389     RET(t2);
1390     CODE
1391   end
1393   defprim :compare_bytes
1394   def compare_bytes
1395     <<-CODE
1396     ARITY(3);
1397     OBJECT t1, t2, t3;
1398     native_int j, k, m;
1399     native_int len, a, b, n, cmp;
1401     GUARD(object_stores_bytes_p(state, msg->recv));
1402     t1 = stack_pop();
1403     GUARD(object_stores_bytes_p(state, t1));
1404     POP(t2, FIXNUM);
1405     POP(t3, FIXNUM);
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);
1411     m = j < a ? j : a;
1412     n = k < b ? k : b;
1414     /* regardless of the user's request,
1415      * don't compare more bytes than there are
1416      */
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 */
1423     if(cmp == 0) {
1424       if(m < n) {
1425         RET(I2N(-1));
1426       } else if(m > n) {
1427         RET(I2N(1));
1428       } else {
1429         RET(I2N(0));
1430       }
1431     } else {
1432       RET(cmp < 0 ? I2N(-1) : I2N(1));
1433     }
1434     CODE
1435   end
1437   defprim :bytearray_size
1438   def bytearray_size
1439     <<-CODE
1440     ARITY(0);
1441     native_int j;
1442     GUARD( object_stores_bytes_p(state, msg->recv) )
1444     j = bytearray_bytes(state, msg->recv);
1446     RET(I2N(j));
1447     CODE
1448   end
1450   defprim :load_file
1451   def load_file
1452     <<-CODE
1453     ARITY(2);
1454     OBJECT t1, t2;
1456     POP(t1, STRING);
1457     POP(t2, FIXNUM);
1459     char *path = rbx_string_as_cstr(state, t1);
1460     t2 = cpu_unmarshal_file(state, path, N2I(t2));
1462     RET(t2);
1463     CODE
1464   end
1466   defprim :activate_as_script
1467   def activate_as_script
1468     <<-CODE
1469     ARITY(0);
1470     GUARD(CMETHOD_P(msg->recv));
1472     cpu_run_script(state, c, msg->recv);
1473     DONE();
1474     CODE
1475   end
1477   defprim :process_exit
1478   def process_exit
1479     <<-CODE
1480     ARITY(1);
1481     OBJECT t1;
1483     POP(t1, FIXNUM);
1485 #ifdef TIME_LOOKUP
1486     cpu_show_lookup_time(state);
1487 #endif
1489     if(state->gc_stats) {
1490       printf("[GC M %6dK total]\\n", state->om->ms->allocated_bytes / 1024);
1491     }
1493     if(current_machine->sub) {
1494       environment_exit_machine();
1495     } else {
1496       exit(N2I(t1));
1497     }
1498     CODE
1499   end
1501   defprim :micro_sleep
1502   def micro_sleep
1503     <<-CODE
1504     ARITY(1);
1505     OBJECT t1, t2;
1506     native_int j;
1507     struct timespec ts;
1508     POP(t1, FIXNUM);
1510     j = N2I(t1);
1511     ts.tv_sec = j / 1000000;
1512     ts.tv_nsec = (j % 1000000) * 1000;
1514     if(!nanosleep(&ts, NULL)) {
1515       t2 = Qfalse;
1516     } else {
1517       t2 = Qtrue;
1518     }
1520     RET(t2);
1521     CODE
1522   end
1524   defprim :activate_context
1525   def activate_context
1526     <<-CODE
1527     OBJECT t1;
1528     sassert(0);
1529     if(block_context_p(state, msg->recv)) {
1530       t1 = blokctx_home(state, msg->recv);
1531     } else {
1532       t1 = msg->recv;
1533     }
1535     cpu_activate_context(state, c, msg->recv, t1, 0);
1536     CODE
1537   end
1539   defprim :context_sender
1540   def context_sender
1541     <<-CODE
1542     ARITY(0);
1543     OBJECT t1;
1544     GUARD(CTX_P(msg->recv));
1546     t1 = FASTCTX(msg->recv)->sender;
1548     if(t1 != Qnil) {
1549       methctx_reference(state, t1);
1550     }
1552     RET(t1);
1553     CODE
1554   end
1556   defprim :string_to_sexp
1557   def string_to_sexp
1558     <<-CODE
1559     ARITY(3);
1560     bstring contents;
1561     const char *name;
1562     OBJECT t1, t2, t3;
1564     GUARD(STRING_P(msg->recv));
1566     POP(t1, STRING);
1567     POP(t2, FIXNUM);
1568     t3 = stack_pop();
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));
1573     bdestroy(contents);
1575     RET(t1);
1576     CODE
1577   end
1579   defprim :file_to_sexp
1580   def file_to_sexp
1581     <<-CODE
1582     ARITY(2);
1583     FILE *file;
1584     char *name;
1585     OBJECT t1, t2;
1587     POP(t1, STRING); /* The filename */
1588     t2 = stack_pop();
1590     name = rbx_string_as_cstr(state, t1);
1591     file = fopen(name, "r");
1593     if(!file) {
1594       FAIL();
1595     } else {
1596       t1 = syd_compile_file(state, name, file, 1, RTEST(t2));
1597       fclose(file);
1598       RET(t1);
1599     }
1600     CODE
1601   end
1603   defprim :terminal_raw
1604   def terminal_raw
1605     <<-CODE
1606     ARITY(0);
1607     struct termios ts;
1608     int err;
1609     OBJECT t3;
1611     if(NULL == state->termios) {
1612       if(!isatty(STDOUT_FILENO)) {
1613         RET(Qfalse);
1614       }
1616       /* HACK: this memory is never freed */
1617       state->termios = ALLOC(struct termios);
1619       if(NULL == state->termios) {
1620         RET(Qfalse);
1621       }
1623       err = tcgetattr(STDOUT_FILENO, state->termios);
1625       if(err == -1) { /* TODO: handle errno */
1626         XFREE(state->termios);
1627         RET(Qfalse);
1628       }
1629     }
1631     err = tcgetattr(STDOUT_FILENO, &ts);
1633     if(err == -1) { /* TODO: handle errno */
1634       RET(Qfalse);
1635     }
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 */
1645       RET(Qfalse);
1646     }
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])
1651     );
1653     RET(t3);
1654     CODE
1655   end
1657   defprim :terminal_normal
1658   def terminal_normal
1659     <<-CODE
1660     ARITY(0);
1661     if(NULL == state->termios) {
1662       RET(Qfalse);
1663     } else if (isatty(STDOUT_FILENO)) {
1664       int err;
1666       err = tcsetattr(STDOUT_FILENO, TCSANOW, state->termios);
1668       if (err == -1) {
1669         RET(Qfalse);
1670       } else {
1671         RET(Qtrue);
1672       }
1673     } else {
1674       RET(Qfalse);
1675     }
1676     CODE
1677   end
1679   defprim :regexp_new
1680   def regexp_new
1681     <<-CODE
1682     ARITY(2);
1683     OBJECT t1, t2, t3;
1684     char err_buf[1024];
1686     GUARD(CLASS_P(msg->recv));
1687     POP(t1, STRING);
1688     t2 = stack_pop();
1689     t3 = regexp_new(state, t1, t2, err_buf);
1691     if(NIL_P(t3)) {
1692       RAISE("RegexpError", err_buf);
1693     } else {
1694       t3->klass = msg->recv;   /* Subclasses */
1695     }
1697     RET(t3);
1698     CODE
1699   end
1701   defprim :regexp_match
1702   def regexp_match
1703     <<-CODE
1704     ARITY(1);
1705     OBJECT t1;
1706     GUARD(REGEXP_P(msg->recv));
1708     POP(t1, STRING);
1710     RET(regexp_match(state, msg->recv, t1));
1711     CODE
1712   end
1714   defprim :regexp_match_start
1715   def regexp_match_start
1716     <<-CODE
1717     ARITY(2);
1718     OBJECT t1, t2;
1719     GUARD(REGEXP_P(msg->recv));
1721     POP(t1, STRING);
1722     POP(t2, FIXNUM);
1724     RET(regexp_match_start(state, msg->recv, t1, t2));
1725     CODE
1726   end
1728   defprim :regexp_search_region
1729   def regexp_search_region
1730     <<-CODE
1731     ARITY(4);
1732     OBJECT t1, t2, t3, t4, t5;
1733     GUARD(REGEXP_P(msg->recv));
1735     POP(t1, STRING);
1736     POP(t2, FIXNUM);
1737     POP(t3, FIXNUM);
1738     t4 = stack_pop();
1740     t5 = regexp_search_region(state, msg->recv, t1, t2, t3, t4);
1742     RET(t5);
1743     CODE
1744   end
1746   defprim :regexp_options
1747   def regexp_options
1748     <<-CODE
1749     ARITY(0);
1750     GUARD(REGEXP_P(msg->recv));
1752     RET(regexp_options(state, msg->recv));
1753     CODE
1754   end
1756   defprim :gc_start
1757   def gc_start
1758     <<-CODE
1759     ARITY(1);
1760     OBJECT t1 = stack_pop();
1761     if(RTEST(t1)) {
1762       state->om->collect_now = OMCollectYoung;
1763     } else {
1764       state->om->collect_now = OMCollectYoung | OMCollectMature;
1765     }
1766     RET(Qtrue);
1767     CODE
1768   end
1770   defprim :get_ivar
1771   def get_ivar
1772     <<-CODE
1773     ARITY(0);
1774     OBJECT t1 = NTH_FIELD(msg->method, 4);
1775     RET(object_get_ivar(state, msg->recv, t1));
1776     CODE
1777   end
1779   defprim :set_ivar
1780   def set_ivar
1781     <<-CODE
1782     ARITY(1);
1783     OBJECT t1, t2;
1785     t1 = NTH_FIELD(msg->method, 4);
1786     t2 = stack_pop();
1787     object_set_ivar(state, msg->recv, t1, t2);
1789     RET(t2);
1790     CODE
1791   end
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
1798     <<-CODE
1799     OBJECT t1, t2, t3;
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);
1806     if(Qtrue == t3) {
1807       stack_push(msg->recv);
1808       args++;
1809     }
1811     cpu_send(state, c, t2, t1, args, Qnil);
1812     CODE
1813   end
1815   defprim :set_index
1816   def set_index
1817     <<-CODE
1818     ARITY(1);
1819     native_int j;
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));
1826     CODE
1827   end
1829   defprim :get_index
1830   def get_index
1831     <<-CODE
1832     ARITY(0);
1833     native_int j;
1834     GUARD(INDEXED(msg->recv));
1836     j = N2I(NTH_FIELD(msg->method, 4));
1837     RET(NTH_FIELD(msg->recv, j));
1838     CODE
1839   end
1841   defprim :fixnum_modulo
1842   def fixnum_modulo
1843     <<-CODE
1844     ARITY(1);
1845     OBJECT t1;
1847     GUARD(FIXNUM_P(msg->recv));
1848     POP(t1, FIXNUM);
1850     GUARD(N2I(t1) != 0) // no divide by zero
1851     native_int mod;
1852     fixnum_div(state, msg->recv, t1, &mod);
1853     RET(I2N(mod));
1854     CODE
1855   end
1857   defprim :marshal_object
1858   def marshal_object
1859     <<-CODE
1860     ARITY(2);
1861     OBJECT t1, t2;
1862     t1 = stack_pop();
1863     POP(t2, FIXNUM);
1865     RET(cpu_marshal(state, t1, N2I(t2)));
1866     CODE
1867   end
1869   defprim :unmarshal_object
1870   def unmarshal_object
1871     <<-CODE
1872     ARITY(2);
1873     OBJECT t1, t2, t3;
1874     POP(t1, STRING);
1875     POP(t2, FIXNUM);
1876     t3 = cpu_unmarshal(state,
1877                        (uint8_t*)rbx_string_as_cstr(state, t1),
1878                        N2I(string_get_bytes(t1)),
1879                        N2I(t2));
1880     RET(t3);
1881     CODE
1882   end
1884   defprim :marshal_to_file
1885   def marshal_to_file
1886     <<-CODE
1887     ARITY(3);
1888     OBJECT t1, t2, t3;
1890     char *_path;
1891     t1 = stack_pop();
1892     POP(t2, STRING);
1893     POP(t3, FIXNUM);
1895     _path = rbx_string_as_cstr(state, t2);
1896     RET(cpu_marshal_to_file(state, t1, _path, N2I(t3)));
1897     CODE
1898   end
1900   defprim :unmarshal_from_file
1901   def unmarshal_from_file
1902     <<-CODE
1903     ARITY(2);
1904     char *_path;
1905     OBJECT t1, t2;
1907     POP(t1, STRING);
1908     POP(t2, FIXNUM);
1910     _path = rbx_string_as_cstr(state, t1);
1911     RET(cpu_unmarshal_file(state, _path, N2I(t2)));
1912     CODE
1913   end
1915   defprim :fixnum_and
1916   def fixnum_and
1917     <<-CODE
1918     ARITY(1);
1919     GUARD(FIXNUM_P(msg->recv));
1920     OBJECT t1 = stack_pop();
1921     native_int j, k = 0;
1923     j = N2I(msg->recv);
1924     if(FIXNUM_P(t1)) {
1925       k = N2I(t1);
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);
1932       } else {
1933         FAIL();
1934       }
1935     } else {
1936       FAIL();
1937     }
1938     RET(I2N(j & k));
1939     CODE
1940   end
1942   defprim :fixnum_or
1943   def fixnum_or
1944     <<-CODE
1945     ARITY(1);
1946     GUARD(FIXNUM_P(msg->recv));
1947     OBJECT t1 = stack_pop();
1948     native_int j, k = 0;
1950     j = N2I(msg->recv);
1951     if(FIXNUM_P(t1)) {
1952       k = N2I(t1);
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);
1959       } else {
1960         FAIL();
1961       }
1962     } else {
1963       FAIL();
1964     }
1965     RET(I2N(j | k));
1966     CODE
1967   end
1969   defprim :fixnum_xor
1970   def fixnum_xor
1971     <<-CODE
1972     ARITY(1);
1973     GUARD(FIXNUM_P(msg->recv));
1974     OBJECT t1 = stack_pop();
1975     native_int j, k = 0;
1977     j = N2I(msg->recv);
1978     if(FIXNUM_P(t1)) {
1979       k = N2I(t1);
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);
1986       } else {
1987         FAIL();
1988       }
1989     } else {
1990       FAIL();
1991     }
1992     RET(I2N(j ^ k));
1993     CODE
1994   end
1996   defprim :fixnum_invert
1997   def fixnum_invert
1998     <<-CODE
1999     ARITY(0);
2000     native_int j;
2001     GUARD(FIXNUM_P(msg->recv));
2003     j = N2I(msg->recv);
2004     RET(I2N(~j));
2005     CODE
2006   end
2008   defprim :fixnum_neg
2009   def fixnum_neg
2010     <<-CODE
2011     ARITY(0);
2012     native_int j;
2013     GUARD(FIXNUM_P(msg->recv));
2015     j = N2I(msg->recv);
2016     RET(I2N(-j));
2017     CODE
2018   end
2020   defprim :fixnum_right_shift
2021   def fixnum_right_shift
2022     <<-CODE
2023     ARITY(1);
2024     OBJECT t1, t2;
2025     native_int value, width;
2027     GUARD(FIXNUM_P(msg->recv));
2028     POP(t1, FIXNUM);
2030     value = N2I(msg->recv);
2031     width = N2I(t1);
2033     if (width > 0) {
2034       if (width >= sizeof(value)*8-1) {
2035         if (value < 0) {
2036           value = -1;
2037         } else {
2038           value = 0;
2039         }
2040       } else {
2041         value >>= width;
2042       }
2043     }
2045     t2 = I2N(value);
2046     RET(t2);
2047     CODE
2048   end
2050   defprim :fixnum_left_shift
2051   def fixnum_left_shift
2052     <<-CODE
2053     ARITY(1);
2054     OBJECT t1, t2;
2055     native_int value, width;
2057     GUARD(FIXNUM_P(msg->recv));
2058     POP(t1, FIXNUM);
2060     value = N2I(msg->recv);
2061     width = N2I(t1);
2063     value <<= width;
2064     t2 = I2N(value);
2065     RET(t2);
2066     CODE
2067   end
2069   defprim :bignum_new
2070   def bignum_new
2071     <<-CODE
2072     ARITY(1);
2073     OBJECT t1;
2074     POP(t1, FIXNUM);
2075     RET(bignum_new(state, N2I(t1)));
2076     CODE
2077   end
2079   defprim :bignum_to_float
2080   def bignum_to_float
2081     <<-CODE
2082     ARITY(0);
2083     GUARD(BIGNUM_P(msg->recv));
2085     RET(float_new(state, bignum_to_double(state, msg->recv)));
2086     CODE
2087   end
2089   defprim :bignum_and
2090   def bignum_and
2091     <<-CODE
2092     ARITY(1);
2093     GUARD(BIGNUM_P(msg->recv));
2094     OBJECT t1 = stack_pop();
2095     if(INTEGER_P(t1)) {
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))));
2100     } else {
2101       FAIL();
2102     }
2103     CODE
2104   end
2106   defprim :bignum_or
2107   def bignum_or
2108     <<-CODE
2109     ARITY(1);
2110     GUARD(BIGNUM_P(msg->recv));
2111     OBJECT t1 = stack_pop();
2112     if(INTEGER_P(t1)) {
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))));
2117     } else {
2118       FAIL();
2119     }
2120     CODE
2121   end
2123   defprim :bignum_xor
2124   def bignum_xor
2125     <<-CODE
2126     ARITY(1);
2127     GUARD(BIGNUM_P(msg->recv));
2128     OBJECT t1 = stack_pop();
2129     if(INTEGER_P(t1)) {
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))));
2134     } else {
2135       FAIL();
2136     }
2137     CODE
2138   end
2140   defprim :bignum_neg
2141   def bignum_neg
2142     <<-CODE
2143     ARITY(0);
2144     GUARD(BIGNUM_P(msg->recv));
2146     RET(bignum_neg(state, msg->recv));
2147     CODE
2148   end
2150   defprim :bignum_invert
2151   def bignum_invert
2152     <<-CODE
2153     ARITY(0);
2154     GUARD(BIGNUM_P(msg->recv));
2156     RET(bignum_invert(state, msg->recv));
2157     CODE
2158   end
2160   defprim :numeric_coerce
2161   def numeric_coerce
2162     <<-CODE
2163     ARITY(1);
2164     OBJECT t1, t3;
2166     GUARD(INTEGER_P(msg->recv));
2167     POP(t1, INTEGER);
2169     t3 = array_new(state, 2);
2170     if(BIGNUM_P(msg->recv)) {
2171       if(BIGNUM_P(t1)) {
2172         array_set(state, t3, 0, t1);
2173       } else {
2174         array_set(state, t3, 0, bignum_new(state, N2I(t1)));
2175       }
2176       array_set(state, t3, 1, msg->recv);
2177     } else {
2178       if(BIGNUM_P(t1)) {
2179         array_set(state, t3, 0, t1);
2180         array_set(state, t3, 1, bignum_new(state, N2I(msg->recv)));
2181       } else {
2182         array_set(state, t3, 0, t1);
2183         array_set(state, t3, 1, msg->recv);
2184       }
2185     }
2186     RET(t3);
2187     CODE
2188   end
2190   defprim :bignum_compare
2191   def bignum_compare
2192     <<-CODE
2193     ARITY(1);
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)));
2201     } else {
2202       FAIL();
2203     }
2204     CODE
2205   end
2207   defprim :fixnum_to_f
2208   def fixnum_to_f
2209     <<-CODE
2210     ARITY(0);
2211     GUARD(FIXNUM_P(msg->recv));
2213     RET(float_new(state, FIXNUM_TO_DOUBLE(msg->recv)));
2214     CODE
2215   end
2217   defprim :string_to_f
2218   def string_to_f
2219     <<-CODE
2220     ARITY(0);
2221     GUARD(STRING_P(msg->recv));
2223     RET(float_new(state, string_to_double(state, msg->recv)));
2224     CODE
2225   end
2227   defprim :fixnum_divmod
2228   def fixnum_divmod
2229     <<-CODE
2230     ARITY(1);
2231     OBJECT t1;
2232     GUARD(FIXNUM_P(msg->recv));
2233     POP(t1, FIXNUM);
2235     GUARD( N2I(t1) != 0 ) // no divide by zero
2236     RET(fixnum_divmod(state, msg->recv, t1));
2237     CODE
2238   end
2240   defprim :bignum_left_shift
2241   def bignum_left_shift
2242     <<-CODE
2243     ARITY(1);
2244     OBJECT t1;
2245     GUARD(BIGNUM_P(msg->recv));
2247     POP(t1, FIXNUM);
2249     RET(bignum_left_shift(state, msg->recv, t1));
2250     CODE
2251   end
2253   defprim :bignum_right_shift
2254   def bignum_right_shift
2255     <<-CODE
2256     ARITY(1);
2257     OBJECT t1;
2258     GUARD(BIGNUM_P(msg->recv));
2260     POP(t1, FIXNUM);
2262     RET(bignum_right_shift(state, msg->recv, t1));
2263     CODE
2264   end
2266   defprim :find_method
2267   def find_method
2268     <<-CODE
2269     ARITY(1);
2270     OBJECT t1, t2, t3;
2271     POP(t1, SYMBOL);
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);
2278     RET(t3);
2279     CODE
2280   end
2282   defprim :bignum_divmod
2283   def bignum_divmod
2284     <<-CODE
2285     ARITY(1);
2286     OBJECT t1;
2288     GUARD(BIGNUM_P(msg->recv));
2289     t1 = stack_pop();
2291     // no divide by zero
2292     if(FIXNUM_P(t1)) {
2293       GUARD(N2I(t1) != 0);
2294     } else if(BIGNUM_P(t1)) {
2295       GUARD(!bignum_is_zero(state, t1));
2296     } else {
2297       FAIL();
2298     }
2300     RET(bignum_divmod(state, msg->recv, t1));
2301     CODE
2302   end
2304   defprim :object_taint
2305   def object_taint
2306     <<-CODE
2307     ARITY(0);
2308     GUARD(REFERENCE_P(msg->recv));
2309     object_set_tainted(state, msg->recv);
2310     RET(msg->recv);
2311     CODE
2312   end
2314   defprim :object_tainted_p
2315   def object_tainted_p
2316     <<-CODE
2317     ARITY(0);
2318     GUARD(REFERENCE_P(msg->recv));
2319     RET(object_tainted_p(state, msg->recv) ? Qtrue : Qfalse);
2320     CODE
2321   end
2323   defprim :object_untaint
2324   def object_untaint
2325     <<-CODE
2326     ARITY(0);
2327     GUARD(REFERENCE_P(msg->recv));
2328     object_set_untainted(state, msg->recv);
2329     RET(msg->recv);
2330     CODE
2331   end
2333   defprim :object_freeze
2334   def object_freeze
2335     <<-CODE
2336     ARITY(0);
2337     GUARD(REFERENCE_P(msg->recv));
2338     object_set_frozen(state, msg->recv);
2339     RET(msg->recv);
2340     CODE
2341   end
2343   defprim :object_frozen_p
2344   def object_frozen_p
2345     <<-CODE
2346     ARITY(0);
2347     GUARD(REFERENCE_P(msg->recv));
2348     RET(object_frozen_p(state, msg->recv) ? Qtrue : Qfalse);
2349     CODE
2350   end
2352   defprim :fastctx_get_field
2353   def fastctx_get_field
2354     <<-CODE
2355     ARITY(1);
2356     native_int i;
2357     struct fast_context *fc;
2358     OBJECT t1;
2360     GUARD(CTX_P(msg->recv));
2361     POP(t1, FIXNUM);
2363     fc = FASTCTX(msg->recv);
2364     i = N2I(t1);
2366     switch(i) {
2367       case 0:
2368         if(!NIL_P(fc->sender)) {
2369           methctx_reference(state, fc->sender);
2370         }
2371         RET(fc->sender);
2372         break;
2373       case 1:
2374         RET(I2N(fc->ip));
2375         break;
2376       case 2:
2377         RET(I2N(fc->sp));
2378         break;
2379       case 3:
2380         RET(fc->block);
2381         break;
2382       case 5:
2383         RET(fc->method);
2384         break;
2385       case 6:
2386         RET(fc->literals);
2387         break;
2388       case 7:
2389         RET(fc->self);
2390         break;
2391       case 8:
2392         RET(fc->locals);
2393         break;
2394       case 9:
2395         RET(I2N(fc->argcount));
2396         break;
2397       case 10:
2398         RET(fc->name);
2399         break;
2400       case 11:
2401         RET(fc->method_module);
2402         break;
2403       case 12:
2404         RET(I2N(fc->flags));
2405         break;
2406       case 13:
2407         RET(I2N(fc->fp));
2408         break;
2409       default:
2410         RET(Qnil);
2411     }
2412     CODE
2413   end
2415   defprim :fastctx_set_field
2416   def fastctx_set_field
2417     <<-CODE
2418     ARITY(2);
2419     native_int i;
2420     struct fast_context *fc;
2421     OBJECT t2;
2423     GUARD(CTX_P(msg->recv));
2425     POP(t2, FIXNUM);
2426     i = N2I(t2);
2428     t2 = stack_pop();
2429     fc = FASTCTX(msg->recv);
2431     switch(i) {
2432       case 0:
2433         GUARD(CTX_P(t2));
2434         SET_STRUCT_FIELD(msg->recv, fc->sender, t2);
2435         break;
2436       case 1:
2437         GUARD(FIXNUM_P(t2));
2438         fc->ip = N2I(t2);
2439         break;
2440       case 2:
2441         GUARD(FIXNUM_P(t2));
2442         fc->sp = N2I(t2);
2443         break;
2444       case 3:
2445         SET_STRUCT_FIELD(msg->recv, fc->block, t2);
2446         break;
2447       case 5:
2448         SET_STRUCT_FIELD(msg->recv, fc->method, t2);
2449         break;
2450       case 6:
2451         SET_STRUCT_FIELD(msg->recv, fc->literals, t2);
2452         break;
2453       case 7:
2454         SET_STRUCT_FIELD(msg->recv, fc->self, t2);
2455         break;
2456       case 8:
2457         SET_STRUCT_FIELD(msg->recv, fc->locals, t2);
2458         break;
2459       case 9:
2460         GUARD(FIXNUM_P(t2));
2461         fc->argcount = N2I(t2);
2462         break;
2463       case 10:
2464         SET_STRUCT_FIELD(msg->recv, fc->name, t2);
2465         break;
2466       case 11:
2467         SET_STRUCT_FIELD(msg->recv, fc->method_module, t2);
2468         break;
2469       case 12:
2470         if(NIL_P(t2)) {
2471           fc->flags = 0;
2472         } else if(FIXNUM_P(t2)) {
2473           fc->flags |= N2I(t2);
2474         }
2475         break;
2476       default:
2477         FAIL();
2478     }
2480     RET(t2);
2481     CODE
2482   end
2484   defprim :fastctx_reload_method
2485   def fastctx_reload_method
2486     <<-CODE
2487     ARITY(0);
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));
2495     }
2497     RET(Qtrue);
2498     CODE
2499   end
2501   defprim :fastctx_set_iseq
2502   def fastctx_set_iseq
2503     <<-CODE
2504     ARITY(1);
2505     struct fast_context *fc;
2506     OBJECT t1, ba;
2507     int target_size;
2509     GUARD(CTX_P(msg->recv));
2510     POP(t1, BYTEARRAY);
2511     fc = FASTCTX(msg->recv);
2512     GUARD(fc->method->obj_type == CMethodType);
2514 #if DIRECT_THREADED
2515     target_size = (BYTEARRAY_SIZE(t1) / sizeof(uint32_t)) * sizeof(uintptr_t);
2516 #else
2517     target_size = BYTEARRAY_SIZE(t1);
2518 #endif
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);
2525     RET(Qtrue);
2526     CODE
2527   end
2529   defprim :vm_stats
2530   def vm_stats
2531     <<-CODE
2532     ARITY(0);
2533 #ifdef TRACK_STATS
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));
2542     RET(t1);
2543 #else
2544     RET(Qfalse);
2545 #endif
2546     CODE
2547   end
2549   defprim :nmethod_call
2550   def nmethod_call
2551     <<-CODE
2552     OBJECT t1;
2553     cpu_flush_ip(c);
2554     cpu_flush_sp(c);
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);
2561     CODE
2562   end
2564   defprim :nfunc_call
2565   def nfunc_call
2566     <<-CODE
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     OBJECT ptr;
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);
2578     CODE
2579   end
2581   defprim :nfunc_call_object
2582   def nfunc_call_object
2583     <<-CODE
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);
2592     CODE
2593   end
2595   defprim :nfunc_add
2596   def nfunc_add
2597     <<-CODE
2598     ARITY(4);
2599     OBJECT t1, t2, t3, t4;
2601     POP(t1, STRING_OR_NIL);
2602     POP(t2, STRING);
2603     POP(t3, ARRAY);
2604     POP(t4, FIXNUM);
2605     RET(ffi_function_create(state, t1, t2, t3, t4));
2606     CODE
2607   end
2609   defprim :load_library
2610   def load_library
2611     <<-CODE
2612     ARITY(2);
2613     OBJECT t1, t2;
2615     POP(t1, STRING);
2616     POP(t2, STRING);
2617     OBJECT ret = subtend_load_library(state, c, t1, t2);
2618     if(ret != Qtrue) RET(ret);
2619     CODE
2620   end
2622   defprim :dir_glob
2623   def dir_glob
2624     <<-CODE
2625     ARITY(2);
2626     glob_t gd;
2627     char *pat;
2628     int flags = GLOB_NOSORT | GLOB_BRACE;
2629     OBJECT t1, t2;
2630     native_int j, k;
2632     POP(t1, STRING);
2633     POP(t2, FIXNUM);
2635     /* TODO: use t2. */
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]));
2642     }
2643     globfree(&gd);
2644     RET(t2);
2645     CODE
2646   end
2648   defprim :dir_chdir
2649   def dir_chdir
2650     <<-CODE
2651     ARITY(1);
2652     char *path;
2653     OBJECT t1;
2655     POP(t1, STRING);
2657     path = rbx_string_as_cstr(state, t1);
2658     if(!chdir(path)) {
2659       RET(Qtrue);
2660     } else {
2661       RET(Qfalse);
2662     }
2663     CODE
2664   end
2666   defprim :yield_gdb
2667   def yield_gdb
2668     <<-CODE
2669     ARITY(1);
2670     OBJECT t1 = stack_pop();
2671     *((OBJECT*)4) = t1; /* cause a SIGBUS */
2672     RET(Qtrue);
2673     CODE
2674   end
2676   defprim :make_weak_ref
2677   def make_weak_ref
2678     <<-CODE
2679     ARITY(1);
2680     OBJECT t1;
2681     POP(t1, REFERENCE);
2683     RET(object_make_weak_ref(state, t1));
2684     CODE
2685   end
2687   defprim :gc_collect_references
2688   def gc_collect_references
2689     <<-CODE
2690     ARITY(1);
2691     OBJECT t1;
2692     POP(t1, REFERENCE);
2694     RET(object_memory_collect_references(state, state->om, t1));
2695     CODE
2696   end
2698   defprim :task_dup
2699   def task_dup
2700     <<-CODE
2701     ARITY(0);
2702     OBJECT t1;
2703     /* This is a little contrived so the dup'd task has
2704        it stack setup properly. */
2706     stack_push(Qnil);
2708     if(TASK_P(msg->recv)) {
2709       t1 = cpu_task_dup(state, c, msg->recv);
2710     } else {
2711       t1 = cpu_task_dup(state, c, Qnil);
2712     }
2714     cpu_stack_set_top(state, c, t1);
2715     CODE
2716   end
2718   defprim :task_set_current
2719   def task_set_current
2720     <<-CODE
2721     ARITY(1);
2722     OBJECT t1;
2723     POP(t1, TASK);
2725     stack_push(Qnil);
2726     cpu_task_select(state, c, t1);
2727     CODE
2728   end
2730   defprim :task_associate
2731   def task_associate
2732     <<-CODE
2733     ARITY(1);
2734     OBJECT t1;
2736     GUARD(TASK_P(msg->recv));
2737     POP(t1, BLOCKENV);
2739     RET(cpu_task_associate(state, c, msg->recv, t1));
2740     CODE
2741   end
2743   defprim :task_current
2744   def task_current
2745     <<-CODE
2746     ARITY(0);
2747     RET(c->current_task);
2748     CODE
2749   end
2751   defprim :task_at
2752   def task_at
2753     <<-CODE
2754     ARITY(1);
2755     struct cpu_task *task;
2756     OBJECT t1, t2;
2757     native_int k;
2759     GUARD(TASK_P(msg->recv));
2760     POP(t1, FIXNUM);
2762     task = (struct cpu_task*)BYTES_OF(msg->recv);
2763     k = N2I(t1);
2765     switch(k) {
2766     case 0:
2767       t2 = task->main;
2768       break;
2769     case 1:
2770       t2 = task->active_context;
2771       if(REFERENCE_P(t2)) methctx_reference(state, t2);
2772       break;
2773     default:
2774       t2 = Qnil;
2775     }
2777     RET(t2);
2778     CODE
2779   end
2781   defprim :task_set_debugging
2782   def task_set_debugging
2783     <<-CODE
2784     ARITY(2);
2785     OBJECT t1, t2;
2786     GUARD(TASK_P(msg->recv));
2788     t1 = stack_pop();
2789     t2 = stack_pop();
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;
2797     } else {
2798       cpu_task_set_debugging(state, msg->recv, t1, t2);
2799     }
2800     RET(Qtrue);
2801     CODE
2802   end
2804   defprim :task_debug_channel
2805   def task_debug_channel
2806     <<-CODE
2807     ARITY(0);
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);
2814     CODE
2815   end
2817   defprim :task_control_channel
2818   def task_control_channel
2819     <<-CODE
2820     ARITY(0);
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);
2827     CODE
2828   end
2830   defprim :task_get_debug_context_change
2831   def task_get_debug_context_change
2832     <<-CODE
2833     ARITY(0);
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)) {
2839       RET(Qtrue);
2840     } else {
2841       RET(Qfalse);
2842     }
2843     CODE
2844   end
2846   defprim :task_set_debug_context_change
2847   def task_set_debug_context_change
2848     <<-CODE
2849     ARITY(1);
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);
2855     if(RTEST(t1)) {
2856       TASK_SET_FLAG(task, TASK_DEBUG_ON_CTXT_CHANGE);
2857       if(task->active) {
2858         TASK_SET_FLAG(c, TASK_DEBUG_ON_CTXT_CHANGE);
2859       }
2860       RET(Qtrue);
2861     } else {
2862       if(TASK_FLAG_P(task, TASK_DEBUG_ON_CTXT_CHANGE)) {
2863         TASK_CLEAR_FLAG(task, TASK_DEBUG_ON_CTXT_CHANGE);
2864         if(task->active) {
2865           TASK_CLEAR_FLAG(c, TASK_DEBUG_ON_CTXT_CHANGE);
2866         }
2867       }
2868       RET(Qfalse);
2869     }
2870     CODE
2871   end
2873   defprim :task_stack_size
2874   def task_stack_size
2875     <<-CODE
2876     ARITY(0);
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);
2883     RET(t1);
2884     CODE
2885   end
2887   defprim :task_get_stack_value
2888   def task_get_stack_value
2889     <<-CODE
2890     ARITY(1);
2891     struct cpu_task *task;
2892     OBJECT t1, t2;
2894     GUARD(TASK_P(msg->recv));
2895     POP(t1, FIXNUM);
2897     task = (struct cpu_task*)BYTES_OF(msg->recv);
2898     int idx = N2I(t1);
2899     GUARD(idx >=0 && idx < (task->sp_ptr - task->stack_top));
2901     t2 = *(task->sp_ptr - idx);
2903     RET(t2);
2904     CODE
2905   end
2907   defprim :task_raise
2908   def task_raise
2909     <<-CODE
2910     ARITY(1);
2911     OBJECT t1;
2912     GUARD(TASK_P(msg->recv));
2914     t1 = stack_pop();
2916     /* The return value */
2917     stack_push(Qnil);
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);
2925     }
2926     CODE
2927   end
2929   defprim :thread_raise
2930   def thread_raise
2931     <<-CODE
2932     ARITY(1);
2933     OBJECT t1;
2934     GUARD(THREAD_P(msg->recv));
2936     t1 = stack_pop();
2938     if(!cpu_thread_alive_p(state, msg->recv)) {
2939       RET(Qfalse);
2940     } else {
2942       /* The return value */
2943       stack_push(Qtrue);
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);
2952     }
2953     CODE
2954   end
2956   defprim :channel_new
2957   def channel_new
2958     <<-CODE
2959     ARITY(0);
2960     RET(cpu_channel_new(state));
2961     CODE
2962   end
2964   defprim :channel_send
2965   def channel_send
2966     <<-CODE
2967     ARITY(1);
2968     OBJECT t1;
2969     GUARD(CHANNEL_P(msg->recv));
2971     t1 = stack_pop();
2972     RET(cpu_channel_send(state, c, msg->recv, t1));
2973     CODE
2974   end
2976   defprim :channel_receive
2977   def channel_receive
2978     <<-CODE
2979     ARITY(0);
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. */
2986     CODE
2987   end
2989   defprim :channel_send_in_microseconds
2990   def channel_send_in_microseconds
2991     <<-CODE
2992     ARITY(3);
2993     double seconds;
2994     OBJECT channel, usec_r, tag;
2995     native_int k;
2997     POP(channel, CHANNEL);
2998     POP(usec_r, INTEGER);
2999     tag = stack_pop();
3001     if(FIXNUM_P(usec_r)) {
3002       k = (long)N2I(usec_r);
3003     } else {
3004       k = (long)bignum_to_int(state, usec_r);
3005     }
3007     seconds = k / 1000000.0;
3009     RET(cpu_event_wake_channel(state, c, channel, seconds, tag));
3010     CODE
3011   end
3013   defprim :channel_send_in_seconds
3014   def channel_send_in_seconds
3015     <<-CODE
3016     ARITY(3);
3017     double seconds;
3018     OBJECT channel, seconds_r, tag;
3020     POP(channel, CHANNEL);
3021     POP(seconds_r, FLOAT);
3022     tag = stack_pop();
3024     seconds = FLOAT_TO_DOUBLE(seconds_r);
3026     RET(cpu_event_wake_channel(state, c, channel, seconds, tag));
3027     CODE
3028   end
3030   defprim :channel_send_on_readable
3031   def channel_send_on_readable
3032     <<-CODE
3033     ARITY(4);
3034     OBJECT t1, t2, t3, t4;
3035     native_int j;
3037     POP(t4, CHANNEL);
3038     t1 = stack_pop();
3039     t2 = stack_pop();
3040     t3 = stack_pop();
3042     GUARD(STRING_P(t2) || NIL_P(t2));
3043     GUARD(FIXNUM_P(t3) || NIL_P(t3));
3045     if(IO_P(t1)) {
3046       j = io_to_fd(t1);
3047     } else if(FIXNUM_P(t1)) {
3048       j = N2I(t1);
3049     } else {
3050       GUARD(0);
3051     }
3053     RET(cpu_event_wait_readable(state, c, t4, j, t2, N2I(t3)));
3054     CODE
3055   end
3057   defprim :channel_send_on_writable
3058   def channel_send_on_writable
3059     <<-CODE
3060     ARITY(2);
3061     OBJECT t1, t2;
3062     native_int j;
3064     POP(t2, CHANNEL);
3065     POP(t1, IO);
3067     j = io_to_fd(t1);
3068     RET(cpu_event_wait_writable(state, c, t2, j));
3069     CODE
3070   end
3072   defprim :channel_send_on_signal
3073   def channel_send_on_signal
3074     <<-CODE
3075     ARITY(2);
3076     OBJECT t1, t2;
3078     POP(t2, CHANNEL);
3079     POP(t1, FIXNUM);
3081     RET(cpu_event_wait_signal(state, c, t2, N2I(t1)));
3082     CODE
3083   end
3085   defprim :channel_send_on_stopped
3086   def channel_send_on_stopped
3087     <<-CODE
3088     ARITY(3);
3089     OBJECT t1, t2, t3;
3091     POP(t3, CHANNEL);
3092     POP(t1, FIXNUM);
3093     POP(t2, FIXNUM);
3095     RET(cpu_event_wait_child(state, c, t3, N2I(t1), N2I(t2)));
3096     CODE
3097   end
3099   defprim :scheduler_cancel
3100   def scheduler_cancel
3101     <<-CODE
3102     ARITY(1);
3103     OBJECT t1;
3104     POP(t1, FIXNUM);
3106     RET(cpu_event_cancel_event(state, t1) ? Qtrue : Qfalse);
3107     CODE
3108   end
3110   defprim :thread_new
3111   def thread_new
3112     <<-CODE
3113     ARITY(0);
3114     RET(cpu_thread_new(state, c));
3115     CODE
3116   end
3118   defprim :thread_run
3119   def thread_run
3120     <<-CODE
3121     ARITY(0);
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. */
3127     stack_push(Qnil);
3128     cpu_thread_schedule(state, c->current_thread);
3129     cpu_thread_force_run(state, c, msg->recv);
3130     CODE
3131   end
3133   defprim :thread_schedule
3134   def thread_schedule
3135     <<-CODE
3136     ARITY(0);
3137     GUARD(THREAD_P(msg->recv));
3139     cpu_thread_schedule(state, msg->recv);
3140     RET(Qnil);
3141     CODE
3142   end
3144   defprim :thread_yield
3145   def thread_yield
3146     <<-CODE
3147     ARITY(0);
3148     /* Same reason as thread_run */
3149     stack_push(Qnil);
3150     cpu_thread_schedule(state, c->current_thread);
3151     THDEBUG("%d: thread yield.\\n", getpid());
3152     cpu_thread_run_best(state, c);
3153     CODE
3154   end
3156   defprim :thread_dequeue
3157   def thread_dequeue
3158     <<-CODE
3159     ARITY(0);
3160     THDEBUG("%d: dequeue thread.\\n", getpid());
3161     cpu_thread_exited(state, c);
3162     CODE
3163   end
3165   defprim :thread_current
3166   def thread_current
3167     <<-CODE
3168     ARITY(0);
3169     RET(c->current_thread);
3170     CODE
3171   end
3173   defprim :object_become
3174   def object_become
3175     <<-CODE
3176     ARITY(2);
3177     void state_object_become(STATE, cpu c, OBJECT from, OBJECT to);
3178     OBJECT t1, t2;
3180     POP(t2, REFERENCE);
3181     POP(t1, REFERENCE);
3182     state_object_become(state, c, t2, t1);
3183     RET(t2);
3184     CODE
3185   end
3187   defprim :sampler_activate
3188   def sampler_activate
3189     <<-CODE
3190     ARITY(1);
3191     OBJECT t1;
3193     POP(t1, FIXNUM);
3194     cpu_sampler_activate(state, N2I(t1), environment_current_machine());
3195     RET(ML2N(clock()));
3196     CODE
3197   end
3199   defprim :sampler_stop
3200   def sampler_stop
3201     <<-CODE
3202     ARITY(0);
3203     OBJECT t1 = cpu_sampler_disable(state, environment_current_machine());
3204     RET(t1);
3205     CODE
3206   end
3208   defprim :fork_process
3209   def fork_process
3210     <<-CODE
3211     ARITY(0);
3212     native_int k = fork();
3213     if(k == -1) {
3214       RAISE_FROM_ERRNO("Unable to fork");
3215     } else {
3216       if (k == 0) {
3217         environment_fork();
3218       }
3219       RET(I2N(k));
3220     }
3221     CODE
3222   end
3225   defprim :replace_process# aka execve().
3226   def replace_process
3227     <<-CODE
3228     ARITY(2);
3229     native_int i, j, k;
3230     char *tmp, *file;
3231     char **argv;
3232     OBJECT t1, t2, t3;
3234     POP(t1, STRING);
3235     POP(t2, ARRAY);
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++) {
3243           XFREE(argv[i]);
3244         }
3245         XFREE(argv);
3246         return FALSE;
3247       }
3249       tmp = rbx_string_as_cstr(state, t3);
3250       argv[j] = tmp ? strdup(tmp) : NULL;
3251     }
3253     argv[k] = 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");
3265     CODE
3266   end
3268   defprim :ivar_get
3269   def ivar_get
3270     <<-CODE
3271     ARITY(1);
3272     OBJECT t1;
3273     POP(t1, SYMBOL);
3274     RET(object_get_ivar(state, msg->recv, t1));
3275     CODE
3276   end
3278   defprim :ivar_set
3279   def ivar_set
3280     <<-CODE
3281     ARITY(2);
3282     OBJECT t1, t2;
3283     POP(t1, SYMBOL);
3284     t2 = stack_pop();
3285     object_set_ivar(state, msg->recv, t1, t2);
3286     RET(t2);
3287     CODE
3288   end
3290   defprim :ivars_get
3291   def ivars_get
3292     <<-CODE
3293     ARITY(0);
3294     RET(object_get_ivars(state, msg->recv));
3295     CODE
3296   end
3298   defprim :str_crypt
3299   def str_crypt
3300     <<-CODE
3301     ARITY(1);
3302     OBJECT t1;
3304     GUARD(STRING_P(msg->recv));
3305     POP(t1, STRING);
3306     RET(string_new(state, crypt(rbx_string_as_cstr(state, msg->recv),
3307         rbx_string_as_cstr(state, t1))));
3308     CODE
3309   end
3311   defprim :env_get
3312   def env_get
3313     <<-CODE
3314     ARITY(1);
3315     char *key;
3316     OBJECT t1, t2;
3318     POP(t1, STRING);
3320     t2 = Qnil;
3322     key = rbx_string_as_cstr(state, t1);
3323     if (key) {
3324       char *value = getenv(key);
3326       if (value) {
3327         t2 = string_new(state, value);
3328       }
3329     }
3331     RET(t2);
3332     CODE
3333   end
3335   defprim :env_set
3336   def env_set
3337     <<-CODE
3338     ARITY(2);
3339     char *key, *value;
3340     OBJECT t1, t2;
3342     POP(t1, STRING);
3343     t2 = stack_pop();
3345     key = rbx_string_as_cstr(state, t1);
3346     if(key) {
3347       /* if t2 is nil, we need to delete the variable
3348        * and return its value.
3349        */
3350       if(NIL_P(t2)) {
3351         value = getenv(key);
3352         if(value) {
3353           unsetenv(key);
3354           RET(string_new(state, value));
3355         } else {
3356           RET(Qnil);
3357         }
3358       } else {
3359         GUARD(STRING_P(t2));
3360         value = rbx_string_as_cstr(state, t2);
3361         if(value) {
3362           setenv(key, value, 1);
3363           RET(t2);
3364         } else {
3365           RET(Qnil);
3366         }
3367       }
3368     }
3369     CODE
3370   end
3372   defprim :env_as_hash
3373   def env_as_hash
3374     <<-CODE
3375     ARITY(0);
3376     char *cur, **total = environ;
3378     OBJECT hash = hash_new(state);
3380     do {
3381       cur = *total++;
3382       if(!cur) break;
3384       char *name = cur;
3385       int i = 0;
3387       while(*cur && *cur != '=') {
3388         i++; cur++;
3389       }
3391       OBJECT key = string_new2(state, name, i);
3392       OBJECT val = string_new(state, cur+1);
3394       hash_set(state, hash, key, val);
3395     } while(cur);
3397     RET(hash);
3398     CODE
3399   end
3401   defprim :bignum_size
3402   def bignum_size
3403     <<-CODE
3404     ARITY(0);
3405     GUARD(BIGNUM_P(msg->recv));
3406     RET(bignum_size(state, msg->recv));
3407     CODE
3408   end
3410   defprim :iseq_compile
3411   def iseq_compile
3412     <<-CODE
3413     ARITY(0);
3414     GUARD(CMETHOD_P(msg->recv));
3415     cpu_compile_method(state, msg->recv);
3416     RET(Qtrue);
3417     CODE
3418   end
3420   defprim :reset_method_cache
3421   def reset_method_cache
3422     <<-CODE
3423     ARITY(1);
3424     OBJECT t1;
3425     POP(t1, SYMBOL);
3426     cpu_clear_cache_for_method(state, c, t1, TRUE);
3427     CODE
3428   end
3430   defprim :bignum_from_float
3431   def bignum_from_float
3432     <<-CODE
3433     ARITY(1);
3434     OBJECT t1;
3435     POP(t1, FLOAT);
3436     RET(bignum_from_double(state, FLOAT_TO_DOUBLE(t1)));
3437     CODE
3438   end
3440   defprim :save_encloser_path
3441   def save_encloser_path
3442     <<-CODE
3443     ARITY(0);
3444     cpu_set_encloser_path(state, c, state->global->object);
3445     RET(Qnil);
3446     CODE
3447   end
3449   defprim :restore_encloser_path
3450   def restore_encloser_path
3451     <<-CODE
3452     ARITY(0);
3453     cpu_push_encloser(state, c);
3454     RET(Qnil);
3455     CODE
3456   end
3458   defprim :array_aref
3459   def array_aref
3460     <<-CODE
3461     OBJECT t1, t3;
3462     native_int j, k;
3464     GUARD(msg->args == 1);
3465     t1 = stack_top();
3466     GUARD(FIXNUM_P(t1));
3468     j = N2I(array_get_total(msg->recv));
3470     k = N2I(t1);
3472     if(k < 0) k += j;
3474     if(k < 0 || k >= j) {
3475       stack_set_top(Qnil);
3476     } else {
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));
3482     }
3483     CODE
3484   end
3486   defprim :array_aset
3487   def array_aset
3488     <<-CODE
3489     OBJECT t1, t3;
3490     native_int j, k;
3492     GUARD(msg->args == 2);
3493     t1 = stack_pop();
3494     GUARD(FIXNUM_P(t1));
3496     j = N2I(array_get_total(msg->recv));
3497     k = N2I(t1);
3499     if(k < 0) k += j;
3500     GUARD(k >= 0);
3502     if(k >= j - 1) {
3503       array_set_total(msg->recv, I2N(k + 1));
3504     }
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());
3511     CODE
3512   end
3514   defprim :string_append
3515   def string_append
3516     <<-CODE
3517     OBJECT t1;
3519     GUARD(msg->args == 1);
3520     POP(t1, STRING);
3522     string_append(state, msg->recv, t1);
3523     RET(msg->recv);
3524     CODE
3525   end
3527   defprim :string_dup
3528   def string_dup
3529     <<-CODE
3530     ARITY(0);
3531     RET(string_dup(state, msg->recv));
3532     CODE
3533   end
3535   defprim :string_equal
3536   def string_equal
3537     <<-CODE
3538     ARITY(1);
3539     OBJECT t1, t2, t3;
3540     native_int j, k, m;
3542     POP(t1, STRING);
3544     if(msg->recv == t1) {
3545       RET(Qtrue);
3546     } else {
3547       t2 = string_get_bytes(msg->recv);
3548       t3 = string_get_bytes(t1);
3550       if(t2 != t3) {
3551         RET(Qfalse);
3552       } else {
3553         j = N2I(t2);
3554         k = N2I(t3);
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);
3560       }
3561     }
3562     CODE
3563   end
3565   defprim :object_send
3566   def object_send
3567     <<-CODE
3568     OBJECT t1;
3569     GUARD(msg->args >= 1);
3570     t1 = stack_pop();
3571     if(!SYMBOL_P(t1)) {
3572       if(STRING_P(t1)) {
3573         t1 = string_to_sym(state, t1);
3574       } else {
3575         GUARD(0);
3576       }
3577     }
3579     /* Send is allowed to call private methods. */
3580     c->call_flags = 1;
3582     cpu_send(state, c, msg->recv, t1, msg->args - 1, msg->block);
3583     CODE
3584   end
3586   defprim :machine_new
3587   def machine_new
3588     <<-CODE
3589     ARITY(1);
3590     int *pipes;
3591     int argc;
3592     char **argv;
3593     OBJECT ret, ary, str;
3594     int i;
3595     machine m;
3596     environment e = environment_current();
3598     POP(ary, ARRAY);
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);
3604       if(STRING_P(str)) {
3605         argv[i] = strdup(rbx_string_as_cstr(state, str));
3606       } else {
3607         argv[i] = strdup("");
3608       }
3609     }
3611     m = machine_new(e);
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"));
3622     stack_push(ret);
3623     environment_start_thread(e, m);
3625     DONE();
3626     CODE
3627   end
3629   defprim :machine_join
3630   def machine_join
3631     <<-CODE
3632     ARITY(1);
3633     OBJECT t1;
3634     POP(t1, FIXNUM);
3635     if(environment_join_machine(environment_current(), N2I(t1))) {
3636       RET(Qtrue);
3637     } else {
3638       RET(Qfalse);
3639     }
3640     CODE
3641   end
3643   defprim :machine_get_message
3644   def machine_get_message
3645     <<-CODE
3646     ARITY(0);
3647     RET(environment_get_message(environment_current(), current_machine->id));
3648     CODE
3649   end
3651   defprim :machine_send_message
3652   def machine_send_message
3653     <<-CODE
3654     ARITY(2);
3655     OBJECT t1, t2;
3656     POP(t1, FIXNUM);
3657     t2 = stack_pop();
3659     environment_send_message(environment_current(), N2I(t1), t2);
3661     RET(Qtrue);
3662     CODE
3663   end
3665   defprim :dir_open
3666   def dir_open
3667     <<-CODE
3668     ARITY(1);
3669     OBJECT t1;
3670     DIR *dir;
3672     POP(t1, STRING);
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));
3678     CODE
3679   end
3681   defprim :dir_close
3682   def dir_close
3683     <<-CODE
3684     ARITY(1);
3685     DIR *dir;
3686     OBJECT t1;
3688     POP(t1, POINTER);
3690     dir = *DATA_STRUCT(t1, void**);
3691     if(dir) {
3692       *DATA_STRUCT(t1, void**) = NULL;
3693       closedir(dir);
3694       RET(Qtrue);
3695     } else {
3696       RET(Qfalse);
3697     }
3698     CODE
3699   end
3701   defprim :dir_control
3702   def dir_control
3703     <<-CODE
3704     ARITY(3);
3705     OBJECT kind, pos;
3706     OBJECT t1;
3707     POP(t1, POINTER);
3708     DIR *dir = *DATA_STRUCT(t1, void**);
3710     POP(kind, FIXNUM);
3711     POP(pos, FIXNUM);
3713     switch(N2I(kind)) {
3714     case 0:
3715       seekdir(dir, N2I(pos));
3716       RET(Qtrue);
3717     case 1:
3718       rewinddir(dir);
3719       RET(Qtrue);
3720     case 2:
3721       RET(I2N(telldir(dir)));
3722     default:
3723       RET(Qnil);
3724     }
3725     CODE
3726   end
3728   defprim :dir_read
3729   def dir_read
3730     <<-CODE
3731     ARITY(1);
3732     struct dirent *ent;
3733     OBJECT t1;
3734     POP(t1, POINTER);
3735     DIR *dir = *DATA_STRUCT(t1, void**);
3736     ent = readdir(dir);
3738     if(!ent) {
3739       RET(Qnil);
3740     } else {
3741       RET(string_new(state, ent->d_name));
3742     }
3744     CODE
3745   end
3747   defprim :opt_push_literal
3748   def opt_push_literal
3749     <<-CODE
3750     ARITY(0);
3751     OBJECT lits;
3753     lits = cmethod_get_literals(msg->method);
3754     RET(fast_fetch(lits, 0));
3755     CODE
3756   end
3758   defprim :opt_push_self
3759   def opt_push_self
3760     <<-CODE
3761     ARITY(0);
3762     RET(msg->recv);
3763     CODE
3764   end
3766   defprim :opt_push_ivar
3767   def opt_push_ivar
3768     <<-CODE
3769     ARITY(0);
3770     OBJECT lits;
3772     lits = cmethod_get_literals(msg->method);
3773     RET(object_get_ivar(state, msg->recv, fast_fetch(lits, 0)));
3774     CODE
3775   end
3777   defprim :opt_push_my_field
3778   def opt_push_my_field
3779     <<-CODE
3780     ARITY(0);
3781     OBJECT lits;
3783     lits = cmethod_get_literals(msg->method);
3784     RET(NTH_FIELD(msg->recv, N2I(fast_fetch(lits, 0))));
3785     CODE
3786   end
3788   defprim :opt_kind_of
3789   def opt_kind_of
3790     <<-CODE
3791     ARITY(1);
3792     OBJECT t1;
3794     POP(t1, REFERENCE);
3795     GUARD(CLASS_P(t1) || MODULE_P(t1));
3797     RET(object_kind_of_p(state, msg->recv, t1) ? Qtrue : Qfalse);
3798     CODE
3799   end
3801   defprim :float_add
3802   def float_add
3803     <<-CODE
3804     ARITY(1);
3805     GUARD(FLOAT_P(msg->recv));
3806     double a = FLOAT_TO_DOUBLE(msg->recv);
3807     OBJECT t1 = stack_pop();
3808     if(!FLOAT_P(t1)) {
3809       t1 = float_coerce(state, t1);
3810       GUARD(FLOAT_P(t1));
3811     }
3812     RET(float_new(state, a + FLOAT_TO_DOUBLE(t1)));
3813     CODE
3814   end
3816   defprim :float_sub
3817   def float_sub
3818     <<-CODE
3819     ARITY(1);
3820     GUARD(FLOAT_P(msg->recv));
3821     double a = FLOAT_TO_DOUBLE(msg->recv);
3822     OBJECT t1 = stack_pop();
3823     if(!FLOAT_P(t1)) {
3824       t1 = float_coerce(state, t1);
3825       GUARD(FLOAT_P(t1));
3826     }
3827     RET(float_new(state, a - FLOAT_TO_DOUBLE(t1)));
3828     CODE
3829   end
3831   defprim :float_mul
3832   def float_mul
3833     <<-CODE
3834     ARITY(1);
3835     GUARD(FLOAT_P(msg->recv));
3836     double a = FLOAT_TO_DOUBLE(msg->recv);
3837     OBJECT t1 = stack_pop();
3838     if(!FLOAT_P(t1)) {
3839       t1 = float_coerce(state, t1);
3840       GUARD(FLOAT_P(t1));
3841     }
3842     RET(float_new(state, a * FLOAT_TO_DOUBLE(t1)));
3843     CODE
3844   end
3846   defprim :float_div
3847   def float_div
3848     <<-CODE
3849     ARITY(1);
3850     GUARD(FLOAT_P(msg->recv));
3851     double a = FLOAT_TO_DOUBLE(msg->recv);
3852     OBJECT t1 = stack_pop();
3853     if(!FLOAT_P(t1)) {
3854       t1 = float_coerce(state, t1);
3855       GUARD(FLOAT_P(t1));
3856     }
3857     RET(float_new(state, a / FLOAT_TO_DOUBLE(t1)));
3858     CODE
3859   end
3861   defprim :float_uminus
3862   def float_uminus
3863     <<-CODE
3864     ARITY(0);
3865     GUARD(FLOAT_P(msg->recv));
3866     double a = FLOAT_TO_DOUBLE(msg->recv);
3867     RET(float_new(state, -a));
3868     CODE
3869   end
3871   defprim :float_equal
3872   def float_equal
3873     <<-CODE
3874     ARITY(1);
3875     GUARD(FLOAT_P(msg->recv));
3876     double a = FLOAT_TO_DOUBLE(msg->recv);
3877     OBJECT t1 = stack_pop();
3878     if(!FLOAT_P(t1)) {
3879       t1 = float_coerce(state, t1);
3880       GUARD(FLOAT_P(t1));
3881     }
3882     RET(a == FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
3883     CODE
3884   end
3886   defprim :float_eql
3887   def float_eql
3888     <<-CODE
3889     ARITY(1);
3890     GUARD(FLOAT_P(msg->recv));
3891     OBJECT t1 = stack_pop();
3892     if(FLOAT_P(t1)) {
3893       double a = FLOAT_TO_DOUBLE(msg->recv),
3894              b = FLOAT_TO_DOUBLE(t1);
3895       RET(a == b ? Qtrue : Qfalse);
3896     } else {
3897       RET(Qfalse);
3898     }
3899     CODE
3900   end
3902   defprim :float_compare
3903   def float_compare
3904     <<-CODE
3905     ARITY(1);
3906     GUARD(FLOAT_P(msg->recv));
3907     double a = FLOAT_TO_DOUBLE(msg->recv);
3908     OBJECT t1 = stack_pop();
3909     if(!FLOAT_P(t1)) {
3910       t1 = float_coerce(state, t1);
3911       GUARD(FLOAT_P(t1));
3912     }
3913     double b = FLOAT_TO_DOUBLE(t1);
3914     RET(float_compare(state, a, b));
3915     CODE
3916   end
3918   defprim :float_lt
3919   def float_lt
3920     <<-CODE
3921     ARITY(1);
3922     GUARD(FLOAT_P(msg->recv));
3923     double a = FLOAT_TO_DOUBLE(msg->recv);
3924     OBJECT t1 = stack_pop();
3925     if(!FLOAT_P(t1)) {
3926       t1 = float_coerce(state, t1);
3927       GUARD(FLOAT_P(t1));
3928     }
3929     RET(a < FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
3930     CODE
3931   end
3933   defprim :float_le
3934   def float_le
3935     <<-CODE
3936     ARITY(1);
3937     GUARD(FLOAT_P(msg->recv));
3938     double a = FLOAT_TO_DOUBLE(msg->recv);
3939     OBJECT t1 = stack_pop();
3940     if(!FLOAT_P(t1)) {
3941       t1 = float_coerce(state, t1);
3942       GUARD(FLOAT_P(t1));
3943     }
3944     RET(a <= FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
3945     CODE
3946   end
3948   defprim :float_gt
3949   def float_gt
3950     <<-CODE
3951     ARITY(1);
3952     GUARD(FLOAT_P(msg->recv));
3953     double a = FLOAT_TO_DOUBLE(msg->recv);
3954     OBJECT t1 = stack_pop();
3955     if(!FLOAT_P(t1)) {
3956       t1 = float_coerce(state, t1);
3957       GUARD(FLOAT_P(t1));
3958     }
3959     RET(a > FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
3960     CODE
3961   end
3963   defprim :float_ge
3964   def float_ge
3965     <<-CODE
3966     ARITY(1);
3967     GUARD(FLOAT_P(msg->recv));
3968     double a = FLOAT_TO_DOUBLE(msg->recv);
3969     OBJECT t1 = stack_pop();
3970     if(!FLOAT_P(t1)) {
3971       t1 = float_coerce(state, t1);
3972       GUARD(FLOAT_P(t1));
3973     }
3974     RET(a >= FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
3975     CODE
3976   end
3978   defprim :float_to_i
3979   def float_to_i
3980     <<-CODE
3981     ARITY(0);
3982     GUARD(FLOAT_P(msg->recv));
3983     double b = FLOAT_TO_DOUBLE(msg->recv);
3984     if(isinf(b)) {
3985       RAISE("FloatDomainError", b < 0 ? "-Infinity" : "Infinity");
3986     } else if(isnan(b)) {
3987       RET(msg->recv);
3988     } else {
3989       RET(bignum_from_double(state, float_truncate(b)));
3990     }
3991     CODE
3992   end
3994   defprim :float_round
3995   def float_round
3996     <<-CODE
3997     ARITY(0);
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));
4003     CODE
4004   end
4006   defprim :float_divmod
4007   def float_divmod
4008     <<-CODE
4009     ARITY(1);
4010     GUARD(FLOAT_P(msg->recv));
4011     double a = FLOAT_TO_DOUBLE(msg->recv);
4012     OBJECT t1 = stack_pop();
4013     if(!FLOAT_P(t1)) {
4014       t1 = float_coerce(state, t1);
4015       GUARD(FLOAT_P(t1));
4016     }
4017     double b = FLOAT_TO_DOUBLE(t1);
4018     if(b == 0.0) {
4019       RAISE("FloatDomainError", "divide by 0");
4020     } else {
4021       double div = floor(a / b);
4022       double mod = fmod(a, b);
4023       if(b * mod < 0) {
4024         mod += b;
4025       }
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));
4029       RET(ary);
4030     }
4031     CODE
4032   end
4034   defprim :float_pow
4035   def float_pow
4036     <<-CODE
4037     ARITY(1);
4038     GUARD(FLOAT_P(msg->recv));
4039     double a = FLOAT_TO_DOUBLE(msg->recv);
4040     OBJECT t1 = stack_pop();
4041     if(!FLOAT_P(t1)) {
4042       t1 = float_coerce(state, t1);
4043       GUARD(FLOAT_P(t1));
4044     }
4045     RET(float_new(state, pow(a, FLOAT_TO_DOUBLE(t1))));
4046     CODE
4047   end
4049   defprim :float_isnan
4050   def float_isnan
4051     <<-CODE
4052     ARITY(0);
4053     GUARD(FLOAT_P(msg->recv));
4054     RET(isnan(FLOAT_TO_DOUBLE(msg->recv)) == 1 ? Qtrue : Qfalse);
4055     CODE
4056   end
4058   defprim :float_isinf
4059   def float_isinf
4060     <<-CODE
4061     ARITY(0);
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));
4066     } else {
4067       RET(Qnil);
4068     }
4069     CODE
4070   end
4072   defprim :bignum_gt
4073   def bignum_gt
4074     <<-CODE
4075     ARITY(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);
4083     } else {
4084       FAIL();
4085     }
4086     CODE
4087   end
4089   defprim :bignum_ge
4090   def bignum_ge
4091     <<-CODE
4092     ARITY(1);
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);
4100     } else {
4101       FAIL();
4102     }
4103     CODE
4104   end
4106   defprim :bignum_lt
4107   def bignum_lt
4108     <<-CODE
4109     ARITY(1);
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);
4117     } else {
4118       FAIL();
4119     }
4120     CODE
4121   end
4123   defprim :bignum_le
4124   def bignum_le
4125     <<-CODE
4126     ARITY(1);
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);
4134     } else {
4135       FAIL();
4136     }
4137     CODE
4138   end
4140   defprim :sendsite_create
4141   def sendsite_create
4142     <<-CODE
4143     ARITY(1);
4144     OBJECT t1, ss;
4146     GUARD(CLASS_P(msg->recv));
4147     POP(t1, SYMBOL);
4149     ss = send_site_create(state, t1);
4150     RET(ss);
4151     CODE
4152   end
4154   defprim :sendsite_set_sender
4155   def sendsite_set_sender
4156     <<-CODE
4157     ARITY(1);
4158     OBJECT cm;
4160     GUARD(SENDSITE_P(msg->recv));
4161     POP(cm, CMETHOD);
4163     send_site_set_sender(state, msg->recv, cm);
4164     RET(Qnil);
4165     CODE
4166   end
4168   defprim :sendsite_at
4169   def sendsite_at
4170     <<-CODE
4171     ARITY(1);
4172     OBJECT t1;
4174     GUARD(SENDSITE_P(msg->recv));
4175     POP(t1, FIXNUM);
4177     switch(N2I(t1)) {
4178     case 0:
4179       RET(SENDSITE(msg->recv)->name);
4180     case 1:
4181       RET(SENDSITE(msg->recv)->selector);
4182     case 2:
4183       RET(SENDSITE(msg->recv)->data1);
4184     case 3:
4185       RET(SENDSITE(msg->recv)->data2);
4186     case 4:
4187       RET(SENDSITE(msg->recv)->data3);
4188     case 5:
4189       RET(ffi_new_pointer(state, SENDSITE(msg->recv)->c_data));
4190     case 6:
4191       RET(I2N(SENDSITE(msg->recv)->hits));
4192     case 7:
4193       RET(I2N(SENDSITE(msg->recv)->misses));
4194     case 8:
4195       RET(SENDSITE(msg->recv)->sender);
4196     default:
4197       RET(Qnil);
4198     }
4199     CODE
4200   end
4202   defprim :selector_clear
4203   def selector_clear
4204     <<-CODE
4205     GUARD(SELECTOR_P(msg->recv));
4207     selector_clear(state, msg->recv);
4209     RET(Qnil);
4210     CODE
4211   end
4213   defprim :dtrace_fire_ruby_probe
4214   def dtrace_fire_ruby_probe
4215     <<-CODE
4216     ARITY(2);
4218     OBJECT t1, t2;
4220     POP(t1, STRING);
4221     POP(t2, STRING);
4223 #if ENABLE_DTRACE
4224     if (RUBINIUS_RUBY_PROBE_ENABLED()) {
4225       RUBINIUS_RUBY_PROBE(rbx_string_as_cstr(state, t1), rbx_string_as_cstr(state, t2));
4226     }
4227 #endif
4229     RET(Qnil);
4230     CODE
4231   end
4233   defprim :allocate_table
4234   def allocate_table
4235     <<-CODE
4236     ARITY(0);
4237     GUARD(CLASS_P(msg->recv));
4238     OBJECT t1;
4240     t1 = lookuptable_new(state);
4241     SET_CLASS(t1, msg->recv);
4242     RET(t1);
4243     CODE
4244   end
4246   defprim :lookuptable_store
4247   def lookuptable_store
4248     <<-CODE
4249     ARITY(2);
4250     GUARD(LOOKUPTABLE_P(msg->recv));
4251     OBJECT t1, t2;
4253     t1 = stack_pop();
4254     t2 = stack_pop();
4255     RET(lookuptable_store(state, msg->recv, t1, t2));
4256     CODE
4257   end
4259   defprim :lookuptable_fetch
4260   def lookuptable_fetch
4261     <<-CODE
4262     ARITY(1);
4263     GUARD(LOOKUPTABLE_P(msg->recv));
4264     OBJECT t1, t2;
4266     t1 = stack_pop();
4267     t2 = lookuptable_fetch(state, msg->recv, t1);
4268     RET(t2 == Qundef ? Qnil : t2);
4269     CODE
4270   end
4272   defprim :lookuptable_delete
4273   def lookuptable_delete
4274     <<-CODE
4275     ARITY(1);
4276     GUARD(LOOKUPTABLE_P(msg->recv));
4277     OBJECT t1, t2;
4279     t1 = stack_pop();
4280     t2 = lookuptable_delete(state, msg->recv, t1);
4281     RET(t2 == Qundef ? Qnil : t2);
4282     CODE
4283   end
4285   defprim :lookuptable_has_key
4286   def lookuptable_has_key
4287     <<-CODE
4288     ARITY(1);
4289     GUARD(LOOKUPTABLE_P(msg->recv));
4290     OBJECT t1;
4292     t1 = stack_pop();
4293     RET(lookuptable_has_key(state, msg->recv, t1));
4294     CODE
4295   end
4297   defprim :lookuptable_keys
4298   def lookuptable_keys
4299     <<-CODE
4300     ARITY(0);
4301     GUARD(LOOKUPTABLE_P(msg->recv));
4302     RET(lookuptable_keys(state, msg->recv));
4303     CODE
4304   end
4306   defprim :lookuptable_values
4307   def lookuptable_values
4308     <<-CODE
4309     ARITY(0);
4310     GUARD(LOOKUPTABLE_P(msg->recv));
4311     RET(lookuptable_values(state, msg->recv));
4312     CODE
4313   end
4315   defprim :lookuptable_entries
4316   def lookuptable_entries
4317     <<-CODE
4318     ARITY(0);
4319     GUARD(LOOKUPTABLE_P(msg->recv));
4320     RET(lookuptable_entries(state, msg->recv));
4321     CODE
4322   end
4324   defprim :lookuptable_dup
4325   def lookuptable_dup
4326     <<-CODE
4327     ARITY(0);
4328     GUARD(LOOKUPTABLE_P(msg->recv));
4329     RET(lookuptable_dup(state, msg->recv));
4330     CODE
4331   end
4333   defprim :allocate_module
4334   def allocate_module
4335     <<-CODE
4336     ARITY(0);
4337     GUARD(CLASS_P(msg->recv));
4338     OBJECT t1, t2;
4340     t1 = class_get_instance_fields(msg->recv);
4341     t2 = NEW_OBJECT(msg->recv, N2I(t1));
4342     module_setup_fields(state, t2);
4343     RET(t2);
4344     CODE
4345   end
4347   defprim :allocate_hash
4348   def allocate_hash
4349     <<-CODE
4350     ARITY(0);
4351     GUARD(CLASS_P(msg->recv));
4352     OBJECT t1;
4354     t1 = hash_new(state);
4355     SET_CLASS(t1, msg->recv);
4356     RET(t1);
4357     CODE
4358   end
4360   defprim :string_tr_expand
4361   def string_tr_expand
4362     <<-CODE
4363     ARITY(1);
4364     GUARD(STRING_P(msg->recv));
4365     OBJECT t1;
4366     t1 = stack_pop();
4367     RET(string_tr_expand(state, msg->recv, t1));
4368     CODE
4369   end
4371   defprim :string_template
4372   def string_template
4373     <<-CODE
4374     ARITY(2);
4375     GUARD(CLASS_P(msg->recv));
4376     OBJECT t1, t2, t3;
4377     native_int k;
4378     char *data;
4380     POP(t1, FIXNUM);
4381     k = N2I(t1);
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);
4387     t2 = stack_pop();
4388     if(FIXNUM_P(t2)) {
4389       memset(data, N2I(t2), k);
4390     } else if(STRING_P(t2)) {
4391       int bytes;
4392       char *str;
4394       t3->IsTainted |= t2->IsTainted;
4395       bytes = N2I(string_get_bytes(t2));
4396       str = rbx_string_as_cstr(state, t2);
4397       if(bytes == 1) {
4398         memset(data, str[0], k);
4399       } else if(bytes > 1) {
4400         int i, j, n, size;
4402         size = k / bytes;
4403         for(n = i = 0; i < size; i++) {
4404           for(j = 0; j < bytes; j++, n++) {
4405             data[n] = str[j];
4406           }
4407         }
4408         for(i = n, j = 0; i < k; i++, j++) {
4409           data[i] = str[j];
4410         }
4411       }
4412     } else {
4413       FAIL();
4414     }
4415     RET(t3);
4416     CODE
4417   end
4419   defprim :string_apply_and
4420   def string_apply_and
4421     <<-CODE
4422     ARITY(1);
4423     GUARD(STRING_P(msg->recv));
4424     OBJECT t1;
4425     native_int i, j, k, size;
4426     char *a, *b;
4428     POP(t1, STRING);
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];
4437     }
4438     RET(Qnil);
4439     CODE
4440   end
4442   defprim :tuple_template
4443   def tuple_template
4444     <<-CODE
4445     ARITY(2)
4446     GUARD(CLASS_P(msg->recv));
4447     OBJECT t1, t2, t3;
4448     native_int i, k;
4450     POP(t1, FIXNUM);
4451     k = N2I(t1);
4452     t2 = stack_pop();
4453     t3 = tuple_new(state, k);
4454     for(i = 0; i < k; i++) {
4455       tuple_put(state, t3, i, t2);
4456     }
4457     RET(t3);
4458     CODE
4459   end
4461   defprim :string_copy_from
4462   def string_copy_from
4463     <<-CODE
4464     ARITY(4);
4465     GUARD(STRING_P(msg->recv));
4466     OBJECT t1, t2, t3, t4;
4467     native_int n, start, size, dest;
4468     char *a, *b;
4470     POP(t1, STRING);
4471     POP(t2, FIXNUM);
4472     POP(t3, FIXNUM);
4473     POP(t4, FIXNUM);
4475     start = N2I(t2);
4476     size = N2I(t3);
4477     dest = N2I(t4);
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);
4493     RET(msg->recv);
4494     CODE
4495   end
4497   defprim :string_compare_substring
4498   def string_compare_substring
4499     <<-CODE
4500     ARITY(3);
4501     GUARD(STRING_P(msg->recv));
4502     OBJECT t1, t2, t3;
4503     native_int bytes, start, size, cmp;
4504     char *a, *b;
4506     POP(t1, STRING);
4507     POP(t2, FIXNUM);
4508     POP(t3, FIXNUM);
4510     start = N2I(t2);
4511     size = N2I(t3);
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);
4524     if(cmp < 0) {
4525       RET(I2N(-1));
4526     } else if(cmp > 0) {
4527       RET(I2N(1));
4528     } else {
4529       RET(I2N(0));
4530     }
4531     CODE
4532   end
4534   defprim :io_close_ng
4535   def io_close_ng
4536     <<-CODE
4537     ARITY(0);
4538     native_int j;
4540     GUARD(IO_P(msg->recv));
4542     j = io_to_fd(msg->recv);
4544     if(j == -1) {
4545       RAISE("IOError", "instance of IO already closed");
4546     } else if(close(j)) {
4547       RAISE_FROM_ERRNO("Unable to close IO object");
4548     } else {
4549       cpu_event_clear(state, j);
4550       io_set_descriptor(msg->recv, I2N(-1));
4551       RET(Qnil);
4552     }
4553     CODE
4554   end
4557 prim = ShotgunPrimitives.new
4558 prim.generate_select(STDOUT)