源链接:https://www.axa6.com/zh/an-excellent-virtual-machine-memory-architecture

简介

虚拟机内存架构直接影响虚拟机的性能和占用。设计一个优秀的架构可以有效提升性能和效率。

本文将介绍AQ虚拟机使用的内存架构,以及AQ虚拟机内存的详细标准。

通过对于虚拟机内存架构的优化,有助于虚拟机运行效率减少占用。如果可以,应该尽可能地平衡两者,使虚拟机达到最佳状态。

在某些情况下,应该根据虚拟机的特殊需求进行不同的开发。

例如:在单片机内存受限情况下,需要尽可能地减少占用

而在并行计算性能敏感情况,则需要侧重于性能优化

设计思路

内存架构

基础内存架构

AQ采取了寄存器的基础内存架构,但与标准的寄存器架构有所不同,对寄存器架构进行了部分改进和优化。

此处的寄存器并非CPU中的寄存器,而是在内存中模拟出的虚拟寄存器

选择寄存器的原因

相较与JAVAPython等主流语言虚拟机采取堆栈架构不同,AQ决定采取寄存器架构的原因是性能的优化与字节码的容易理解。

虽然堆栈架构被普遍认为更容易移植和编写,但在实际的性能中会有一些损耗,对于内存的多次访问会减缓其速度,这是不可避免并且难以彻底优化的。因此,为了解决此处的性能损耗AQ采用了寄存器架构。同时,从字节码的角度上说,寄存器架构的字节码更容易理解,其指令类似于函数参数方式,而不是直接面对堆栈的众多操作。

寄存器架构的区别

标准的寄存器架构

标准的寄存器架构中,寄存器包含:

  1. 数据类型 - 寄存器将存储的数据的类型(如int、float、double等)
  2. 数据 - 寄存器将存储的数据的值
  3. (可选)标记 - 寄存器将存储的数据的标记(如变量、函数、类等)
  4. (可选)引用 - 寄存器将存储的数据的引用(如对象的地址等)

尽管不同语言的虚拟机内存架构可能有所不同,但大致都存储了这些信息。

而在AQ开发过程中曾使用了该架构,但是经过测试,其存在较大的内存占用。

以下是AQ曾使用的register.h代码:

// Copyright 2024 AQ authors, All Rights Reserved.
// This program is licensed under the AQ License. You can find the AQ license in
// the root directory. #ifndef AQ_AQVM_MEMORY_REGISTER_H_
#define AQ_AQVM_MEMORY_REGISTER_H_ #include <stdbool.h> enum AqvmMemoryRegister_ValueType {
// TODO(Register): Waiting for the improvement of the register.
AqvmMemoryRegisterValueType_INT,
AqvmMemoryRegisterValueType_CONSTINT,
AqvmMemoryRegisterValueType_FLOAT,
AqvmMemoryRegisterValueType_CONSTFLOAT,
AqvmMemoryRegisterValueType_DOUBLE,
AqvmMemoryRegisterValueType_CONSTDOUBLE,
AqvmMemoryRegisterValueType_LONG,
AqvmMemoryRegisterValueType_CONSTLONG,
AqvmMemoryRegisterValueType_CHARACTER,
AqvmMemoryRegisterValueType_CONSTCHARACTER,
AqvmMemoryRegisterValueType_BOOLEAN,
AqvmMemoryRegisterValueType_CONSTBOOLEAN
}; union AqvmMemoryRegister_Value {
// TODO(Register): Waiting for the improvement of the register.
int int_value;
const int const_int_value;
float float_value;
const float const_float_value;
double double_value;
const double const_double_value;
long long_value;
const long const_long_value;
char character_value;
const char const_character_value;
bool boolean_value;
const bool const_boolean_value;
}; struct AqvmMemoryRegister_Register {
enum AqvmMemoryRegister_ValueType type;
union AqvmMemoryRegister_Value value;
}; #endif

从上述代码可以看出,即使仅保留了必要内容,但由于enum类型的AqvmMemoryRegister_ValueType占用4字节,union类型的AqvmMemoryRegister_Value占用8字节,struct类型本身就会占用12字节内存。

同时,由于C编译器的优化,struct类型的AqvmMemoryRegister_Registerenum类型的type为与union类型的value进行内存对齐,因此加入4字节的填充内存。使struct类型的AqvmMemoryRegister_Register占用16字节。

其中如果使用int等非8字节类型,则会有4字节的填充内存被浪费,从而造成内存损耗。因此在全部的寄存器中会有4-8字节的内存浪费。

AQ的寄存器架构

为了解决传统寄存器架构的占用问题,AQ结合了JVM栈帧局部变量表特点,对内存架构进行了优化,使占用问题显著减少。

以下是备选的三种方案:

// plan 1:
struct AqvmMemoryRegister_Register{
uint8_t type;
void* value_ptr;
};
void* value;
AqvmMemoryRegister_Register array[]; // plan 2:
void* value;
// value to the memory address of index 0 is int, the index 0 to the index 1 is
// float, etc.
size_t type[]; // plan 3:
struct AqvmMemoryRegister_Register {
uint32_t* value;
size_t size;
};

由于指针占用4-8字节,数据本身占用1-8字节,加上类型1字节,因此plan 1占用6-17字节,同时可能会存在内存对齐,因此plan 1同样会造成极大的内存损失。

事实上,在要求保留内存类型信息时,内存利用率最高的是plan 2,但plan 2不能保存在同一数据结构(如:结构体)中不同类型数据的连贯性,可能会使部分指针操作失效。因此为了内存安全,不使用plan 2

在某些情况下(虚拟机指令集包括类型),plan 3也可以满足内存存储的需要,但由于精简指令集的需要,没有在指令中包含类型信息,因此无法满足虚拟机运行需要。

因此我们采取如下设计,保证对于内存利用率,同时使内存占用问题有了很大改善。

AQ内存直接使用void*指针存储数据,size_t存储占用内存大小,并且使用uint8_t数组存储类型。由于uint8_t占用8位,为减少占用,每个字节使用4位来存储类型。因此,一个uint8_t变量可以存储2个类型。每个uint8_t变量的前4位用于偶数字节的类型,后4位用于奇数字节的类型。

// The struct stores information about the memory.
// |type| is a pointer to an array that stores the type of each byte in the
// memory. Each byte uses 4 bits to store the type. So a uint8_t variable can
// store 2 types. Each uint8_t variable's first 4 bits are used for the even
// byte's type and the next 4 bits are used for the odd byte's type. The type
// list is in types.h.
// |data| is a pointer of type void* to the memory that stores the data.
// |size| is the size of the memory.
// NOTICE: The struct AqvmMemory_Memory only stores information of the memory.
// The memory is allocated by the bytecode function when storing the bytecode.
// The memory of |memory| and |type| is part of the bytecode memory.
struct AqvmMemory_Memory {
uint8_t* type;
void* data;
size_t size;
};

由于内存的原因,对于type的存取需要精确的利用。uint8_t类型需要8位,但是超过了类型的存储需要,因此4位既可以满足对于类型的存储需要,同时又可以减少内存占用。但是需要特殊的函数维持type的存取。

// Sets the type of the data at |index| bytes in |memory| to |type|. |type|
// should be less than 4 bits.
// Returns 0 if successful. Returns -1 if the memory pointer is NULL. Returns -2
// if the type pointer is NULL. Returns -3 if the index is out of range. Returns
// -4 if the type is out of range.
int AqvmMemory_SetType(const struct AqvmMemory_Memory* memory, size_t index,
uint8_t type) {
if (memory == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_SetType_NullMemoryPointer\"",
"\"The memory pointer is NULL.\"", NULL);
return -1;
}
if (memory->type == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_SetType_NullTypePointer\"",
"\"The type pointer is NULL.\"", NULL);
return -2;
}
if (index > memory->size) {
AqvmRuntimeDebugger_OutputReport(
"\"ERROR\"", "\"AqvmMemory_SetType_OutOfMemoryRange\"",
"\"The index is out of memory range.\"", NULL);
return -3;
}
if (type > 0x0F) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_SetType_OutOfTypeRange\"",
"\"The type is out of range.\"", NULL);
return -4;
} // Sets the type of the data at |index| bytes in memory.
// Since Aqvm stores type data occupying 4 bits and uint8_t occupying 8 bits,
// each uint8_t type location stores two type data. The storage locations
// (high 4 bits, low 4 bits) are set according to the parity of |index|. Even
// numbers are stored in the high bits of (|index| / 2) and odd numbers are
// stored in the low bits of (|index| / 2).
if (index % 2 != 0) {
memory->type[index / 2] = (memory->type[index / 2] & 0xF0) | type;
} else {
memory->type[index / 2] = (memory->type[index / 2] & 0x0F) | (type << 4);
} return 0;
} // Gets the type of the data at |index| bytes in |memory|.
// Returns the type that is less than 4 bits (0X0F) if successful. Returns 0x11
// if the memory pointer is NULL. Returns 0x12 if the type pointer is NULL.
// Returns 0x13 if the index is out of memory range.
uint8_t AqvmMemory_GetType(struct AqvmMemory_Memory* memory, size_t index) {
if (memory == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_GetType_NullMemoryPointer\"",
"\"The memory pointer is NULL.\"", NULL);
return 0x11;
}
if (memory->type == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_GetType_NullTypePointer\"",
"\"The type pointer is NULL.\"", NULL);
return 0x12;
}
if (index > memory->size) {
AqvmRuntimeDebugger_OutputReport(
"\"ERROR\"", "\"AqvmMemory_GetType_OutOfMemoryRange\"",
"\"The index is out of memory range.\"", NULL);
return 0x13;
} // Gets the type of the data at |index| bytes in memory.
// Since Aqvm stores type data occupying 4 bits and uint8_t occupying 8 bits,
// each uint8_t type location stores two type data. The storage locations
// (high 4 bits, low 4 bits) are set according to the parity of |index|. Even
// numbers are stored in the high bits of (|index| / 2) and odd numbers are
// stored in the low bits of (|index| / 2).
if (index % 2 != 0) {
return memory->type[index / 2] & 0x0F;
} else {
return (memory->type[index / 2] & 0xF0) >> 4;
}
}

但使用该设计对于数据的存储有较高要求,因为数据的长度不固定,因此需要专门的函数配合内存进行操作。

// Writes the data that |data_ptr| points to of size |size| to the data of at
// |index| bytes in |memory|.
// Returns 0 if successful. Returns -1 if the memory pointer is NULL. Returns -2
// if the type pointer is NULL. Returns -3 if the index is out of range. Returns
// -4 if the data pointer is NULL.
int AqvmMemory_WriteData(struct AqvmMemory_Memory* memory, size_t index,
void* data_ptr, size_t size) {
if (memory == NULL) {
AqvmRuntimeDebugger_OutputReport(
"\"ERROR\"", "\"AqvmMemory_WriteData_NullMemoryPointer\"",
"\"The memory pointer is NULL.\"", NULL);
return -1;
}
if (memory->type == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_WriteData_NullTypePointer\"",
"\"The type pointer is NULL.\"", NULL);
return -2;
}
if (index > memory->size) {
AqvmRuntimeDebugger_OutputReport(
"\"ERROR\"", "\"AqvmMemory_WriteData_OutOfMemoryRange\"",
"\"The index is out of memory range.\"", NULL);
return -3;
}
if (data_ptr == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_WriteData_NullDataPointer\"",
"\"The data pointer is NULL.\"", NULL);
return -4;
} // Since void* does not have a specific size, pointer moves need to be
// converted before moving.
memcpy((void*)((uintptr_t)memory->data + index), data_ptr, size); return 0;
}

除了减少内存使用外,避免内存的二次占用同样重要。因此我们复用字节码内存,将内存数据和类型存储在字节码的内存部分中,利用字节码文件中预先分配的内存(字节码文件中包含内存的数据和类型),实现对于内存的高效利用。

因为如果单独存储两部分,则需要有两部分重复的内存数据和类型,一份在内存部分,而另一份,字节码部分则不会被使用,因此我们采取了复用的方法,减少了因内存数据和类型而造成的内存浪费。

但因此需要特殊的函数实现,同时需要注意内存数据和类型的内存的分配和释放由字节码的相关函数进行管理。

// Creates the struct AqvmMemory_Memory with |data|, |type|, and |size|.
// The function will allocate a struct AqvmMemory_Memory and copy |data|,
// |type|, and |size| into the struct. Returns a pointer to the struct if
// successful. Returns NULL if creation fails.
struct AqvmMemory_Memory* AqvmMemory_CreateMemory(void* data, void* type,
size_t size) {
struct AqvmMemory_Memory* memory_ptr =
(struct AqvmMemory_Memory*)malloc(sizeof(struct AqvmMemory_Memory));
if (memory_ptr == NULL) {
AqvmRuntimeDebugger_OutputReport(
"\"ERROR\"", "\"AqvmMemory_CreateMemory_MemoryAllocationFailure\"",
"\"Failed to allocate memory.\"", NULL);
return NULL;
} memory_ptr->data = data;
memory_ptr->type = type;
memory_ptr->size = size; return memory_ptr;
} // Free the memory of the |memory_ptr|. No return.
// NOTICE: The function only free the memory of the struct. The memory pointed
// to by pointers to data and type in struct is not freed. This memory is
// managed by bytecode related functions.
void AqvmMemory_FreeMemory(struct AqvmMemory_Memory* memory_ptr) {
free(memory_ptr);
}

除此之外,由于部分系统对于类型的定义与AQ标准有所差异,因此设计了相关函数确保虚拟机符合标准。如果系统与标准存在差异,应当为这些系统进行特殊的设计。

// Checks the memory conditions in the system.
// Returns the number of warnings.
int AqvmMemory_CheckMemoryConditions() {
int warning_count = 0;
if (sizeof(aqint) != 4) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_IntLengthWarning\"",
"\"The length requirement for the int type does not conform to the "
"type "
"definition.\"",
NULL);
++warning_count;
}
if (sizeof(aqlong) != 8) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_LongLengthWarning\"",
"\"The length requirement for the long type does not conform to the "
"type "
"definition.\"",
NULL);
++warning_count;
}
if (sizeof(aqfloat) != 4) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"",
"\"AqvmMemory_CheckMemoryConditions_FloatLengthWarning\"",
"\"The length requirement for the float type does not conform to the "
"type definition.\"",
NULL);
++warning_count;
}
if (sizeof(aqdouble) != 4) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"",
"\"AqvmMemory_CheckMemoryConditions_DoubleLengthWarning\"",
"\"The length requirement for the double type does not conform to the "
"type definition.\"",
NULL);
++warning_count;
}
if (sizeof(aqchar) != 1) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_CharLengthWarning\"",
"\"The length requirement for the char type does not conform to the "
"type "
"definition.\"",
NULL);
++warning_count;
}
if (sizeof(aqbool) != 1) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_BoolLengthWarning\"",
"The length requirement for the bool type does not conform to the type "
"definition.",
NULL);
++warning_count;
} if (warning_count == 0) {
AqvmRuntimeDebugger_OutputReport("\"INFO\"",
"\"AqvmMemory_CheckMemoryConditions_CheckNormal\"",
"\"No memory conditions warning.\"", NULL);
} return warning_count;
}

详细标准:

目录结构

memory部分的代码位于/aqvm/memory。内含多个代码文件。

  1. CMakeLists.txt - 该目录下的CMake构建文件
  2. memory.h - 内存的数据结构和相关函数
  3. memory.c - 内存的相关函数的实现
  4. types.h - 内存类型的定义

memory.h

AqvmMemory_Memory

该结构体存储有关内存的信息。

|type| 是一个指向数组的指针,该数组存储内存中每个字节的类型。每个字节使用4位来存储类型。因此,一个 uint8_t 变量可以存储2个类型。每个 uint8_t 变量的前4位用于偶数字节的类型,后4位用于奇数字节的类型。类型列表在 types.h 中。

|data| 是一个指向存储数据的内存的 void* 类型的指针。

|size| 是内存的大小。

注意:结构体 AqvmMemory_Memory 仅存储内存的信息。内存由存储字节码时的字节码函数分配。|memory| 和 |type| 的内存是字节码内存的一部分。

struct AqvmMemory_Memory {
uint8_t* type;
void* data;
size_t size;
};

AqvmMemory_CheckMemoryConditions

检查系统中的内存条件。

返回警告数量。

int AqvmMemory_CheckMemoryConditions() {
int warning_count = 0;
if (sizeof(aqint) != 4) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_IntLengthWarning\"",
"\"The length requirement for the int type does not conform to the "
"type "
"definition.\"",
NULL);
++warning_count;
}
if (sizeof(aqlong) != 8) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_LongLengthWarning\"",
"\"The length requirement for the long type does not conform to the "
"type "
"definition.\"",
NULL);
++warning_count;
}
if (sizeof(aqfloat) != 4) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"",
"\"AqvmMemory_CheckMemoryConditions_FloatLengthWarning\"",
"\"The length requirement for the float type does not conform to the "
"type definition.\"",
NULL);
++warning_count;
}
if (sizeof(aqdouble) != 4) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"",
"\"AqvmMemory_CheckMemoryConditions_DoubleLengthWarning\"",
"\"The length requirement for the double type does not conform to the "
"type definition.\"",
NULL);
++warning_count;
}
if (sizeof(aqchar) != 1) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_CharLengthWarning\"",
"\"The length requirement for the char type does not conform to the "
"type "
"definition.\"",
NULL);
++warning_count;
}
if (sizeof(aqbool) != 1) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_BoolLengthWarning\"",
"The length requirement for the bool type does not conform to the type "
"definition.",
NULL);
++warning_count;
} if (warning_count == 0) {
AqvmRuntimeDebugger_OutputReport("\"INFO\"",
"\"AqvmMemory_CheckMemoryConditions_CheckNormal\"",
"\"No memory conditions warning.\"", NULL);
} return warning_count;
}

AqvmMemory_CreateMemory

创建包含 |data|、|type| 和 |size| 的结构体 AqvmMemory_Memory。

该函数将分配一个 AqvmMemory_Memory 结构体,并将 |data|、|type| 和 |size| 复制到结构体中。返回指向该结构体的指针。如果创建失败则返回NULL。

struct AqvmMemory_Memory* AqvmMemory_CreateMemory(void* data, void* type,
size_t size) {
struct AqvmMemory_Memory* memory_ptr =
(struct AqvmMemory_Memory*)malloc(sizeof(struct AqvmMemory_Memory));
if (memory_ptr == NULL) {
AqvmRuntimeDebugger_OutputReport(
"\"ERROR\"", "\"AqvmMemory_CreateMemory_MemoryAllocationFailure\"",
"\"Failed to allocate memory.\"", NULL);
return NULL;
} memory_ptr->data = data;
memory_ptr->type = type;
memory_ptr->size = size; return memory_ptr;
}

AqvmMemory_FreeMemory

释放 |memory_ptr| 的内存。无返回值。

注意:该函数仅释放结构体的内存。结构体中指向数据和类型的指针所指向的内存不会被释放。这些内存由字节码相关函数管理。

void AqvmMemory_FreeMemory(struct AqvmMemory_Memory* memory_ptr) {
free(memory_ptr);
}

AqvmMemory_SetType

设置 |memory| 中 |index| 字节处的数据类型为 |type|。|type| 应小于 4 位。

成功时返回 0。如果内存指针为 NULL,返回 -1。如果索引指针为 NULL,返回 -2。如果索引超出范围,返回 -3。如果类型超出范围,返回 -4。

int AqvmMemory_SetType(const struct AqvmMemory_Memory* memory, size_t index,
uint8_t type) {
if (memory == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_SetType_NullMemoryPointer\"",
"\"The memory pointer is NULL.\"", NULL);
return -1;
}
if (memory->type == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_SetType_NullTypePointer\"",
"\"The type pointer is NULL.\"", NULL);
return -2;
}
if (index > memory->size) {
AqvmRuntimeDebugger_OutputReport(
"\"ERROR\"", "\"AqvmMemory_SetType_OutOfMemoryRange\"",
"\"The index is out of memory range.\"", NULL);
return -3;
}
if (type > 0x0F) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_SetType_OutOfTypeRange\"",
"\"The type is out of range.\"", NULL);
return -4;
} // Sets the type of the data at |index| bytes in memory.
// Since Aqvm stores type data occupying 4 bits and uint8_t occupying 8 bits,
// each uint8_t type location stores two type data. The storage locations
// (high 4 bits, low 4 bits) are set according to the parity of |index|. Even
// numbers are stored in the high bits of (|index| / 2) and odd numbers are
// stored in the low bits of (|index| / 2).
if (index % 2 != 0) {
memory->type[index / 2] = (memory->type[index / 2] & 0xF0) | type;
} else {
memory->type[index / 2] = (memory->type[index / 2] & 0x0F) | (type << 4);
} return 0;
}

AqvmMemory_GetType

获取 |memory| 中 |index| 字节处的数据类型。

成功时返回小于 4 位 (0X0F) 的类型。如果内存指针为 NULL,返回 0x11。如果索引指针为 NULL,返回 0x12。如果索引超出内存范围,返回 0x13。

uint8_t AqvmMemory_GetType(struct AqvmMemory_Memory* memory, size_t index) {
if (memory == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_GetType_NullMemoryPointer\"",
"\"The memory pointer is NULL.\"", NULL);
return 0x11;
}
if (memory->type == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_GetType_NullTypePointer\"",
"\"The type pointer is NULL.\"", NULL);
return 0x12;
}
if (index > memory->size) {
AqvmRuntimeDebugger_OutputReport(
"\"ERROR\"", "\"AqvmMemory_GetType_OutOfMemoryRange\"",
"\"The index is out of memory range.\"", NULL);
return 0x13;
} // Gets the type of the data at |index| bytes in memory.
// Since Aqvm stores type data occupying 4 bits and uint8_t occupying 8 bits,
// each uint8_t type location stores two type data. The storage locations
// (high 4 bits, low 4 bits) are set according to the parity of |index|. Even
// numbers are stored in the high bits of (|index| / 2) and odd numbers are
// stored in the low bits of (|index| / 2).
if (index % 2 != 0) {
return memory->type[index / 2] & 0x0F;
} else {
return (memory->type[index / 2] & 0xF0) >> 4;
}
}

AqvmMemory_WriteData

将 |data_ptr| 指向的大小为 |size| 的数据写入 |memory| 中 |index| 字节处的数据。

成功时返回 0。如果内存指针为 NULL,返回 -1。如果索引指针为 NULL,返回 -2。如果索引超出内存范围,返回 -3。如果数据指针为 NULL,返回 -4。

int AqvmMemory_WriteData(struct AqvmMemory_Memory* memory, size_t index,
void* data_ptr, size_t size) {
if (memory == NULL) {
AqvmRuntimeDebugger_OutputReport(
"\"ERROR\"", "\"AqvmMemory_WriteData_NullMemoryPointer\"",
"\"The memory pointer is NULL.\"", NULL);
return -1;
}
if (memory->type == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_WriteData_NullTypePointer\"",
"\"The type pointer is NULL.\"", NULL);
return -2;
}
if (index > memory->size) {
AqvmRuntimeDebugger_OutputReport(
"\"ERROR\"", "\"AqvmMemory_WriteData_OutOfMemoryRange\"",
"\"The index is out of memory range.\"", NULL);
return -3;
}
if (data_ptr == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_WriteData_NullDataPointer\"",
"\"The data pointer is NULL.\"", NULL);
return -4;
} // Since void* does not have a specific size, pointer moves need to be
// converted before moving.
memcpy((void*)((uintptr_t)memory->data + index), data_ptr, size); return 0;
}

memory.h完整代码:

// Copyright 2024 AQ author, All Rights Reserved.
// This program is licensed under the AQ License. You can find the AQ license in
// the root directory. #ifndef AQ_AQVM_MEMORY_MEMORY_H_
#define AQ_AQVM_MEMORY_MEMORY_H_ #include <stddef.h>
#include <stdint.h> #include "aqvm/memory/types.h" // The struct stores information about the memory.
// |type| is a pointer to an array that stores the type of each byte in the
// memory. Each byte uses 4 bits to store the type. So a uint8_t variable can
// store 2 types. Each uint8_t variable's first 4 bits are used for the even
// byte's type and the next 4 bits are used for the odd byte's type. The type
// list is in types.h.
// |data| is a pointer of type void* to the memory that stores the data.
// |size| is the size of the memory.
// NOTICE: The struct AqvmMemory_Memory only stores information of the memory.
// The memory is allocated by the bytecode function when storing the bytecode.
// The memory of |memory| and |type| is part of the bytecode memory.
struct AqvmMemory_Memory {
uint8_t* type;
void* data;
size_t size;
}; // Checks the memory conditions in the system.
// Returns the number of warnings.
int AqvmMemory_CheckMemoryConditions(); // Creates the struct AqvmMemory_Memory with |data|, |type|, and |size|.
// The function will allocate a struct AqvmMemory_Memory and copy |data|,
// |type|, and |size| into the struct. Returns a pointer to the struct if
// successful. Returns NULL if creation fails.
struct AqvmMemory_Memory* AqvmMemory_CreateMemory(void* data, void* type,
size_t size); // Free the memory of the |memory_ptr|. No return.
// NOTICE: The function only free the memory of the struct. The memory pointed
// to by pointers to data and type in struct is not freed. This memory is
// managed by bytecode related functions.
void AqvmMemory_FreeMemory(struct AqvmMemory_Memory* memory_ptr); // Sets the type of the data at |index| bytes in |memory| to |type|. |type|
// should be less than 4 bits.
// Returns 0 if successful. Returns -1 if the memory pointer is NULL. Returns -2
// if the type pointer is NULL. Returns -3 if the index is out of range. Returns
// -4 if the type is out of range.
int AqvmMemory_SetType(const struct AqvmMemory_Memory* memory, size_t index,
uint8_t type); // Gets the type of the data at |index| bytes in |memory|.
// Returns the type that is less than 4 bits (0X0F) if successful. Returns 0x11
// if the memory pointer is NULL. Returns 0x12 if the type pointer is NULL.
// Returns 0x13 if the index is out of memory range.
uint8_t AqvmMemory_GetType(struct AqvmMemory_Memory* memory, size_t index); // Writes the data that |data_ptr| points to of size |size| to the data of at
// |index| bytes in |memory|.
// Returns 0 if successful. Returns -1 if the memory pointer is NULL. Returns -2
// if the type pointer is NULL. Returns -3 if the index is out of range. Returns
// -4 if the data pointer is NULL.
int AqvmMemory_WriteData(struct AqvmMemory_Memory* memory, size_t index,
void* data_ptr, size_t size); #endif

memory.c

memory.c完整代码:

// Copyright 2024 AQ author, All Rights Reserved.
// This program is licensed under the AQ License. You can find the AQ license in
// the root directory. #include "aqvm/memory/memory.h" #include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h> #include "aqvm/memory/types.h"
#include "aqvm/runtime/debugger/debugger.h" int AqvmMemory_CheckMemoryConditions() {
int warning_count = 0;
if (sizeof(aqint) != 4) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_IntLengthWarning\"",
"\"The length requirement for the int type does not conform to the "
"type "
"definition.\"",
NULL);
++warning_count;
}
if (sizeof(aqlong) != 8) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_LongLengthWarning\"",
"\"The length requirement for the long type does not conform to the "
"type "
"definition.\"",
NULL);
++warning_count;
}
if (sizeof(aqfloat) != 4) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"",
"\"AqvmMemory_CheckMemoryConditions_FloatLengthWarning\"",
"\"The length requirement for the float type does not conform to the "
"type definition.\"",
NULL);
++warning_count;
}
if (sizeof(aqdouble) != 4) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"",
"\"AqvmMemory_CheckMemoryConditions_DoubleLengthWarning\"",
"\"The length requirement for the double type does not conform to the "
"type definition.\"",
NULL);
++warning_count;
}
if (sizeof(aqchar) != 1) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_CharLengthWarning\"",
"\"The length requirement for the char type does not conform to the "
"type "
"definition.\"",
NULL);
++warning_count;
}
if (sizeof(aqbool) != 1) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_BoolLengthWarning\"",
"The length requirement for the bool type does not conform to the type "
"definition.",
NULL);
++warning_count;
} if (warning_count == 0) {
AqvmRuntimeDebugger_OutputReport("\"INFO\"",
"\"AqvmMemory_CheckMemoryConditions_CheckNormal\"",
"\"No memory conditions warning.\"", NULL);
} return warning_count;
} struct AqvmMemory_Memory* AqvmMemory_CreateMemory(void* data, void* type,
size_t size) {
struct AqvmMemory_Memory* memory_ptr =
(struct AqvmMemory_Memory*)malloc(sizeof(struct AqvmMemory_Memory));
if (memory_ptr == NULL) {
AqvmRuntimeDebugger_OutputReport(
"\"ERROR\"", "\"AqvmMemory_CreateMemory_MemoryAllocationFailure\"",
"\"Failed to allocate memory.\"", NULL);
return NULL;
} memory_ptr->data = data;
memory_ptr->type = type;
memory_ptr->size = size; return memory_ptr;
} void AqvmMemory_FreeMemory(struct AqvmMemory_Memory* memory_ptr) {
free(memory_ptr);
} int AqvmMemory_SetType(const struct AqvmMemory_Memory* memory, size_t index,
uint8_t type) {
if (memory == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_SetType_NullMemoryPointer\"",
"\"The memory pointer is NULL.\"", NULL);
return -1;
}
if (memory->type == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_SetType_NullTypePointer\"",
"\"The type pointer is NULL.\"", NULL);
return -2;
}
if (index > memory->size) {
AqvmRuntimeDebugger_OutputReport(
"\"ERROR\"", "\"AqvmMemory_SetType_OutOfMemoryRange\"",
"\"The index is out of memory range.\"", NULL);
return -3;
}
if (type > 0x0F) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_SetType_OutOfTypeRange\"",
"\"The type is out of range.\"", NULL);
return -4;
} // Sets the type of the data at |index| bytes in memory.
// Since Aqvm stores type data occupying 4 bits and uint8_t occupying 8 bits,
// each uint8_t type location stores two type data. The storage locations
// (high 4 bits, low 4 bits) are set according to the parity of |index|. Even
// numbers are stored in the high bits of (|index| / 2) and odd numbers are
// stored in the low bits of (|index| / 2).
if (index % 2 != 0) {
memory->type[index / 2] = (memory->type[index / 2] & 0xF0) | type;
} else {
memory->type[index / 2] = (memory->type[index / 2] & 0x0F) | (type << 4);
} return 0;
} uint8_t AqvmMemory_GetType(struct AqvmMemory_Memory* memory, size_t index) {
if (memory == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_GetType_NullMemoryPointer\"",
"\"The memory pointer is NULL.\"", NULL);
return 0x11;
}
if (memory->type == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_GetType_NullTypePointer\"",
"\"The type pointer is NULL.\"", NULL);
return 0x12;
}
if (index > memory->size) {
AqvmRuntimeDebugger_OutputReport(
"\"ERROR\"", "\"AqvmMemory_GetType_OutOfMemoryRange\"",
"\"The index is out of memory range.\"", NULL);
return 0x13;
} // Gets the type of the data at |index| bytes in memory.
// Since Aqvm stores type data occupying 4 bits and uint8_t occupying 8 bits,
// each uint8_t type location stores two type data. The storage locations
// (high 4 bits, low 4 bits) are set according to the parity of |index|. Even
// numbers are stored in the high bits of (|index| / 2) and odd numbers are
// stored in the low bits of (|index| / 2).
if (index % 2 != 0) {
return memory->type[index / 2] & 0x0F;
} else {
return (memory->type[index / 2] & 0xF0) >> 4;
}
} int AqvmMemory_WriteData(struct AqvmMemory_Memory* memory, size_t index,
void* data_ptr, size_t size) {
if (memory == NULL) {
AqvmRuntimeDebugger_OutputReport(
"\"ERROR\"", "\"AqvmMemory_WriteData_NullMemoryPointer\"",
"\"The memory pointer is NULL.\"", NULL);
return -1;
}
if (memory->type == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_WriteData_NullTypePointer\"",
"\"The type pointer is NULL.\"", NULL);
return -2;
}
if (index > memory->size) {
AqvmRuntimeDebugger_OutputReport(
"\"ERROR\"", "\"AqvmMemory_WriteData_OutOfMemoryRange\"",
"\"The index is out of memory range.\"", NULL);
return -3;
}
if (data_ptr == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_WriteData_NullDataPointer\"",
"\"The data pointer is NULL.\"", NULL);
return -4;
} // Since void* does not have a specific size, pointer moves need to be
// converted before moving.
memcpy((void*)((uintptr_t)memory->data + index), data_ptr, size); return 0;
}

通过这些代码的配合,共同构成了完整的Aqvm的内存架构,有效缓解内存压力的同时,提高了Aqvm的运行效率。

我们正在更加努力地开发AQ虚拟机。如果您想了解更多信息或参与开发工作,请关注我们的官网:https://www.axa6.com 和 Github:https://github.com/aq-org/AQ。

本文章基于AQ License:https://github.com/aq-org/AQ/blob/main/LICENSE 发布,如有需要,请根据AQ License进行改编或转载。

一种优秀的虚拟机内存架构 - AQ的更多相关文章

  1. JAVA虚拟机内存架构

    Java在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途.创建和销毁的时间,有一些是随虚拟机的启动而创建,随虚拟机的退出而销毁,有些则是与线程一一对应,随 ...

  2. jvm 虚拟机内存模型

    来源:https://blog.csdn.net/A_zhenzhen/article/details/77917991?locationNum=8&fps=1    https://blog ...

  3. Hanlp等七种优秀的开源中文分词库推荐

    Hanlp等七种优秀的开源中文分词库推荐 中文分词是中文文本处理的基础步骤,也是中文人机自然语言交互的基础模块.由于中文句子中没有词的界限,因此在进行中文自然语言处理时,通常需要先进行分词. 纵观整个 ...

  4. 深入理解Java虚拟机内存模型

    前言 本文中部分内容引用至<深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)>第12章,如果有兴趣可自行深入阅读,文末放有书籍PDF版本连接. 一.物理机中的并发 物理机遇到的并 ...

  5. java中JVM虚拟机内存模型详细说明

    java中JVM虚拟机内存模型详细说明 2012-12-12 18:36:03|  分类: JAVA |  标签:java  jvm  堆内存  虚拟机  |举报|字号 订阅     JVM的内部结构 ...

  6. 设置TOMCAT的JVM虚拟机内存大小

    你知道如何设置TOMCAT的JVM虚拟机内存大小吗,这里和大家分享一下,JAVA程序启动时JVM都会分配一个初始内存和最大内存给这个应用程序.这个初始内存和最大内存在一定程度都会影响程序的性能. 设置 ...

  7. 人工智能深度学习Caffe框架介绍,优秀的深度学习架构

    人工智能深度学习Caffe框架介绍,优秀的深度学习架构 在深度学习领域,Caffe框架是人们无法绕过的一座山.这不仅是因为它无论在结构.性能上,还是在代码质量上,都称得上一款十分出色的开源框架.更重要 ...

  8. Java虚拟机内存模型及垃圾回收监控调优

    Java虚拟机内存模型及垃圾回收监控调优 如果你想理解Java垃圾回收如果工作,那么理解JVM的内存模型就显的非常重要.今天我们就来看看JVM内存的各不同部分及如果监控和实现垃圾回收调优. JVM内存 ...

  9. Java虚拟机-内存tips

    java虚拟机内存可以分为独占区和共享区. 独占区:虚拟内存栈.本地方法栈.程序计数器. 共享区:方法区.Java堆(用来存放对象实例). 程序计数器 比较小的内存空间,当前线程所执行的字节码的行号指 ...

  10. JVM基础系列第6讲:Java 虚拟机内存结构

    看到这里,我相信大家对于一个 Java 源文件是如何变成字节码文件,以及字节码文件的含义已经非常清楚了.那么接下来就是让 Java 虚拟机运行字节码文件,从而得出我们最终想要的结果了.在这个过程中,J ...

随机推荐

  1. 解决input中输入中文过程中会触发input事件的问题

    问题描述: 监听文本输入框的input事件,在拼写汉字时会触发input事件,如下图: 需求: 选词完成后触发input事件,只触发一次. 解决办法: 通过查阅资料得知在输入中文(包括语音识别时)会先 ...

  2. 无需重新学习,使用 Kibana 查询/可视化 SLS 数据

    1. 场景 现在通过 SLS 的 ES 兼容能力,可以很方便地实现用 Kibana 来查询和可视化 SLS 的数据.对于从 ES 迁移到 SLS 的用户可以继续保留原来的 Kibana 使用习惯.下面 ...

  3. C# XML转Json Json转XML XML 转对象 对象转XML

    对象转XML对象时,只能是一个JObject对象,不能是一个集合对象.如果对象是一个列表集合,需要定义一个根对象比如这样:var obj =new { Root = ListLogs[ListLogs ...

  4. iNeuOS工业互联网操作系统,增加电力IEC104协议

    1.      概述... 2 2.      配置IEC104协议设备驱动... 2 1.   概述 IEC60870-5-104 是一种电力自动化系统中常用的通信协议,使用 TCP/IP 协议作为 ...

  5. uniapp 输入有值后按钮变色

    我们在开发中难免会遇到一些登录注册输入框中的值为空时,按钮的状态变成为不可点击的状态,当输入框有值后就把按钮变为可点击的状态 代码部分: <input placeholder="请输入 ...

  6. 查看SO KO 执行程序相关信息命令

    1 查看SO 查看so库的方法__臣本布衣_新浪博客 (sina.com.cn) 1.nm -D libxxx.so 打印出符号信息. 一般这样用:nm -D libxxx.so |grep T $ ...

  7. 系统镜像烧写及U-Boot编译

    1 系统镜像烧写 1.1 工具介绍 烧写软件:使用NXP的MfgTool2工具烧写,工具路径:[正点原子]阿尔法Linux开发板(A盘)-基础资料\05.开发工具\04.正点原子MFG_TOOL出厂固 ...

  8. [SWPUCTF 2021 新生赛]gift_F12

    首先我们打开环境会发现花里胡哨的,而题目中有提示:F12,所以我们直接F12查看源码 然后ctrl+f信息检索flag.直接找到flag提交 但要注意提交格式为NSSCTF{}

  9. 启动 bert-as-service

    S1:启动bert-as-service时,执行命令 bert-serving-start -model_dir /downloads/uncased_L-12_H-768_A-12/ -num_wo ...

  10. post请求方式 - 使用restTemplate而不使用httpClient,headers.setContentType(MediaType.APPLICATION_JSON_UTF8)

    public static String doPostForJson(String url, String json,String byteAuthorization) { RestTemplate ...