コード例 #1
0
ファイル: ffi.c プロジェクト: FeepingCreature/jerboa
static void ffi_ptr_dereference_assign(VMState *state, CallInfo *info) {
  VM_ASSERT(info->args_len == 3, "wrong arity: expected 2, got %i", info->args_len);
  Object *root = state->root;
  Object *pointer_base = state->shared->vcache.pointer_base;

  FFIObject *ffi = (FFIObject*) AS_OBJ(OBJECT_LOOKUP(root, ffi));
  Object *ffi_type = AS_OBJ(OBJECT_LOOKUP((Object*) ffi, type));

  Object *thisptr = AS_OBJ(load_arg(state->frame, info->this_arg));
  VM_ASSERT(thisptr->parent == pointer_base, "internal error");
  PointerObject *thisptr_obj = (PointerObject*) thisptr;

  Object *ffi_type_obj = obj_instance_of(OBJ_OR_NULL(load_arg(state->frame, INFO_ARGS_PTR(info)[0])), ffi_type);
  Value offs_val = load_arg(state->frame, INFO_ARGS_PTR(info)[1]);
  VM_ASSERT(IS_INT(offs_val), "offset must be integer");
  int offs = AS_INT(offs_val);
  VM_ASSERT(ffi_type_obj, "type is not a FFI type");
  char *offset_ptr = (char*) thisptr_obj->ptr + offs;

  Value value = load_arg(state->frame, INFO_ARGS_PTR(info)[2]);

  (void) offset_ptr; (void) value;
  if (ffi_type_obj == ffi->long_obj) {
    VM_ASSERT(IS_INT(value), "can only assign integer to long");
    *(long*) offset_ptr = AS_INT(value);
  } else {
    fprintf(stderr, "TODO\n");
    abort();
  }
}
コード例 #2
0
ファイル: wren_value.c プロジェクト: Zhangli88/wren
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
}
コード例 #3
0
ファイル: wren_debug.c プロジェクト: minirop/wren
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
}
コード例 #4
0
ファイル: ffi.c プロジェクト: FeepingCreature/jerboa
static void ffi_ptr_dereference(VMState *state, CallInfo *info) {
  VM_ASSERT(info->args_len == 2, "wrong arity: expected 2, got %i", info->args_len);
  Object *root = state->root;
  Object *pointer_base = state->shared->vcache.pointer_base;

  FFIObject *ffi = (FFIObject*) AS_OBJ(OBJECT_LOOKUP(root, ffi));
  Object *ffi_type = AS_OBJ(OBJECT_LOOKUP((Object*) ffi, type));

  Object *thisptr = AS_OBJ(load_arg(state->frame, info->this_arg));
  VM_ASSERT(thisptr->parent == pointer_base, "internal error");
  PointerObject *thisptr_obj = (PointerObject*) thisptr;

  Object *ffi_type_obj = obj_instance_of(OBJ_OR_NULL(load_arg(state->frame, INFO_ARGS_PTR(info)[0])), ffi_type);
  Value offs_val = load_arg(state->frame, INFO_ARGS_PTR(info)[1]);
  VM_ASSERT(IS_INT(offs_val), "offset must be integer");
  int offs = AS_INT(offs_val);
  VM_ASSERT(ffi_type_obj, "type is not a FFI type");
  char *offset_ptr = (char*) thisptr_obj->ptr + offs;
  if (ffi_type_obj == ffi->short_obj) {
    short s = *(short*) offset_ptr;
    vm_return(state, info, INT2VAL(s));
  } else if (ffi_type_obj == ffi->ushort_obj) {
    unsigned short us = *(unsigned short*) offset_ptr;
    vm_return(state, info, INT2VAL(us));
  } else if (ffi_type_obj == ffi->int_obj) {
    int i = *(int*) offset_ptr;
    vm_return(state, info, INT2VAL(i));
  } else if (ffi_type_obj == ffi->uint_obj) {
    unsigned int u = *(unsigned int*) offset_ptr;
    vm_return(state, info, INT2VAL(u));
  } else if (ffi_type_obj == ffi->int8_obj) {
    int8_t i8 = *(int8_t*) offset_ptr;
    vm_return(state, info, INT2VAL(i8));
  } else if (ffi_type_obj == ffi->uint8_obj) {
    uint8_t u8 = *(uint8_t*) offset_ptr;
    vm_return(state, info, INT2VAL(u8));
  } else if (ffi_type_obj == ffi->int32_obj) {
    int32_t i32 = *(int32_t*) offset_ptr;
    vm_return(state, info, INT2VAL(i32));
  } else if (ffi_type_obj == ffi->uint32_obj) {
    uint32_t u32 = *(uint32_t*) offset_ptr;
    vm_return(state, info, INT2VAL(u32));
  } else if (ffi_type_obj == ffi->pointer_obj) {
    void *ptr = *(void**) offset_ptr;
    vm_return(state, info, make_ffi_pointer(state, ptr));
  } else if (ffi_type_obj == ffi->char_pointer_obj) {
    char *ptr = *(char**) offset_ptr;
    vm_return(state, info, make_string_static(state, ptr));
  } else if (ffi_type_obj == ffi->long_obj) {
    long l = *(long*) offset_ptr;
    if (l < INT_MIN || l > INT_MAX) {
      VM_ASSERT(false, "value exceeds bounds of my int type");
    }
    vm_return(state, info, INT2VAL((int) l));
  } else { fprintf(stderr, "TODO\n"); abort(); }
}
コード例 #5
0
ファイル: ffi.c プロジェクト: FeepingCreature/jerboa
static void ffi_open_fn(VMState *state, CallInfo *info) {
  VM_ASSERT(info->args_len == 1, "wrong arity: expected 1, got %i", info->args_len);
  Object *root = state->root;
  Object *string_base = state->shared->vcache.string_base;
  Object *array_base = state->shared->vcache.array_base;
  Object *ffi = AS_OBJ(OBJECT_LOOKUP(root, ffi));
  Object *handle_base = AS_OBJ(OBJECT_LOOKUP(ffi, handle));

  StringObject *sarg = (StringObject*) obj_instance_of(OBJ_OR_NULL(load_arg(state->frame, INFO_ARGS_PTR(info)[0])), string_base);
  VM_ASSERT(sarg, "argument to ffi.open must be string!");

  Object *libmap = AS_OBJ(OBJECT_LOOKUP(ffi, library_map));

  char *file = sarg->value;

  bool file_found = false;
  FastKey file_key = prepare_key(file, strlen(file));
  Value mapping = object_lookup_p(libmap, &file_key, &file_found);
  const char **file_list_ptr = NULL;
  int file_list_len = 0;
  if (file_found) {
    ArrayObject *aobj = (ArrayObject*) obj_instance_of(OBJ_OR_NULL(mapping), array_base);
    StringObject *sobj = (StringObject*) obj_instance_of(OBJ_OR_NULL(mapping), string_base);
    if (aobj) {
      file_list_len = aobj->length;
      file_list_ptr = malloc(sizeof(char*) * file_list_len);
      for (int i = 0; i < file_list_len; i++) {
        StringObject *file = (StringObject*) obj_instance_of(OBJ_OR_NULL(aobj->ptr[i]), string_base);
        VM_ASSERT(file, "library_map sub-entries must be string");
        file_list_ptr[i] = my_asprintf("%s", file->value); // outside gc, make copy
      }
    } else if (sobj) {
      file_list_len = 1;
      file_list_ptr = malloc(sizeof(char*) * 1);
      file_list_ptr[0] = my_asprintf("%s", sobj->value);
    } else VM_ASSERT(false, "library_map entries must be string or array");
  } else {
    file_list_len = 1;
    file_list_ptr = malloc(sizeof(char*) * 1);
    file_list_ptr[0] = file;
  }

  void *dlptr = my_dlopen(file_list_len, file_list_ptr);

  Object *handle_obj = AS_OBJ(make_object(state, handle_base, false));
  handle_obj->flags |= OBJ_FROZEN;
  OBJECT_SET(state, handle_obj, pointer, make_ptr(state, dlptr));
  vm_return(state, info, OBJ2VAL(handle_obj));
}
コード例 #6
0
ファイル: wren_value.c プロジェクト: 1100110/wren
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
ファイル: wren_value.c プロジェクト: Zhangli88/wren
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;
}
コード例 #8
0
ファイル: ffi.c プロジェクト: FeepingCreature/jerboa
Value ffi_pointer_read(VMState *state, Object *type, void *ptr) {
  ValueCache *vcache = &state->shared->vcache;
  Object *string_base = vcache->string_base;
  FFIObject *ffi = (FFIObject*) vcache->ffi_obj;
  if (type == ffi->float_obj) {
    float f = *(float*) ptr;
    return FLOAT2VAL(f);
  } else if (type == ffi->int_obj) {
    int i = *(int*) ptr;
    return INT2VAL(i);
  } else if (type == ffi->uint_obj) {
    unsigned int i = *(unsigned int*) ptr;
    return INT2VAL(i);
  } else {
    bool has_pointer = false;
    OBJECT_LOOKUP_P(type, pointer, &has_pointer);
    if (!has_pointer) {
      Object *c_type_obj = OBJ_OR_NULL(OBJECT_LOOKUP(type, c_type));
      StringObject *c_type = (StringObject*) obj_instance_of(c_type_obj, string_base);
      VM_ASSERT(c_type, "internal type error") VNULL;
      VM_ASSERT(false, "unhandled pointer read type: %s", c_type->value) VNULL;
    }
    Value res = make_object(state, type, false);
    char *error = OBJECT_SET(state, AS_OBJ(res), pointer, make_ffi_pointer(state, ptr));
    VM_ASSERT(!error, error) VNULL;
    return res;
  }
}
コード例 #9
0
ファイル: wren_value.c プロジェクト: Drooids/wren
ObjClass* wrenNewClass(WrenVM* vm, ObjClass* superclass, int numFields,
                       ObjString* name)
{
  // Create the metaclass.
  Value metaclassName = wrenStringFormat(vm, "@ metaclass", OBJ_VAL(name));
  wrenPushRoot(vm, AS_OBJ(metaclassName));

  ObjClass* metaclass = wrenNewSingleClass(vm, 0, AS_STRING(metaclassName));
  metaclass->obj.classObj = vm->classClass;

  wrenPopRoot(vm);

  // Make sure the metaclass isn't collected when we allocate the class.
  wrenPushRoot(vm, (Obj*)metaclass);

  // Metaclasses always inherit Class and do not parallel the non-metaclass
  // hierarchy.
  wrenBindSuperclass(vm, metaclass, vm->classClass);

  ObjClass* classObj = wrenNewSingleClass(vm, numFields, name);

  // Make sure the class isn't collected while the inherited methods are being
  // bound.
  wrenPushRoot(vm, (Obj*)classObj);

  classObj->obj.classObj = metaclass;
  wrenBindSuperclass(vm, classObj, superclass);

  wrenPopRoot(vm);
  wrenPopRoot(vm);

  return classObj;
}
コード例 #10
0
ファイル: Interpreter.cpp プロジェクト: jdegeete/SOMpp
void Interpreter::doSuperSend(long bytecodeIndex) {
    VMSymbol* signature = static_cast<VMSymbol*>(method->GetConstant(bytecodeIndex));

    VMFrame* ctxt = GetFrame()->GetOuterContext();
    VMMethod* realMethod = ctxt->GetMethod();
    VMClass* holder = realMethod->GetHolder();
    VMClass* super = holder->GetSuperClass();
    VMInvokable* invokable = static_cast<VMInvokable*>(super->LookupInvokable(signature));

    if (invokable != nullptr)
        (*invokable)(GetFrame());
    else {
        long numOfArgs = Signature::GetNumberOfArguments(signature);
        vm_oop_t receiver = GetFrame()->GetStackElement(numOfArgs - 1);
        VMArray* argumentsArray = GetUniverse()->NewArray(numOfArgs);

        for (long i = numOfArgs - 1; i >= 0; --i) {
            vm_oop_t o = GetFrame()->Pop();
            argumentsArray->SetIndexableField(i, o);
        }
        vm_oop_t arguments[] = {signature, argumentsArray};

        AS_OBJ(receiver)->Send(doesNotUnderstand, arguments, 2);
    }
}
コード例 #11
0
ファイル: wren_value.c プロジェクト: Zhangli88/wren
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;
}
コード例 #12
0
ファイル: VMMethod.cpp プロジェクト: jdegeete/SOMpp
void VMMethod::SetHolderAll(VMClass* hld) {
    long numIndexableFields = GetNumberOfIndexableFields();
    for (long i = 0; i < numIndexableFields; ++i) {
        vm_oop_t o = GetIndexableField(i);
        if (!IS_TAGGED(o)) {
            VMInvokable* vmi = dynamic_cast<VMInvokable*>(AS_OBJ(o));
            if (vmi != nullptr) {
                vmi->SetHolder(hld);
            }
        }
    }
}
コード例 #13
0
ファイル: wren_vm.c プロジェクト: zeckalpha/wren
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;
}
コード例 #14
0
ファイル: Interpreter.cpp プロジェクト: jdegeete/SOMpp
void Interpreter::send(VMSymbol* signature, VMClass* receiverClass) {
    VMInvokable* invokable = receiverClass->LookupInvokable(signature);

    if (invokable != nullptr) {
#ifdef LOG_RECEIVER_TYPES
        StdString name = receiverClass->GetName()->GetStdString();
        if (GetUniverse()->callStats.find(name) == GetUniverse()->callStats.end())
        GetUniverse()->callStats[name] = {0,0};
        GetUniverse()->callStats[name].noCalls++;
        if (invokable->IsPrimitive())
        GetUniverse()->callStats[name].noPrimitiveCalls++;
#endif
        // since an invokable is able to change/use the frame, we have to write
        // cached values before, and read cached values after calling
        GetFrame()->SetBytecodeIndex(bytecodeIndexGlobal);
        (*invokable)(GetFrame());
        bytecodeIndexGlobal = GetFrame()->GetBytecodeIndex();
    } else {
        GetFrame()->PrintStackTrace();
        //doesNotUnderstand
        long numberOfArgs = Signature::GetNumberOfArguments(signature);

        vm_oop_t receiver = GetFrame()->GetStackElement(numberOfArgs-1);

        VMArray* argumentsArray = GetUniverse()->NewArray(numberOfArgs - 1); // without receiver

        // the receiver should not go into the argumentsArray
        // so, numberOfArgs - 2
        for (long i = numberOfArgs - 2; i >= 0; --i) {
            vm_oop_t o = GetFrame()->Pop();
            argumentsArray->SetIndexableField(i, o);
        }
        vm_oop_t arguments[] = {signature, argumentsArray};
        
        GetFrame()->Pop(); // pop the receiver

        //check if current frame is big enough for this unplanned Send
        //doesNotUnderstand: needs 3 slots, one for this, one for method name, one for args
        long additionalStackSlots = 3 - GetFrame()->RemainingStackSize();
        if (additionalStackSlots > 0) {
            GetFrame()->SetBytecodeIndex(bytecodeIndexGlobal);
            //copy current frame into a bigger one and replace the current frame
            SetFrame(VMFrame::EmergencyFrameFrom(GetFrame(), additionalStackSlots));
        }

        AS_OBJ(receiver)->Send(doesNotUnderstand, arguments, 2);
    }
}
コード例 #15
0
ファイル: wren_value.c プロジェクト: Zhangli88/wren
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++;
}
コード例 #16
0
ファイル: ffi.c プロジェクト: FeepingCreature/jerboa
bool ffi_pointer_write(VMState *state, Object *type, void *ptr, Value val) {
  ValueCache *vcache = &state->shared->vcache;
  Object *string_base = vcache->string_base;
  FFIObject *ffi = (FFIObject*) vcache->ffi_obj;
  if (type == ffi->float_obj) {
    if (IS_FLOAT(val)) *(float*) ptr = AS_FLOAT(val);
    else if (IS_INT(val)) *(float*) ptr = AS_INT(val);
    else {
      VM_ASSERT(false, "invalid value for float type") false;
    }
    return true;
  } else {
    Object *c_type_obj = AS_OBJ(OBJECT_LOOKUP(type, c_type));
    StringObject *c_type = (StringObject*) obj_instance_of(c_type_obj, string_base);
    assert(c_type);
    VM_ASSERT(false, "unhandled pointer write type: %s", c_type->value) false;
  }
}
コード例 #17
0
ファイル: ffi.c プロジェクト: FeepingCreature/jerboa
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);
  }
コード例 #18
0
ファイル: Interpreter.cpp プロジェクト: jdegeete/SOMpp
void Interpreter::doPushGlobal(long bytecodeIndex) {
    VMSymbol* globalName = static_cast<VMSymbol*>(method->GetConstant(bytecodeIndex));
    vm_oop_t global = GetUniverse()->GetGlobal(globalName);

    if (global != nullptr)
        GetFrame()->Push(global);
    else {
        vm_oop_t arguments[] = {globalName};
        vm_oop_t self = GetSelf();

        //check if there is enough space on the stack for this unplanned Send
        //unknowGlobal: needs 2 slots, one for "this" and one for the argument
        long additionalStackSlots = 2 - GetFrame()->RemainingStackSize();
        if (additionalStackSlots > 0) {
            GetFrame()->SetBytecodeIndex(bytecodeIndexGlobal);
            //copy current frame into a bigger one and replace the current frame
            SetFrame(VMFrame::EmergencyFrameFrom(GetFrame(), additionalStackSlots));
        }

        AS_OBJ(self)->Send(unknownGlobal, arguments, 1);
    }
}
コード例 #19
0
ファイル: wren_vm.c プロジェクト: zeckalpha/wren
static void bindMethod(WrenVM* vm, int methodType, int symbol,
                       ObjClass* classObj, Value methodValue)
{
  ObjFn* methodFn = IS_FN(methodValue) ? AS_FN(methodValue)
                                       : AS_CLOSURE(methodValue)->fn;

  // Methods are always bound against the class, and not the metaclass, even
  // for static methods, so that constructors (which are static) get bound like
  // instance methods.
  wrenBindMethodCode(classObj, methodFn);

  Method method;
  method.type = METHOD_BLOCK;
  method.fn.obj = AS_OBJ(methodValue);

  if (methodType == CODE_METHOD_STATIC)
  {
    classObj = classObj->obj.classObj;
  }

  wrenBindMethod(vm, classObj, symbol, method);
}
コード例 #20
0
ファイル: Interpreter.cpp プロジェクト: jdegeete/SOMpp
void Interpreter::doReturnNonLocal() {
    vm_oop_t result = GetFrame()->Pop();

    VMFrame* context = GetFrame()->GetOuterContext();

    if (!context->HasPreviousFrame()) {
        VMBlock* block = static_cast<VMBlock*>(GetFrame()->GetArgument(0, 0));
        VMFrame* prevFrame = GetFrame()->GetPreviousFrame();
        VMFrame* outerContext = prevFrame->GetOuterContext();
        vm_oop_t sender = outerContext->GetArgument(0, 0);
        vm_oop_t arguments[] = {block};

        popFrame();
        
        // Pop old arguments from stack
        VMMethod* method = GetFrame()->GetMethod();
        long numberOfArgs = method->GetNumberOfArguments();
        for (long i = 0; i < numberOfArgs; ++i)
            GetFrame()->Pop();

        // check if current frame is big enough for this unplanned send
        // #escapedBlock: needs 2 slots, one for self, and one for the block
        long additionalStackSlots = 2 - GetFrame()->RemainingStackSize();
        if (additionalStackSlots > 0) {
            GetFrame()->SetBytecodeIndex(bytecodeIndexGlobal);
            // copy current frame into a bigger one, and replace it
            SetFrame(VMFrame::EmergencyFrameFrom(GetFrame(), additionalStackSlots));
        }

        AS_OBJ(sender)->Send(escapedBlock, arguments, 1);
        return;
    }

    while (GetFrame() != context) popFrame();

    popFrameAndPushResult(result);
}
コード例 #21
0
ファイル: ffi.c プロジェクト: FeepingCreature/jerboa
static void ffi_ptr_index_assign_fn(VMState *state, CallInfo *info) {
  VM_ASSERT(info->args_len == 2, "wrong arity: expected 2, 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, "invalid pointer index write on non-pointer object");
  PointerObject *thisptr_obj = (PointerObject*) thisptr;

  Object *ffi_type_obj = AS_OBJ(OBJECT_LOOKUP(thisptr, target_type));
  VM_ASSERT(ffi_type_obj, "cannot assign index on untyped pointer!");

  Value offs_val = load_arg(state->frame, INFO_ARGS_PTR(info)[0]);
  VM_ASSERT(IS_INT(offs_val), "offset must be integer");
  int offs = AS_INT(offs_val);

  Value sizeof_val = OBJECT_LOOKUP(ffi_type_obj, sizeof);
  VM_ASSERT(IS_INT(sizeof_val), "internal error: sizeof wrong type or undefined");
  int elemsize = AS_INT(sizeof_val);

  char *offset_ptr = (char*) thisptr_obj->ptr + elemsize * offs;

  bool res = ffi_pointer_write(state, ffi_type_obj, (void*) offset_ptr, load_arg(state->frame, INFO_ARGS_PTR(info)[1]));
  if (!res) return;
}
コード例 #22
0
ファイル: wren_vm.c プロジェクト: zeckalpha/wren
// The main bytecode interpreter loop. This is where the magic happens. It is
// also, as you can imagine, highly performance critical. Returns `true` if the
// fiber completed without error.
static bool runInterpreter(WrenVM* vm)
{
  // Hoist these into local variables. They are accessed frequently in the loop
  // but assigned less frequently. Keeping them in locals and updating them when
  // a call frame has been pushed or popped gives a large speed boost.
  register ObjFiber* fiber = vm->fiber;
  register CallFrame* frame;
  register Value* stackStart;
  register uint8_t* ip;
  register ObjFn* fn;

  // These macros are designed to only be invoked within this function.
  #define PUSH(value)  (*fiber->stackTop++ = value)
  #define POP()        (*(--fiber->stackTop))
  #define DROP()       (fiber->stackTop--)
  #define PEEK()       (*(fiber->stackTop - 1))
  #define PEEK2()      (*(fiber->stackTop - 2))
  #define READ_BYTE()  (*ip++)
  #define READ_SHORT() (ip += 2, (ip[-2] << 8) | ip[-1])

  // Use this before a CallFrame is pushed to store the local variables back
  // into the current one.
  #define STORE_FRAME() frame->ip = ip

  // Use this after a CallFrame has been pushed or popped to refresh the local
  // variables.
  #define LOAD_FRAME()                                 \
      frame = &fiber->frames[fiber->numFrames - 1];    \
      stackStart = frame->stackStart;                  \
      ip = frame->ip;                                  \
      if (frame->fn->type == OBJ_FN)                   \
      {                                                \
        fn = (ObjFn*)frame->fn;                        \
      }                                                \
      else                                             \
      {                                                \
        fn = ((ObjClosure*)frame->fn)->fn;             \
      }

  // Terminates the current fiber with error string [error]. If another calling
  // fiber is willing to catch the error, transfers control to it, otherwise
  // exits the interpreter.
  #define RUNTIME_ERROR(error)                         \
      do {                                             \
        STORE_FRAME();                                 \
        fiber = runtimeError(vm, fiber, error);        \
        if (fiber == NULL) return false;               \
        LOAD_FRAME();                                  \
        DISPATCH();                                    \
      }                                                \
      while (false)

  #if WREN_COMPUTED_GOTO

  // Note that the order of instructions here must exacly match the Code enum
  // in wren_vm.h or horrendously bad things happen.
  static void* dispatchTable[] = {
    &&code_CONSTANT,
    &&code_NULL,
    &&code_FALSE,
    &&code_TRUE,
    &&code_LOAD_LOCAL_0,
    &&code_LOAD_LOCAL_1,
    &&code_LOAD_LOCAL_2,
    &&code_LOAD_LOCAL_3,
    &&code_LOAD_LOCAL_4,
    &&code_LOAD_LOCAL_5,
    &&code_LOAD_LOCAL_6,
    &&code_LOAD_LOCAL_7,
    &&code_LOAD_LOCAL_8,
    &&code_LOAD_LOCAL,
    &&code_STORE_LOCAL,
    &&code_LOAD_UPVALUE,
    &&code_STORE_UPVALUE,
    &&code_LOAD_GLOBAL,
    &&code_STORE_GLOBAL,
    &&code_LOAD_FIELD_THIS,
    &&code_STORE_FIELD_THIS,
    &&code_LOAD_FIELD,
    &&code_STORE_FIELD,
    &&code_POP,
    &&code_CALL_0,
    &&code_CALL_1,
    &&code_CALL_2,
    &&code_CALL_3,
    &&code_CALL_4,
    &&code_CALL_5,
    &&code_CALL_6,
    &&code_CALL_7,
    &&code_CALL_8,
    &&code_CALL_9,
    &&code_CALL_10,
    &&code_CALL_11,
    &&code_CALL_12,
    &&code_CALL_13,
    &&code_CALL_14,
    &&code_CALL_15,
    &&code_CALL_16,
    &&code_SUPER_0,
    &&code_SUPER_1,
    &&code_SUPER_2,
    &&code_SUPER_3,
    &&code_SUPER_4,
    &&code_SUPER_5,
    &&code_SUPER_6,
    &&code_SUPER_7,
    &&code_SUPER_8,
    &&code_SUPER_9,
    &&code_SUPER_10,
    &&code_SUPER_11,
    &&code_SUPER_12,
    &&code_SUPER_13,
    &&code_SUPER_14,
    &&code_SUPER_15,
    &&code_SUPER_16,
    &&code_JUMP,
    &&code_LOOP,
    &&code_JUMP_IF,
    &&code_AND,
    &&code_OR,
    &&code_IS,
    &&code_CLOSE_UPVALUE,
    &&code_RETURN,
    &&code_LIST,
    &&code_CLOSURE,
    &&code_CLASS,
    &&code_METHOD_INSTANCE,
    &&code_METHOD_STATIC,
    &&code_END
  };

  #define INTERPRET_LOOP    DISPATCH();
  #define CASE_CODE(name)   code_##name

  #if WREN_DEBUG_TRACE_INSTRUCTIONS
    // Prints the stack and instruction before each instruction is executed.
    #define DISPATCH() \
        { \
          wrenDebugPrintStack(fiber); \
          wrenDebugPrintInstruction(vm, fn, (int)(ip - fn->bytecode)); \
          instruction = *ip++; \
          goto *dispatchTable[instruction]; \
        }
  #else

    #define DISPATCH()      goto *dispatchTable[instruction = READ_BYTE()];

  #endif

  #else

  #define INTERPRET_LOOP    for (;;) switch (instruction = READ_BYTE())
  #define CASE_CODE(name)   case CODE_##name
  #define DISPATCH()        break

  #endif

  LOAD_FRAME();

  Code instruction;
  INTERPRET_LOOP
  {
    CASE_CODE(LOAD_LOCAL_0):
    CASE_CODE(LOAD_LOCAL_1):
    CASE_CODE(LOAD_LOCAL_2):
    CASE_CODE(LOAD_LOCAL_3):
    CASE_CODE(LOAD_LOCAL_4):
    CASE_CODE(LOAD_LOCAL_5):
    CASE_CODE(LOAD_LOCAL_6):
    CASE_CODE(LOAD_LOCAL_7):
    CASE_CODE(LOAD_LOCAL_8):
      PUSH(stackStart[instruction - CODE_LOAD_LOCAL_0]);
      DISPATCH();

    CASE_CODE(LOAD_LOCAL):
      PUSH(stackStart[READ_BYTE()]);
      DISPATCH();

    CASE_CODE(LOAD_FIELD_THIS):
    {
      int field = READ_BYTE();
      Value receiver = stackStart[0];
      ASSERT(IS_INSTANCE(receiver), "Receiver should be instance.");
      ObjInstance* instance = AS_INSTANCE(receiver);
      ASSERT(field < instance->obj.classObj->numFields, "Out of bounds field.");
      PUSH(instance->fields[field]);
      DISPATCH();
    }

    CASE_CODE(POP):   DROP(); DISPATCH();
    CASE_CODE(NULL):  PUSH(NULL_VAL); DISPATCH();
    CASE_CODE(FALSE): PUSH(FALSE_VAL); DISPATCH();
    CASE_CODE(TRUE):  PUSH(TRUE_VAL); DISPATCH();

    CASE_CODE(CALL_0):
    CASE_CODE(CALL_1):
    CASE_CODE(CALL_2):
    CASE_CODE(CALL_3):
    CASE_CODE(CALL_4):
    CASE_CODE(CALL_5):
    CASE_CODE(CALL_6):
    CASE_CODE(CALL_7):
    CASE_CODE(CALL_8):
    CASE_CODE(CALL_9):
    CASE_CODE(CALL_10):
    CASE_CODE(CALL_11):
    CASE_CODE(CALL_12):
    CASE_CODE(CALL_13):
    CASE_CODE(CALL_14):
    CASE_CODE(CALL_15):
    CASE_CODE(CALL_16):
    {
      // Add one for the implicit receiver argument.
      int numArgs = instruction - CODE_CALL_0 + 1;
      int symbol = READ_SHORT();

      Value receiver = *(fiber->stackTop - numArgs);
      ObjClass* classObj = wrenGetClassInline(vm, receiver);

      // If the class's method table doesn't include the symbol, bail.
      if (symbol >= classObj->methods.count)
      {
        RUNTIME_ERROR(methodNotFound(vm, classObj, symbol));
      }

      Method* method = &classObj->methods.data[symbol];
      switch (method->type)
      {
        case METHOD_PRIMITIVE:
        {
          Value* args = fiber->stackTop - numArgs;

          // After calling this, the result will be in the first arg slot.
          switch (method->fn.primitive(vm, fiber, args))
          {
            case PRIM_VALUE:
              // The result is now in the first arg slot. Discard the other
              // stack slots.
              fiber->stackTop -= numArgs - 1;
              break;

            case PRIM_ERROR:
              RUNTIME_ERROR(AS_STRING(args[0]));

            case PRIM_CALL:
              STORE_FRAME();
              callFunction(fiber, AS_OBJ(args[0]), numArgs);
              LOAD_FRAME();
              break;

            case PRIM_RUN_FIBER:
              STORE_FRAME();
              fiber = AS_FIBER(args[0]);
              LOAD_FRAME();
              break;
          }
          break;
        }

        case METHOD_FOREIGN:
          callForeign(vm, fiber, method->fn.foreign, numArgs);
          break;

        case METHOD_BLOCK:
          STORE_FRAME();
          callFunction(fiber, method->fn.obj, numArgs);
          LOAD_FRAME();
          break;

        case METHOD_NONE:
          RUNTIME_ERROR(methodNotFound(vm, classObj, symbol));
          break;
      }
      DISPATCH();
    }

    CASE_CODE(STORE_LOCAL):
      stackStart[READ_BYTE()] = PEEK();
      DISPATCH();

    CASE_CODE(CONSTANT):
      PUSH(fn->constants[READ_SHORT()]);
      DISPATCH();

    CASE_CODE(SUPER_0):
    CASE_CODE(SUPER_1):
    CASE_CODE(SUPER_2):
    CASE_CODE(SUPER_3):
    CASE_CODE(SUPER_4):
    CASE_CODE(SUPER_5):
    CASE_CODE(SUPER_6):
    CASE_CODE(SUPER_7):
    CASE_CODE(SUPER_8):
    CASE_CODE(SUPER_9):
    CASE_CODE(SUPER_10):
    CASE_CODE(SUPER_11):
    CASE_CODE(SUPER_12):
    CASE_CODE(SUPER_13):
    CASE_CODE(SUPER_14):
    CASE_CODE(SUPER_15):
    CASE_CODE(SUPER_16):
    {
      // TODO: Almost completely copied from CALL. Unify somehow.

      // Add one for the implicit receiver argument.
      int numArgs = instruction - CODE_SUPER_0 + 1;
      int symbol = READ_SHORT();

      Value receiver = *(fiber->stackTop - numArgs);
      ObjClass* classObj = wrenGetClassInline(vm, receiver);

      // Ignore methods defined on the receiver's immediate class.
      classObj = classObj->superclass;

      // If the class's method table doesn't include the symbol, bail.
      if (symbol >= classObj->methods.count)
      {
        RUNTIME_ERROR(methodNotFound(vm, classObj, symbol));
      }

      Method* method = &classObj->methods.data[symbol];
      switch (method->type)
      {
        case METHOD_PRIMITIVE:
        {
          Value* args = fiber->stackTop - numArgs;

          // After calling this, the result will be in the first arg slot.
          switch (method->fn.primitive(vm, fiber, args))
          {
            case PRIM_VALUE:
              // The result is now in the first arg slot. Discard the other
              // stack slots.
              fiber->stackTop -= numArgs - 1;
              break;

            case PRIM_ERROR:
              RUNTIME_ERROR(AS_STRING(args[0]));

            case PRIM_CALL:
              STORE_FRAME();
              callFunction(fiber, AS_OBJ(args[0]), numArgs);
              LOAD_FRAME();
              break;

            case PRIM_RUN_FIBER:
              STORE_FRAME();
              fiber = AS_FIBER(args[0]);
              LOAD_FRAME();
              break;
          }
          break;
        }

        case METHOD_FOREIGN:
          callForeign(vm, fiber, method->fn.foreign, numArgs);
          break;

        case METHOD_BLOCK:
          STORE_FRAME();
          callFunction(fiber, method->fn.obj, numArgs);
          LOAD_FRAME();
          break;

        case METHOD_NONE:
          RUNTIME_ERROR(methodNotFound(vm, classObj, symbol));
          break;
      }
      DISPATCH();
    }

    CASE_CODE(LOAD_UPVALUE):
    {
      Upvalue** upvalues = ((ObjClosure*)frame->fn)->upvalues;
      PUSH(*upvalues[READ_BYTE()]->value);
      DISPATCH();
    }

    CASE_CODE(STORE_UPVALUE):
    {
      Upvalue** upvalues = ((ObjClosure*)frame->fn)->upvalues;
      *upvalues[READ_BYTE()]->value = PEEK();
      DISPATCH();
    }

    CASE_CODE(LOAD_GLOBAL):
      PUSH(vm->globals.data[READ_SHORT()]);
      DISPATCH();

    CASE_CODE(STORE_GLOBAL):
      vm->globals.data[READ_SHORT()] = PEEK();
      DISPATCH();

    CASE_CODE(STORE_FIELD_THIS):
    {
      int field = READ_BYTE();
      Value receiver = stackStart[0];
      ASSERT(IS_INSTANCE(receiver), "Receiver should be instance.");
      ObjInstance* instance = AS_INSTANCE(receiver);
      ASSERT(field < instance->obj.classObj->numFields, "Out of bounds field.");
      instance->fields[field] = PEEK();
      DISPATCH();
    }

    CASE_CODE(LOAD_FIELD):
    {
      int field = READ_BYTE();
      Value receiver = POP();
      ASSERT(IS_INSTANCE(receiver), "Receiver should be instance.");
      ObjInstance* instance = AS_INSTANCE(receiver);
      ASSERT(field < instance->obj.classObj->numFields, "Out of bounds field.");
      PUSH(instance->fields[field]);
      DISPATCH();
    }

    CASE_CODE(STORE_FIELD):
    {
      int field = READ_BYTE();
      Value receiver = POP();
      ASSERT(IS_INSTANCE(receiver), "Receiver should be instance.");
      ObjInstance* instance = AS_INSTANCE(receiver);
      ASSERT(field < instance->obj.classObj->numFields, "Out of bounds field.");
      instance->fields[field] = PEEK();
      DISPATCH();
    }

    CASE_CODE(JUMP):
    {
      int offset = READ_SHORT();
      ip += offset;
      DISPATCH();
    }

    CASE_CODE(LOOP):
    {
      // Jump back to the top of the loop.
      int offset = READ_SHORT();
      ip -= offset;
      DISPATCH();
    }

    CASE_CODE(JUMP_IF):
    {
      int offset = READ_SHORT();
      Value condition = POP();

      if (IS_FALSE(condition) || IS_NULL(condition)) ip += offset;
      DISPATCH();
    }

    CASE_CODE(AND):
    {
      int offset = READ_SHORT();
      Value condition = PEEK();

      if (IS_FALSE(condition) || IS_NULL(condition))
      {
        // Short-circuit the right hand side.
        ip += offset;
      }
      else
      {
        // Discard the condition and evaluate the right hand side.
        DROP();
      }
      DISPATCH();
    }

    CASE_CODE(OR):
    {
      int offset = READ_SHORT();
      Value condition = PEEK();

      if (IS_FALSE(condition) || IS_NULL(condition))
      {
        // Discard the condition and evaluate the right hand side.
        DROP();
      }
      else
      {
        // Short-circuit the right hand side.
        ip += offset;
      }
      DISPATCH();
    }

    CASE_CODE(IS):
    {
      Value expected = POP();
      if (!IS_CLASS(expected))
      {
        const char* message = "Right operand must be a class.";
        RUNTIME_ERROR(AS_STRING(wrenNewString(vm, message, strlen(message))));
      }

      ObjClass* actual = wrenGetClass(vm, POP());
      bool isInstance = false;

      // Walk the superclass chain looking for the class.
      while (actual != NULL)
      {
        if (actual == AS_CLASS(expected))
        {
          isInstance = true;
          break;
        }
        actual = actual->superclass;
      }
      PUSH(BOOL_VAL(isInstance));
      DISPATCH();
    }

    CASE_CODE(CLOSE_UPVALUE):
      closeUpvalue(fiber);
      DROP();
      DISPATCH();

    CASE_CODE(RETURN):
    {
      Value result = POP();
      fiber->numFrames--;

      // Close any upvalues still in scope.
      Value* firstValue = stackStart;
      while (fiber->openUpvalues != NULL &&
             fiber->openUpvalues->value >= firstValue)
      {
        closeUpvalue(fiber);
      }

      // If the fiber is complete, end it.
      if (fiber->numFrames == 0)
      {
        // If this is the main fiber, we're done.
        if (fiber->caller == NULL) return true;

        // We have a calling fiber to resume.
        fiber = fiber->caller;

        // Store the result in the resuming fiber.
        *(fiber->stackTop - 1) = result;
      }
      else
      {
        // Store the result of the block in the first slot, which is where the
        // caller expects it.
        stackStart[0] = result;

        // Discard the stack slots for the call frame (leaving one slot for the
        // result).
        fiber->stackTop = frame->stackStart + 1;
      }

      LOAD_FRAME();
      DISPATCH();
    }

    CASE_CODE(LIST):
    {
      int numElements = READ_BYTE();
      ObjList* list = wrenNewList(vm, numElements);
      // TODO: Do a straight memcopy.
      for (int i = 0; i < numElements; i++)
      {
        list->elements[i] = *(fiber->stackTop - numElements + i);
      }

      // Discard the elements.
      fiber->stackTop -= numElements;

      PUSH(OBJ_VAL(list));
      DISPATCH();
    }

    CASE_CODE(CLOSURE):
    {
      ObjFn* prototype = AS_FN(fn->constants[READ_SHORT()]);

      ASSERT(prototype->numUpvalues > 0,
             "Should not create closure for functions that don't need it.");

      // Create the closure and push it on the stack before creating upvalues
      // so that it doesn't get collected.
      ObjClosure* closure = wrenNewClosure(vm, prototype);
      PUSH(OBJ_VAL(closure));

      // Capture upvalues.
      for (int i = 0; i < prototype->numUpvalues; i++)
      {
        bool isLocal = READ_BYTE();
        int index = READ_BYTE();
        if (isLocal)
        {
          // Make an new upvalue to close over the parent's local variable.
          closure->upvalues[i] = captureUpvalue(vm, fiber,
                                                frame->stackStart + index);
        }
        else
        {
          // Use the same upvalue as the current call frame.
          closure->upvalues[i] = ((ObjClosure*)frame->fn)->upvalues[index];
        }
      }

      DISPATCH();
    }

    CASE_CODE(CLASS):
    {
      ObjString* name = AS_STRING(PEEK2());

      ObjClass* superclass;
      if (IS_NULL(PEEK()))
      {
        // Implicit Object superclass.
        superclass = vm->objectClass;
      }
      else
      {
        // TODO: Handle the superclass not being a class object!
        superclass = AS_CLASS(PEEK());
      }

      int numFields = READ_BYTE();

      ObjClass* classObj = wrenNewClass(vm, superclass, numFields, name);

      // Don't pop the superclass and name off the stack until the subclass is
      // done being created, to make sure it doesn't get collected.
      DROP();
      DROP();

      // Now that we know the total number of fields, make sure we don't
      // overflow.
      if (superclass->numFields + numFields > MAX_FIELDS)
      {
        char message[70 + MAX_VARIABLE_NAME];
        snprintf(message, 70 + MAX_VARIABLE_NAME,
            "Class '%s' may not have more than %d fields, including inherited "
            "ones.", name->value, MAX_FIELDS);

        RUNTIME_ERROR(AS_STRING(wrenNewString(vm, message, strlen(message))));
      }

      PUSH(OBJ_VAL(classObj));
      DISPATCH();
    }

    CASE_CODE(METHOD_INSTANCE):
    CASE_CODE(METHOD_STATIC):
    {
      int type = instruction;
      int symbol = READ_SHORT();
      ObjClass* classObj = AS_CLASS(PEEK());
      Value method = PEEK2();
      bindMethod(vm, type, symbol, classObj, method);
      DROP();
      DROP();
      DISPATCH();
    }

    CASE_CODE(END):
      // A CODE_END should always be preceded by a CODE_RETURN. If we get here,
      // the compiler generated wrong code.
      UNREACHABLE();
  }

  // We should only exit this function from an explicit return from CODE_RETURN
  // or a runtime error.
  UNREACHABLE();
  return false;
}

WrenInterpretResult wrenInterpret(WrenVM* vm, const char* sourcePath,
                                  const char* source)
{
  // TODO: Check for freed VM.
  ObjFn* fn = wrenCompile(vm, sourcePath, source);
  if (fn == NULL) return WREN_RESULT_COMPILE_ERROR;

  WREN_PIN(vm, fn);
  vm->fiber = wrenNewFiber(vm, (Obj*)fn);
  WREN_UNPIN(vm);

  if (runInterpreter(vm))
  {
    return WREN_RESULT_SUCCESS;
  }
  else
  {
    return WREN_RESULT_RUNTIME_ERROR;
  }
}
コード例 #23
0
ファイル: wren_value.c プロジェクト: Zhangli88/wren
void wrenMarkValue(WrenVM* vm, Value value)
{
  if (!IS_OBJ(value)) return;
  wrenMarkObj(vm, AS_OBJ(value));
}