源鏈接:https://www.axa6.com/zh/an-excellent-virtual-machine-memory-architecture 簡介 虛擬機記憶體架構直接影響虛擬機的性能和占用。設計一個優秀的架構可以有效提升性能和效率。 本文將介紹AQ虛擬機使用的記憶體架構,以及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進行改編或轉載。