static void testSetIterator() { // Add 1..9 to a HashSet. HashSet<Uptr> a; for(Uptr i = 1;i < 10;++i) { a.add(i); } // 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 = 45 { Uptr sum = 0; for(Uptr i : a) { sum += i; } errorUnless(sum == 45); } // Remove 5. a.remove(5); // 1 + 2 + 3 + 4 + 6 + 7 + 8 + 9 = 40 { Uptr sum = 0; for(Uptr i : a) { sum += i; } errorUnless(sum == 40); } }
Runtime::ModuleInstance* instantiateModule( Runtime::Compartment* compartment, const Intrinsics::Module& moduleRef, std::string&& debugName, const HashMap<std::string,Runtime::Object*>& extraExports) { auto moduleInstance = new Runtime::ModuleInstance(compartment,{},{},{},{},{},std::move(debugName)); if(moduleRef.impl) { for(const auto& pair : moduleRef.impl->functionMap) { auto functionInstance = pair.value->instantiate(compartment); moduleInstance->functions.push_back(functionInstance); errorUnless(moduleInstance->exportMap.add(pair.key, functionInstance)); } for(const auto& pair : moduleRef.impl->tableMap) { auto tableInstance = pair.value->instantiate(compartment); moduleInstance->tables.push_back(tableInstance); errorUnless(moduleInstance->exportMap.add(pair.key, tableInstance)); } for(const auto& pair : moduleRef.impl->memoryMap) { auto memoryInstance = pair.value->instantiate(compartment); moduleInstance->memories.push_back(memoryInstance); errorUnless(moduleInstance->exportMap.add(pair.key, memoryInstance)); } for(const auto& pair : moduleRef.impl->globalMap) { auto globalInstance = pair.value->instantiate(compartment); moduleInstance->globals.push_back(globalInstance); errorUnless(moduleInstance->exportMap.add(pair.key, globalInstance)); } for(const auto& pair : extraExports) { Runtime::Object* object = pair.value; moduleInstance->exportMap.set(pair.key, object); switch(object->kind) { case Runtime::ObjectKind::function: moduleInstance->functions.push_back(asFunction(object)); break; case Runtime::ObjectKind::table: moduleInstance->tables.push_back(asTable(object)); break; case Runtime::ObjectKind::memory: moduleInstance->memories.push_back(asMemory(object)); break; case Runtime::ObjectKind::global: moduleInstance->globals.push_back(asGlobal(object)); break; case Runtime::ObjectKind::exceptionTypeInstance: moduleInstance->exceptionTypeInstances.push_back(asExceptionTypeInstance(object)); break; default: Errors::unreachable(); }; } } return moduleInstance; }
static void testMapSet() { HashMap<Uptr, Uptr> map; errorUnless(!map.get(0)); errorUnless(map.set(0, 1) == 1); errorUnless(*map.get(0) == 1); errorUnless(map.set(0, 3) == 3); errorUnless(*map.get(0) == 3); }
static void testSetMove() { // Add 1000..1999 to a HashSet. HashSet<Uptr> a; for(Uptr i = 0;i < 1000;++i) { a.add(i + 1000); } // Move the set to a new HashSet. HashSet<Uptr> b {std::move(a)}; // Test that the new HashSet contains the expected numbers. for(Uptr i = 0;i < 1000;++i) { errorUnless(!b.contains(i)); errorUnless(b.contains(i + 1000)); errorUnless(!b.contains(i + 2000)); } // Test moving the set to itself. b = std::move(b); // Test that the set wasn't changed by the move-to-self. for(Uptr i = 0;i < 1000;++i) { errorUnless(!b.contains(i)); errorUnless(b.contains(i + 1000)); errorUnless(!b.contains(i + 2000)); } }
static void testMapMove() { // Add 1000..1999 to a HashMap. HashMap<Uptr, Uptr> a; for(Uptr i = 0;i < 1000;++i) { a.add(i + 1000, i); } // Move the map to a new HashMap. HashMap<Uptr, Uptr> b {std::move(a)}; // Test that the new HashMap contains the expected numbers. for(Uptr i = 0;i < 1000;++i) { errorUnless(!b.get(i)); errorUnless(*b.get(i + 1000) == i); errorUnless(!b.get(i + 2000)); } // Test moving the map to itself. b = std::move(b); // Test that the map wasn't changed by the move-to-self. for(Uptr i = 0;i < 1000;++i) { errorUnless(!b.get(i)); errorUnless(*b.get(i + 1000) == i); errorUnless(!b.get(i + 2000)); } }
static void testMapBracketOperator() { HashMap<Uptr, Uptr> map {{1,1},{3,2},{5,3},{7,4},{11,5},{13,6},{17,7}}; errorUnless(map[1] == 1); errorUnless(map[3] == 2); errorUnless(map[5] == 3); errorUnless(map[7] == 4); errorUnless(map[11] == 5); errorUnless(map[13] == 6); errorUnless(map[17] == 7); }
static void testSetBracketOperator() { HashSet<Uptr> set {1,3,5,7,11,13,17}; errorUnless(set[1] == 1); errorUnless(set[3] == 3); errorUnless(set[5] == 5); errorUnless(set[7] == 7); errorUnless(set[11] == 11); errorUnless(set[13] == 13); errorUnless(set[17] == 17); }
static void testMapIterator() { // Add 1..9 to a HashMap. HashMap<Uptr, Uptr> a; for(Uptr i = 1;i < 10;++i) { a.add(i, i * 2); } // 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 = 45 { Uptr keySum = 0; Uptr valueSum = 0; for(const auto& pair : a) { keySum += pair.key; valueSum += pair.value; } errorUnless(keySum == 45); errorUnless(valueSum == 90); } // Remove 5. a.remove(5); // 1 + 2 + 3 + 4 + 6 + 7 + 8 + 9 = 40 { Uptr keySum = 0; Uptr valueSum = 0; for(const auto& pair : a) { keySum += pair.key; valueSum += pair.value; } errorUnless(keySum == 40); errorUnless(valueSum == 80); } }
static void testMapGetOrAdd() { HashMap<Uptr, Uptr> map; errorUnless(!map.get(0)); errorUnless(map.getOrAdd(0, 1) == 1); errorUnless(*map.get(0) == 1); errorUnless(map.getOrAdd(0, 3) == 1); errorUnless(*map.get(0) == 1); errorUnless((map.getOrAdd(0, 5) += 7) == 8); errorUnless(*map.get(0) == 8); }
static void testStringSet() { enum { numStrings = 1000 }; HashSet<std::string> set; std::vector<std::string> strings; srand(0); for(Uptr i = 0;i < numStrings;++i) { while(true) { std::string randomString = generateRandomString(); bool alreadySawString = false; for(const std::string& string : strings) { if(string == randomString) { alreadySawString = true; break; } } if(!alreadySawString) { strings.push_back(std::move(randomString)); break; } }; } for(Uptr i = 0;i < strings.size();++i) { errorUnless(set.add(strings[i])); errorUnless(!set.add(strings[i])); for(Uptr j = 0;j < strings.size();++j) { const bool expectedContains = j <= i; errorUnless(set.contains(strings[j]) == expectedContains); } } for(Uptr i = 0;i < strings.size();++i) { errorUnless(set.remove(strings[i])); errorUnless(!set.remove(strings[i])); for(Uptr j = 0;j < strings.size();++j) { const bool expectedContains = j > i; errorUnless(set.contains(strings[j]) == expectedContains); } } }
static void testMapEmplace() { HashMap<Uptr, EmplacedValue> map; EmplacedValue& a = map.getOrAdd(0, "a", "b"); errorUnless(a.a == "a"); errorUnless(a.b == "b"); errorUnless(map.add(1, "c", "d")); const EmplacedValue& b = *map.get(1); errorUnless(b.a == "c"); errorUnless(b.b == "d"); EmplacedValue& c = map.set(2, "e", "f"); errorUnless(c.a == "e"); errorUnless(c.b == "f"); EmplacedValue& d = map.getOrAdd(2, "g", "h"); errorUnless(d.a == "e"); errorUnless(d.b == "f"); }
Value evaluateInitializer(ModuleInstance* moduleInstance,InitializerExpression expression) { switch(expression.type) { case InitializerExpression::Type::i32_const: return expression.i32; case InitializerExpression::Type::i64_const: return expression.i64; case InitializerExpression::Type::f32_const: return expression.f32; case InitializerExpression::Type::f64_const: return expression.f64; case InitializerExpression::Type::get_global: { // Find the import this refers to. errorUnless(expression.globalIndex < moduleInstance->globals.size()); GlobalInstance* globalInstance = moduleInstance->globals[expression.globalIndex]; return Runtime::Value(globalInstance->type.valueType,globalInstance->value); } default: Errors::unreachable(); }; }
static void testU32Set() { HashSet<U32> set; enum { maxI = 1024 * 1024 }; for(Uptr i = 0;i < maxI;++i) { errorUnless(!set.contains(U32(i))); } errorUnless(set.size() == 0); for(Uptr i = 0;i < maxI;++i) { errorUnless(!set.contains(U32(i))); errorUnless(!set.get(U32(i))); errorUnless(set.add(U32(i))); errorUnless(set.contains(U32(i))); errorUnless(set.get(U32(i))); errorUnless(set.size() == i + 1); } for(Uptr i = 0;i < maxI;++i) { errorUnless(set.contains(U32(i))); errorUnless(set.remove(U32(i))); errorUnless(!set.contains(U32(i))); errorUnless(set.size() == maxI - i - 1); } for(Uptr i = 0;i < maxI;++i) { errorUnless(!set.contains(U32(i))); } }
static void testStringMap() { enum { numStrings = 1000 }; HashMap<std::string, U32> map; std::vector<HashMapPair<std::string, U32>> pairs; srand(0); for(Uptr i = 0;i < numStrings;++i) { while(true) { std::string randomString = generateRandomString(); bool alreadySawString = false; for(const HashMapPair<std::string, U32>& pair : pairs) { if(pair.key == randomString) { alreadySawString = true; break; } } if(!alreadySawString) { pairs.emplace_back(std::move(randomString), rand()); break; } }; } for(Uptr i = 0;i < pairs.size();++i) { errorUnless(map.add(pairs[i].key, pairs[i].value)); errorUnless(!map.add(pairs[i].key, pairs[i].value)); for(Uptr j = 0;j < pairs.size();++j) { const U32* valuePtr = map.get(pairs[j].key); if(j <= i) { errorUnless(valuePtr && *valuePtr == pairs[j].value); } else { errorUnless(!valuePtr); } } } for(Uptr i = 0;i < pairs.size();++i) { errorUnless(map.remove(pairs[i].key)); errorUnless(!map.remove(pairs[i].key)); for(Uptr j = 0;j < pairs.size();++j) { const U32* valuePtr = map.get(pairs[j].key); if(j > i) { errorUnless(valuePtr && *valuePtr == pairs[j].value); } else { errorUnless(!valuePtr); } } } }
static void testSetInitializerList() { HashSet<Uptr> set {1,3,5,7,11,13,17}; errorUnless(!set.contains(0)); errorUnless( set.contains(1)); errorUnless(!set.contains(2)); errorUnless( set.contains(3)); errorUnless(!set.contains(4)); errorUnless( set.contains(5)); errorUnless(!set.contains(6)); errorUnless( set.contains(7)); errorUnless(!set.contains(8)); errorUnless(!set.contains(9)); errorUnless(!set.contains(10)); errorUnless( set.contains(11)); errorUnless(!set.contains(12)); errorUnless( set.contains(13)); errorUnless(!set.contains(14)); errorUnless(!set.contains(15)); errorUnless(!set.contains(16)); errorUnless( set.contains(17)); }
static void testMapInitializerList() { HashMap<Uptr, Uptr> map {{1,1},{3,2},{5,3},{7,4},{11,5},{13,6},{17,7}}; errorUnless(!map.get(0)); errorUnless(*map.get(1) == 1); errorUnless(!map.get(2)); errorUnless(*map.get(3) == 2); errorUnless(!map.get(4)); errorUnless(*map.get(5) == 3); errorUnless(!map.get(6)); errorUnless(*map.get(7) == 4); errorUnless(!map.get(8)); errorUnless(!map.get(9)); errorUnless(!map.get(10)); errorUnless(*map.get(11) == 5); errorUnless(!map.get(12)); errorUnless(*map.get(13) == 6); errorUnless(!map.get(14)); errorUnless(!map.get(15)); errorUnless(!map.get(16)); errorUnless(*map.get(17) == 7); }
static void testSetCopy() { // Add 1000..1999 to a HashSet. HashSet<Uptr> a; for(Uptr i = 0;i < 1000;++i) { a.add(i + 1000); } // Copy the set to a new HashSet. HashSet<Uptr> b {a}; // Test that both the new and old HashSet contain the expected numbers. for(Uptr i = 0;i < 1000;++i) { errorUnless(!a.contains(i)); errorUnless(a.contains(i + 1000)); errorUnless(!a.contains(i + 2000)); errorUnless(!b.contains(i)); errorUnless(b.contains(i + 1000)); errorUnless(!b.contains(i + 2000)); } // Test copying a set from itself. b = b; // Test that the set wasn't changed by the copy-to-self. for(Uptr i = 0;i < 1000;++i) { errorUnless(!b.contains(i)); errorUnless(b.contains(i + 1000)); errorUnless(!b.contains(i + 2000)); } // Test removing an element from the set. b.remove(1000); errorUnless(a.contains(1000)); errorUnless(!b.contains(1000)); }
static Uptr getLineOffset(const LineInfo* lineInfo,Uptr lineIndex) { errorUnless(lineIndex < lineInfo->numLineStarts); return lineInfo->lineStarts[lineIndex]; }
static void testMapCopy() { // Add 1000..1999 to a HashMap. HashMap<Uptr, Uptr> a; for(Uptr i = 0;i < 1000;++i) { a.add(i + 1000,i); } // Copy the map to a new HashMap. HashMap<Uptr, Uptr> b {a}; // Test that both the new and old HashMap contain the expected numbers. for(Uptr i = 0;i < 1000;++i) { errorUnless(!a.get(i)); errorUnless(*a.get(i + 1000) == i); errorUnless(!a.get(i + 2000)); errorUnless(!b.get(i)); errorUnless(*b.get(i + 1000) == i); errorUnless(!b.get(i + 2000)); } // Test copying a map from itself. b = b; // Test that the map wasn't changed by the copy-to-self. for(Uptr i = 0;i < 1000;++i) { errorUnless(!b.get(i)); errorUnless(*b.get(i + 1000) == i); errorUnless(!b.get(i + 2000)); } // Test removing an element from the map. b.remove(1000); errorUnless(*a.get(1000) == 0); errorUnless(!b.get(1000)); }
ModuleInstance* instantiateModule(const IR::Module& module,ImportBindings&& imports) { ModuleInstance* moduleInstance = new ModuleInstance( std::move(imports.functions), std::move(imports.tables), std::move(imports.memories), std::move(imports.globals) ); // Get disassembly names for the module's objects. DisassemblyNames disassemblyNames; IR::getDisassemblyNames(module,disassemblyNames); // Check the type of the ModuleInstance's imports. errorUnless(moduleInstance->functions.size() == module.functions.imports.size()); for(Uptr importIndex = 0;importIndex < module.functions.imports.size();++importIndex) { errorUnless(isA(moduleInstance->functions[importIndex],module.types[module.functions.imports[importIndex].type.index])); } errorUnless(moduleInstance->tables.size() == module.tables.imports.size()); for(Uptr importIndex = 0;importIndex < module.tables.imports.size();++importIndex) { errorUnless(isA(moduleInstance->tables[importIndex],module.tables.imports[importIndex].type)); } errorUnless(moduleInstance->memories.size() == module.memories.imports.size()); for(Uptr importIndex = 0;importIndex < module.memories.imports.size();++importIndex) { errorUnless(isA(moduleInstance->memories[importIndex],module.memories.imports[importIndex].type)); } errorUnless(moduleInstance->globals.size() == module.globals.imports.size()); for(Uptr importIndex = 0;importIndex < module.globals.imports.size();++importIndex) { errorUnless(isA(moduleInstance->globals[importIndex],module.globals.imports[importIndex].type)); } // Instantiate the module's memory and table definitions. for(const TableDef& tableDef : module.tables.defs) { auto table = createTable(tableDef.type); if(!table) { causeException(Exception::Cause::outOfMemory); } moduleInstance->tables.push_back(table); } for(const MemoryDef& memoryDef : module.memories.defs) { if(!MemoryInstance::theMemoryInstance) { MemoryInstance::theMemoryInstance = createMemory(memoryDef.type); if(!MemoryInstance::theMemoryInstance) { causeException(Exception::Cause::outOfMemory); } } moduleInstance->memories.push_back(MemoryInstance::theMemoryInstance); } // Find the default memory and table for the module. if(moduleInstance->memories.size() != 0) { assert(moduleInstance->memories.size() == 1); moduleInstance->defaultMemory = moduleInstance->memories[0]; } if(moduleInstance->tables.size() != 0) { assert(moduleInstance->tables.size() == 1); moduleInstance->defaultTable = moduleInstance->tables[0]; } // If any memory or table segment doesn't fit, throw an exception before mutating any memory/table. for(auto& tableSegment : module.tableSegments) { TableInstance* table = moduleInstance->tables[tableSegment.tableIndex]; const Value baseOffsetValue = evaluateInitializer(moduleInstance,tableSegment.baseOffset); errorUnless(baseOffsetValue.type == ValueType::i32); const U32 baseOffset = baseOffsetValue.i32; if(baseOffset > table->elements.size() || table->elements.size() - baseOffset < tableSegment.indices.size()) { causeException(Exception::Cause::invalidSegmentOffset); } } //Previously, the module instantiation would write in to the memoryInstance here. Don't do that //since the memoryInstance is shared across all moduleInstances and we could be compiling //a new instance while another instance is running // Instantiate the module's global definitions. for(const GlobalDef& globalDef : module.globals.defs) { const Value initialValue = evaluateInitializer(moduleInstance,globalDef.initializer); errorUnless(initialValue.type == globalDef.type.valueType); moduleInstance->globals.push_back(new GlobalInstance(globalDef.type,initialValue)); } // Create the FunctionInstance objects for the module's function definitions. for(Uptr functionDefIndex = 0;functionDefIndex < module.functions.defs.size();++functionDefIndex) { const Uptr functionIndex = moduleInstance->functions.size(); const DisassemblyNames::Function& functionNames = disassemblyNames.functions[functionIndex]; std::string debugName = functionNames.name; if(!debugName.size()) { debugName = "<function #" + std::to_string(functionDefIndex) + ">"; } auto functionInstance = new FunctionInstance(moduleInstance,module.types[module.functions.defs[functionDefIndex].type.index],nullptr,debugName.c_str()); moduleInstance->functionDefs.push_back(functionInstance); moduleInstance->functions.push_back(functionInstance); } // Generate machine code for the module. LLVMJIT::instantiateModule(module,moduleInstance); // Set up the instance's exports. for(const Export& exportIt : module.exports) { ObjectInstance* exportedObject = nullptr; switch(exportIt.kind) { case ObjectKind::function: exportedObject = moduleInstance->functions[exportIt.index]; break; case ObjectKind::table: exportedObject = moduleInstance->tables[exportIt.index]; break; case ObjectKind::memory: exportedObject = moduleInstance->memories[exportIt.index]; break; case ObjectKind::global: exportedObject = moduleInstance->globals[exportIt.index]; break; default: Errors::unreachable(); } moduleInstance->exportMap[exportIt.name] = exportedObject; } // Copy the module's table segments into the module's default table. for(const TableSegment& tableSegment : module.tableSegments) { TableInstance* table = moduleInstance->tables[tableSegment.tableIndex]; const Value baseOffsetValue = evaluateInitializer(moduleInstance,tableSegment.baseOffset); errorUnless(baseOffsetValue.type == ValueType::i32); const U32 baseOffset = baseOffsetValue.i32; assert(baseOffset + tableSegment.indices.size() <= table->elements.size()); for(Uptr index = 0;index < tableSegment.indices.size();++index) { const Uptr functionIndex = tableSegment.indices[index]; assert(functionIndex < moduleInstance->functions.size()); setTableElement(table,baseOffset + index,moduleInstance->functions[functionIndex]); } } // Call the module's start function. if(module.startFunctionIndex != UINTPTR_MAX) { assert(moduleInstance->functions[module.startFunctionIndex]->type == IR::FunctionType::get()); moduleInstance->startFunctionIndex = module.startFunctionIndex; } moduleInstances.push_back(moduleInstance); return moduleInstance; }
static void testU32Map() { HashMap<U32, U32> map; enum { maxI = 1024 * 1024 }; for(Uptr i = 0;i < maxI;++i) { errorUnless(!map.contains(U32(i))); } errorUnless(map.size() == 0); for(Uptr i = 0;i < maxI;++i) { errorUnless(!map.contains(U32(i))); errorUnless(!map.get(U32(i))); errorUnless(map.add(U32(i),U32(i * 2))); errorUnless(map.contains(U32(i))); errorUnless(map.get(U32(i))); errorUnless(*map.get(U32(i)) == U32(i * 2)); errorUnless(map.size() == i + 1); } for(Uptr i = 0;i < maxI;++i) { errorUnless(map.contains(U32(i))); errorUnless(map.remove(U32(i))); errorUnless(!map.contains(U32(i))); errorUnless(map.size() == maxI - i - 1); } for(Uptr i = 0;i < maxI;++i) { errorUnless(!map.contains(U32(i))); } }