Example #1
0
void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) {
  if (e->k == VCALL) {  /* expression is an open function call? */
    SETARG_C(getcode(fs, e), nresults+1);
  }
  else if (e->k == VVARARG) {
    SETARG_B(getcode(fs, e), nresults+1);
    SETARG_A(getcode(fs, e), fs->freereg);
    luaK_reserveregs(fs, 1);
  }
}
Example #2
0
static int patchtestreg (FuncState *fs, int node, int reg) {
  Instruction *i = getjumpcontrol(fs, node);
  if (GET_OPCODE(*i) != OP_TESTSET)
    return 0;  /* cannot patch other instructions */
  if (reg != NO_REG && reg != GETARG_B(*i))
    SETARG_A(*i, reg);
  else  /* no register to put value or register already has the value */
    *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i));

  return 1;
}
Example #3
0
void luaK_patchclose (FuncState *fs, int list, int level) {
  level++;  /* argument is +1 to reserve 0 as non-op */
  while (list != NO_JUMP) {
    int next = getjump(fs, list);
    lua_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP &&
                (GETARG_A(fs->f->code[list]) == 0 ||
                 GETARG_A(fs->f->code[list]) >= level));
    SETARG_A(fs->f->code[list], level);
    list = next;
  }
}
Example #4
0
/*
** Fix an expression to return the number of results 'nresults'.
** Either 'e' is a multi-ret expression (function call or vararg)
** or 'nresults' is LUA_MULTRET (as any expression can satisfy that).
*/
void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) {
  if (e->k == VCALL) {  /* expression is an open function call? */
    SETARG_C(getinstruction(fs, e), nresults + 1);
  }
  else if (e->k == VVARARG) {
    Instruction *pc = &getinstruction(fs, e);
    SETARG_B(*pc, nresults + 1);
    SETARG_A(*pc, fs->freereg);
    luaK_reserveregs(fs, 1);
  }
  else lua_assert(nresults == LUA_MULTRET);
}
Example #5
0
File: lcode.c Project: galek/ravi
void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) {
  if (e->k == VCALL) {  /* expression is an open function call? */
    SETARG_C(getcode(fs, e), nresults+1);
    DEBUG_CODEGEN(raviY_printf(fs, "[%d]* %o ; set C to %d\n", e->u.info, getcode(fs,e), nresults+1));
  }
  else if (e->k == VVARARG) {
    SETARG_B(getcode(fs, e), nresults+1);
    DEBUG_CODEGEN(raviY_printf(fs, "[%d]* %o ; set B to %d\n", e->u.info, getcode(fs,e), nresults + 1));
    SETARG_A(getcode(fs, e), fs->freereg);
    DEBUG_CODEGEN(raviY_printf(fs, "[%d]* %o ; set A to %d\n", e->u.info, getcode(fs,e), fs->freereg));
    luaK_reserveregs(fs, 1);
  }
}
Example #6
0
static void discharge2reg(FuncState *fs, expdesc *e, int reg)
{
    luaK_dischargevars(fs, e);

    switch (e->k)
    {
    case VNIL: {
        luaK_nil(fs, reg, 1);
        break;
    }

    case VFALSE:
    case VTRUE: {
        luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0);
        break;
    }

    case VK: {
        luaK_codek(fs, reg, e->u.info);
        break;
    }

    case VKNUM: {
        luaK_codek(fs, reg, luaK_numberK(fs, e->u.nval));
        break;
    }

    case VRELOCABLE: {
        Instruction *pc = &getcode(fs, e);
        SETARG_A(*pc, reg);
        break;
    }

    case VNONRELOC: {
        if (reg != e->u.info)
            luaK_codeABC(fs, OP_MOVE, reg, e->u.info, 0);

        break;
    }

    default: {
        lua_assert(e->k == VVOID || e->k == VJMP);
        return; /* nothing to do... */
    }
    }

    e->u.info = reg;
    e->k      = VNONRELOC;
}
Example #7
0
File: lcode.c Project: galek/ravi
/* Patch register of test instructions. */
static int patchtestreg (FuncState *fs, int node, int reg) {
  Instruction *i = getjumpcontrol(fs, node);
  if (GET_OPCODE(*i) != OP_TESTSET)
    return 0;  /* cannot patch other instructions */
  if (reg != NO_REG && reg != GETARG_B(*i)) {
    SETARG_A(*i, reg);
    DEBUG_CODEGEN(raviY_printf(fs, "[?]* %o ; set A to %d\n", *i, reg));
  }
  else  /* no register to put value or register already has the value */ {
    *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i));
    DEBUG_CODEGEN(raviY_printf(fs, "[?]* %o ; generate OP_TEST\n", *i));
  }

  return 1;
}
Example #8
0
static void discharge2reg(ktap_funcstate *fs, ktap_expdesc *e, int reg)
{
	codegen_dischargevars(fs, e);
	switch (e->k) {
	case VNIL: {
		codegen_nil(fs, reg, 1);
		break;
	}
	case VFALSE:  case VTRUE: {
		codegen_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0);
 		break;
	}
	case VEVENT:
		codegen_codeABC(fs, OP_EVENT, reg, 0, 0);
		break;
	case VEVENTNAME:
		codegen_codeABC(fs, OP_EVENTNAME, reg, 0, 0);
		break;
	case VEVENTARG:
		codegen_codeABC(fs, OP_EVENTARG, reg, e->u.info, 0);
		break;
	case VK: {
		codegen_codek(fs, reg, e->u.info);
		break;
	}
	case VKNUM: {
		codegen_codek(fs, reg, codegen_numberK(fs, e->u.nval));
		break;
	}
	case VRELOCABLE: {
		ktap_instruction *pc = &getcode(fs, e);
		SETARG_A(*pc, reg);
		break;
	}
	case VNONRELOC: {
		if (reg != e->u.info)
			codegen_codeABC(fs, OP_MOVE, reg, e->u.info, 0);
		break;
	}
	default:
		ktap_assert(e->k == VVOID || e->k == VJMP);
		return;  /* nothing to do... */
	}

	e->u.info = reg;
	e->k = VNONRELOC;
}
Example #9
0
/*
** Create a OP_LOADNIL instruction, but try to optimize: if the previous
** instruction is also OP_LOADNIL and ranges are compatible, adjust
** range of previous instruction instead of emitting a new one. (For
** instance, 'local a; local b' will generate a single opcode.)
*/
void luaK_nil (FuncState *fs, int from, int n) {
  Instruction *previous;
  int l = from + n - 1;  /* last register to set nil */
  if (fs->pc > fs->lasttarget) {  /* no jumps to current position? */
    previous = &fs->f->code[fs->pc-1];
    if (GET_OPCODE(*previous) == OP_LOADNIL) {  /* previous is LOADNIL? */
      int pfrom = GETARG_A(*previous);  /* get previous range */
      int pl = pfrom + GETARG_B(*previous);
      if ((pfrom <= from && from <= pl + 1) ||
          (from <= pfrom && pfrom <= l + 1)) {  /* can connect both? */
        if (pfrom < from) from = pfrom;  /* from = min(from, pfrom) */
        if (pl > l) l = pl;  /* l = max(l, pl) */
        SETARG_A(*previous, from);
        SETARG_B(*previous, l - from);
        return;
      }
    }  /* else go through */
  }
  luaK_codeABC(fs, OP_LOADNIL, from, n - 1, 0);  /* else no optimization */
}
Example #10
0
TrCallSite *TrVM::lookup(TrBlock *b, OBJ receiver, OBJ msg, TrInst *ip)
{
   TrVM *vm = this;
   
   OBJ method = TrObject_method(this, receiver, msg);
   
   TrInst *boing = (ip - 1);
   /* TODO: do not prealloc TrCallSite here, every one is a memory leak and a new
    one is created on polymorphic calls. */
   b->sites.emplace_back();
   TrCallSite *s = &b->sites.back();
   s->klass = TR_CLASS(receiver);
   s->miss = 0;
   s->method = method;
   s->message = msg;
   if (unlikely(method == TR_NIL))
   {
      s->method = TrObject_method(this, receiver, tr_intern("method_missing"));
      s->method_missing = 1;
   }
   
   /* Implement Monomorphic method cache by replacing the previous instruction (BOING)
    w/ CACHE that uses the CallSite to find the method instead of doing a full lookup. */
   if (GET_OPCODE(*boing) == TR_OP_CACHE)
   {
      /* Existing call site */
      /* TODO: maybe take existing call site hit miss into consideration to replace it with this one.
       For now, we just don't replace it, the first one is always the cached one. */
   }
   else
   {
      /* New call site, we cache it fo shizzly! */
      SET_OPCODE(*boing, TR_OP_CACHE);
      SETARG_A(*boing, GETARG_A(*ip)); /* receiver register */
      SETARG_B(*boing, 1); /* jmp */
      SETARG_C(*boing, b->sites.size()-1); /* CallSite index */
   }
   
   return s;
}
Example #11
0
File: lcode.c Project: galek/ravi
/* Emit bytecode to set a range of registers to nil. */
void luaK_nil (FuncState *fs, int from, int n) {
  Instruction *previous;
  int l = from + n - 1;  /* last register to set nil */
  if (fs->pc > fs->lasttarget) {  /* no jumps to current position? */
    previous = &fs->f->code[fs->pc-1];
    if (GET_OPCODE(*previous) == OP_LOADNIL) { /* Try to merge with the previous instruction. */
      int pfrom = GETARG_A(*previous);
      int pl = pfrom + GETARG_B(*previous);
      if ((pfrom <= from && from <= pl + 1) ||
          (from <= pfrom && pfrom <= l + 1)) {  /* can connect both? */
        if (pfrom < from) from = pfrom;  /* from = min(from, pfrom) */
        if (pl > l) l = pl;  /* l = max(l, pl) */
        SETARG_A(*previous, from);
        DEBUG_CODEGEN(raviY_printf(fs, "[%d]* %o ; set A to %d\n", fs->pc - 1, *previous, from));
        SETARG_B(*previous, l - from);
        DEBUG_CODEGEN(raviY_printf(fs, "[%d]* %o ; set B to %d\n", fs->pc - 1, *previous, (l - from)));
        return;
      }
    }  /* else go through */
  }
  luaK_codeABC(fs, OP_LOADNIL, from, n - 1, 0);  /* else no optimization */
}
Example #12
0
static void patchtestreg (Instruction *i, int reg) {
  if (reg != NO_REG)
    SETARG_A(*i, reg);
  else  /* no register to put value; change TESTSET to TEST */
    *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i));
}
Example #13
0
File: lcode.c Project: galek/ravi
static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
  luaK_dischargevars(fs, e);
  switch (e->k) {
    case VNIL: {
      luaK_nil(fs, reg, 1);
      break;
    }
    case VFALSE: case VTRUE: {
      luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0);
      break;
    }
    case VK: {
      luaK_codek(fs, reg, e->u.info);
      break;
    }
    case VKFLT: {
      luaK_codek(fs, reg, luaK_numberK(fs, e->u.nval));
      break;
    }
    case VKINT: {
      luaK_codek(fs, reg, luaK_intK(fs, e->u.ival));
      break;
    }
    case VRELOCABLE: {
      Instruction *pc = &getcode(fs, e);
      SETARG_A(*pc, reg);
      DEBUG_EXPR(raviY_printf(fs, "discharge2reg (VRELOCABLE set arg A) %e\n", e));
      DEBUG_CODEGEN(raviY_printf(fs, "[%d]* %o ; set A to %d\n", e->u.info, *pc, reg));
      break;
    }
    case VNONRELOC: {
      if (reg != e->u.info) {
        /* code a MOVEI or MOVEF if the target register is a local typed variable */
        int ravi_type = raviY_get_register_typeinfo(fs, reg);
        switch (ravi_type) {
        case RAVI_TNUMINT:
          luaK_codeABC(fs, OP_RAVI_MOVEI, reg, e->u.info, 0);
          break;
        case RAVI_TNUMFLT:
          luaK_codeABC(fs, OP_RAVI_MOVEF, reg, e->u.info, 0);
          break;
        case RAVI_TARRAYINT:
          luaK_codeABC(fs, OP_RAVI_MOVEAI, reg, e->u.info, 0);
          break;
        case RAVI_TARRAYFLT:
          luaK_codeABC(fs, OP_RAVI_MOVEAF, reg, e->u.info, 0);
          break;
        default:
          luaK_codeABC(fs, OP_MOVE, reg, e->u.info, 0);
          break;
        }
      }
      break;
    }
    default: {
      lua_assert(e->k == VVOID || e->k == VJMP);
      return;  /* nothing to do... */
    }
  }
  e->u.info = reg;
  e->k = VNONRELOC;
}
Example #14
0
static void patchtestreg (Instruction *i, int reg) {
  if (reg == NO_REG) reg = GETARG_B(*i);
  SETARG_A(*i, reg);
}
Example #15
0
OBJ TrCompiler_compile_node(VM, TrCompiler *c, TrBlock *b, TrNode *n, int reg) {
  if (!n) return TR_NIL;
  int start_reg = reg;
  REG(reg);
  b->line = n->line;
  /* TODO this shit is very repetitive, need to refactor */
  switch (n->ntype) {
    case NODE_ROOT:
    case NODE_BLOCK:
      COMPILE_NODES(b, n->args[0], i, reg, 0);
      break;
    case NODE_VALUE: {
      int i = TrBlock_push_value(b, n->args[0]);
      PUSH_OP_ABx(b, LOADK, reg, i);
    } break;
    case NODE_STRING: {
      int i = TrBlock_push_string(b, TR_STR_PTR(n->args[0]));
      PUSH_OP_ABx(b, STRING, reg, i);
    } break;
    case NODE_ARRAY: {
      size_t size = 0;
      if (n->args[0]) {
        size = TR_ARRAY_SIZE(n->args[0]);
        /* compile args */
        COMPILE_NODES(b, n->args[0], i, reg, i+1);
        ASSERT_NO_LOCAL_IN(Array);
      }
      PUSH_OP_AB(b, NEWARRAY, reg, size);
    } break;
    case NODE_HASH: {
      size_t size = 0;
      if (n->args[0]) {
        size = TR_ARRAY_SIZE(n->args[0]);
        /* compile args */
        COMPILE_NODES(b, n->args[0], i, reg, i+1);
        ASSERT_NO_LOCAL_IN(Hash);
      }
      PUSH_OP_AB(b, NEWHASH, reg, size/2);
    } break;
    case NODE_RANGE: {
      COMPILE_NODE(b, n->args[0], reg);
      COMPILE_NODE(b, n->args[1], reg+1);
      REG(reg+1);
      ASSERT_NO_LOCAL_IN(Range);
      PUSH_OP_ABC(b, NEWRANGE, reg, reg+1, n->args[2]);
    } break;
    case NODE_ASSIGN: {
      OBJ name = n->args[0];
      COMPILE_NODE(b, n->args[1], reg);
	  
      if (TrBlock_find_upval_in_scope(b, name) != -1) {
        /* upval */
		int i = TrBlock_push_upval(b, name);
        PUSH_OP_AB(b, SETUPVAL, reg, i);
      } else {
        /* local */
        int i = TrBlock_push_local(b, name);
        TrInst *last_inst = &kv_A(b->code, kv_size(b->code) - 1);
        switch (GET_OPCODE(*last_inst)) {
          case TR_OP_ADD: /* Those instructions can load direcly into a local */
          case TR_OP_SUB:
          case TR_OP_LT:
          case TR_OP_NEG:
          case TR_OP_NOT:
            SETARG_A(*last_inst, i); break;
          default:
            if (i != reg) PUSH_OP_AB(b, MOVE, i, reg);
        }
      }
    } break;
    case NODE_SETIVAR:
      COMPILE_NODE(b, n->args[1], reg);
      PUSH_OP_ABx(b, SETIVAR, reg, TrBlock_push_value(b, n->args[0]));
      break;
    case NODE_GETIVAR:
      PUSH_OP_ABx(b, GETIVAR, reg, TrBlock_push_value(b, n->args[0]));
      break;
    case NODE_SETCVAR:
      COMPILE_NODE(b, n->args[1], reg);
      PUSH_OP_ABx(b, SETCVAR, reg, TrBlock_push_value(b, n->args[0]));
      break;
    case NODE_GETCVAR:
      PUSH_OP_ABx(b, GETCVAR, reg, TrBlock_push_value(b, n->args[0]));
      break;
    case NODE_SETGLOBAL:
      COMPILE_NODE(b, n->args[1], reg);
      PUSH_OP_ABx(b, SETGLOBAL, reg, TrBlock_push_value(b, n->args[0]));
      break;
    case NODE_GETGLOBAL:
      PUSH_OP_ABx(b, GETGLOBAL, reg, TrBlock_push_value(b, n->args[0]));
      break;
    case NODE_SEND:
    /* can also be a variable access */
    {
      TrNode *msg = (TrNode *)n->args[1];
      OBJ name = msg->args[0];
      assert(msg->ntype == NODE_MSG);
      int i;
      /* local */
      if ((i = TrBlock_find_local(b, name)) != -1) {
        if (reg != i) PUSH_OP_AB(b, MOVE, reg, i);
        
      /* upval */
      } else if (TrBlock_find_upval_in_scope(b, name) != -1) {
        i = TrBlock_push_upval(b, name);
        PUSH_OP_AB(b, GETUPVAL, reg, i);
        
      /* method call */
      } else {
        /* receiver */
        if (n->args[0])
          COMPILE_NODE(b, n->args[0], reg);
        else
          PUSH_OP_A(b, SELF, reg);
        i = TrBlock_push_value(b, name);
        /* args */
        size_t argc = 0;
        if (msg->args[1]) {
          argc = TR_ARRAY_SIZE(msg->args[1]) << 1;
          TR_ARRAY_EACH(msg->args[1], i, v, {
            TrNode *arg = (TrNode *)v;
            assert(arg->ntype == NODE_ARG);
            reg += COMPILE_NODE(b, arg->args[0], reg+i+2);
            if (arg->args[1]) argc |= 1; /* splat */
          });
          ASSERT_NO_LOCAL_IN(arguments);
        }
        /* block */
        size_t blki = 0;
        TrBlock *blk = 0;
        if (n->args[2]) {
          blk = TrBlock_new(c, b);
          TrNode *blkn = (TrNode *)n->args[2];
          blki = kv_size(b->blocks) + 1;
          blk->argc = 0;
          if (blkn->args[1]) {
            blk->argc = TR_ARRAY_SIZE(blkn->args[1]);
            /* add parameters as locals in block context */
            TR_ARRAY_EACH(blkn->args[1], i, v, {
              TrNode *param = (TrNode *)v;
              TrBlock_push_local(blk, param->args[0]);
            });
Example #16
0
static void invertjump (FuncState *fs, expdesc *e) {
  Instruction *pc = getjumpcontrol(fs, e->u.info);
  lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TEST);
  SETARG_A(*pc, !(GETARG_A(*pc)));
}