Added spec:commit task to commit changes to spec/ruby sources.
[rbx.git] / shotgun / lib / primitives.rb
blob7abb071c4c0a2f5c235e4c2ade4d6d84f308ad34
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         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         fc->block = t2;
2446         break;
2447       case 5:
2448         fc->method = t2;
2449         break;
2450       case 6:
2451         fc->literals = t2;
2452         break;
2453       case 7:
2454         fc->self = t2;
2455         break;
2456       case 8:
2457         fc->locals = t2;
2458         break;
2459       case 9:
2460         GUARD(FIXNUM_P(t2));
2461         fc->argcount = N2I(t2);
2462         break;
2463       case 10:
2464         fc->name = t2;
2465         break;
2466       case 11:
2467         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     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     cpu_patch_ffi(state, msg);
2572     ffi_call(state, c, nfunc_get_data(msg->method));
2573     CODE
2574   end
2576   defprim :nfunc_call_object
2577   def nfunc_call_object
2578     <<-CODE
2579     /* The definition of beauty. Simplicity. To call a native function, there is no work
2580        to be done. The stub contains all the serialization code.
2582        That being said, this might get more complicated when callbacks are supported. */
2583     ffi_call(state, c, nfunc_get_data(msg->recv));
2584     CODE
2585   end
2587   defprim :nfunc_add
2588   def nfunc_add
2589     <<-CODE
2590     ARITY(4);
2591     OBJECT t1, t2, t3, t4;
2593     POP(t1, STRING_OR_NIL);
2594     POP(t2, STRING);
2595     POP(t3, ARRAY);
2596     POP(t4, FIXNUM);
2597     RET(ffi_function_create(state, t1, t2, t3, t4));
2598     CODE
2599   end
2601   defprim :load_library
2602   def load_library
2603     <<-CODE
2604     ARITY(2);
2605     OBJECT t1, t2;
2607     POP(t1, STRING);
2608     POP(t2, STRING);
2609     RET(subtend_load_library(state, c, t1, t2));
2610     CODE
2611   end
2613   defprim :dir_glob
2614   def dir_glob
2615     <<-CODE
2616     ARITY(2);
2617     glob_t gd;
2618     char *pat;
2619     int flags = GLOB_NOSORT | GLOB_BRACE;
2620     OBJECT t1, t2;
2621     native_int j, k;
2623     POP(t1, STRING);
2624     POP(t2, FIXNUM);
2626     /* TODO: use t2. */
2628     pat = rbx_string_as_cstr(state, t1);
2629     k = glob(pat, flags, NULL, &gd);
2630     t2 = array_new(state, gd.gl_pathc);
2631     for(j = 0; j < gd.gl_pathc; j++) {
2632       array_set(state, t2, j, string_new(state, gd.gl_pathv[j]));
2633     }
2634     globfree(&gd);
2635     RET(t2);
2636     CODE
2637   end
2639   defprim :dir_chdir
2640   def dir_chdir
2641     <<-CODE
2642     ARITY(1);
2643     char *path;
2644     OBJECT t1;
2646     POP(t1, STRING);
2648     path = rbx_string_as_cstr(state, t1);
2649     if(!chdir(path)) {
2650       RET(Qtrue);
2651     } else {
2652       RET(Qfalse);
2653     }
2654     CODE
2655   end
2657   defprim :yield_gdb
2658   def yield_gdb
2659     <<-CODE
2660     ARITY(1);
2661     OBJECT t1 = stack_pop();
2662     *((OBJECT*)4) = t1; /* cause a SIGBUS */
2663     RET(Qtrue);
2664     CODE
2665   end
2667   defprim :make_weak_ref
2668   def make_weak_ref
2669     <<-CODE
2670     ARITY(1);
2671     OBJECT t1;
2672     POP(t1, REFERENCE);
2674     RET(object_make_weak_ref(state, t1));
2675     CODE
2676   end
2678   defprim :gc_collect_references
2679   def gc_collect_references
2680     <<-CODE
2681     ARITY(1);
2682     OBJECT t1;
2683     POP(t1, REFERENCE);
2685     RET(object_memory_collect_references(state, state->om, t1));
2686     CODE
2687   end
2689   defprim :task_dup
2690   def task_dup
2691     <<-CODE
2692     ARITY(0);
2693     OBJECT t1;
2694     /* This is a little contrived so the dup'd task has
2695        it stack setup properly. */
2697     stack_push(Qnil);
2699     if(TASK_P(msg->recv)) {
2700       t1 = cpu_task_dup(state, c, msg->recv);
2701     } else {
2702       t1 = cpu_task_dup(state, c, Qnil);
2703     }
2705     cpu_stack_set_top(state, c, t1);
2706     CODE
2707   end
2709   defprim :task_set_current
2710   def task_set_current
2711     <<-CODE
2712     ARITY(1);
2713     OBJECT t1;
2714     POP(t1, TASK);
2716     stack_push(Qnil);
2717     cpu_task_select(state, c, t1);
2718     CODE
2719   end
2721   defprim :task_associate
2722   def task_associate
2723     <<-CODE
2724     ARITY(1);
2725     OBJECT t1;
2727     GUARD(TASK_P(msg->recv));
2728     POP(t1, BLOCKENV);
2730     RET(cpu_task_associate(state, c, msg->recv, t1));
2731     CODE
2732   end
2734   defprim :task_current
2735   def task_current
2736     <<-CODE
2737     ARITY(0);
2738     RET(c->current_task);
2739     CODE
2740   end
2742   defprim :task_at
2743   def task_at
2744     <<-CODE
2745     ARITY(1);
2746     struct cpu_task *task;
2747     OBJECT t1, t2;
2748     native_int k;
2750     GUARD(TASK_P(msg->recv));
2751     POP(t1, FIXNUM);
2753     task = (struct cpu_task*)BYTES_OF(msg->recv);
2754     k = N2I(t1);
2756     switch(k) {
2757     case 0:
2758       t2 = task->main;
2759       break;
2760     case 1:
2761       t2 = task->active_context;
2762       if(REFERENCE_P(t2)) methctx_reference(state, t2);
2763       break;
2764     default:
2765       t2 = Qnil;
2766     }
2768     RET(t2);
2769     CODE
2770   end
2772   defprim :task_set_debugging
2773   def task_set_debugging
2774     <<-CODE
2775     ARITY(2);
2776     OBJECT t1, t2;
2777     GUARD(TASK_P(msg->recv));
2779     t1 = stack_pop();
2780     t2 = stack_pop();
2782     GUARD(t1 == Qnil || CHANNEL_P(t1));
2783     GUARD(t2 == Qnil || CHANNEL_P(t2));
2785     if(msg->recv == c->current_task) {
2786       c->debug_channel = t1;
2787       c->control_channel = t2;
2788     } else {
2789       cpu_task_set_debugging(state, msg->recv, t1, t2);
2790     }
2791     RET(Qtrue);
2792     CODE
2793   end
2795   defprim :task_debug_channel
2796   def task_debug_channel
2797     <<-CODE
2798     ARITY(0);
2799     struct cpu_task *task;
2800     GUARD(TASK_P(msg->recv));
2802     task = (struct cpu_task*)BYTES_OF(msg->recv);
2804     RET(task->debug_channel);
2805     CODE
2806   end
2808   defprim :task_control_channel
2809   def task_control_channel
2810     <<-CODE
2811     ARITY(0);
2812     struct cpu_task *task;
2813     GUARD(TASK_P(msg->recv));
2815     task = (struct cpu_task*)BYTES_OF(msg->recv);
2817     RET(task->control_channel);
2818     CODE
2819   end
2821   defprim :task_get_debug_context_change
2822   def task_get_debug_context_change
2823     <<-CODE
2824     ARITY(0);
2825     struct cpu_task *task;
2826     GUARD(TASK_P(msg->recv));
2828     task = (struct cpu_task*)BYTES_OF(msg->recv);
2829     if(TASK_FLAG_P(task, TASK_DEBUG_ON_CTXT_CHANGE)) {
2830       RET(Qtrue);
2831     } else {
2832       RET(Qfalse);
2833     }
2834     CODE
2835   end
2837   defprim :task_set_debug_context_change
2838   def task_set_debug_context_change
2839     <<-CODE
2840     ARITY(1);
2841     struct cpu_task *task;
2842     GUARD(TASK_P(msg->recv));
2843     OBJECT t1 = stack_pop();
2845     task = (struct cpu_task*)BYTES_OF(msg->recv);
2846     if(RTEST(t1)) {
2847       TASK_SET_FLAG(task, TASK_DEBUG_ON_CTXT_CHANGE);
2848       if(task->active) {
2849         TASK_SET_FLAG(c, TASK_DEBUG_ON_CTXT_CHANGE);
2850       }
2851       RET(Qtrue);
2852     } else {
2853       if(TASK_FLAG_P(task, TASK_DEBUG_ON_CTXT_CHANGE)) {
2854         TASK_CLEAR_FLAG(task, TASK_DEBUG_ON_CTXT_CHANGE);
2855         if(task->active) {
2856           TASK_CLEAR_FLAG(c, TASK_DEBUG_ON_CTXT_CHANGE);
2857         }
2858       }
2859       RET(Qfalse);
2860     }
2861     CODE
2862   end
2864   defprim :task_stack_size
2865   def task_stack_size
2866     <<-CODE
2867     ARITY(0);
2868     struct cpu_task *task;
2869     GUARD(TASK_P(msg->recv));
2871     task = (struct cpu_task*)BYTES_OF(msg->recv);
2872     OBJECT t1 = I2N(task->sp_ptr - task->stack_top);
2874     RET(t1);
2875     CODE
2876   end
2878   defprim :task_get_stack_value
2879   def task_get_stack_value
2880     <<-CODE
2881     ARITY(1);
2882     struct cpu_task *task;
2883     OBJECT t1, t2;
2885     GUARD(TASK_P(msg->recv));
2886     POP(t1, FIXNUM);
2888     task = (struct cpu_task*)BYTES_OF(msg->recv);
2889     int idx = N2I(t1);
2890     GUARD(idx >=0 && idx < (task->sp_ptr - task->stack_top));
2892     t2 = *(task->sp_ptr - idx);
2894     RET(t2);
2895     CODE
2896   end
2898   defprim :task_raise
2899   def task_raise
2900     <<-CODE
2901     ARITY(1);
2902     OBJECT t1;
2903     GUARD(TASK_P(msg->recv));
2905     t1 = stack_pop();
2907     /* The return value */
2908     stack_push(Qnil);
2910     /* This is conditional because task_select can decide that it's not
2911        not possible to select this task, in which case it handles letting
2912        the user know this on it's own. */
2914     if(cpu_task_select(state, c, msg->recv)) {
2915       cpu_raise_exception(state, c, t1);
2916     }
2917     CODE
2918   end
2920   defprim :thread_raise
2921   def thread_raise
2922     <<-CODE
2923     ARITY(1);
2924     OBJECT t1;
2925     GUARD(THREAD_P(msg->recv));
2927     t1 = stack_pop();
2929     if(!cpu_thread_alive_p(state, msg->recv)) {
2930       RET(Qfalse);
2931     } else {
2933       /* The return value */
2934       stack_push(Qtrue);
2936       cpu_thread_schedule(state, c->current_thread);
2937       cpu_thread_force_run(state, c, msg->recv);
2939       methctx_reference(state, c->active_context);
2940       exception_set_context(t1, c->active_context);
2942       cpu_raise_exception(state, c, t1);
2943     }
2944     CODE
2945   end
2947   defprim :channel_new
2948   def channel_new
2949     <<-CODE
2950     ARITY(0);
2951     RET(cpu_channel_new(state));
2952     CODE
2953   end
2955   defprim :channel_send
2956   def channel_send
2957     <<-CODE
2958     ARITY(1);
2959     OBJECT t1;
2960     GUARD(CHANNEL_P(msg->recv));
2962     t1 = stack_pop();
2963     RET(cpu_channel_send(state, c, msg->recv, t1));
2964     CODE
2965   end
2967   defprim :channel_receive
2968   def channel_receive
2969     <<-CODE
2970     ARITY(0);
2971     GUARD(CHANNEL_P(msg->recv));
2973     cpu_channel_receive(state, c, msg->recv, c->current_thread);
2974     /* Don't touch the stack as we may be in a different task at this
2975        point. The original task's stack is updated when the channel
2976        is written to and the task restored. */
2977     CODE
2978   end
2980   defprim :channel_send_in_microseconds
2981   def channel_send_in_microseconds
2982     <<-CODE
2983     ARITY(3);
2984     double seconds;
2985     OBJECT channel, usec_r, tag;
2986     native_int k;
2988     POP(channel, CHANNEL);
2989     POP(usec_r, INTEGER);
2990     tag = stack_pop();
2992     if(FIXNUM_P(usec_r)) {
2993       k = (long)N2I(usec_r);
2994     } else {
2995       k = (long)bignum_to_int(state, usec_r);
2996     }
2998     seconds = k / 1000000.0;
3000     RET(cpu_event_wake_channel(state, c, channel, seconds, tag));
3001     CODE
3002   end
3004   defprim :channel_send_in_seconds
3005   def channel_send_in_seconds
3006     <<-CODE
3007     ARITY(3);
3008     double seconds;
3009     OBJECT channel, seconds_r, tag;
3011     POP(channel, CHANNEL);
3012     POP(seconds_r, FLOAT);
3013     tag = stack_pop();
3015     seconds = FLOAT_TO_DOUBLE(seconds_r);
3017     RET(cpu_event_wake_channel(state, c, channel, seconds, tag));
3018     CODE
3019   end
3021   defprim :channel_send_on_readable
3022   def channel_send_on_readable
3023     <<-CODE
3024     ARITY(4);
3025     OBJECT t1, t2, t3, t4;
3026     native_int j;
3028     POP(t4, CHANNEL);
3029     t1 = stack_pop();
3030     t2 = stack_pop();
3031     t3 = stack_pop();
3033     GUARD(STRING_P(t2) || NIL_P(t2));
3034     GUARD(FIXNUM_P(t3) || NIL_P(t3));
3036     if(IO_P(t1)) {
3037       j = io_to_fd(t1);
3038     } else if(FIXNUM_P(t1)) {
3039       j = N2I(t1);
3040     } else {
3041       GUARD(0);
3042     }
3044     RET(cpu_event_wait_readable(state, c, t4, j, t2, N2I(t3)));
3045     CODE
3046   end
3048   defprim :channel_send_on_writable
3049   def channel_send_on_writable
3050     <<-CODE
3051     ARITY(2);
3052     OBJECT t1, t2;
3053     native_int j;
3055     POP(t2, CHANNEL);
3056     POP(t1, IO);
3058     j = io_to_fd(t1);
3059     RET(cpu_event_wait_writable(state, c, t2, j));
3060     CODE
3061   end
3063   defprim :channel_send_on_signal
3064   def channel_send_on_signal
3065     <<-CODE
3066     ARITY(2);
3067     OBJECT t1, t2;
3069     POP(t2, CHANNEL);
3070     POP(t1, FIXNUM);
3072     RET(cpu_event_wait_signal(state, c, t2, N2I(t1)));
3073     CODE
3074   end
3076   defprim :channel_send_on_stopped
3077   def channel_send_on_stopped
3078     <<-CODE
3079     ARITY(3);
3080     OBJECT t1, t2, t3;
3082     POP(t3, CHANNEL);
3083     POP(t1, FIXNUM);
3084     POP(t2, FIXNUM);
3086     RET(cpu_event_wait_child(state, c, t3, N2I(t1), N2I(t2)));
3087     CODE
3088   end
3090   defprim :scheduler_cancel
3091   def scheduler_cancel
3092     <<-CODE
3093     ARITY(1);
3094     OBJECT t1;
3095     POP(t1, FIXNUM);
3097     RET(cpu_event_cancel_event(state, t1) ? Qtrue : Qfalse);
3098     CODE
3099   end
3101   defprim :thread_new
3102   def thread_new
3103     <<-CODE
3104     ARITY(0);
3105     RET(cpu_thread_new(state, c));
3106     CODE
3107   end
3109   defprim :thread_run
3110   def thread_run
3111     <<-CODE
3112     ARITY(0);
3113     GUARD(THREAD_P(msg->recv));
3115     GUARD(cpu_thread_alive_p(state, msg->recv));
3117     /* So when we're restored, there is a ret val. */
3118     stack_push(Qnil);
3119     cpu_thread_schedule(state, c->current_thread);
3120     cpu_thread_force_run(state, c, msg->recv);
3121     CODE
3122   end
3124   defprim :thread_schedule
3125   def thread_schedule
3126     <<-CODE
3127     ARITY(0);
3128     GUARD(THREAD_P(msg->recv));
3130     cpu_thread_schedule(state, msg->recv);
3131     RET(Qnil);
3132     CODE
3133   end
3135   defprim :thread_yield
3136   def thread_yield
3137     <<-CODE
3138     ARITY(0);
3139     /* Same reason as thread_run */
3140     stack_push(Qnil);
3141     cpu_thread_schedule(state, c->current_thread);
3142     THDEBUG("%d: thread yield.\\n", getpid());
3143     cpu_thread_run_best(state, c);
3144     CODE
3145   end
3147   defprim :thread_dequeue
3148   def thread_dequeue
3149     <<-CODE
3150     ARITY(0);
3151     THDEBUG("%d: dequeue thread.\\n", getpid());
3152     cpu_thread_exited(state, c);
3153     CODE
3154   end
3156   defprim :thread_current
3157   def thread_current
3158     <<-CODE
3159     ARITY(0);
3160     RET(c->current_thread);
3161     CODE
3162   end
3164   defprim :object_become
3165   def object_become
3166     <<-CODE
3167     ARITY(2);
3168     void state_object_become(STATE, cpu c, OBJECT from, OBJECT to);
3169     OBJECT t1, t2;
3171     POP(t2, REFERENCE);
3172     POP(t1, REFERENCE);
3173     state_object_become(state, c, t2, t1);
3174     RET(t2);
3175     CODE
3176   end
3178   defprim :sampler_activate
3179   def sampler_activate
3180     <<-CODE
3181     ARITY(1);
3182     OBJECT t1;
3184     POP(t1, FIXNUM);
3185     cpu_sampler_activate(state, N2I(t1));
3186     RET(ML2N(clock()));
3187     CODE
3188   end
3190   defprim :sampler_stop
3191   def sampler_stop
3192     <<-CODE
3193     ARITY(0);
3194     OBJECT t1 = cpu_sampler_disable(state);
3195     RET(t1);
3196     CODE
3197   end
3199   defprim :fork_process
3200   def fork_process
3201     <<-CODE
3202     ARITY(0);
3203     native_int k = fork();
3204     if(k == -1) {
3205       RAISE_FROM_ERRNO("Unable to fork");
3206     } else {
3207       if (k == 0) {
3208         environment_fork();
3209       }
3210       RET(I2N(k));
3211     }
3212     CODE
3213   end
3216   defprim :replace_process# aka execve().
3217   def replace_process
3218     <<-CODE
3219     ARITY(2);
3220     native_int i, j, k;
3221     char *tmp, *file;
3222     char **argv;
3223     OBJECT t1, t2, t3;
3225     POP(t1, STRING);
3226     POP(t2, ARRAY);
3228     k = N2I(array_get_total(t2));
3229     argv = ALLOC_N(char*, k + 1);
3230     for(j = 0; j < k; j++) {
3231       t3 = array_get(state, t2, j);
3232       if(!ISA(t3, state->global->string)) {
3233         for(i = 0; i < j; i++) {
3234           XFREE(argv[i]);
3235         }
3236         XFREE(argv);
3237         return FALSE;
3238       }
3240       tmp = rbx_string_as_cstr(state, t3);
3241       argv[j] = tmp ? strdup(tmp) : NULL;
3242     }
3244     argv[k] = NULL;
3246     tmp = rbx_string_as_cstr(state, t1);
3247     file = tmp ? strdup(tmp) : NULL;
3249     cpu_task_disable_preemption(state);
3250     k = execvp(file, argv);
3252     /* If you're here, there was an error. */
3253     cpu_task_configure_preemption(state);
3254     RAISE_FROM_ERRNO("Unable to execute");
3256     CODE
3257   end
3259   defprim :ivar_get
3260   def ivar_get
3261     <<-CODE
3262     ARITY(1);
3263     OBJECT t1;
3264     POP(t1, SYMBOL);
3265     RET(object_get_ivar(state, msg->recv, t1));
3266     CODE
3267   end
3269   defprim :ivar_set
3270   def ivar_set
3271     <<-CODE
3272     ARITY(2);
3273     OBJECT t1, t2;
3274     POP(t1, SYMBOL);
3275     t2 = stack_pop();
3276     object_set_ivar(state, msg->recv, t1, t2);
3277     RET(t2);
3278     CODE
3279   end
3281   defprim :ivars_get
3282   def ivars_get
3283     <<-CODE
3284     ARITY(0);
3285     RET(object_get_ivars(state, msg->recv));
3286     CODE
3287   end
3289   defprim :str_crypt
3290   def str_crypt
3291     <<-CODE
3292     ARITY(1);
3293     OBJECT t1;
3295     GUARD(STRING_P(msg->recv));
3296     POP(t1, STRING);
3297     RET(string_new(state, crypt(rbx_string_as_cstr(state, msg->recv),
3298         rbx_string_as_cstr(state, t1))));
3299     CODE
3300   end
3302   defprim :env_get
3303   def env_get
3304     <<-CODE
3305     ARITY(1);
3306     char *key;
3307     OBJECT t1, t2;
3309     POP(t1, STRING);
3311     t2 = Qnil;
3313     key = rbx_string_as_cstr(state, t1);
3314     if (key) {
3315       char *value = getenv(key);
3317       if (value) {
3318         t2 = string_new(state, value);
3319       }
3320     }
3322     RET(t2);
3323     CODE
3324   end
3326   defprim :env_set
3327   def env_set
3328     <<-CODE
3329     ARITY(2);
3330     char *key, *value;
3331     OBJECT t1, t2;
3333     POP(t1, STRING);
3334     t2 = stack_pop();
3336     key = rbx_string_as_cstr(state, t1);
3337     if(key) {
3338       /* if t2 is nil, we need to delete the variable
3339        * and return its value.
3340        */
3341       if(NIL_P(t2)) {
3342         value = getenv(key);
3343         if(value) {
3344           unsetenv(key);
3345           RET(string_new(state, value));
3346         } else {
3347           RET(Qnil);
3348         }
3349       } else {
3350         GUARD(STRING_P(t2));
3351         value = rbx_string_as_cstr(state, t2);
3352         if(value) {
3353           setenv(key, value, 1);
3354           RET(t2);
3355         } else {
3356           RET(Qnil);
3357         }
3358       }
3359     }
3360     CODE
3361   end
3363   defprim :env_as_hash
3364   def env_as_hash
3365     <<-CODE
3366     ARITY(0);
3367     char *cur, **total = environ;
3369     OBJECT hash = hash_new(state);
3371     do {
3372       cur = *total++;
3373       if(!cur) break;
3375       char *name = cur;
3376       int i = 0;
3378       while(*cur && *cur != '=') {
3379         i++; cur++;
3380       }
3382       OBJECT key = string_new2(state, name, i);
3383       OBJECT val = string_new(state, cur+1);
3385       hash_set(state, hash, key, val);
3386     } while(cur);
3388     RET(hash);
3389     CODE
3390   end
3392   defprim :bignum_size
3393   def bignum_size
3394     <<-CODE
3395     ARITY(0);
3396     GUARD(BIGNUM_P(msg->recv));
3397     RET(bignum_size(state, msg->recv));
3398     CODE
3399   end
3401   defprim :iseq_compile
3402   def iseq_compile
3403     <<-CODE
3404     ARITY(0);
3405     GUARD(CMETHOD_P(msg->recv));
3406     cpu_compile_method(state, msg->recv);
3407     RET(Qtrue);
3408     CODE
3409   end
3411   defprim :reset_method_cache
3412   def reset_method_cache
3413     <<-CODE
3414     ARITY(1);
3415     OBJECT t1;
3416     POP(t1, SYMBOL);
3417     cpu_clear_cache_for_method(state, c, t1, TRUE);
3418     CODE
3419   end
3421   defprim :bignum_from_float
3422   def bignum_from_float
3423     <<-CODE
3424     ARITY(1);
3425     OBJECT t1;
3426     POP(t1, FLOAT);
3427     RET(bignum_from_double(state, FLOAT_TO_DOUBLE(t1)));
3428     CODE
3429   end
3431   defprim :save_encloser_path
3432   def save_encloser_path
3433     <<-CODE
3434     ARITY(0);
3435     cpu_set_encloser_path(state, c, state->global->object);
3436     RET(Qnil);
3437     CODE
3438   end
3440   defprim :restore_encloser_path
3441   def restore_encloser_path
3442     <<-CODE
3443     ARITY(0);
3444     cpu_push_encloser(state, c);
3445     RET(Qnil);
3446     CODE
3447   end
3449   defprim :array_aref
3450   def array_aref
3451     <<-CODE
3452     OBJECT t1, t3;
3453     native_int j, k;
3455     GUARD(msg->args == 1);
3456     t1 = stack_top();
3457     GUARD(FIXNUM_P(t1));
3459     j = N2I(array_get_total(msg->recv));
3461     k = N2I(t1);
3463     if(k < 0) k += j;
3465     if(k < 0 || k >= j) {
3466       stack_set_top(Qnil);
3467     } else {
3468       k += N2I(array_get_start(msg->recv));
3469       t3 = array_get_tuple(msg->recv);
3470       GUARD(k < NUM_FIELDS(t3));
3472       stack_set_top(tuple_at(state, t3, k));
3473     }
3474     CODE
3475   end
3477   defprim :array_aset
3478   def array_aset
3479     <<-CODE
3480     OBJECT t1, t3;
3481     native_int j, k;
3483     GUARD(msg->args == 2);
3484     t1 = stack_pop();
3485     GUARD(FIXNUM_P(t1));
3487     j = N2I(array_get_total(msg->recv));
3488     k = N2I(t1);
3490     if(k < 0) k += j;
3491     GUARD(k >= 0);
3493     if(k >= j - 1) {
3494       array_set_total(msg->recv, I2N(k + 1));
3495     }
3497     k += N2I(array_get_start(msg->recv));
3498     t3 = array_get_tuple(msg->recv);
3499     GUARD(k < NUM_FIELDS(t3));
3501     tuple_put(state, t3, k, stack_top());
3502     CODE
3503   end
3505   defprim :string_append
3506   def string_append
3507     <<-CODE
3508     OBJECT t1;
3510     GUARD(msg->args == 1);
3511     POP(t1, STRING);
3513     string_append(state, msg->recv, t1);
3514     RET(msg->recv);
3515     CODE
3516   end
3518   defprim :string_dup
3519   def string_dup
3520     <<-CODE
3521     ARITY(0);
3522     RET(string_dup(state, msg->recv));
3523     CODE
3524   end
3526   defprim :string_equal
3527   def string_equal
3528     <<-CODE
3529     ARITY(1);
3530     OBJECT t1, t2, t3;
3531     native_int j, k, m;
3533     POP(t1, STRING);
3535     if(msg->recv == t1) {
3536       RET(Qtrue);
3537     } else {
3538       t2 = string_get_bytes(msg->recv);
3539       t3 = string_get_bytes(t1);
3541       if(t2 != t3) {
3542         RET(Qfalse);
3543       } else {
3544         j = N2I(t2);
3545         k = N2I(t3);
3546         t2 = string_get_data(msg->recv);
3547         t3 = string_get_data(t1);
3549         m = memcmp(BYTEARRAY_ADDRESS(t2), BYTEARRAY_ADDRESS(t3), j < k ? j : k);
3550         RET(m == 0 ? Qtrue : Qfalse);
3551       }
3552     }
3553     CODE
3554   end
3556   defprim :object_send
3557   def object_send
3558     <<-CODE
3559     OBJECT t1;
3560     GUARD(msg->args >= 1);
3561     t1 = stack_pop();
3562     if(!SYMBOL_P(t1)) {
3563       if(STRING_P(t1)) {
3564         t1 = string_to_sym(state, t1);
3565       } else {
3566         GUARD(0);
3567       }
3568     }
3570     /* Send is allowed to call private methods. */
3571     c->call_flags = 1;
3573     cpu_send(state, c, msg->recv, t1, msg->args - 1, msg->block);
3574     CODE
3575   end
3577   defprim :machine_new
3578   def machine_new
3579     <<-CODE
3580     ARITY(1);
3581     int *pipes;
3582     int argc;
3583     char **argv;
3584     OBJECT ret, ary, str;
3585     int i;
3586     machine m;
3587     environment e = environment_current();
3589     POP(ary, ARRAY);
3591     argc = N2I(array_get_total(ary));
3592     argv = ALLOC_N(char*, argc);
3593     for(i = 0; i < argc; i++) {
3594       str = array_get(state, ary, i);
3595       if(STRING_P(str)) {
3596         argv[i] = strdup(rbx_string_as_cstr(state, str));
3597       } else {
3598         argv[i] = strdup("");
3599       }
3600     }
3602     m = machine_new(e);
3603     pipes = machine_setup_thread(m, argc, argv);
3605     m->parent_id = current_machine->id;
3607     ret = tuple_new(state, 4);
3608     tuple_put(state, ret, 0, I2N(m->id));
3609     tuple_put(state, ret, 1, io_new(state, pipes[0], "w"));
3610     tuple_put(state, ret, 2, io_new(state, pipes[1], "r"));
3611     tuple_put(state, ret, 3, io_new(state, pipes[2], "r"));
3613     stack_push(ret);
3614     environment_start_thread(e, m);
3616     DONE();
3617     CODE
3618   end
3620   defprim :machine_join
3621   def machine_join
3622     <<-CODE
3623     ARITY(1);
3624     OBJECT t1;
3625     POP(t1, FIXNUM);
3626     if(environment_join_machine(environment_current(), N2I(t1))) {
3627       RET(Qtrue);
3628     } else {
3629       RET(Qfalse);
3630     }
3631     CODE
3632   end
3634   defprim :machine_get_message
3635   def machine_get_message
3636     <<-CODE
3637     ARITY(0);
3638     RET(environment_get_message(environment_current(), current_machine->id));
3639     CODE
3640   end
3642   defprim :machine_send_message
3643   def machine_send_message
3644     <<-CODE
3645     ARITY(2);
3646     OBJECT t1, t2;
3647     POP(t1, FIXNUM);
3648     t2 = stack_pop();
3650     environment_send_message(environment_current(), N2I(t1), t2);
3652     RET(Qtrue);
3653     CODE
3654   end
3656   defprim :dir_open
3657   def dir_open
3658     <<-CODE
3659     ARITY(1);
3660     OBJECT t1;
3661     DIR *dir;
3663     POP(t1, STRING);
3665     dir = opendir(rbx_string_as_cstr(state, t1));
3666     if(!dir) RAISE_FROM_ERRNO("Unable to open directory");
3668     RET(ffi_new_pointer(state, dir));
3669     CODE
3670   end
3672   defprim :dir_close
3673   def dir_close
3674     <<-CODE
3675     ARITY(1);
3676     DIR *dir;
3677     OBJECT t1;
3679     POP(t1, POINTER);
3681     dir = *DATA_STRUCT(t1, void**);
3682     if(dir) {
3683       *DATA_STRUCT(t1, void**) = NULL;
3684       closedir(dir);
3685       RET(Qtrue);
3686     } else {
3687       RET(Qfalse);
3688     }
3689     CODE
3690   end
3692   defprim :dir_control
3693   def dir_control
3694     <<-CODE
3695     ARITY(3);
3696     OBJECT kind, pos;
3697     OBJECT t1;
3698     POP(t1, POINTER);
3699     DIR *dir = *DATA_STRUCT(t1, void**);
3701     POP(kind, FIXNUM);
3702     POP(pos, FIXNUM);
3704     switch(N2I(kind)) {
3705     case 0:
3706       seekdir(dir, N2I(pos));
3707       RET(Qtrue);
3708     case 1:
3709       rewinddir(dir);
3710       RET(Qtrue);
3711     case 2:
3712       RET(I2N(telldir(dir)));
3713     default:
3714       RET(Qnil);
3715     }
3716     CODE
3717   end
3719   defprim :dir_read
3720   def dir_read
3721     <<-CODE
3722     ARITY(1);
3723     struct dirent *ent;
3724     OBJECT t1;
3725     POP(t1, POINTER);
3726     DIR *dir = *DATA_STRUCT(t1, void**);
3727     ent = readdir(dir);
3729     if(!ent) {
3730       RET(Qnil);
3731     } else {
3732       RET(string_new(state, ent->d_name));
3733     }
3735     CODE
3736   end
3738   defprim :opt_push_literal
3739   def opt_push_literal
3740     <<-CODE
3741     ARITY(0);
3742     OBJECT lits;
3744     lits = cmethod_get_literals(msg->method);
3745     RET(fast_fetch(lits, 0));
3746     CODE
3747   end
3749   defprim :opt_push_self
3750   def opt_push_self
3751     <<-CODE
3752     ARITY(0);
3753     RET(msg->recv);
3754     CODE
3755   end
3757   defprim :opt_push_ivar
3758   def opt_push_ivar
3759     <<-CODE
3760     ARITY(0);
3761     OBJECT lits;
3763     lits = cmethod_get_literals(msg->method);
3764     RET(object_get_ivar(state, msg->recv, fast_fetch(lits, 0)));
3765     CODE
3766   end
3768   defprim :opt_push_my_field
3769   def opt_push_my_field
3770     <<-CODE
3771     ARITY(0);
3772     OBJECT lits;
3774     lits = cmethod_get_literals(msg->method);
3775     RET(NTH_FIELD(msg->recv, N2I(fast_fetch(lits, 0))));
3776     CODE
3777   end
3779   defprim :opt_kind_of
3780   def opt_kind_of
3781     <<-CODE
3782     ARITY(1);
3783     OBJECT t1;
3785     POP(t1, REFERENCE);
3786     GUARD(CLASS_P(t1) || MODULE_P(t1));
3788     RET(object_kind_of_p(state, msg->recv, t1) ? Qtrue : Qfalse);
3789     CODE
3790   end
3792   defprim :float_add
3793   def float_add
3794     <<-CODE
3795     ARITY(1);
3796     GUARD(FLOAT_P(msg->recv));
3797     double a = FLOAT_TO_DOUBLE(msg->recv);
3798     OBJECT t1 = stack_pop();
3799     if(!FLOAT_P(t1)) {
3800       t1 = float_coerce(state, t1);
3801       GUARD(FLOAT_P(t1));
3802     }
3803     RET(float_new(state, a + FLOAT_TO_DOUBLE(t1)));
3804     CODE
3805   end
3807   defprim :float_sub
3808   def float_sub
3809     <<-CODE
3810     ARITY(1);
3811     GUARD(FLOAT_P(msg->recv));
3812     double a = FLOAT_TO_DOUBLE(msg->recv);
3813     OBJECT t1 = stack_pop();
3814     if(!FLOAT_P(t1)) {
3815       t1 = float_coerce(state, t1);
3816       GUARD(FLOAT_P(t1));
3817     }
3818     RET(float_new(state, a - FLOAT_TO_DOUBLE(t1)));
3819     CODE
3820   end
3822   defprim :float_mul
3823   def float_mul
3824     <<-CODE
3825     ARITY(1);
3826     GUARD(FLOAT_P(msg->recv));
3827     double a = FLOAT_TO_DOUBLE(msg->recv);
3828     OBJECT t1 = stack_pop();
3829     if(!FLOAT_P(t1)) {
3830       t1 = float_coerce(state, t1);
3831       GUARD(FLOAT_P(t1));
3832     }
3833     RET(float_new(state, a * FLOAT_TO_DOUBLE(t1)));
3834     CODE
3835   end
3837   defprim :float_div
3838   def float_div
3839     <<-CODE
3840     ARITY(1);
3841     GUARD(FLOAT_P(msg->recv));
3842     double a = FLOAT_TO_DOUBLE(msg->recv);
3843     OBJECT t1 = stack_pop();
3844     if(!FLOAT_P(t1)) {
3845       t1 = float_coerce(state, t1);
3846       GUARD(FLOAT_P(t1));
3847     }
3848     RET(float_new(state, a / FLOAT_TO_DOUBLE(t1)));
3849     CODE
3850   end
3852   defprim :float_uminus
3853   def float_uminus
3854     <<-CODE
3855     ARITY(0);
3856     GUARD(FLOAT_P(msg->recv));
3857     double a = FLOAT_TO_DOUBLE(msg->recv);
3858     RET(float_new(state, -a));
3859     CODE
3860   end
3862   defprim :float_equal
3863   def float_equal
3864     <<-CODE
3865     ARITY(1);
3866     GUARD(FLOAT_P(msg->recv));
3867     double a = FLOAT_TO_DOUBLE(msg->recv);
3868     OBJECT t1 = stack_pop();
3869     if(!FLOAT_P(t1)) {
3870       t1 = float_coerce(state, t1);
3871       GUARD(FLOAT_P(t1));
3872     }
3873     RET(a == FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
3874     CODE
3875   end
3877   defprim :float_eql
3878   def float_eql
3879     <<-CODE
3880     ARITY(1);
3881     GUARD(FLOAT_P(msg->recv));
3882     OBJECT t1 = stack_pop();
3883     if(FLOAT_P(t1)) {
3884       double a = FLOAT_TO_DOUBLE(msg->recv),
3885              b = FLOAT_TO_DOUBLE(t1);
3886       RET(a == b ? Qtrue : Qfalse);
3887     } else {
3888       RET(Qfalse);
3889     }
3890     CODE
3891   end
3893   defprim :float_compare
3894   def float_compare
3895     <<-CODE
3896     ARITY(1);
3897     GUARD(FLOAT_P(msg->recv));
3898     double a = FLOAT_TO_DOUBLE(msg->recv);
3899     OBJECT t1 = stack_pop();
3900     if(!FLOAT_P(t1)) {
3901       t1 = float_coerce(state, t1);
3902       GUARD(FLOAT_P(t1));
3903     }
3904     double b = FLOAT_TO_DOUBLE(t1);
3905     RET(float_compare(state, a, b));
3906     CODE
3907   end
3909   defprim :float_lt
3910   def float_lt
3911     <<-CODE
3912     ARITY(1);
3913     GUARD(FLOAT_P(msg->recv));
3914     double a = FLOAT_TO_DOUBLE(msg->recv);
3915     OBJECT t1 = stack_pop();
3916     if(!FLOAT_P(t1)) {
3917       t1 = float_coerce(state, t1);
3918       GUARD(FLOAT_P(t1));
3919     }
3920     RET(a < FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
3921     CODE
3922   end
3924   defprim :float_le
3925   def float_le
3926     <<-CODE
3927     ARITY(1);
3928     GUARD(FLOAT_P(msg->recv));
3929     double a = FLOAT_TO_DOUBLE(msg->recv);
3930     OBJECT t1 = stack_pop();
3931     if(!FLOAT_P(t1)) {
3932       t1 = float_coerce(state, t1);
3933       GUARD(FLOAT_P(t1));
3934     }
3935     RET(a <= FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
3936     CODE
3937   end
3939   defprim :float_gt
3940   def float_gt
3941     <<-CODE
3942     ARITY(1);
3943     GUARD(FLOAT_P(msg->recv));
3944     double a = FLOAT_TO_DOUBLE(msg->recv);
3945     OBJECT t1 = stack_pop();
3946     if(!FLOAT_P(t1)) {
3947       t1 = float_coerce(state, t1);
3948       GUARD(FLOAT_P(t1));
3949     }
3950     RET(a > FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
3951     CODE
3952   end
3954   defprim :float_ge
3955   def float_ge
3956     <<-CODE
3957     ARITY(1);
3958     GUARD(FLOAT_P(msg->recv));
3959     double a = FLOAT_TO_DOUBLE(msg->recv);
3960     OBJECT t1 = stack_pop();
3961     if(!FLOAT_P(t1)) {
3962       t1 = float_coerce(state, t1);
3963       GUARD(FLOAT_P(t1));
3964     }
3965     RET(a >= FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
3966     CODE
3967   end
3969   defprim :float_to_i
3970   def float_to_i
3971     <<-CODE
3972     ARITY(0);
3973     GUARD(FLOAT_P(msg->recv));
3974     double b = FLOAT_TO_DOUBLE(msg->recv);
3975     if(isinf(b)) {
3976       RAISE("FloatDomainError", b < 0 ? "-Infinity" : "Infinity");
3977     } else if(isnan(b)) {
3978       RET(msg->recv);
3979     } else {
3980       RET(bignum_from_double(state, float_truncate(b)));
3981     }
3982     CODE
3983   end
3985   defprim :float_round
3986   def float_round
3987     <<-CODE
3988     ARITY(0);
3989     GUARD(FLOAT_P(msg->recv));
3990     double value = FLOAT_TO_DOUBLE(msg->recv);
3991     if (value > 0.0) value = floor(value+0.5);
3992     if (value < 0.0) value = ceil(value-0.5);
3993     RET(bignum_from_double(state, value));
3994     CODE
3995   end
3997   defprim :float_divmod
3998   def float_divmod
3999     <<-CODE
4000     ARITY(1);
4001     GUARD(FLOAT_P(msg->recv));
4002     double a = FLOAT_TO_DOUBLE(msg->recv);
4003     OBJECT t1 = stack_pop();
4004     if(!FLOAT_P(t1)) {
4005       t1 = float_coerce(state, t1);
4006       GUARD(FLOAT_P(t1));
4007     }
4008     double b = FLOAT_TO_DOUBLE(t1);
4009     if(b == 0.0) {
4010       RAISE("FloatDomainError", "divide by 0");
4011     } else {
4012       double div = floor(a / b);
4013       double mod = fmod(a, b);
4014       if(b * mod < 0) {
4015         mod += b;
4016       }
4017       OBJECT ary = array_new(state, 2);
4018       array_set(state, ary, 0, bignum_from_double(state, float_truncate(div)));
4019       array_set(state, ary, 1, float_new(state, mod));
4020       RET(ary);
4021     }
4022     CODE
4023   end
4025   defprim :float_pow
4026   def float_pow
4027     <<-CODE
4028     ARITY(1);
4029     GUARD(FLOAT_P(msg->recv));
4030     double a = FLOAT_TO_DOUBLE(msg->recv);
4031     OBJECT t1 = stack_pop();
4032     if(!FLOAT_P(t1)) {
4033       t1 = float_coerce(state, t1);
4034       GUARD(FLOAT_P(t1));
4035     }
4036     RET(float_new(state, pow(a, FLOAT_TO_DOUBLE(t1))));
4037     CODE
4038   end
4040   defprim :float_isnan
4041   def float_isnan
4042     <<-CODE
4043     ARITY(0);
4044     GUARD(FLOAT_P(msg->recv));
4045     RET(isnan(FLOAT_TO_DOUBLE(msg->recv)) == 1 ? Qtrue : Qfalse);
4046     CODE
4047   end
4049   defprim :float_isinf
4050   def float_isinf
4051     <<-CODE
4052     ARITY(0);
4053     GUARD(FLOAT_P(msg->recv));
4054     double value = FLOAT_TO_DOUBLE(msg->recv);
4055     if(isinf(value) != 0) {
4056       RET(value < 0 ? I2N(-1) : I2N(1));
4057     } else {
4058       RET(Qnil);
4059     }
4060     CODE
4061   end
4063   defprim :bignum_gt
4064   def bignum_gt
4065     <<-CODE
4066     ARITY(1);
4067     GUARD(BIGNUM_P(msg->recv));
4068     OBJECT t1 = stack_pop();
4069     if(BIGNUM_P(t1) || FIXNUM_P(t1)) {
4070       RET(bignum_gt(state, msg->recv, t1));
4071     } else if(FLOAT_P(t1)) {
4072       double a = bignum_to_double(state, msg->recv);
4073       RET(a > FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
4074     } else {
4075       FAIL();
4076     }
4077     CODE
4078   end
4080   defprim :bignum_ge
4081   def bignum_ge
4082     <<-CODE
4083     ARITY(1);
4084     GUARD(BIGNUM_P(msg->recv));
4085     OBJECT t1 = stack_pop();
4086     if(BIGNUM_P(t1) || FIXNUM_P(t1)) {
4087       RET(bignum_ge(state, msg->recv, t1));
4088     } else if(FLOAT_P(t1)) {
4089       double a = bignum_to_double(state, msg->recv);
4090       RET(a >= FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
4091     } else {
4092       FAIL();
4093     }
4094     CODE
4095   end
4097   defprim :bignum_lt
4098   def bignum_lt
4099     <<-CODE
4100     ARITY(1);
4101     GUARD(BIGNUM_P(msg->recv));
4102     OBJECT t1 = stack_pop();
4103     if(BIGNUM_P(t1) || FIXNUM_P(t1)) {
4104       RET(bignum_lt(state, msg->recv, t1));
4105     } else if(FLOAT_P(t1)) {
4106       double a = bignum_to_double(state, msg->recv);
4107       RET(a < FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
4108     } else {
4109       FAIL();
4110     }
4111     CODE
4112   end
4114   defprim :bignum_le
4115   def bignum_le
4116     <<-CODE
4117     ARITY(1);
4118     GUARD(BIGNUM_P(msg->recv));
4119     OBJECT t1 = stack_pop();
4120     if(BIGNUM_P(t1) || FIXNUM_P(t1)) {
4121       RET(bignum_le(state, msg->recv, t1));
4122     } else if(FLOAT_P(t1)) {
4123       double a = bignum_to_double(state, msg->recv);
4124       RET(a <= FLOAT_TO_DOUBLE(t1) ? Qtrue : Qfalse);
4125     } else {
4126       FAIL();
4127     }
4128     CODE
4129   end
4131   defprim :sendsite_create
4132   def sendsite_create
4133     <<-CODE
4134     ARITY(1);
4135     OBJECT t1, ss;
4137     GUARD(CLASS_P(msg->recv));
4138     POP(t1, SYMBOL);
4140     ss = send_site_create(state, t1);
4141     RET(ss);
4142     CODE
4143   end
4145   defprim :sendsite_set_sender
4146   def sendsite_set_sender
4147     <<-CODE
4148     ARITY(1);
4149     OBJECT cm;
4151     GUARD(SENDSITE_P(msg->recv));
4152     POP(cm, CMETHOD);
4154     send_site_set_sender(state, msg->recv, cm);
4155     RET(Qnil);
4156     CODE
4157   end
4159   defprim :sendsite_at
4160   def sendsite_at
4161     <<-CODE
4162     ARITY(1);
4163     OBJECT t1;
4165     GUARD(SENDSITE_P(msg->recv));
4166     POP(t1, FIXNUM);
4168     switch(N2I(t1)) {
4169     case 0:
4170       RET(SENDSITE(msg->recv)->name);
4171     case 1:
4172       RET(SENDSITE(msg->recv)->selector);
4173     case 2:
4174       RET(SENDSITE(msg->recv)->data1);
4175     case 3:
4176       RET(SENDSITE(msg->recv)->data2);
4177     case 4:
4178       RET(SENDSITE(msg->recv)->data3);
4179     case 5:
4180       RET(ffi_new_pointer(state, SENDSITE(msg->recv)->c_data));
4181     case 6:
4182       RET(I2N(SENDSITE(msg->recv)->hits));
4183     case 7:
4184       RET(I2N(SENDSITE(msg->recv)->misses));
4185     case 8:
4186       RET(SENDSITE(msg->recv)->sender);
4187     default:
4188       RET(Qnil);
4189     }
4190     CODE
4191   end
4193   defprim :selector_clear
4194   def selector_clear
4195     <<-CODE
4196     GUARD(SELECTOR_P(msg->recv));
4198     selector_clear(state, msg->recv);
4200     RET(Qnil);
4201     CODE
4202   end
4204   defprim :dtrace_fire_ruby_probe
4205   def dtrace_fire_ruby_probe
4206     <<-CODE
4207     ARITY(2);
4209     OBJECT t1, t2;
4211     POP(t1, STRING);
4212     POP(t2, STRING);
4214 #if ENABLE_DTRACE
4215     if (RUBINIUS_RUBY_PROBE_ENABLED()) {
4216       RUBINIUS_RUBY_PROBE(rbx_string_as_cstr(state, t1), rbx_string_as_cstr(state, t2));
4217     }
4218 #endif
4220     RET(Qnil);
4221     CODE
4222   end
4224   defprim :allocate_table
4225   def allocate_table
4226     <<-CODE
4227     ARITY(0);
4228     GUARD(CLASS_P(msg->recv));
4229     OBJECT t1;
4231     t1 = lookuptable_new(state);
4232     SET_CLASS(t1, msg->recv);
4233     RET(t1);
4234     CODE
4235   end
4237   defprim :lookuptable_store
4238   def lookuptable_store
4239     <<-CODE
4240     ARITY(2);
4241     GUARD(LOOKUPTABLE_P(msg->recv));
4242     OBJECT t1, t2;
4244     t1 = stack_pop();
4245     t2 = stack_pop();
4246     RET(lookuptable_store(state, msg->recv, t1, t2));
4247     CODE
4248   end
4250   defprim :lookuptable_fetch
4251   def lookuptable_fetch
4252     <<-CODE
4253     ARITY(1);
4254     GUARD(LOOKUPTABLE_P(msg->recv));
4255     OBJECT t1, t2;
4257     t1 = stack_pop();
4258     t2 = lookuptable_fetch(state, msg->recv, t1);
4259     RET(t2 == Qundef ? Qnil : t2);
4260     CODE
4261   end
4263   defprim :lookuptable_delete
4264   def lookuptable_delete
4265     <<-CODE
4266     ARITY(1);
4267     GUARD(LOOKUPTABLE_P(msg->recv));
4268     OBJECT t1, t2;
4270     t1 = stack_pop();
4271     t2 = lookuptable_delete(state, msg->recv, t1);
4272     RET(t2 == Qundef ? Qnil : t2);
4273     CODE
4274   end
4276   defprim :lookuptable_has_key
4277   def lookuptable_has_key
4278     <<-CODE
4279     ARITY(1);
4280     GUARD(LOOKUPTABLE_P(msg->recv));
4281     OBJECT t1;
4283     t1 = stack_pop();
4284     RET(lookuptable_has_key(state, msg->recv, t1));
4285     CODE
4286   end
4288   defprim :lookuptable_keys
4289   def lookuptable_keys
4290     <<-CODE
4291     ARITY(0);
4292     GUARD(LOOKUPTABLE_P(msg->recv));
4293     RET(lookuptable_keys(state, msg->recv));
4294     CODE
4295   end
4297   defprim :lookuptable_values
4298   def lookuptable_values
4299     <<-CODE
4300     ARITY(0);
4301     GUARD(LOOKUPTABLE_P(msg->recv));
4302     RET(lookuptable_values(state, msg->recv));
4303     CODE
4304   end
4306   defprim :lookuptable_entries
4307   def lookuptable_entries
4308     <<-CODE
4309     ARITY(0);
4310     GUARD(LOOKUPTABLE_P(msg->recv));
4311     RET(lookuptable_entries(state, msg->recv));
4312     CODE
4313   end
4315   defprim :lookuptable_dup
4316   def lookuptable_dup
4317     <<-CODE
4318     ARITY(0);
4319     GUARD(LOOKUPTABLE_P(msg->recv));
4320     RET(lookuptable_dup(state, msg->recv));
4321     CODE
4322   end
4324   defprim :allocate_module
4325   def allocate_module
4326     <<-CODE
4327     ARITY(0);
4328     GUARD(CLASS_P(msg->recv));
4329     OBJECT t1, t2;
4331     t1 = class_get_instance_fields(msg->recv);
4332     t2 = NEW_OBJECT(msg->recv, N2I(t1));
4333     module_setup_fields(state, t2);
4334     RET(t2);
4335     CODE
4336   end
4338   defprim :allocate_hash
4339   def allocate_hash
4340     <<-CODE
4341     ARITY(0);
4342     GUARD(CLASS_P(msg->recv));
4343     OBJECT t1;
4345     t1 = hash_new(state);
4346     SET_CLASS(t1, msg->recv);
4347     RET(t1);
4348     CODE
4349   end
4351   defprim :string_tr_expand
4352   def string_tr_expand
4353     <<-CODE
4354     ARITY(1);
4355     GUARD(STRING_P(msg->recv));
4356     OBJECT t1;
4357     t1 = stack_pop();
4358     RET(string_tr_expand(state, msg->recv, t1));
4359     CODE
4360   end
4362   defprim :string_template
4363   def string_template
4364     <<-CODE
4365     ARITY(2);
4366     GUARD(CLASS_P(msg->recv));
4367     OBJECT t1, t2, t3;
4368     native_int k;
4369     char *data;
4371     POP(t1, FIXNUM);
4372     k = N2I(t1);
4373     t3 = string_new2(state, NULL, k);
4374     SET_CLASS(t3, msg->recv);
4375     t3->IsTainted = msg->recv->IsTainted;
4376     data = rbx_string_as_cstr(state, t3);
4378     t2 = stack_pop();
4379     if(FIXNUM_P(t2)) {
4380       memset(data, N2I(t2), k);
4381     } else if(STRING_P(t2)) {
4382       int bytes;
4383       char *str;
4385       t3->IsTainted |= t2->IsTainted;
4386       bytes = N2I(string_get_bytes(t2));
4387       str = rbx_string_as_cstr(state, t2);
4388       if(bytes == 1) {
4389         memset(data, str[0], k);
4390       } else if(bytes > 1) {
4391         int i, j, n, size;
4393         size = k / bytes;
4394         for(n = i = 0; i < size; i++) {
4395           for(j = 0; j < bytes; j++, n++) {
4396             data[n] = str[j];
4397           }
4398         }
4399         for(i = n, j = 0; i < k; i++, j++) {
4400           data[i] = str[j];
4401         }
4402       }
4403     } else {
4404       FAIL();
4405     }
4406     RET(t3);
4407     CODE
4408   end
4410   defprim :string_apply_and
4411   def string_apply_and
4412     <<-CODE
4413     ARITY(1);
4414     GUARD(STRING_P(msg->recv));
4415     OBJECT t1;
4416     native_int i, j, k, size;
4417     char *a, *b;
4419     POP(t1, STRING);
4420     a = rbx_string_as_cstr(state, msg->recv);
4421     b = rbx_string_as_cstr(state, t1);
4422     j = N2I(string_get_bytes(msg->recv));
4423     k = N2I(string_get_bytes(t1));
4424     size = j < k ? j : k;
4426     for(i = 0; i < size; i++) {
4427       a[i] = a[i] && b[i];
4428     }
4429     RET(Qnil);
4430     CODE
4431   end
4433   defprim :tuple_template
4434   def tuple_template
4435     <<-CODE
4436     ARITY(2)
4437     GUARD(CLASS_P(msg->recv));
4438     OBJECT t1, t2, t3;
4439     native_int i, k;
4441     POP(t1, FIXNUM);
4442     k = N2I(t1);
4443     t2 = stack_pop();
4444     t3 = tuple_new(state, k);
4445     for(i = 0; i < k; i++) {
4446       tuple_put(state, t3, i, t2);
4447     }
4448     RET(t3);
4449     CODE
4450   end
4452   defprim :string_copy_from
4453   def string_copy_from
4454     <<-CODE
4455     ARITY(4);
4456     GUARD(STRING_P(msg->recv));
4457     OBJECT t1, t2, t3, t4;
4458     native_int n, start, size, dest;
4459     char *a, *b;
4461     POP(t1, STRING);
4462     POP(t2, FIXNUM);
4463     POP(t3, FIXNUM);
4464     POP(t4, FIXNUM);
4466     start = N2I(t2);
4467     size = N2I(t3);
4468     dest = N2I(t4);
4470     if(start < 0) { start = 0; }
4471     n = N2I(string_get_bytes(t1));
4472     if(start >= n) { RET(msg->recv); }
4473     if(size > n - start) { size = n - start; }
4475     n = N2I(string_get_bytes(msg->recv));
4476     if(dest < 0) { dest = 0; }
4477     if(dest >= n) { RET(msg->recv); }
4478     if(size > n - dest) { size = n - dest; }
4480     a = rbx_string_as_cstr(state, msg->recv);
4481     b = rbx_string_as_cstr(state, t1);
4482     memcpy(a + dest, b + start, size);
4484     RET(msg->recv);
4485     CODE
4486   end
4488   defprim :string_compare_substring
4489   def string_compare_substring
4490     <<-CODE
4491     ARITY(3);
4492     GUARD(STRING_P(msg->recv));
4493     OBJECT t1, t2, t3;
4494     native_int bytes, start, size, cmp;
4495     char *a, *b;
4497     POP(t1, STRING);
4498     POP(t2, FIXNUM);
4499     POP(t3, FIXNUM);
4501     start = N2I(t2);
4502     size = N2I(t3);
4504     bytes = N2I(string_get_bytes(t1));
4505     if(start < 0) { start = bytes + start; }
4506     if(start >= bytes || start < 0) { FAIL(); }
4507     if(start + size > bytes) { size = bytes - start; }
4509     bytes = N2I(string_get_bytes(msg->recv));
4510     if(size > bytes) { size = bytes; }
4512     a = rbx_string_as_cstr(state, msg->recv);
4513     b = rbx_string_as_cstr(state, t1);
4514     cmp = memcmp(a, b + start, size);
4515     if(cmp < 0) {
4516       RET(I2N(-1));
4517     } else if(cmp > 0) {
4518       RET(I2N(1));
4519     } else {
4520       RET(I2N(0));
4521     }
4522     CODE
4523   end
4525   defprim :io_close_ng
4526   def io_close_ng
4527     <<-CODE
4528     ARITY(0);
4529     native_int j;
4531     GUARD(IO_P(msg->recv));
4533     j = io_to_fd(msg->recv);
4535     if(j == -1) {
4536       RAISE("IOError", "instance of IO already closed");
4537     } else if(close(j)) {
4538       RAISE_FROM_ERRNO("Unable to close IO object");
4539     } else {
4540       cpu_event_clear(state, j);
4541       io_set_descriptor(msg->recv, I2N(-1));
4542       RET(Qnil);
4543     }
4544     CODE
4545   end
4548 prim = ShotgunPrimitives.new
4549 prim.generate_select(STDOUT)