/vm/tinyrb/call.h

http://github.com/feyeleanor/RubyGoLightly · C++ Header · 68 lines · 59 code · 7 blank · 2 comment · 10 complexity · df44f35e73021df159526cbba455ac52 MD5 · raw file

  1. /* Inlined functions frequently used in the method calling process. */
  2. #include <alloca.h>
  3. #define TR_WITH_FRAME(SELF,CLASS,CLOS,BODY) ({ \
  4. /* push a frame */ \
  5. if (unlikely(++vm->cf >= TR_MAX_FRAMES)) tr_raise(SystemStackError, "Stack overflow"); \
  6. TrFrame __f; \
  7. register TrFrame *__fp = &__f; \
  8. __f.previous = vm->frame; \
  9. if (vm->cf == 0) vm->top_frame = __fp; \
  10. vm->frame = __fp; \
  11. vm->throw_reason = vm->throw_value = 0; \
  12. __f.method = NULL; \
  13. __f.filename = __f.line = 0; \
  14. __f.self = SELF; \
  15. __f.class = CLASS; \
  16. __f.closure = CLOS; \
  17. /* execute BODY inside the frame */ \
  18. BODY \
  19. /* pop the frame */ \
  20. vm->cf--; \
  21. vm->frame = vm->frame->previous; \
  22. })
  23. static inline OBJ TrMethod_call(VM, OBJ self, OBJ receiver, int argc, OBJ *args, int splat, TrClosure *cl) {
  24. OBJ ret = TR_NIL;
  25. TrFrame *f = NULL;
  26. TR_WITH_FRAME(receiver, TR_CLASS(receiver), cl, {
  27. f = vm->frame;
  28. TrMethod *m = f->method = TR_CMETHOD(self);
  29. TrFunc *func = f->method->func;
  30. /* splat last arg is needed */
  31. if (unlikely(splat)) {
  32. OBJ splated = args[argc-1];
  33. int splatedn = TR_ARRAY_SIZE(splated);
  34. OBJ *new_args = TR_ALLOC_N(OBJ, argc);
  35. TR_MEMCPY_N(new_args, args, OBJ, argc-1);
  36. TR_MEMCPY_N(new_args + argc-1, &TR_ARRAY_AT(splated, 0), OBJ, splatedn);
  37. argc += splatedn-1;
  38. args = new_args;
  39. }
  40. if (m->arity == -1) {
  41. ret = func(vm, receiver, argc, args);
  42. } else {
  43. if (m->arity != argc) tr_raise(ArgumentError, "Expected %d arguments, got %d.", f->method->arity, argc);
  44. switch (argc) {
  45. case 0: ret = func(vm, receiver); break;
  46. case 1: ret = func(vm, receiver, args[0]); break;
  47. case 2: ret = func(vm, receiver, args[0], args[1]); break;
  48. case 3: ret = func(vm, receiver, args[0], args[1], args[2]); break;
  49. case 4: ret = func(vm, receiver, args[0], args[1], args[2], args[3]); break;
  50. case 5: ret = func(vm, receiver, args[0], args[1], args[2], args[3], args[4]); break;
  51. case 6: ret = func(vm, receiver, args[0], args[1], args[2], args[3], args[4], args[5]); break;
  52. case 7: ret = func(vm, receiver, args[0], args[1], args[2], args[3], args[4], args[5], args[6]); break;
  53. case 8: ret = func(vm, receiver, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); break;
  54. case 9: ret = func(vm, receiver, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); break;
  55. case 10: ret = func(vm, receiver, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]); break;
  56. default: tr_raise(ArgumentError, "Too much arguments: %d, max is %d for now.", argc, 10);
  57. }
  58. }
  59. });
  60. return ret;
  61. }