Пример #1
0
Value wrenListRemoveAt(WrenVM* vm, ObjList* list, int index)
{
  Value removed = list->elements[index];

  if (IS_OBJ(removed)) WREN_PIN(vm, AS_OBJ(removed));

  // Shift items up.
  for (int i = index; i < list->count - 1; i++)
  {
    list->elements[i] = list->elements[i + 1];
  }

  // If we have too much excess capacity, shrink it.
  if (list->capacity / LIST_GROW_FACTOR >= list->count)
  {
    list->elements = wrenReallocate(vm, list->elements,
        sizeof(Value) * list->capacity,
        sizeof(Value) * (list->capacity / LIST_GROW_FACTOR));
    list->capacity /= LIST_GROW_FACTOR;
  }

  if (IS_OBJ(removed)) WREN_UNPIN(vm);

  list->count--;
  return removed;
}
Пример #2
0
void wrenListAdd(WrenVM* vm, ObjList* list, Value value)
{
  if (IS_OBJ(value)) WREN_PIN(vm, AS_OBJ(value));

  ensureListCapacity(vm, list, list->count + 1);

  if (IS_OBJ(value)) WREN_UNPIN(vm);

  list->elements[list->count++] = value;
}
Пример #3
0
int wrenDefineGlobal(WrenVM* vm, const char* name, size_t length, Value value)
{
  if (vm->globals.count == MAX_GLOBALS) return -2;

  if (IS_OBJ(value)) WREN_PIN(vm, AS_OBJ(value));

  int symbol = wrenSymbolTableAdd(vm, &vm->globalNames, name, length);
  if (symbol != -1) wrenValueBufferWrite(vm, &vm->globals, value);

  if (IS_OBJ(value)) WREN_UNPIN(vm);

  return symbol;
}
Пример #4
0
void wrenDumpValue(Value value)
{
#if WREN_NAN_TAGGING
  if (IS_NUM(value))
  {
    printf("%.14g", AS_NUM(value));
  }
  else if (IS_OBJ(value))
  {
    dumpObject(AS_OBJ(value));
  }
  else
  {
    switch (GET_TAG(value))
    {
      case TAG_FALSE:     printf("false"); break;
      case TAG_NAN:       printf("NaN"); break;
      case TAG_NULL:      printf("null"); break;
      case TAG_TRUE:      printf("true"); break;
      case TAG_UNDEFINED: UNREACHABLE();
    }
  }
#else
  switch (value.type)
  {
    case VAL_FALSE:     printf("false"); break;
    case VAL_NULL:      printf("null"); break;
    case VAL_NUM:       printf("%.14g", AS_NUM(value)); break;
    case VAL_TRUE:      printf("true"); break;
    case VAL_OBJ:       dumpObject(AS_OBJ(value)); break;
    case VAL_UNDEFINED: UNREACHABLE();
  }
#endif
}
Пример #5
0
void wrenPrintValue(Value value)
{
  #if WREN_NAN_TAGGING
  if (IS_NUM(value))
  {
    printf("%.14g", AS_NUM(value));
  }
  else if (IS_OBJ(value))
  {
    printObject(AS_OBJ(value));
  }
  else
  {
    switch (GET_TAG(value))
    {
      case TAG_FALSE: printf("false"); break;
      case TAG_NAN: printf("NaN"); break;
      case TAG_NULL: printf("null"); break;
      case TAG_TRUE: printf("true"); break;
    }
  }
  #else
  switch (value.type)
  {
    case VAL_FALSE: printf("false"); break;
    case VAL_NULL: printf("null"); break;
    case VAL_NUM: printf("%.14g", AS_NUM(value)); break;
    case VAL_TRUE: printf("true"); break;
    case VAL_OBJ:
    {
      printObject(AS_OBJ(value));
    }
  }
  #endif
}
Пример #6
0
ObjClass* wrenGetClass(WrenVM* vm, Value value)
{
  #if WREN_NAN_TAGGING
  if (IS_NUM(value)) return vm->numClass;
  if (IS_OBJ(value)) return getObjectClass(vm, AS_OBJ(value));

  switch (GET_TAG(value))
  {
    case TAG_FALSE: return vm->boolClass;
    case TAG_NAN: return vm->numClass;
    case TAG_NULL: return vm->nullClass;
    case TAG_TRUE: return vm->boolClass;
  }
  #else
  switch (value.type)
  {
    case VAL_FALSE: return vm->boolClass;
    case VAL_NULL: return vm->nullClass;
    case VAL_NUM: return vm->numClass;
    case VAL_TRUE: return vm->boolClass;
    case VAL_OBJ: return getObjectClass(vm, value.obj);
  }
  #endif

  return NULL; // Unreachable.
}
Пример #7
0
// Debug an object with extra verbosity, displaying non-enumerable properties.
void
fh_debug_verbose(FILE *stream, js_val *val, int indent)
{
  switch (val->type) {
    case T_BOOLEAN:
      fprintf(stream, "Boolean: (%s)", !val->boolean.val ? "false" : "true");
      break;
    case T_NUMBER:
      debug_num(stream, val);
      break;
    case T_STRING:
      cfprintf(stream, ANSI_YELLOW, "String: '%s'", val->string.ptr);
      break;
    case T_NULL:
      cfprintf(stream, ANSI_GRAY, "null");
      break;
    case T_UNDEF:
      cfprintf(stream, ANSI_GRAY, "undefined");
      break;
    case T_OBJECT:
      if (IS_ARR(val))
        fprintf(stream, "Array: ");
      else if (IS_FUNC(val))
        cfprintf(stream, ANSI_BLUE, "Function: ");
      else
        fprintf(stream, "Object: ");
      break;
  }

  if (IS_OBJ(val))
    debug_obj(stream, val, indent, true);

  fprintf(stream, "\n");
}
Пример #8
0
void wrenListInsert(WrenVM* vm, ObjList* list, Value value, int index)
{
  if (IS_OBJ(value)) WREN_PIN(vm, AS_OBJ(value));

  ensureListCapacity(vm, list, list->count + 1);

  if (IS_OBJ(value)) WREN_UNPIN(vm);

  // Shift items down.
  for (int i = list->count; i > index; i--)
  {
    list->elements[i] = list->elements[i - 1];
  }

  list->elements[index] = value;
  list->count++;
}
Пример #9
0
// Error.prototype.toString()
js_val *
error_proto_to_string(js_val *instance, js_args *args, eval_state *state)
{
  if (!IS_OBJ(instance))
    fh_error(state, E_TYPE, "Error.prototype.toString called on a non-object");

  js_val *name_prop = fh_get_proto(instance, "name");
  js_val *msg_prop = fh_get_proto(instance, "message");
  js_val *name = IS_UNDEF(name_prop) ? JSSTR("Error") : TO_STR(name_prop);
  js_val *msg = IS_UNDEF(msg_prop) ? JSSTR("") : TO_STR(msg_prop);

  if (strlen(name->string.ptr) == 0) return msg;
  if (strlen(msg->string.ptr) == 0) return name;
  return JSSTR(fh_str_concat(fh_str_concat(name->string.ptr, ": "), msg->string.ptr));
}
Пример #10
0
static void ffi_ptr_add(VMState *state, CallInfo *info) {
  VM_ASSERT(info->args_len == 1, "wrong arity: expected 1, got %i", info->args_len);
  Object *pointer_base = state->shared->vcache.pointer_base;
  Object *thisptr = OBJ_OR_NULL(load_arg(state->frame, info->this_arg));

  VM_ASSERT(thisptr && thisptr->parent == pointer_base, "internal error");
  PointerObject *thisptr_obj = (PointerObject*) thisptr;
  void *ptr = (void*) thisptr_obj->ptr;

  int elemsize = 1;
  Value target_type = OBJECT_LOOKUP(thisptr, target_type);
  if (!IS_NULL(target_type)) {
    VM_ASSERT(IS_OBJ(target_type), "target type must be ffi type");

    Value sizeof_val = OBJECT_LOOKUP(AS_OBJ(target_type), sizeof);
    VM_ASSERT(IS_INT(sizeof_val), "internal error: sizeof wrong type or undefined");
    elemsize = AS_INT(sizeof_val);
  }
Пример #11
0
static void
fh_gc_mark(js_val *val)
{
  if (!val || val->marked) return;

  val->marked = true;

  fh_gc_mark(val->proto);

  if (IS_OBJ(val)) {
    fh_gc_mark(val->object.primitive);
    fh_gc_mark(val->object.bound_this);
    fh_gc_mark(val->object.scope);
    fh_gc_mark(val->object.instance);
    fh_gc_mark(val->object.parent);
  }

  if (val->map) {
    js_prop *prop;
    OBJ_ITER(val, prop) {
      if (prop->ptr && !prop->circular)
        fh_gc_mark(prop->ptr);
    }
  }
Пример #12
0
// extern __thread jmp_buf jumpBuf;
int VM::call(Value A, int nEffArgs, Value *regs, Stack *stack) {
    Vector<RetInfo> retInfo; // only used if FAST_CALL

    if (!(IS_O_TYPE(A, O_FUNC) || IS_CF(A) || IS_O_TYPE(A, O_CFUNC))) { return -1; }
    regs  = stack->maybeGrow(regs, 256);
    int nExpectedArgs = IS_O_TYPE(A, O_FUNC) ? ((Func *)GET_OBJ(A))->proto->nArgs : NARGS_CFUNC;
    nEffArgs = prepareStackForCall(regs, nExpectedArgs, nEffArgs, gc);

    if (IS_CF(A) || IS_O_TYPE(A, O_CFUNC)) {
        if (IS_CF(A)) {
            tfunc f = GET_CF(A);
            *regs = f(this, CFunc::CFUNC_CALL, 0, regs, nEffArgs);
        } else {
            ((CFunc *) GET_OBJ(A))->call(this, regs, nEffArgs);
        }
        return 0;
    }

    unsigned code = 0;
    Value B;
    Value *ptrC;
    Func *activeFunc = (Func *) GET_OBJ(A);
    unsigned *pc = (unsigned *) activeFunc->proto->code.buf();

    static void *dispatch[] = {
#define _(name) &&name
#include "opcodes.inc"
#undef _
    };

    assert(sizeof(dispatch)/sizeof(dispatch[0]) == N_OPCODES);

    copyUpvals(activeFunc, regs);

    STEP;

 JMP:  pc += OD(code);    STEP;
 JT:   if (!IS_FALSE(*ptrC)) { pc += OD(code);  } STEP;
 JF:   if ( IS_FALSE(*ptrC)) { pc += OD(code);  } STEP;
 JLT:  if (lessThan(A, B))   { pc += OSC(code); } STEP;
 JNIS: if (A != B)           { pc += OSC(code); } STEP;

 FOR: 
    A = *(ptrC + 1);
    B = *(ptrC + 2);
    if (!IS_NUM(A) || !IS_NUM(B)) { goto error; } // E_FOR_NOT_NUMBER
    *ptrC = B;
    if (!(GET_NUM(B) < GET_NUM(A))) { pc += OD(code); }
    STEP;

 LOOP: {
        const double counter = GET_NUM(*ptrC) + 1;
        if (counter < GET_NUM(*(ptrC+1))) { pc += OD(code); }
        *ptrC = VAL_NUM(counter);
        STEP;
    }

 FUNC:
    assert(IS_PROTO(A));
    *ptrC = VAL_OBJ(Func::alloc(gc, PROTO(A), regs + 256, regs, OB(code)));
    STEP;

    // index, A[B]
 GETI: *ptrC = types->type(A)->indexGet(A, B); if (*ptrC == VERR) { goto error; } STEP;
 GETF: *ptrC = types->type(A)->fieldGet(A, B); if (*ptrC == VERR) { goto error; } STEP;
    
 SETI: if (!types->type(*ptrC)->indexSet(*ptrC, A, B)) { goto error; } STEP;
 SETF: if (!types->type(*ptrC)->fieldSet(*ptrC, A, B)) { goto error; } STEP;
    /*
      const int oa = OA(code);
      const int ob = OB(code);
      int top = max(oa, ob) + 1;
      top = max(top, activeFunc->proto->localsTop);
      Value *base = regs + top;
      printf("top %d\n", top);
      base[0] = A;
      base[1] = B;
      int cPos = ptrC - regs;
      DO_CALL(v, 2, regs, base, stack);
      regs[cPos] = base[0];
      break;
      if (*ptrC == VERR) { goto error; }
    */
        
 GETS: *ptrC = getSlice(gc, A, B, regs[OB(code)+1]); if (*ptrC==VERR) { goto error; } STEP;
 SETS: if (setSlice(*ptrC, A, regs[OA(code)+1], B)) { goto error; } STEP;

 RET: {
        regs[0] = A;
        Value *root = stack->base;
        gc->maybeCollect(root, regs - root + 1);
#if FAST_CALL
        if (!retInfo.size()) {
            return 0;
        }
        RetInfo *ri = retInfo.top();
        pc         = ri->pc;
        regs       = stack->base + ri->base;
        activeFunc = ri->func;
        retInfo.pop();
        copyUpvals(activeFunc, regs);
        STEP;
#else
        return 0;
#endif
    }

CALL: { 
        if (!IS_OBJ(A) && !IS_CF(A)) { goto error; } // E_CALL_NOT_FUNC
        int nEffArgs = OSB(code);
        assert(nEffArgs != 0);
        Value *base = ptrC;
#if FAST_CALL
        if (IS_O_TYPE(A, O_FUNC)) {
            Func *f = (Func *) GET_OBJ(A);
            Proto *proto = f->proto;
            prepareStackForCall(base, proto->nArgs, nEffArgs, gc);
            RetInfo *ret = retInfo.push();
            ret->pc    = pc;
            ret->base  = regs - stack->base;
            ret->func  = activeFunc;
            regs = stack->maybeGrow(base, 256);
            copyUpvals(f, regs);
            pc   = proto->code.buf();
            activeFunc = f;
        } else {
#endif
            int ret = DO_CALL(A, nEffArgs, regs, base, stack);
            if (ret) { goto error; }
#if FAST_CALL
        }
#endif
        STEP;
    }
    
 MOVEUP: {
        const int slot = regs + 256 - ptrC;
        activeFunc->setUp(slot, A);
    }
    
 MOVE_R: *ptrC = A; STEP;
 MOVE_I: *ptrC = VAL_NUM(OD(code)); STEP;
 MOVE_V: {
        int id = OA(code);
        *ptrC =
            id == CONST_NIL          ? VNIL :
            id == CONST_EMPTY_STRING ? EMPTY_STRING :
            id == CONST_EMPTY_ARRAY  ? VAL_OBJ(emptyArray->copy(gc)) :
            VAL_OBJ(emptyMap->copy(gc));
        STEP;
    }
    
 MOVE_C: {
        Value v = *pc | (((u64) *(pc+1)) << 32);
        pc += 2;
        if (IS_ARRAY(v)) {
            v = VAL_OBJ(ARRAY(v)->copy(gc));
        } else if (IS_MAP(v)) {
            v = VAL_OBJ(MAP(v)->copy(gc));
        }
        *ptrC = v;
        STEP;
    }
 LEN:    *ptrC = VAL_NUM(len(A)); STEP;
 NOTL:   *ptrC = IS_FALSE(A) ? TRUE : FALSE; STEP;
    // notb: *ptrC = IS_INT(A)? VAL_INT(~getInteger(A)):ERROR(E_WRONG_TYPE); STEP;

 ADD: *ptrC = doAdd(gc, A, B); if (*ptrC == VERR) { goto error; } STEP;
 SUB: *ptrC = BINOP(-, A, B); STEP;
 MUL: *ptrC = BINOP(*, A, B); STEP;
 DIV: *ptrC = BINOP(/, A, B); STEP;
 MOD: *ptrC = doMod(A, B); if (*ptrC == VERR) { goto error; } STEP;
 POW: *ptrC = doPow(A, B); if (*ptrC == VERR) { goto error; } STEP;

 AND: *ptrC = BITOP(&,  A, B); STEP;
 OR:  *ptrC = BITOP(|,  A, B); STEP;
 XOR: *ptrC = BITOP(^,  A, B); STEP;

 SHL_RR: ERR(!IS_NUM(B), E_WRONG_TYPE); *ptrC = doSHL(A, (int)GET_NUM(B)); STEP;
 SHR_RR: ERR(!IS_NUM(B), E_WRONG_TYPE); *ptrC = doSHR(A, (int)GET_NUM(B)); STEP;
 SHL_RI: *ptrC = doSHL(A, OSB(code));       STEP;
 SHR_RI: *ptrC = doSHR(A, OSB(code));       STEP;

 EQ:  *ptrC = equals(A, B)  ? TRUE : FALSE; STEP;
 NEQ: *ptrC = !equals(A, B) ? TRUE : FALSE; STEP;
 IS:  *ptrC = A == B ? TRUE : FALSE; STEP;
 NIS: *ptrC = A != B ? TRUE : FALSE; STEP;

 LT:  *ptrC = lessThan(A, B) ? TRUE : FALSE; STEP;
 LE:  *ptrC = (equals(A, B) || lessThan(A, B)) ? TRUE : FALSE; STEP;

 error: return pc - (unsigned *) activeFunc->proto->code.buf();
}
Пример #13
0
void wrenMarkValue(WrenVM* vm, Value value)
{
  if (!IS_OBJ(value)) return;
  wrenMarkObj(vm, AS_OBJ(value));
}