Explorar o código

randomx_cache and randomx_dataset changed to standard-layout structs

tevador %!s(int64=7) %!d(string=hai) anos
pai
achega
22a3aa8d79

+ 4 - 0
src/common.hpp

@@ -113,6 +113,10 @@ namespace randomx {
 	typedef void(*DatasetReadFunc)(addr_t, MemoryRegisters&, int_reg_t(&reg)[RegistersCount]);
 	typedef void(*ProgramFunc)(RegisterFile&, MemoryRegisters&, uint8_t* /* scratchpad */, uint64_t);
 	typedef void(*DatasetInitFunc)(randomx_cache* cache, uint8_t* dataset, uint32_t startBlock, uint32_t endBlock);
+
+	typedef void(*DatasetDeallocFunc)(randomx_dataset*);
+	typedef void(*CacheDeallocFunc)(randomx_cache*);
+	typedef void(*CacheInitializeFunc)(randomx_cache*, const void*, size_t);
 }
 
 std::ostream& operator<<(std::ostream& os, const randomx::RegisterFile& rf);

+ 68 - 110
src/dataset.cpp

@@ -40,126 +40,84 @@ along with RandomX.  If not, see<http://www.gnu.org/licenses/>.
 #include "argon2.h"
 #include "argon2_core.h"
 
-randomx_dataset::~randomx_dataset() {
-
-}
-
 static_assert(RANDOMX_ARGON_MEMORY % (RANDOMX_ARGON_LANES * ARGON2_SYNC_POINTS) == 0, "RANDOMX_ARGON_MEMORY - invalid value");
 static_assert(ARGON2_BLOCK_SIZE == randomx::ArgonBlockSize, "Unpexpected value of ARGON2_BLOCK_SIZE");
 
-void randomx_cache::initialize(const void *seed, size_t seedSize) {
-	uint32_t memory_blocks, segment_length;
-	argon2_instance_t instance;
-	argon2_context context;
-
-	context.out = nullptr;
-	context.outlen = 0;
-	context.pwd = CONST_CAST(uint8_t *)seed;
-	context.pwdlen = (uint32_t)seedSize;
-	context.salt = CONST_CAST(uint8_t *)RANDOMX_ARGON_SALT;
-	context.saltlen = (uint32_t)randomx::ArgonSaltSize;
-	context.secret = NULL;
-	context.secretlen = 0;
-	context.ad = NULL;
-	context.adlen = 0;
-	context.t_cost = RANDOMX_ARGON_ITERATIONS;
-	context.m_cost = RANDOMX_ARGON_MEMORY;
-	context.lanes = RANDOMX_ARGON_LANES;
-	context.threads = 1;
-	context.allocate_cbk = NULL;
-	context.free_cbk = NULL;
-	context.flags = ARGON2_DEFAULT_FLAGS;
-	context.version = ARGON2_VERSION_NUMBER;
-
-	/* 2. Align memory size */
-	/* Minimum memory_blocks = 8L blocks, where L is the number of lanes */
-	memory_blocks = context.m_cost;
-
-	segment_length = memory_blocks / (context.lanes * ARGON2_SYNC_POINTS);
-
-	instance.version = context.version;
-	instance.memory = NULL;
-	instance.passes = context.t_cost;
-	instance.memory_blocks = memory_blocks;
-	instance.segment_length = segment_length;
-	instance.lane_length = segment_length * ARGON2_SYNC_POINTS;
-	instance.lanes = context.lanes;
-	instance.threads = context.threads;
-	instance.type = Argon2_d;
-	instance.memory = (block*)memory;
-
-	if (instance.threads > instance.lanes) {
-		instance.threads = instance.lanes;
-	}
-
-	/* 3. Initialization: Hashing inputs, allocating memory, filling first
-	 * blocks
-	 */
-	argon_initialize(&instance, &context);
-
-	fill_memory_blocks(&instance);
-
-	reciprocalCache.clear();
-	randomx::Blake2Generator gen(seed, seedSize);
-	for (int i = 0; i < RANDOMX_CACHE_ACCESSES; ++i) {
-		randomx::generateSuperscalar(programs[i], gen);
-		for (unsigned j = 0; j < programs[i].getSize(); ++j) {
-			auto& instr = programs[i](j);
-			if (instr.opcode == randomx::SuperscalarInstructionType::IMUL_RCP) {
-				auto rcp = randomx_reciprocal(instr.getImm32());
-				instr.setImm32(reciprocalCache.size());
-				reciprocalCache.push_back(rcp);
-			}
-		}
-	}
-}
-
 namespace randomx {
 
-	template<class Allocator>
-	void Dataset<Allocator>::allocate() {
-		memory = (uint8_t*)Allocator::allocMemory(DatasetSize);
-	}
-
-	template<class Allocator>
-	Dataset<Allocator>::~Dataset() {
-		Allocator::freeMemory(memory, DatasetSize);
-	}
-
-	template<class Allocator>
-	void Cache<Allocator>::allocate() {
-		memory = (uint8_t*)Allocator::allocMemory(CacheSize);
-	}
-
-	template<class Allocator>
-	Cache<Allocator>::~Cache() {
-		Allocator::freeMemory(memory, CacheSize);
-	}
-
-	template<class Allocator>
-	DatasetInitFunc Cache<Allocator>::getInitFunc() {
-		return &initDataset;
-	}
+	void initCache(randomx_cache* cache, const void* seed, size_t seedSize) {
+		uint32_t memory_blocks, segment_length;
+		argon2_instance_t instance;
+		argon2_context context;
+
+		context.out = nullptr;
+		context.outlen = 0;
+		context.pwd = CONST_CAST(uint8_t *)seed;
+		context.pwdlen = (uint32_t)seedSize;
+		context.salt = CONST_CAST(uint8_t *)RANDOMX_ARGON_SALT;
+		context.saltlen = (uint32_t)randomx::ArgonSaltSize;
+		context.secret = NULL;
+		context.secretlen = 0;
+		context.ad = NULL;
+		context.adlen = 0;
+		context.t_cost = RANDOMX_ARGON_ITERATIONS;
+		context.m_cost = RANDOMX_ARGON_MEMORY;
+		context.lanes = RANDOMX_ARGON_LANES;
+		context.threads = 1;
+		context.allocate_cbk = NULL;
+		context.free_cbk = NULL;
+		context.flags = ARGON2_DEFAULT_FLAGS;
+		context.version = ARGON2_VERSION_NUMBER;
+
+		/* 2. Align memory size */
+		/* Minimum memory_blocks = 8L blocks, where L is the number of lanes */
+		memory_blocks = context.m_cost;
+
+		segment_length = memory_blocks / (context.lanes * ARGON2_SYNC_POINTS);
+
+		instance.version = context.version;
+		instance.memory = NULL;
+		instance.passes = context.t_cost;
+		instance.memory_blocks = memory_blocks;
+		instance.segment_length = segment_length;
+		instance.lane_length = segment_length * ARGON2_SYNC_POINTS;
+		instance.lanes = context.lanes;
+		instance.threads = context.threads;
+		instance.type = Argon2_d;
+		instance.memory = (block*)cache->memory;
+
+		if (instance.threads > instance.lanes) {
+			instance.threads = instance.lanes;
+		}
 
-	template<class Allocator>
-	DatasetInitFunc CacheWithJit<Allocator>::getInitFunc() {
-		return jit.getDatasetInitFunc();
+		/* 3. Initialization: Hashing inputs, allocating memory, filling first
+		 * blocks
+		 */
+		argon_initialize(&instance, &context);
+
+		fill_memory_blocks(&instance);
+
+		cache->reciprocalCache.clear();
+		randomx::Blake2Generator gen(seed, seedSize);
+		for (int i = 0; i < RANDOMX_CACHE_ACCESSES; ++i) {
+			randomx::generateSuperscalar(cache->programs[i], gen);
+			for (unsigned j = 0; j < cache->programs[i].getSize(); ++j) {
+				auto& instr = cache->programs[i](j);
+				if (instr.opcode == randomx::SuperscalarInstructionType::IMUL_RCP) {
+					auto rcp = randomx_reciprocal(instr.getImm32());
+					instr.setImm32(cache->reciprocalCache.size());
+					cache->reciprocalCache.push_back(rcp);
+				}
+			}
+		}
 	}
 
-	template<class Allocator>
-	void CacheWithJit<Allocator>::initialize(const void *seed, size_t seedSize) {
-		randomx_cache::initialize(seed, seedSize);
-		jit.generateSuperscalarHash(programs, reciprocalCache);
-		jit.generateDatasetInitCode();
+	void initCacheCompile(randomx_cache* cache, const void* seed, size_t seedSize) {
+		initCache(cache, seed, seedSize);
+		cache->jit->generateSuperscalarHash(cache->programs, cache->reciprocalCache);
+		cache->jit->generateDatasetInitCode();
 	}
 
-	template class Dataset<AlignedAllocator<CacheLineSize>>;
-	template class Dataset<LargePageAllocator>;
-	template class Cache<AlignedAllocator<CacheLineSize>>;
-	template class Cache<LargePageAllocator>;
-	template class CacheWithJit<AlignedAllocator<CacheLineSize>>;
-	template class CacheWithJit<LargePageAllocator>;
-
 	constexpr uint64_t superscalarMul0 = 6364136223846793005ULL;
 	constexpr uint64_t superscalarAdd1 = 9298411001130361340ULL;
 	constexpr uint64_t superscalarAdd2 = 12065312585734608966ULL;

+ 25 - 30
src/dataset.hpp

@@ -21,6 +21,7 @@ along with RandomX.  If not, see<http://www.gnu.org/licenses/>.
 
 #include <cstdint>
 #include <vector>
+#include <type_traits>
 #include "common.hpp"
 #include "superscalar_program.hpp"
 #include "jit_compiler_x86.hpp"
@@ -28,51 +29,45 @@ along with RandomX.  If not, see<http://www.gnu.org/licenses/>.
 
 /* Global scope for C binding */
 struct randomx_dataset {
-	virtual ~randomx_dataset() = 0;
-	virtual void allocate() = 0;
 	uint8_t* memory = nullptr;
+	randomx::DatasetDeallocFunc dealloc;
 };
 
 /* Global scope for C binding */
-struct randomx_cache : public randomx_dataset {
-	virtual randomx::DatasetInitFunc getInitFunc() = 0;
-	virtual void initialize(const void *seed, size_t seedSize);
+struct randomx_cache {
+	uint8_t* memory = nullptr;
+	randomx::CacheDeallocFunc dealloc;
+	randomx::JitCompilerX86* jit;
+	randomx::CacheInitializeFunc initialize;
+	randomx::DatasetInitFunc datasetInit;
 	randomx::SuperscalarProgram programs[RANDOMX_CACHE_ACCESSES];
 	std::vector<uint64_t> reciprocalCache;
 };
 
-namespace randomx {
+//A pointer to a standard-layout struct object points to its initial member
+static_assert(std::is_standard_layout<randomx_dataset>(), "randomx_dataset must be a standard-layout struct");
+static_assert(std::is_standard_layout<randomx_cache>(), "randomx_cache must be a standard-layout struct");
 
-	template<class Allocator>
-	struct Dataset : public randomx_dataset {
-		~Dataset() override;
-		void allocate() override;
-	};
+namespace randomx {
 
-	using DatasetDefault = Dataset<AlignedAllocator<CacheLineSize>>;
-	using DatasetLargePage = Dataset<LargePageAllocator>;
+	using DefaultAllocator = AlignedAllocator<CacheLineSize>;
 
 	template<class Allocator>
-	struct Cache : public randomx_cache {
-		~Cache() override;
-		void allocate() override;
-		DatasetInitFunc getInitFunc() override;
-	};
+	void deallocDataset(randomx_dataset* dataset) {
+		if (dataset->memory != nullptr)
+			Allocator::freeMemory(dataset->memory, DatasetSize);
+	}
 
 	template<class Allocator>
-	struct CacheWithJit : public Cache<Allocator> {
-		using Cache<Allocator>::programs;
-		using Cache<Allocator>::reciprocalCache;
-		void initialize(const void *seed, size_t seedSize) override;
-		DatasetInitFunc getInitFunc() override;
-		JitCompilerX86 jit;
-	};
-
-	using CacheDefault = Cache<AlignedAllocator<CacheLineSize>>;
-	using CacheWithJitDefault = CacheWithJit<AlignedAllocator<CacheLineSize>>;
-	using CacheLargePage = Cache<LargePageAllocator>;
-	using CacheWithJitLargePage = CacheWithJit<LargePageAllocator>;
+	void deallocCache(randomx_cache* cache) {
+		if(cache->memory != nullptr)
+			Allocator::freeMemory(cache->memory, CacheSize);
+		if (cache->jit != nullptr)
+			delete cache->jit;
+	}
 
+	void initCache(randomx_cache*, const void*, size_t);
+	void initCacheCompile(randomx_cache*, const void*, size_t);
 	void initDatasetItem(randomx_cache* cache, uint8_t* out, uint64_t blockNumber);
 	void initDataset(randomx_cache* cache, uint8_t* dataset, uint32_t startBlock, uint32_t endBlock);
 }

+ 3 - 3
src/instruction.hpp

@@ -21,6 +21,7 @@ along with RandomX.  If not, see<http://www.gnu.org/licenses/>.
 
 #include <cstdint>
 #include <iostream>
+#include <type_traits>
 #include "blake2/endian.h"
 
 namespace randomx {
@@ -93,10 +94,9 @@ namespace randomx {
 		uint8_t opcode;
 		uint8_t dst;
 		uint8_t src;
-	private:
 		uint8_t mod;
 		uint32_t imm32;
-
+	private:
 		void print(std::ostream&) const;
 		static const char* names[256];
 		static InstructionFormatter engine[256];
@@ -136,5 +136,5 @@ namespace randomx {
 	};
 
 	static_assert(sizeof(Instruction) == 8, "Invalid size of struct randomx::Instruction");
-
+	static_assert(std::is_standard_layout<Instruction>(), "randomx::Instruction must be a standard-layout struct");
 }

+ 1 - 1
src/jit_compiler_x86_static.S

@@ -89,7 +89,7 @@ DECL(randomx_dataset_init):
 	push r13
 	push r14
 	push r15
-	mov rdi, qword ptr [rdi+8] ;# after virtual method table pointer
+	mov rdi, qword ptr [rdi] ;# cache->memory
 	;# dataset in rsi
 	mov rbp, rdx  ;# block index
 	push rcx      ;# max. block index

+ 1 - 1
src/jit_compiler_x86_static.asm

@@ -92,7 +92,7 @@ randomx_dataset_init PROC
 	push r13
 	push r14
 	push r15
-	mov rdi, qword ptr [rcx+8] ;# after virtual method table pointer
+	mov rdi, qword ptr [rcx] ;# cache->memory
 	mov rsi, rdx ;# dataset
 	mov rbp, r8  ;# block index
 	push r9      ;# max. block index

+ 32 - 16
src/randomx.cpp

@@ -28,34 +28,48 @@ along with RandomX.  If not, see<http://www.gnu.org/licenses/>.
 extern "C" {
 
 	randomx_cache *randomx_alloc_cache(randomx_flags flags) {
-		randomx_cache *cache = nullptr;
+		randomx_cache *cache = new randomx_cache();
 
 		try {
 			switch (flags & (RANDOMX_FLAG_JIT | RANDOMX_FLAG_LARGE_PAGES)) {
 				case RANDOMX_FLAG_DEFAULT:
-					cache = new randomx::CacheDefault();
+					cache->dealloc = &randomx::deallocCache<randomx::DefaultAllocator>;
+					cache->jit = nullptr;
+					cache->initialize = &randomx::initCache;
+					cache->datasetInit = &randomx::initDataset;
+					cache->memory = (uint8_t*)randomx::DefaultAllocator::allocMemory(randomx::CacheSize);
 					break;
 
 				case RANDOMX_FLAG_JIT:
-					cache = new randomx::CacheWithJitDefault();
+					cache->dealloc = &randomx::deallocCache<randomx::DefaultAllocator>;
+					cache->jit = new randomx::JitCompilerX86();
+					cache->initialize = &randomx::initCacheCompile;
+					cache->datasetInit = cache->jit->getDatasetInitFunc();
+					cache->memory = (uint8_t*)randomx::DefaultAllocator::allocMemory(randomx::CacheSize);
 					break;
 
 				case RANDOMX_FLAG_LARGE_PAGES:
-					cache = new randomx::CacheLargePage();
+					cache->dealloc = &randomx::deallocCache<randomx::LargePageAllocator>;
+					cache->jit = nullptr;
+					cache->initialize = &randomx::initCache;
+					cache->datasetInit = &randomx::initDataset;
+					cache->memory = (uint8_t*)randomx::LargePageAllocator::allocMemory(randomx::CacheSize);
 					break;
 
 				case RANDOMX_FLAG_JIT | RANDOMX_FLAG_LARGE_PAGES:
-					cache = new randomx::CacheWithJitLargePage();
+					cache->dealloc = &randomx::deallocCache<randomx::LargePageAllocator>;
+					cache->jit = new randomx::JitCompilerX86();
+					cache->initialize = &randomx::initCacheCompile;
+					cache->datasetInit = cache->jit->getDatasetInitFunc();
+					cache->memory = (uint8_t*)randomx::LargePageAllocator::allocMemory(randomx::CacheSize);
 					break;
 
 				default:
 					UNREACHABLE;
 			}
-
-			cache->allocate();
 		}
 		catch (std::exception &ex) {
-			delete cache;
+			randomx_release_cache(cache);
 			cache = nullptr;
 		}
 
@@ -63,27 +77,29 @@ extern "C" {
 	}
 
 	void randomx_init_cache(randomx_cache *cache, const void *seed, size_t seedSize) {
-		cache->initialize(seed, seedSize);
+		cache->initialize(cache, seed, seedSize);
 	}
 
 	void randomx_release_cache(randomx_cache* cache) {
+		cache->dealloc(cache);
 		delete cache;
 	}
 
 	randomx_dataset *randomx_alloc_dataset(randomx_flags flags) {
-		randomx_dataset *dataset = nullptr;
+		randomx_dataset *dataset = new randomx_dataset();
 
 		try {
 			if (flags & RANDOMX_FLAG_LARGE_PAGES) {
-				dataset = new randomx::DatasetLargePage();
+				dataset->dealloc = &randomx::deallocDataset<randomx::LargePageAllocator>;
+				dataset->memory = (uint8_t*)randomx::LargePageAllocator::allocMemory(randomx::DatasetSize);
 			}
 			else {
-				dataset = new randomx::DatasetDefault();
+				dataset->dealloc = &randomx::deallocDataset<randomx::DefaultAllocator>;
+				dataset->memory = (uint8_t*)randomx::DefaultAllocator::allocMemory(randomx::DatasetSize);
 			}
-			dataset->allocate();
 		}
 		catch (std::exception &ex) {
-			delete dataset;
+			randomx_release_dataset(dataset);
 			dataset = nullptr;
 		}
 
@@ -95,8 +111,7 @@ extern "C" {
 	}
 
 	void randomx_init_dataset(randomx_dataset *dataset, randomx_cache *cache, unsigned long startItem, unsigned long itemCount) {
-		randomx::DatasetInitFunc dsfunc = cache->getInitFunc();
-		dsfunc(cache, dataset->memory + startItem * randomx::CacheLineSize, startItem, startItem + itemCount);
+		cache->datasetInit(cache, dataset->memory + startItem * randomx::CacheLineSize, startItem, startItem + itemCount);
 	}
 
 	void *randomx_get_dataset_memory(randomx_dataset *dataset) {
@@ -104,6 +119,7 @@ extern "C" {
 	}
 
 	void randomx_release_dataset(randomx_dataset *dataset) {
+		dataset->dealloc(dataset);
 		delete dataset;
 	}
 

+ 4 - 3
src/superscalar_program.hpp

@@ -46,6 +46,10 @@ namespace randomx {
 		void setAddressRegister(uint32_t val) {
 			addrReg = val;
 		}
+
+		Instruction programBuffer[RANDOMX_SUPERSCALAR_MAX_SIZE];
+		uint32_t size;
+		int addrReg;
 		double ipc;
 		int codeSize;
 		int macroOps;
@@ -62,9 +66,6 @@ namespace randomx {
 				os << instr;
 			}
 		}
-		Instruction programBuffer[RANDOMX_SUPERSCALAR_MAX_SIZE];
-		uint32_t size;
-		int addrReg;
 	};
 
 }

+ 10 - 6
src/tests/benchmark.cpp

@@ -165,15 +165,13 @@ int main(int argc, char** argv) {
 		Stopwatch sw(true);
 		cache = randomx_alloc_cache(flags);
 		if (cache == nullptr) {
-			std::cout << "ERROR: Cache allocation failed" << std::endl;
-			return 1;
+			throw std::runtime_error("Cache allocation failed");
 		}
 		randomx_init_cache(cache, &seed, sizeof(seed));
 		if (miningMode) {
 			dataset = randomx_alloc_dataset(flags);
 			if (dataset == nullptr) {
-				std::cout << "ERROR: Dataset allocation failed" << std::endl;
-				return 1;
+				throw std::runtime_error("Dataset allocation failed");
 			}
 			uint32_t datasetItemCount = randomx_dataset_item_count();
 			if (initThreadCount > 1) {
@@ -200,8 +198,7 @@ int main(int argc, char** argv) {
 		for (int i = 0; i < threadCount; ++i) {
 			randomx_vm *vm = randomx_create_vm(flags, cache, dataset);
 			if (vm == nullptr) {
-				std::cout << "ERROR: Unsupported virtual machine options" << std::endl;
-				return 1;
+				throw std::runtime_error("Unsupported virtual machine options");
 			}
 			vms.push_back(vm);
 		}
@@ -221,7 +218,14 @@ int main(int argc, char** argv) {
 		else {
 			mine(vms[0], std::ref(atomicNonce), std::ref(result), noncesCount, 0);
 		}
+
 		double elapsed = sw.getElapsed();
+		for (unsigned i = 0; i < vms.size(); ++i)
+			randomx_destroy_vm(vms[i]);
+		if (miningMode)
+			randomx_release_dataset(dataset);
+		else
+			randomx_release_cache(cache);
 		std::cout << "Calculated result: ";
 		result.print(std::cout);
 		if (noncesCount == 1000 && seedValue == 0)

+ 1 - 1
src/virtual_machine.cpp

@@ -103,7 +103,7 @@ namespace randomx {
 
 	template<class Allocator, bool softAes>
 	void VmBase<Allocator, softAes>::allocate() {
-		if (mem.memory == nullptr)
+		if (datasetPtr == nullptr)
 			throw std::invalid_argument("Cache/Dataset not set");
 		if (!softAes) { //if hardware AES is not supported, it's better to fail now than to return a ticking bomb
 			__m128i tmp = _mm_load_si128((const __m128i*)&aesDummy);

+ 4 - 1
src/virtual_machine.hpp

@@ -44,7 +44,10 @@ protected:
 	alignas(16) randomx::ProgramConfiguration config;
 	randomx::MemoryRegisters mem;
 	uint8_t* scratchpad;
-	uint8_t* datasetBasePtr;
+	union {
+		randomx_cache* cachePtr = nullptr;
+		randomx_dataset* datasetPtr;
+	};
 	uint32_t datasetOffset;
 };
 

+ 2 - 3
src/vm_compiled.cpp

@@ -27,8 +27,7 @@ namespace randomx {
 
 	template<class Allocator, bool softAes>
 	void CompiledVm<Allocator, softAes>::setDataset(randomx_dataset* dataset) {
-		mem.memory = dataset->memory;
-		datasetBasePtr = dataset->memory;
+		datasetPtr = dataset;
 	}
 
 	template<class Allocator, bool softAes>
@@ -36,7 +35,7 @@ namespace randomx {
 		VmBase<Allocator, softAes>::generateProgram(seed);
 		randomx_vm::initialize();
 		compiler.generateProgram(program, config);
-		mem.memory = datasetBasePtr + datasetOffset;
+		mem.memory = datasetPtr->memory + datasetOffset;
 		execute();
 	}
 

+ 1 - 1
src/vm_compiled.hpp

@@ -48,7 +48,7 @@ namespace randomx {
 		using VmBase<Allocator, softAes>::config;
 		using VmBase<Allocator, softAes>::reg;
 		using VmBase<Allocator, softAes>::scratchpad;
-		using VmBase<Allocator, softAes>::datasetBasePtr;
+		using VmBase<Allocator, softAes>::datasetPtr;
 		using VmBase<Allocator, softAes>::datasetOffset;
 	protected:
 		void execute();

+ 1 - 0
src/vm_compiled_light.cpp

@@ -25,6 +25,7 @@ namespace randomx {
 
 	template<class Allocator, bool softAes>
 	void CompiledLightVm<Allocator, softAes>::setCache(randomx_cache* cache) {
+		cachePtr = cache;
 		mem.memory = cache->memory;
 		compiler.generateSuperscalarHash(cache->programs, cache->reciprocalCache);
 	}

+ 1 - 0
src/vm_compiled_light.hpp

@@ -44,6 +44,7 @@ namespace randomx {
 		using CompiledVm<Allocator, softAes>::compiler;
 		using CompiledVm<Allocator, softAes>::program;
 		using CompiledVm<Allocator, softAes>::config;
+		using CompiledVm<Allocator, softAes>::cachePtr;
 		using CompiledVm<Allocator, softAes>::datasetOffset;
 	};
 

+ 1 - 0
src/vm_interpreted.cpp

@@ -45,6 +45,7 @@ namespace randomx {
 
 	template<class Allocator, bool softAes>
 	void InterpretedVm<Allocator, softAes>::setDataset(randomx_dataset* dataset) {
+		datasetPtr = dataset;
 		mem.memory = dataset->memory;
 	}
 

+ 1 - 1
src/vm_interpreted.hpp

@@ -57,7 +57,7 @@ namespace randomx {
 		using VmBase<Allocator, softAes>::program;
 		using VmBase<Allocator, softAes>::config;
 		using VmBase<Allocator, softAes>::reg;
-		using VmBase<Allocator, softAes>::datasetBasePtr;
+		using VmBase<Allocator, softAes>::datasetPtr;
 		using VmBase<Allocator, softAes>::datasetOffset;
 		void* operator new(size_t size) {
 			void* ptr = AlignedAllocator<CacheLineSize>::allocMemory(size);

+ 1 - 1
src/vm_interpreted_light.cpp

@@ -24,8 +24,8 @@ namespace randomx {
 
 	template<class Allocator, bool softAes>
 	void InterpretedLightVm<Allocator, softAes>::setCache(randomx_cache* cache) {
-		mem.memory = cache->memory;
 		cachePtr = cache;
+		mem.memory = cache->memory;
 	}
 
 	template<class Allocator, bool softAes>

+ 1 - 2
src/vm_interpreted_light.hpp

@@ -28,6 +28,7 @@ namespace randomx {
 	class InterpretedLightVm : public InterpretedVm<Allocator, softAes> {
 	public:
 		using VmBase<Allocator, softAes>::mem;
+		using VmBase<Allocator, softAes>::cachePtr;
 		void* operator new(size_t size) {
 			void* ptr = AlignedAllocator<CacheLineSize>::allocMemory(size);
 			if (ptr == nullptr)
@@ -41,8 +42,6 @@ namespace randomx {
 		void setCache(randomx_cache* cache) override;
 	protected:
 		void datasetRead(uint32_t address, int_reg_t(&r)[8]) override;
-	private:
-		randomx_cache* cachePtr;
 	};
 
 	using InterpretedLightVmDefault = InterpretedLightVm<AlignedAllocator<CacheLineSize>, true>;