static VMFnWrap instrAssignStringKey(VMState *state) { const auto *instruction = (Instruction::AssignStringKey *)state->m_instr; const Slot objectSlot = instruction->m_objectSlot; const Slot valueSlot = instruction->m_valueSlot; VM_ASSERTION(objectSlot < state->m_cf->m_count, "slot addressing error"); VM_ASSERTION(valueSlot < state->m_cf->m_count, "slot addressing error"); Object *object = state->m_cf->m_slots[objectSlot]; Object *valueObject = state->m_cf->m_slots[valueSlot]; const char *key = instruction->m_key; AssignType assignType = instruction->m_assignType; switch (assignType) { case kAssignPlain: { Object::setNormal(state->m_restState, object, key, valueObject); break; } case kAssignExisting: { const char *error = Object::setExisting(state->m_restState, object, key, valueObject); VM_ASSERTION(!error, "%s for '%s'", error, key); break; } case kAssignShadowing: { bool keySet = false; const char *error = Object::setShadowing(state->m_restState, object, key, valueObject, &keySet); VM_ASSERTION(!error, "%s for '%s'", error, key); VM_ASSERTION(keySet, "key '%s' not found in object", key); break; } } state->m_instr = (Instruction *)(instruction + 1); return { instrFunctions[state->m_instr->m_type] }; }
static VMFnWrap instrCloseObject(VMState *state) { const auto *instruction = (Instruction::CloseObject *)state->m_instr; const Slot slot = instruction->m_slot; VM_ASSERTION(slot < state->m_cf->m_count, "slot addressing error"); Object *object = state->m_cf->m_slots[slot]; VM_ASSERTION(!(object->m_flags & kClosed), "object is already closed"); object->m_flags |= kClosed; state->m_instr = (Instruction *)(instruction + 1); return { instrFunctions[state->m_instr->m_type] }; }
static VMFnWrap instrCall(VMState *state) { const auto *instruction = (Instruction::Call *)state->m_instr; const Slot functionSlot = instruction->m_functionSlot; const Slot thisSlot = instruction->m_thisSlot; const size_t argsLength = instruction->m_count; VM_ASSERTION(functionSlot < state->m_cf->m_count, "slot addressing error"); VM_ASSERTION(thisSlot < state->m_cf->m_count, "slot addressing error"); Object *thisObject_ = state->m_cf->m_slots[thisSlot]; Object *functionObject_ = state->m_cf->m_slots[functionSlot]; Object **arguments = nullptr; if (argsLength < 10) { arguments = state->m_restState->m_shared->m_valueCache.m_preallocatedArguments[argsLength]; } else { arguments = (Object **)Memory::allocate(sizeof(Object *) * argsLength); } for (size_t i = 0; i < argsLength; i++) { const Slot argumentSlot = instruction->m_arguments[i]; VM_ASSERTION(argumentSlot < state->m_cf->m_count, "slot addressing error"); arguments[i] = state->m_cf->m_slots[argumentSlot]; } CallFrame *oldCallFrame = state->m_restState->m_frame; // TODO: verify if any callable needs to access cf->m_instr state->m_cf->m_instructions = state->m_instr; if (!VM::callCallable(state->m_restState, thisObject_, functionObject_, arguments, argsLength)) { return { instrHalt }; } if (state->m_restState->m_runState == kErrored) { if (argsLength >= 10) { Memory::free(arguments); } return { instrHalt }; } // Step over the call in the old stack frame oldCallFrame->m_instructions = (Instruction *)(instruction + 1); if (argsLength >= 10) { Memory::free(arguments); } state->m_cf = state->m_restState->m_frame; state->m_instr = state->m_cf->m_instructions; return { instrFunctions[state->m_instr->m_type] }; }
static VMFnWrap instrFreeze(VMState *state) { const auto *instruction = (Instruction::Freeze *)state->m_instr; const Slot slot = instruction->m_slot; VM_ASSERTION(slot < state->m_cf->m_count, "slot addressing error"); Object *object = state->m_cf->m_slots[slot]; VM_ASSERTION(!(object->m_flags & kImmutable), "object is already frozen"); object->m_flags |= kImmutable; state->m_instr = (Instruction *)(instruction + 1); return { instrFunctions[state->m_instr->m_type] }; }
static VMFnWrap instrNewClosureObject(VMState *state) { const auto *instruction = (Instruction::NewClosureObject *)state->m_instr; const Slot targetSlot = instruction->m_targetSlot; const Slot contextSlot = instruction->m_contextSlot; VM_ASSERTION(targetSlot < state->m_cf->m_count, "slot addressing error"); VM_ASSERTION(contextSlot < state->m_cf->m_count, "slot addressing error"); Object *context = state->m_cf->m_slots[contextSlot]; state->m_cf->m_slots[targetSlot] = Object::newClosure(state->m_restState, context, instruction->m_function); state->m_instr = (Instruction *)(instruction + 1); return { instrFunctions[state->m_instr->m_type] }; }
static VMFnWrap instrWriteFastSlot(VMState *state) { const auto *instruction = (Instruction::WriteFastSlot *)state->m_instr; const Slot targetSlot = instruction->m_targetSlot; const Slot sourceSlot = instruction->m_sourceSlot; VM_ASSERTION(targetSlot < state->m_cf->m_fastSlotsCount, "fast slot addressing error"); VM_ASSERTION(sourceSlot < state->m_cf->m_count, "slot addressing error"); *state->m_cf->m_fastSlots[targetSlot] = state->m_cf->m_slots[sourceSlot]; state->m_instr = (Instruction *)(instruction + 1); return { instrFunctions[state->m_instr->m_type] }; }
static VMFnWrap instrCall(VMState *state) { const auto *instruction = (Instruction::Call *)state->m_instr; const Slot functionSlot = instruction->m_functionSlot; const Slot thisSlot = instruction->m_thisSlot; const size_t argsLength = instruction->m_count; VM_ASSERTION(functionSlot < state->m_cf->m_count, "slot addressing error"); VM_ASSERTION(thisSlot < state->m_cf->m_count, "slot addressing error"); Object *thisObject_ = state->m_slots[thisSlot]; Object *functionObject_ = state->m_slots[functionSlot]; Object **arguments = nullptr; if (argsLength < 10) { arguments = state->m_restState->m_shared->m_valueCache.m_preallocatedArguments[argsLength]; } else { arguments = (Object **)Memory::allocate(sizeof(Object *) * argsLength); } for (size_t i = 0; i < argsLength; i++) { const Slot argumentSlot = ((Slot *)(instruction + 1))[i]; VM_ASSERTION(argumentSlot < state->m_cf->m_count, "slot addressing error"); arguments[i] = state->m_slots[argumentSlot]; } state->m_instr = (Instruction *)((Slot *)(instruction + 1) + instruction->m_count); state->m_cf->m_instructions = state->m_instr; if (!VM::callCallable(state->m_restState, thisObject_, functionObject_, arguments, argsLength)) { return { instrHalt }; } if (state->m_restState->m_runState == kErrored) { if (argsLength >= 10) { Memory::free(arguments); } return { instrHalt }; } if (argsLength >= 10) { Memory::free(arguments); } VMState::refresh(state); return { instrFunctions[state->m_instr->m_type] }; }
static VMFnWrap instrNewObject(VMState *state) { const auto *instruction = (Instruction::NewObject *)state->m_instr; const Slot targetSlot = instruction->m_targetSlot; const Slot parentSlot = instruction->m_parentSlot; VM_ASSERTION(targetSlot < state->m_cf->m_count, "slot addressing error"); VM_ASSERTION(parentSlot < state->m_cf->m_count, "slot addressing error"); Object *parentObject = state->m_cf->m_slots[parentSlot]; if (parentObject) { VM_ASSERTION(!(parentObject->m_flags & kNoInherit), "cannot inherit from this object"); } state->m_cf->m_slots[targetSlot] = Object::newObject(state->m_restState, parentObject); state->m_instr = (Instruction *)(instruction + 1); return { instrFunctions[state->m_instr->m_type] }; }
static VMFnWrap instrTestBranch(VMState *state) { const auto *instruction = (Instruction::TestBranch *)state->m_instr; const Slot testSlot = instruction->m_testSlot; const size_t trueBlock = instruction->m_trueBlock; const size_t falseBlock = instruction->m_falseBlock; VM_ASSERTION(testSlot < state->m_cf->m_count, "slot addressing error"); Object *testObject = state->m_cf->m_slots[testSlot]; Object *boolBase = state->m_restState->m_shared->m_valueCache.m_boolBase; Object *intBase = state->m_restState->m_shared->m_valueCache.m_intBase; Object *boolObject = Object::instanceOf(testObject, boolBase); Object *intObject = Object::instanceOf(testObject, intBase); bool test = false; if (boolObject) { if (((BoolObject *)boolObject)->m_value) { test = true; } } else if (intObject) { if (((IntObject *)intObject)->m_value != 0) { test = true; } } else { test = !!testObject; } const size_t targetBlock = test ? trueBlock : falseBlock; state->m_instr = (Instruction *)((unsigned char *)state->m_cf->m_function->m_body.m_instructions + state->m_cf->m_function->m_body.m_blocks[targetBlock].m_offset); return { instrFunctions[state->m_instr->m_type] }; }
static VMFnWrap instrSetConstraintStringKey(VMState *state) { const auto *instruction = (Instruction::SetConstraintStringKey *)state->m_instr; const Slot objectSlot = instruction->m_objectSlot; const Slot constraintSlot = instruction->m_constraintSlot; VM_ASSERTION(objectSlot < state->m_cf->m_count, "slot addressing error"); VM_ASSERTION(constraintSlot < state->m_cf->m_count, "slot addressing error"); Object *object = state->m_cf->m_slots[objectSlot]; Object *constraint = state->m_cf->m_slots[constraintSlot]; const char *error = Object::setConstraint(state->m_restState, object, instruction->m_key, instruction->m_keyLength, constraint); VM_ASSERTION(!error, error); state->m_instr = (Instruction *)(instruction + 1); return { instrFunctions[state->m_instr->m_type] }; }
static VMFnWrap instrBranch(VMState *state) { const auto *instruction = (Instruction::Branch *)state->m_instr; const size_t block = instruction->m_block; VM_ASSERTION(block < state->m_cf->m_function->m_body.m_count, "block addressing error"); state->m_instr = (Instruction *)((unsigned char *)state->m_cf->m_function->m_body.m_instructions + state->m_cf->m_function->m_body.m_blocks[block].m_offset); return { instrFunctions[state->m_instr->m_type] }; }
static VMFnWrap instrAccessStringKey(VMState *state) { const auto *instruction = (Instruction::AccessStringKey *)state->m_instr; const Slot objectSlot = instruction->m_objectSlot; const Slot targetSlot = instruction->m_targetSlot; VM_ASSERTION(objectSlot < state->m_cf->m_count, "slot addressing error"); VM_ASSERTION(targetSlot < state->m_cf->m_count, "slot addressing error"); Object *object = state->m_cf->m_slots[objectSlot]; const char *key = instruction->m_key; bool objectFound = false; state->m_cf->m_slots[targetSlot] = Object::lookup(object, key, &objectFound); if (!objectFound) { Object *indexOperation = Object::lookup(object, "[]", nullptr); if (indexOperation) { Object *keyObject = Object::newString(state->m_restState, instruction->m_key, strlen(instruction->m_key)); State subState = { }; subState.m_parent = state->m_restState; subState.m_root = state->m_root; subState.m_shared = state->m_restState->m_shared; if (!VM::callCallable(&subState, object, indexOperation, &keyObject, 1)) { return { instrHalt }; } VM::run(&subState); VM_ASSERTION(subState.m_runState != kErrored, "[] overload failed: %s\n", subState.m_error.c_str()); state->m_cf->m_slots[targetSlot] = subState.m_resultValue; objectFound = true; } } if (!objectFound) { VM_ASSERTION(false, "property not found: '%s'", key); } state->m_instr = (Instruction *)(instruction + 1); return { instrFunctions[state->m_instr->m_type] }; }
static VMFnWrap instrSaveResult(VMState *state) { const auto *instruction = (Instruction::SaveResult *)state->m_instr; const Slot saveSlot = instruction->m_targetSlot; VM_ASSERTION(saveSlot < state->m_cf->m_count, "slot addressing error"); state->m_cf->m_slots[saveSlot] = state->m_restState->m_resultValue; state->m_restState->m_resultValue = nullptr; state->m_instr = (Instruction *)(instruction + 1); return { instrFunctions[state->m_instr->m_type] }; }
static VMFnWrap instrAssign(VMState *state) { const auto *instruction = (Instruction::Assign *)state->m_instr; const Slot objectSlot = instruction->m_objectSlot; const Slot valueSlot = instruction->m_valueSlot; const Slot keySlot = instruction->m_keySlot; VM_ASSERTION(objectSlot < state->m_cf->m_count, "slot addressing error"); VM_ASSERTION(valueSlot < state->m_cf->m_count, "slot addressing error"); VM_ASSERTION(keySlot < state->m_cf->m_count, "slot addressing error"); VM_ASSERTION(state->m_cf->m_slots[keySlot], "null key slot"); Object *object = state->m_cf->m_slots[objectSlot]; Object *valueObject = state->m_cf->m_slots[valueSlot]; Object *stringBase = state->m_restState->m_shared->m_valueCache.m_stringBase; Object *keyObject = state->m_cf->m_slots[keySlot]; StringObject *stringKey = (StringObject *)Object::instanceOf(keyObject, stringBase); if (!stringKey) { Object *indexAssignOperation = Object::lookup(object, "[]=", nullptr); if (indexAssignOperation) { Object *keyValuePair[] = { state->m_cf->m_slots[instruction->m_keySlot], valueObject }; if (!VM::callCallable(state->m_restState, object, indexAssignOperation, keyValuePair, 2)) { return { instrHalt }; } state->m_instr = (Instruction *)(instruction + 1); return { instrFunctions[state->m_instr->m_type] }; } VM_ASSERTION(false, "key is not string"); } char *key = stringKey->m_value; GC::addPermanent(state->m_restState, keyObject); const AssignType assignType = instruction->m_assignType; switch (assignType) { case kAssignPlain: { Object::setNormal(state->m_restState, object, key, valueObject); break; } case kAssignExisting: { const char *error = Object::setExisting(state->m_restState, object, key, valueObject); VM_ASSERTION(!error, "%s for '%s'", error, key); break; } case kAssignShadowing: { bool keySet = false; const char *error = Object::setShadowing(state->m_restState, object, key, valueObject, &keySet); VM_ASSERTION(!error, "%s for '%s'", error, key); VM_ASSERTION(keySet, "key '%s' not found in object", key); break; } } state->m_instr = (Instruction *)(instruction + 1); return { instrFunctions[state->m_instr->m_type] }; }
static VMFnWrap instrDefineFastSlot(VMState *state) { const auto *instruction = (Instruction::DefineFastSlot *)state->m_instr; const Slot targetSlot = instruction->m_targetSlot; const Slot objectSlot = instruction->m_objectSlot; VM_ASSERTION(objectSlot < state->m_cf->m_count, "slot addressing error"); Object *object = state->m_cf->m_slots[objectSlot]; Object **target = Object::lookupReferenceWithHash(object, instruction->m_key, instruction->m_keyLength, instruction->m_keyHash); VM_ASSERTION(target, "key not in object"); state->m_cf->m_fastSlots[targetSlot] = target; state->m_instr = (Instruction *)(instruction + 1); return { instrFunctions[state->m_instr->m_type] }; }
static VMFnWrap instrNewArrayObject(VMState *state) { const auto *instruction = (Instruction::NewArrayObject *)state->m_instr; const Slot targetSlot = instruction->m_targetSlot; VM_ASSERTION(targetSlot < state->m_cf->m_count, "slot addressing error"); auto *array = Object::newArray(state->m_restState, nullptr, (IntObject *)state->m_restState->m_shared->m_valueCache.m_intZero); state->m_cf->m_slots[targetSlot] = array; state->m_instr = (Instruction *)(instruction + 1); return { instrFunctions[state->m_instr->m_type] }; }
static VMFnWrap instrSetConstraint(VMState *state) { const auto *instruction = (Instruction::SetConstraint *)state->m_instr; const Slot keySlot = instruction->m_keySlot; const Slot objectSlot = instruction->m_objectSlot; const Slot constraintSlot = instruction->m_constraintSlot; VM_ASSERTION(keySlot < state->m_cf->m_count, "slot addressing error"); VM_ASSERTION(objectSlot < state->m_cf->m_count, "slot addressing error"); VM_ASSERTION(constraintSlot < state->m_cf->m_count, "slot addressing error"); Object *object = state->m_cf->m_slots[objectSlot]; Object *constraint = state->m_cf->m_slots[constraintSlot]; Object *stringBase = state->m_restState->m_shared->m_valueCache.m_stringBase; Object *keyObject = state->m_cf->m_slots[keySlot]; StringObject *stringKey = (StringObject *)Object::instanceOf(keyObject, stringBase); VM_ASSERTION(stringKey, "internal error"); const char *key = stringKey->m_value; const char *error = Object::setConstraint(state->m_restState, object, key, strlen(key), constraint); VM_ASSERTION(!error, "failed setting type constraint: %s", error); state->m_instr = (Instruction *)(instruction + 1); return { instrFunctions[state->m_instr->m_type] }; }
static VMFnWrap instrNewStringObject(VMState *state) { auto *instruction = (Instruction::NewStringObject *)state->m_instr; const Slot targetSlot = instruction->m_targetSlot; const char *value = instruction->m_value; VM_ASSERTION(targetSlot < state->m_cf->m_count, "slot addressing error"); if (U_UNLIKELY(!instruction->m_stringObject)) { Object *object = Object::newString(state->m_restState, value, strlen(value)); instruction->m_stringObject = object; GC::addPermanent(state->m_restState, object); } state->m_cf->m_slots[targetSlot] = instruction->m_stringObject; state->m_instr = (Instruction *)(instruction + 1); return { instrFunctions[state->m_instr->m_type] }; }
static VMFnWrap instrReturn(VMState *state) { const auto *instruction = (Instruction::Return *)state->m_instr; const Slot returnSlot = instruction->m_returnSlot; VM_ASSERTION(returnSlot < state->m_cf->m_count, "slot addressing error"); Object *result = state->m_cf->m_slots[returnSlot]; GC::delRoots(state->m_restState, &state->m_cf->m_root); VM::delFrame(state->m_restState); state->m_restState->m_resultValue = result; if (!state->m_restState->m_frame) { return { instrHalt }; } state->m_cf = state->m_restState->m_frame; state->m_instr = state->m_cf->m_instructions; return { instrFunctions[state->m_instr->m_type] }; }
static VMFnWrap instrAccess(VMState *state) { const auto *instruction = (Instruction::Access *)state->m_instr; const Slot objectSlot = instruction->m_objectSlot; const Slot targetSlot = instruction->m_targetSlot; const Slot keySlot = instruction->m_keySlot; VM_ASSERTION(objectSlot < state->m_cf->m_count, "slot addressing error"); VM_ASSERTION(targetSlot < state->m_cf->m_count, "slot addressing error"); VM_ASSERTION(keySlot < state->m_cf->m_count, "slot addressing error"); VM_ASSERTION(state->m_cf->m_slots[keySlot], "null key slot"); char *key = nullptr; bool hasKey = false; Object *object = state->m_cf->m_slots[objectSlot]; Object *stringBase = state->m_restState->m_shared->m_valueCache.m_stringBase; Object *keyObject = state->m_cf->m_slots[keySlot]; auto *stringKey = (StringObject *)Object::instanceOf(keyObject, stringBase); bool objectFound = false; if (stringKey) { GC::addPermanent(state->m_restState, keyObject); key = stringKey->m_value; state->m_cf->m_slots[targetSlot] = Object::lookup(object, key, &objectFound); } if (!objectFound) { Object *indexOperation = Object::lookup(object, "[]", nullptr); if (indexOperation) { Object *keyObject = state->m_cf->m_slots[keySlot]; State subState = { }; subState.m_parent = state->m_restState; subState.m_root = state->m_root; subState.m_shared = state->m_restState->m_shared; if (!VM::callCallable(&subState, object, indexOperation, &keyObject, 1)) { return { instrHalt }; } VM::run(&subState); VM_ASSERTION(subState.m_runState != kErrored, "[] overload failed: %s\n", subState.m_error.c_str()); state->m_cf->m_slots[targetSlot] = subState.m_resultValue; objectFound = true; } } if (!objectFound) { if (hasKey) { VM_ASSERTION(false, "property not found: '%s'", key); } else { VM_ASSERTION(false, "property not found"); } } state->m_instr = (Instruction *)(instruction + 1); return { instrFunctions[state->m_instr->m_type] }; }