一種優秀的虛擬機內存架構 - AQ
源鏈接:https://www.axa6.com/zh/an-excellent-virtual-machine-memory-architecture
簡介
虛擬機內存架構直接影響虛擬機的性能和占用。設計一個優秀的架構可以有效提升性能和效率。
本文將介紹AQ虛擬機使用的內存架構,以及AQ虛擬機內存的詳細標準。
通過對于虛擬機內存架構的優化,有助于虛擬機的運行效率和減少占用。如果可以,應該盡可能地平衡兩者,使虛擬機達到最佳狀態。
在某些情況下,應該根據虛擬機的特殊需求進行不同的開發。
例如:在單片機等內存受限情況下,需要盡可能地減少占用。
而在并行計算等性能敏感情況,則需要側重于性能優化。
設計思路
內存架構
基礎內存架構
AQ采取了寄存器的基礎內存架構,但與標準的寄存器架構有所不同,對寄存器架構進行了部分改進和優化。
此處的
寄存器并非CPU中的寄存器,而是在內存中模擬出的虛擬寄存器。
選擇寄存器的原因
相較與JAVA、Python等主流語言虛擬機采取堆棧架構不同,AQ決定采取寄存器架構的原因是性能的優化與字節碼的容易理解。
雖然堆棧架構被普遍認為更容易移植和編寫,但在實際的性能中會有一些損耗,對于內存的多次訪問會減緩其速度,這是不可避免并且難以徹底優化的。因此,為了解決此處的性能損耗,AQ采用了寄存器架構。同時,從字節碼的角度上說,寄存器架構的字節碼更容易理解,其指令類似于函數的參數方式,而不是直接面對堆棧的眾多操作。
寄存器架構的區別
標準的寄存器架構
標準的寄存器架構中,寄存器包含:
數據類型- 寄存器將存儲的數據的類型(如int、float、double等)數據- 寄存器將存儲的數據的值- (可選)標記 - 寄存器將存儲的數據的標記(如變量、函數、類等)
- (可選)引用 - 寄存器將存儲的數據的引用(如對象的地址等)
盡管不同語言的虛擬機內存架構可能有所不同,但大致都存儲了這些信息。
而在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_Register中enum類型的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。內含多個代碼文件。
CMakeLists.txt- 該目錄下的CMake構建文件memory.h- 內存的數據結構和相關函數memory.c- 內存的相關函數的實現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進行改編或轉載。

浙公網安備 33010602011771號