Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 //===- subzero/src/WasmTranslator.cpp - WASM to Subzero Translation -------===// | 1 //===- subzero/src/WasmTranslator.cpp - WASM to Subzero Translation -------===// |
| 2 // | 2 // |
| 3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
| 4 // | 4 // |
| 5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
| 6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
| 7 // | 7 // |
| 8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
| 9 /// | 9 /// |
| 10 /// \file | 10 /// \file |
| (...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 269 LOG(out << "Buffer(" << Count << ")\n"); | 269 LOG(out << "Buffer(" << Count << ")\n"); |
| 270 return Func->allocateArrayOf<Node>(Count); | 270 return Func->allocateArrayOf<Node>(Count); |
| 271 } | 271 } |
| 272 | 272 |
| 273 Node Error() { llvm::report_fatal_error("Error"); } | 273 Node Error() { llvm::report_fatal_error("Error"); } |
| 274 Node Start(uint32_t Params) { | 274 Node Start(uint32_t Params) { |
| 275 LOG(out << "Start(" << Params << ") = "); | 275 LOG(out << "Start(" << Params << ") = "); |
| 276 auto *Entry = Func->getEntryNode(); | 276 auto *Entry = Func->getEntryNode(); |
| 277 assert(Entry); | 277 assert(Entry); |
| 278 LOG(out << Node(Entry) << "\n"); | 278 LOG(out << Node(Entry) << "\n"); |
| 279 | |
| 280 // Load the WasmMemory address to make it available everywhere else in the | |
| 281 // function. | |
| 282 auto *WasmMemoryPtr = | |
| 283 Ctx->getConstantExternSym(Ctx->getGlobalString("WASM_MEMORY")); | |
| 284 assert(!WasmMemory); | |
|
Jim Stichnoth
2016/05/02 16:04:07
assert(WasmMemory == nullptr);
Eric Holk
2016/05/02 17:42:37
Done.
| |
| 285 auto *WasmMemoryV = makeVariable(getPointerType()); | |
| 286 Entry->appendInst(InstLoad::create(Func, WasmMemoryV, WasmMemoryPtr)); | |
| 287 WasmMemory = WasmMemoryV; | |
| 288 | |
| 279 return OperandNode(Entry); | 289 return OperandNode(Entry); |
| 280 } | 290 } |
| 281 Node Param(uint32_t Index, wasm::LocalType Type) { | 291 Node Param(uint32_t Index, wasm::LocalType Type) { |
| 282 LOG(out << "Param(" << Index << ") = "); | 292 LOG(out << "Param(" << Index << ") = "); |
| 283 auto *Arg = makeVariable(toIceType(Type)); | 293 auto *Arg = makeVariable(toIceType(Type)); |
| 284 assert(Index == NextArg); | 294 assert(Index == NextArg); |
| 285 Func->addArg(Arg); | 295 Func->addArg(Arg); |
| 286 ++NextArg; | 296 ++NextArg; |
| 287 LOG(out << Node(Arg) << "\n"); | 297 LOG(out << Node(Arg) << "\n"); |
| 288 return OperandNode(Arg); | 298 return OperandNode(Arg); |
| (...skipping 866 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1155 Node LoadGlobal(uint32_t Index) { | 1165 Node LoadGlobal(uint32_t Index) { |
| 1156 (void)Index; | 1166 (void)Index; |
| 1157 llvm::report_fatal_error("LoadGlobal"); | 1167 llvm::report_fatal_error("LoadGlobal"); |
| 1158 } | 1168 } |
| 1159 Node StoreGlobal(uint32_t Index, Node Val) { | 1169 Node StoreGlobal(uint32_t Index, Node Val) { |
| 1160 (void)Index; | 1170 (void)Index; |
| 1161 (void)Val; | 1171 (void)Val; |
| 1162 llvm::report_fatal_error("StoreGlobal"); | 1172 llvm::report_fatal_error("StoreGlobal"); |
| 1163 } | 1173 } |
| 1164 | 1174 |
| 1165 Operand *sanitizeAddress(Operand *Base, uint32_t Offset) { | |
|
Eric Holk
2016/04/29 22:37:42
This function is just moved down lower to make it
| |
| 1166 SizeT MemSize = Module->module->min_mem_pages * WASM_PAGE_SIZE; | |
| 1167 | |
| 1168 bool ConstZeroBase = false; | |
| 1169 | |
| 1170 // first, add the index and the offset together. | |
| 1171 if (auto *ConstBase = llvm::dyn_cast<ConstantInteger32>(Base)) { | |
| 1172 uint32_t RealOffset = Offset + ConstBase->getValue(); | |
| 1173 if (RealOffset >= MemSize) { | |
| 1174 // We've proven this will always be an out of bounds access, so insert | |
| 1175 // an unconditional trap. | |
| 1176 Control()->appendInst(InstUnreachable::create(Func)); | |
| 1177 // It doesn't matter what we return here, so return something that will | |
| 1178 // allow the rest of code generation to happen. | |
| 1179 // | |
| 1180 // We might be tempted to just abort translation here, but out of bounds | |
| 1181 // memory access is a runtime trap, not a compile error. | |
| 1182 return Ctx->getConstantZero(getPointerType()); | |
| 1183 } | |
| 1184 Base = Ctx->getConstantInt32(RealOffset); | |
| 1185 ConstZeroBase = (0 == RealOffset); | |
| 1186 } else if (0 != Offset) { | |
| 1187 auto *Addr = makeVariable(Ice::getPointerType()); | |
| 1188 auto *OffsetConstant = Ctx->getConstantInt32(Offset); | |
| 1189 Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Add, | |
| 1190 Addr, Base, OffsetConstant)); | |
| 1191 | |
| 1192 Base = Addr; | |
| 1193 } | |
| 1194 | |
| 1195 // Do the bounds check. | |
| 1196 // | |
| 1197 // TODO (eholk): Add a command line argument to control whether bounds | |
| 1198 // checks are inserted, and maybe add a way to duplicate bounds checks to | |
| 1199 // get a better sense of the overhead. | |
| 1200 if (!llvm::dyn_cast<ConstantInteger32>(Base)) { | |
| 1201 // TODO (eholk): creating a new basic block on every memory access is | |
| 1202 // terrible (see https://goo.gl/Zj7DTr). Try adding a new instruction that | |
| 1203 // encapsulates this "abort if false" pattern. | |
| 1204 auto *CheckPassed = Func->makeNode(); | |
| 1205 auto *CheckFailed = getBoundsFailTarget(); | |
| 1206 | |
| 1207 auto *Check = makeVariable(IceType_i1); | |
| 1208 Control()->appendInst(InstIcmp::create(Func, InstIcmp::Ult, Check, Base, | |
| 1209 Ctx->getConstantInt32(MemSize))); | |
| 1210 Control()->appendInst( | |
| 1211 InstBr::create(Func, Check, CheckPassed, CheckFailed)); | |
| 1212 | |
| 1213 *ControlPtr = OperandNode(CheckPassed); | |
| 1214 } | |
| 1215 | |
| 1216 Ice::Operand *RealAddr = nullptr; | |
| 1217 auto MemBase = Ctx->getConstantSym(0, Ctx->getGlobalString("WASM_MEMORY")); | |
| 1218 if (!ConstZeroBase) { | |
| 1219 auto RealAddrV = Func->makeVariable(Ice::getPointerType()); | |
| 1220 Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Add, | |
| 1221 RealAddrV, Base, MemBase)); | |
| 1222 | |
| 1223 RealAddr = RealAddrV; | |
| 1224 } else { | |
| 1225 RealAddr = MemBase; | |
| 1226 } | |
| 1227 return RealAddr; | |
| 1228 } | |
| 1229 | |
| 1230 Node LoadMem(wasm::LocalType Type, MachineType MemType, Node Index, | 1175 Node LoadMem(wasm::LocalType Type, MachineType MemType, Node Index, |
| 1231 uint32_t Offset) { | 1176 uint32_t Offset) { |
| 1232 LOG(out << "LoadMem." << toIceType(MemType) << "(" << Index << "[" << Offset | 1177 LOG(out << "LoadMem." << toIceType(MemType) << "(" << Index << "[" << Offset |
| 1233 << "]) = "); | 1178 << "]) = "); |
| 1234 | 1179 |
| 1235 auto *RealAddr = sanitizeAddress(Index, Offset); | 1180 auto *RealAddr = sanitizeAddress(Index, Offset); |
| 1236 | 1181 |
| 1237 auto *LoadResult = makeVariable(toIceType(MemType)); | 1182 auto *LoadResult = makeVariable(toIceType(MemType)); |
| 1238 Control()->appendInst(InstLoad::create(Func, LoadResult, RealAddr)); | 1183 Control()->appendInst(InstLoad::create(Func, LoadResult, RealAddr)); |
| 1239 | 1184 |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1311 GlobalContext *Ctx; | 1256 GlobalContext *Ctx; |
| 1312 | 1257 |
| 1313 CfgNode *BoundsFailTarget = nullptr; | 1258 CfgNode *BoundsFailTarget = nullptr; |
| 1314 CfgNode *IndirectFailTarget = nullptr; | 1259 CfgNode *IndirectFailTarget = nullptr; |
| 1315 | 1260 |
| 1316 SizeT NextArg = 0; | 1261 SizeT NextArg = 0; |
| 1317 | 1262 |
| 1318 CfgUnorderedMap<Operand *, InstPhi *> PhiMap; | 1263 CfgUnorderedMap<Operand *, InstPhi *> PhiMap; |
| 1319 CfgUnorderedMap<Operand *, CfgNode *> DefNodeMap; | 1264 CfgUnorderedMap<Operand *, CfgNode *> DefNodeMap; |
| 1320 | 1265 |
| 1266 Operand *WasmMemory = nullptr; | |
| 1267 | |
| 1321 InstPhi *getDefiningInst(Operand *Op) const { | 1268 InstPhi *getDefiningInst(Operand *Op) const { |
| 1322 const auto &Iter = PhiMap.find(Op); | 1269 const auto &Iter = PhiMap.find(Op); |
| 1323 if (Iter == PhiMap.end()) { | 1270 if (Iter == PhiMap.end()) { |
| 1324 return nullptr; | 1271 return nullptr; |
| 1325 } | 1272 } |
| 1326 return Iter->second; | 1273 return Iter->second; |
| 1327 } | 1274 } |
| 1328 | 1275 |
| 1329 void setDefiningInst(Operand *Op, InstPhi *Phi) { | 1276 void setDefiningInst(Operand *Op, InstPhi *Phi) { |
| 1330 LOG(out << "\n== setDefiningInst(" << Op << ", " << Phi << ") ==\n"); | 1277 LOG(out << "\n== setDefiningInst(" << Op << ", " << Phi << ") ==\n"); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1371 IndirectFailTarget->appendInst(InstCall::create( | 1318 IndirectFailTarget->appendInst(InstCall::create( |
| 1372 Func, 0, nullptr, | 1319 Func, 0, nullptr, |
| 1373 Ctx->getConstantExternSym(Ctx->getGlobalString("__Sz_indirect_fail")), | 1320 Ctx->getConstantExternSym(Ctx->getGlobalString("__Sz_indirect_fail")), |
| 1374 false)); | 1321 false)); |
| 1375 IndirectFailTarget->appendInst(InstUnreachable::create(Func)); | 1322 IndirectFailTarget->appendInst(InstUnreachable::create(Func)); |
| 1376 } | 1323 } |
| 1377 | 1324 |
| 1378 return IndirectFailTarget; | 1325 return IndirectFailTarget; |
| 1379 } | 1326 } |
| 1380 | 1327 |
| 1328 Operand *getWasmMemory() { | |
| 1329 assert(WasmMemory); | |
|
Jim Stichnoth
2016/05/02 16:04:07
assert(WasmMemory != nullptr);
I think we're pret
Eric Holk
2016/05/02 17:42:37
Done.
| |
| 1330 return WasmMemory; | |
| 1331 } | |
| 1332 | |
| 1333 Operand *sanitizeAddress(Operand *Base, uint32_t Offset) { | |
| 1334 SizeT MemSize = Module->module->min_mem_pages * WASM_PAGE_SIZE; | |
| 1335 | |
| 1336 bool ConstZeroBase = false; | |
| 1337 | |
| 1338 // first, add the index and the offset together. | |
| 1339 if (auto *ConstBase = llvm::dyn_cast<ConstantInteger32>(Base)) { | |
| 1340 uint32_t RealOffset = Offset + ConstBase->getValue(); | |
| 1341 if (RealOffset >= MemSize) { | |
| 1342 // We've proven this will always be an out of bounds access, so insert | |
| 1343 // an unconditional trap. | |
| 1344 Control()->appendInst(InstUnreachable::create(Func)); | |
| 1345 // It doesn't matter what we return here, so return something that will | |
| 1346 // allow the rest of code generation to happen. | |
| 1347 // | |
| 1348 // We might be tempted to just abort translation here, but out of bounds | |
| 1349 // memory access is a runtime trap, not a compile error. | |
| 1350 return Ctx->getConstantZero(getPointerType()); | |
| 1351 } | |
| 1352 Base = Ctx->getConstantInt32(RealOffset); | |
| 1353 ConstZeroBase = (0 == RealOffset); | |
| 1354 } else if (0 != Offset) { | |
| 1355 auto *Addr = makeVariable(Ice::getPointerType()); | |
| 1356 auto *OffsetConstant = Ctx->getConstantInt32(Offset); | |
| 1357 Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Add, | |
| 1358 Addr, Base, OffsetConstant)); | |
| 1359 | |
| 1360 Base = Addr; | |
| 1361 } | |
| 1362 | |
| 1363 // Do the bounds check. | |
| 1364 // | |
| 1365 // TODO (eholk): Add a command line argument to control whether bounds | |
| 1366 // checks are inserted, and maybe add a way to duplicate bounds checks to | |
| 1367 // get a better sense of the overhead. | |
| 1368 if (!llvm::dyn_cast<ConstantInteger32>(Base)) { | |
| 1369 // TODO (eholk): creating a new basic block on every memory access is | |
| 1370 // terrible (see https://goo.gl/Zj7DTr). Try adding a new instruction that | |
| 1371 // encapsulates this "abort if false" pattern. | |
| 1372 auto *CheckPassed = Func->makeNode(); | |
| 1373 auto *CheckFailed = getBoundsFailTarget(); | |
| 1374 | |
| 1375 auto *Check = makeVariable(IceType_i1); | |
| 1376 Control()->appendInst(InstIcmp::create(Func, InstIcmp::Ult, Check, Base, | |
| 1377 Ctx->getConstantInt32(MemSize))); | |
| 1378 Control()->appendInst( | |
| 1379 InstBr::create(Func, Check, CheckPassed, CheckFailed)); | |
| 1380 | |
| 1381 *ControlPtr = OperandNode(CheckPassed); | |
| 1382 } | |
| 1383 | |
| 1384 Ice::Operand *RealAddr = nullptr; | |
| 1385 auto MemBase = getWasmMemory(); | |
| 1386 if (!ConstZeroBase) { | |
| 1387 auto RealAddrV = Func->makeVariable(Ice::getPointerType()); | |
| 1388 Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Add, | |
| 1389 RealAddrV, Base, MemBase)); | |
| 1390 | |
| 1391 RealAddr = RealAddrV; | |
| 1392 } else { | |
| 1393 RealAddr = MemBase; | |
| 1394 } | |
| 1395 return RealAddr; | |
| 1396 } | |
| 1397 | |
| 1381 template <typename F = std::function<void(Ostream &)>> void log(F Fn) const { | 1398 template <typename F = std::function<void(Ostream &)>> void log(F Fn) const { |
| 1382 if (BuildDefs::dump() && (getFlags().getVerbose() & IceV_Wasm)) { | 1399 if (BuildDefs::dump() && (getFlags().getVerbose() & IceV_Wasm)) { |
| 1383 Fn(Ctx->getStrDump()); | 1400 Fn(Ctx->getStrDump()); |
| 1384 Ctx->getStrDump().flush(); | 1401 Ctx->getStrDump().flush(); |
| 1385 } | 1402 } |
| 1386 } | 1403 } |
| 1387 }; | 1404 }; |
| 1388 | 1405 |
| 1389 std::unique_ptr<Cfg> WasmTranslator::translateFunction(Zone *Zone, | 1406 std::unique_ptr<Cfg> WasmTranslator::translateFunction(Zone *Zone, |
| 1390 FunctionBody &Body) { | 1407 FunctionBody &Body) { |
| 1391 OstreamLocker L1(Ctx); | 1408 OstreamLocker L1(Ctx); |
| 1392 auto Func = Cfg::create(Ctx, getNextSequenceNumber()); | 1409 auto Func = Cfg::create(Ctx, getNextSequenceNumber()); |
| 1410 TimerMarker T(TimerStack::TT_wasmGenIce, Func.get()); | |
| 1393 Ice::CfgLocalAllocatorScope L2(Func.get()); | 1411 Ice::CfgLocalAllocatorScope L2(Func.get()); |
| 1394 | 1412 |
| 1395 // TODO(eholk): parse the function signature... | 1413 // TODO(eholk): parse the function signature... |
| 1396 | 1414 |
| 1397 Func->setEntryNode(Func->makeNode()); | 1415 Func->setEntryNode(Func->makeNode()); |
| 1398 | 1416 |
| 1399 IceBuilder Builder(Func.get()); | 1417 IceBuilder Builder(Func.get()); |
| 1400 SR_WasmDecoder<OperandNode, IceBuilder> Decoder(Zone, &Builder, Body); | 1418 SR_WasmDecoder<OperandNode, IceBuilder> Decoder(Zone, &Builder, Body); |
| 1401 | 1419 |
| 1402 LOG(out << getFlags().getDefaultGlobalPrefix() << "\n"); | 1420 LOG(out << getFlags().getDefaultGlobalPrefix() << "\n"); |
| 1403 Decoder.Decode(); | 1421 Decoder.Decode(); |
| 1404 | 1422 |
| 1405 // We don't always know where the incoming branches are in phi nodes, so this | 1423 // We don't always know where the incoming branches are in phi nodes, so this |
| 1406 // function finds them. | 1424 // function finds them. |
| 1407 Func->fixPhiNodes(); | 1425 Func->fixPhiNodes(); |
| 1408 | 1426 |
| 1409 Func->computeInOutEdges(); | 1427 Func->computeInOutEdges(); |
| 1410 | 1428 |
| 1411 return Func; | 1429 return Func; |
| 1412 } | 1430 } |
| 1413 | 1431 |
| 1414 constexpr SizeT InitialBufferSize = 16 << 10; // 16KB | 1432 constexpr SizeT InitialBufferSize = 16 << 10; // 16KB |
| 1415 | 1433 |
| 1416 WasmTranslator::WasmTranslator(GlobalContext *Ctx) | 1434 WasmTranslator::WasmTranslator(GlobalContext *Ctx) |
| 1417 : Translator(Ctx), Buffer(InitialBufferSize) {} | 1435 : Translator(Ctx), Buffer(InitialBufferSize) {} |
| 1418 | 1436 |
| 1419 void WasmTranslator::translate( | 1437 void WasmTranslator::translate( |
| 1420 const std::string &IRFilename, | 1438 const std::string &IRFilename, |
| 1421 std::unique_ptr<llvm::DataStreamer> InputStream) { | 1439 std::unique_ptr<llvm::DataStreamer> InputStream) { |
| 1440 TimerMarker T(TimerStack::TT_wasm, Ctx); | |
| 1441 | |
| 1422 LOG(out << "Initializing v8/wasm stuff..." | 1442 LOG(out << "Initializing v8/wasm stuff..." |
| 1423 << "\n"); | 1443 << "\n"); |
| 1424 Zone Zone; | 1444 Zone Zone; |
| 1425 ZoneScope _(&Zone); | 1445 ZoneScope _(&Zone); |
| 1426 | 1446 |
| 1427 SizeT BytesRead = 0; | 1447 SizeT BytesRead = 0; |
| 1428 while (true) { | 1448 while (true) { |
| 1429 BytesRead += | 1449 BytesRead += |
| 1430 InputStream->GetBytes(&Buffer[BytesRead], Buffer.size() - BytesRead); | 1450 InputStream->GetBytes(&Buffer[BytesRead], Buffer.size() - BytesRead); |
| 1431 LOG(out << "Read " << BytesRead << " bytes" | 1451 LOG(out << "Read " << BytesRead << " bytes" |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1526 Body.module = &ModuleEnv; | 1546 Body.module = &ModuleEnv; |
| 1527 | 1547 |
| 1528 LOG(out << "Translating " << IRFilename << "\n"); | 1548 LOG(out << "Translating " << IRFilename << "\n"); |
| 1529 | 1549 |
| 1530 { | 1550 { |
| 1531 unique_ptr<VariableDeclarationList> Globals = | 1551 unique_ptr<VariableDeclarationList> Globals = |
| 1532 makeUnique<VariableDeclarationList>(); | 1552 makeUnique<VariableDeclarationList>(); |
| 1533 | 1553 |
| 1534 // Global variables, etc go here. | 1554 // Global variables, etc go here. |
| 1535 auto *WasmMemory = VariableDeclaration::createExternal(Globals.get()); | 1555 auto *WasmMemory = VariableDeclaration::createExternal(Globals.get()); |
| 1536 WasmMemory->setName(Ctx->getGlobalString("WASM_MEMORY")); | 1556 WasmMemory->setName(Ctx->getGlobalString("WASM_DATA_INIT")); |
| 1537 | 1557 |
| 1538 // Fill in the segments | 1558 // Fill in the segments |
| 1539 SizeT WritePtr = 0; | 1559 SizeT WritePtr = 0; |
| 1540 for (const auto Seg : Module->data_segments) { | 1560 for (const auto Seg : Module->data_segments) { |
| 1541 // fill in gaps with zero. | 1561 // fill in gaps with zero. |
| 1542 if (Seg.dest_addr > WritePtr) { | 1562 if (Seg.dest_addr > WritePtr) { |
| 1543 WasmMemory->addInitializer(VariableDeclaration::ZeroInitializer::create( | 1563 WasmMemory->addInitializer(VariableDeclaration::ZeroInitializer::create( |
| 1544 Globals.get(), Seg.dest_addr - WritePtr)); | 1564 Globals.get(), Seg.dest_addr - WritePtr)); |
| 1545 WritePtr = Seg.dest_addr; | 1565 WritePtr = Seg.dest_addr; |
| 1546 } | 1566 } |
| 1547 | 1567 |
| 1548 // Add the data | 1568 // Add the data |
| 1549 WasmMemory->addInitializer(VariableDeclaration::DataInitializer::create( | 1569 WasmMemory->addInitializer(VariableDeclaration::DataInitializer::create( |
| 1550 Globals.get(), reinterpret_cast<const char *>(Module->module_start) + | 1570 Globals.get(), reinterpret_cast<const char *>(Module->module_start) + |
| 1551 Seg.source_offset, | 1571 Seg.source_offset, |
| 1552 Seg.source_size)); | 1572 Seg.source_size)); |
| 1553 | 1573 |
| 1554 WritePtr += Seg.source_size; | 1574 WritePtr += Seg.source_size; |
| 1555 } | 1575 } |
| 1556 | 1576 |
| 1557 // Save the size of the initialized data in a global variable so the runtime | 1577 // Save the size of the initialized data in a global variable so the runtime |
| 1558 // can use it to determine the initial heap break. | 1578 // can use it to determine the initial heap break. |
| 1559 auto *GlobalDataSize = VariableDeclaration::createExternal(Globals.get()); | 1579 auto *GlobalDataSize = VariableDeclaration::createExternal(Globals.get()); |
| 1560 GlobalDataSize->setName(Ctx->getGlobalString("WASM_DATA_SIZE")); | 1580 GlobalDataSize->setName(Ctx->getGlobalString("WASM_DATA_SIZE")); |
| 1561 GlobalDataSize->addInitializer(VariableDeclaration::DataInitializer::create( | 1581 GlobalDataSize->addInitializer(VariableDeclaration::DataInitializer::create( |
| 1562 Globals.get(), reinterpret_cast<const char *>(&WritePtr), | 1582 Globals.get(), reinterpret_cast<const char *>(&WritePtr), |
| 1563 sizeof(WritePtr))); | 1583 sizeof(WritePtr))); |
| 1564 | 1584 |
| 1565 // Pad the rest with zeros | |
| 1566 SizeT DataSize = Module->min_mem_pages * WASM_PAGE_SIZE; | |
| 1567 if (WritePtr < DataSize) { | |
| 1568 WasmMemory->addInitializer(VariableDeclaration::ZeroInitializer::create( | |
| 1569 Globals.get(), DataSize - WritePtr)); | |
| 1570 } | |
| 1571 | |
| 1572 // Save the number of pages for the runtime | 1585 // Save the number of pages for the runtime |
| 1573 auto *GlobalNumPages = VariableDeclaration::createExternal(Globals.get()); | 1586 auto *GlobalNumPages = VariableDeclaration::createExternal(Globals.get()); |
| 1574 GlobalNumPages->setName(Ctx->getGlobalString("WASM_NUM_PAGES")); | 1587 GlobalNumPages->setName(Ctx->getGlobalString("WASM_NUM_PAGES")); |
| 1575 GlobalNumPages->addInitializer(VariableDeclaration::DataInitializer::create( | 1588 GlobalNumPages->addInitializer(VariableDeclaration::DataInitializer::create( |
| 1576 Globals.get(), reinterpret_cast<const char *>(&Module->min_mem_pages), | 1589 Globals.get(), reinterpret_cast<const char *>(&Module->min_mem_pages), |
| 1577 sizeof(Module->min_mem_pages))); | 1590 sizeof(Module->min_mem_pages))); |
| 1578 | 1591 |
| 1579 Globals->push_back(WasmMemory); | 1592 Globals->push_back(WasmMemory); |
| 1580 Globals->push_back(GlobalDataSize); | 1593 Globals->push_back(GlobalDataSize); |
| 1581 Globals->push_back(GlobalNumPages); | 1594 Globals->push_back(GlobalNumPages); |
| 1582 | 1595 |
| 1583 lowerGlobals(std::move(Globals)); | 1596 lowerGlobals(std::move(Globals)); |
| 1584 } | 1597 } |
| 1585 | 1598 |
| 1586 // Translate each function. | 1599 // Translate each function. |
| 1587 for (const auto Fn : Module->functions) { | 1600 for (const auto Fn : Module->functions) { |
| 1588 const auto FnName = getFunctionName(Module, Fn.func_index); | 1601 const auto FnName = getFunctionName(Module, Fn.func_index); |
| 1589 | 1602 |
| 1590 LOG(out << " " << Fn.func_index << ": " << FnName << "..."); | 1603 LOG(out << " " << Fn.func_index << ": " << FnName << "..."); |
| 1591 | 1604 |
| 1592 Body.sig = Fn.sig; | 1605 Body.sig = Fn.sig; |
| 1593 Body.base = Buffer.data(); | 1606 Body.base = Buffer.data(); |
| 1594 Body.start = Buffer.data() + Fn.code_start_offset; | 1607 Body.start = Buffer.data() + Fn.code_start_offset; |
| 1595 Body.end = Buffer.data() + Fn.code_end_offset; | 1608 Body.end = Buffer.data() + Fn.code_end_offset; |
| 1596 | 1609 |
| 1597 auto Func = translateFunction(&Zone, Body); | 1610 std::unique_ptr<Cfg> Func = nullptr; |
| 1598 Func->setFunctionName(Ctx->getGlobalString(FnName)); | 1611 { |
| 1599 | 1612 TimerMarker T_func(getContext(), FnName); |
| 1613 Func = translateFunction(&Zone, Body); | |
| 1614 Func->setFunctionName(Ctx->getGlobalString(FnName)); | |
| 1615 } | |
| 1600 Ctx->optQueueBlockingPush(makeUnique<CfgOptWorkItem>(std::move(Func))); | 1616 Ctx->optQueueBlockingPush(makeUnique<CfgOptWorkItem>(std::move(Func))); |
| 1601 LOG(out << "done.\n"); | 1617 LOG(out << "done.\n"); |
| 1602 } | 1618 } |
| 1603 | 1619 |
| 1604 return; | 1620 return; |
| 1605 } | 1621 } |
| 1606 | 1622 |
| 1607 #endif // ALLOW_WASM | 1623 #endif // ALLOW_WASM |
| OLD | NEW |