Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(30)

Side by Side Diff: src/WasmTranslator.cpp

Issue 1913153003: Subzero. Wasm. Implement sbrk and correctly do bounds checks. (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
Patch Set: Cleanup Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« runtime/wasm-runtime.cpp ('K') | « runtime/wasm-runtime.cpp ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 1047 matching lines...) Expand 10 before | Expand all | Expand 10 after
1058 LOG(out << "Call Result = " << Node(Dest) << "\n"); 1058 LOG(out << "Call Result = " << Node(Dest) << "\n");
1059 return OperandNode(Dest); 1059 return OperandNode(Dest);
1060 } 1060 }
1061 Node CallIndirect(uint32_t SigIndex, Node *Args) { 1061 Node CallIndirect(uint32_t SigIndex, Node *Args) {
1062 LOG(out << "CallIndirect(" << SigIndex << ")\n"); 1062 LOG(out << "CallIndirect(" << SigIndex << ")\n");
1063 // TODO(eholk): Compile to something better than a switch. 1063 // TODO(eholk): Compile to something better than a switch.
1064 const auto *Module = this->Module->module; 1064 const auto *Module = this->Module->module;
1065 assert(Module); 1065 assert(Module);
1066 const auto &IndirectTable = Module->function_table; 1066 const auto &IndirectTable = Module->function_table;
1067 1067
1068 // TODO(eholk): This should probably actually call abort instead. 1068 auto *Abort = getAbortTarget();
1069 auto *Abort = Func->makeNode();
1070 Abort->appendInst(InstUnreachable::create(Func));
1071 1069
1072 assert(Args[0].toOperand()); 1070 assert(Args[0].toOperand());
1073 1071
1074 auto *Switch = InstSwitch::create(Func, IndirectTable.size(), 1072 auto *Switch = InstSwitch::create(Func, IndirectTable.size(),
1075 Args[0].toOperand(), Abort); 1073 Args[0].toOperand(), Abort);
1076 assert(Abort); 1074 assert(Abort);
1077 1075
1078 const bool HasReturn = Module->signatures[SigIndex]->return_count() != 0; 1076 const bool HasReturn = Module->signatures[SigIndex]->return_count() != 0;
1079 const Ice::Type DestTy = 1077 const Ice::Type DestTy =
1080 HasReturn ? toIceType(Module->signatures[SigIndex]->GetReturn()) 1078 HasReturn ? toIceType(Module->signatures[SigIndex]->GetReturn())
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
1130 llvm::report_fatal_error("LoadGlobal"); 1128 llvm::report_fatal_error("LoadGlobal");
1131 } 1129 }
1132 Node StoreGlobal(uint32_t Index, Node Val) { 1130 Node StoreGlobal(uint32_t Index, Node Val) {
1133 (void)Index; 1131 (void)Index;
1134 (void)Val; 1132 (void)Val;
1135 llvm::report_fatal_error("StoreGlobal"); 1133 llvm::report_fatal_error("StoreGlobal");
1136 } 1134 }
1137 1135
1138 Operand *sanitizeAddress(Operand *Base, uint32_t Offset) { 1136 Operand *sanitizeAddress(Operand *Base, uint32_t Offset) {
1139 SizeT MemSize = Module->module->min_mem_pages * WASM_PAGE_SIZE; 1137 SizeT MemSize = Module->module->min_mem_pages * WASM_PAGE_SIZE;
1140 SizeT MemMask = MemSize - 1;
1141 1138
1142 bool ConstZeroBase = false; 1139 bool ConstZeroBase = false;
1143 1140
1144 // first, add the index and the offset together. 1141 // first, add the index and the offset together.
1145 if (auto *ConstBase = llvm::dyn_cast<ConstantInteger32>(Base)) { 1142 if (auto *ConstBase = llvm::dyn_cast<ConstantInteger32>(Base)) {
1146 uint32_t RealOffset = Offset + ConstBase->getValue(); 1143 uint32_t RealOffset = Offset + ConstBase->getValue();
1147 RealOffset &= MemMask; 1144 if (RealOffset >= MemSize) {
1145 // We've proven this will always be an out of bounds access, so insert
1146 // an unconditional trap.
1147 Control()->appendInst(InstUnreachable::create(Func));
1148 // It doesn't matter what we return here, so return something that will
1149 // allow the rest of code generation to happen.
1150 //
1151 // We might be tempted to just abort translation here, but out of bounds
1152 // memory access is a runtime trap, not a compile error.
1153 return Base;
Jim Stichnoth 2016/04/22 20:48:54 Another possibility is GlobalContext::getConstantZ
Eric Holk 2016/04/22 22:32:48 Returning 0 is better. It means that even this der
1154 }
1148 Base = Ctx->getConstantInt32(RealOffset); 1155 Base = Ctx->getConstantInt32(RealOffset);
1149 ConstZeroBase = (0 == RealOffset); 1156 ConstZeroBase = (0 == RealOffset);
1150 } else if (0 != Offset) { 1157 } else if (0 != Offset) {
1151 auto *Addr = makeVariable(Ice::getPointerType()); 1158 auto *Addr = makeVariable(Ice::getPointerType());
1152 auto *OffsetConstant = Ctx->getConstantInt32(Offset); 1159 auto *OffsetConstant = Ctx->getConstantInt32(Offset);
1153 Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Add, 1160 Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Add,
1154 Addr, Base, OffsetConstant)); 1161 Addr, Base, OffsetConstant));
1155 1162
1156 Base = Addr; 1163 Base = Addr;
1157 } 1164 }
1158 1165
1166 // Do the bounds check.
Jim Stichnoth 2016/04/22 20:48:54 Maybe in a separate CL, but can you add a flag to
Eric Holk 2016/04/22 22:32:48 I added a TODO.
1159 if (!llvm::dyn_cast<ConstantInteger32>(Base)) { 1167 if (!llvm::dyn_cast<ConstantInteger32>(Base)) {
1160 auto *ClampedAddr = makeVariable(Ice::getPointerType()); 1168 auto *CheckPassed = Func->makeNode();
1169 auto *CheckFailed = getAbortTarget();
1170
1171 auto *Check = makeVariable(IceType_i1);
1172 Control()->appendInst(InstIcmp::create(Func, InstIcmp::Ult, Check, Base,
1173 Ctx->getConstantInt32(MemSize)));
1161 Control()->appendInst( 1174 Control()->appendInst(
1162 InstArithmetic::create(Func, InstArithmetic::And, ClampedAddr, Base, 1175 InstBr::create(Func, Check, CheckPassed, CheckFailed));
1163 Ctx->getConstantInt32(MemSize - 1))); 1176
1164 Base = ClampedAddr; 1177 *ControlPtr = OperandNode(CheckPassed);
Jim Stichnoth 2016/04/22 20:48:54 This one is definitely for a separate CL. I think
Eric Holk 2016/04/22 22:32:48 I added a TODO, with a link to this comment.
1165 } 1178 }
1166 1179
1167 Ice::Operand *RealAddr = nullptr; 1180 Ice::Operand *RealAddr = nullptr;
1168 auto MemBase = Ctx->getConstantSym(0, Ctx->getGlobalString("WASM_MEMORY")); 1181 auto MemBase = Ctx->getConstantSym(0, Ctx->getGlobalString("WASM_MEMORY"));
1169 if (!ConstZeroBase) { 1182 if (!ConstZeroBase) {
1170 auto RealAddrV = Func->makeVariable(Ice::getPointerType()); 1183 auto RealAddrV = Func->makeVariable(Ice::getPointerType());
1171 Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Add, 1184 Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Add,
1172 RealAddrV, Base, MemBase)); 1185 RealAddrV, Base, MemBase));
1173 1186
1174 RealAddr = RealAddrV; 1187 RealAddr = RealAddrV;
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
1254 void set_effect_ptr(Node *Effect) { this->EffectPtr = Effect; } 1267 void set_effect_ptr(Node *Effect) { this->EffectPtr = Effect; }
1255 1268
1256 private: 1269 private:
1257 wasm::ModuleEnv *Module; 1270 wasm::ModuleEnv *Module;
1258 Node *ControlPtr; 1271 Node *ControlPtr;
1259 Node *EffectPtr; 1272 Node *EffectPtr;
1260 1273
1261 class Cfg *Func; 1274 class Cfg *Func;
1262 GlobalContext *Ctx; 1275 GlobalContext *Ctx;
1263 1276
1277 CfgNode *AbortTarget = nullptr;
1278
1264 SizeT NextArg = 0; 1279 SizeT NextArg = 0;
1265 1280
1266 CfgUnorderedMap<Operand *, InstPhi *> PhiMap; 1281 CfgUnorderedMap<Operand *, InstPhi *> PhiMap;
1267 CfgUnorderedMap<Operand *, CfgNode *> DefNodeMap; 1282 CfgUnorderedMap<Operand *, CfgNode *> DefNodeMap;
1268 1283
1269 InstPhi *getDefiningInst(Operand *Op) const { 1284 InstPhi *getDefiningInst(Operand *Op) const {
1270 const auto &Iter = PhiMap.find(Op); 1285 const auto &Iter = PhiMap.find(Op);
1271 if (Iter == PhiMap.end()) { 1286 if (Iter == PhiMap.end()) {
1272 return nullptr; 1287 return nullptr;
1273 } 1288 }
(...skipping 16 matching lines...) Expand all
1290 } 1305 }
1291 1306
1292 CfgNode *getDefNode(Operand *Op) const { 1307 CfgNode *getDefNode(Operand *Op) const {
1293 const auto &Iter = DefNodeMap.find(Op); 1308 const auto &Iter = DefNodeMap.find(Op);
1294 if (Iter == DefNodeMap.end()) { 1309 if (Iter == DefNodeMap.end()) {
1295 return nullptr; 1310 return nullptr;
1296 } 1311 }
1297 return Iter->second; 1312 return Iter->second;
1298 } 1313 }
1299 1314
1315 CfgNode *getAbortTarget() {
Karl 2016/04/22 19:18:14 Does this need an atomic or a mutex to avoid multi
Jim Stichnoth 2016/04/22 20:48:54 I don't think there's any concurrency at this leve
Eric Holk 2016/04/22 21:02:10 I think unless we have plans to parallelize Wasm d
1316 if (!AbortTarget) {
1317 AbortTarget = Func->makeNode();
Jim Stichnoth 2016/04/22 20:48:54 I think it's best if you can somehow force this no
Eric Holk 2016/04/22 22:32:48 Do you know a good strategy for doing this off han
Jim Stichnoth 2016/04/23 16:23:04 I would probably just do a post-pass that heavy-ha
1318 // TODO(eholk): This should probably actually call abort instead.
1319 AbortTarget->appendInst(InstUnreachable::create(Func));
1320 }
1321
1322 return AbortTarget;
1323 }
1324
1300 template <typename F = std::function<void(Ostream &)>> void log(F Fn) const { 1325 template <typename F = std::function<void(Ostream &)>> void log(F Fn) const {
1301 if (BuildDefs::dump() && (getFlags().getVerbose() & IceV_Wasm)) { 1326 if (BuildDefs::dump() && (getFlags().getVerbose() & IceV_Wasm)) {
1302 Fn(Ctx->getStrDump()); 1327 Fn(Ctx->getStrDump());
1303 Ctx->getStrDump().flush(); 1328 Ctx->getStrDump().flush();
1304 } 1329 }
1305 } 1330 }
1306 }; 1331 };
1307 1332
1308 std::unique_ptr<Cfg> WasmTranslator::translateFunction(Zone *Zone, 1333 std::unique_ptr<Cfg> WasmTranslator::translateFunction(Zone *Zone,
1309 FunctionBody &Body) { 1334 FunctionBody &Body) {
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after
1463 1488
1464 // Add the data 1489 // Add the data
1465 WasmMemory->addInitializer(VariableDeclaration::DataInitializer::create( 1490 WasmMemory->addInitializer(VariableDeclaration::DataInitializer::create(
1466 Globals.get(), reinterpret_cast<const char *>(Module->module_start) + 1491 Globals.get(), reinterpret_cast<const char *>(Module->module_start) +
1467 Seg.source_offset, 1492 Seg.source_offset,
1468 Seg.source_size)); 1493 Seg.source_size));
1469 1494
1470 WritePtr += Seg.source_size; 1495 WritePtr += Seg.source_size;
1471 } 1496 }
1472 1497
1498 // Save the size of the initialized data in a global variable so the runtime
1499 // can use it to determine the initial heap break.
1500 auto *GlobalDataSize = VariableDeclaration::createExternal(Globals.get());
1501 GlobalDataSize->setName(Ctx->getGlobalString("WASM_DATA_SIZE"));
1502 GlobalDataSize->addInitializer(VariableDeclaration::DataInitializer::create(
1503 Globals.get(), reinterpret_cast<const char *>(&WritePtr),
1504 sizeof(WritePtr)));
1505
1473 // Pad the rest with zeros 1506 // Pad the rest with zeros
1474 SizeT DataSize = Module->min_mem_pages * WASM_PAGE_SIZE; 1507 SizeT DataSize = Module->min_mem_pages * WASM_PAGE_SIZE;
1475 if (WritePtr < DataSize) { 1508 if (WritePtr < DataSize) {
1476 WasmMemory->addInitializer(VariableDeclaration::ZeroInitializer::create( 1509 WasmMemory->addInitializer(VariableDeclaration::ZeroInitializer::create(
1477 Globals.get(), DataSize - WritePtr)); 1510 Globals.get(), DataSize - WritePtr));
1478 } 1511 }
1479 1512
1513 // Save the number of pages for the runtime
1514 auto *GlobalNumPages = VariableDeclaration::createExternal(Globals.get());
1515 GlobalNumPages->setName(Ctx->getGlobalString("WASM_NUM_PAGES"));
1516 GlobalNumPages->addInitializer(VariableDeclaration::DataInitializer::create(
1517 Globals.get(), reinterpret_cast<const char *>(&Module->min_mem_pages),
1518 sizeof(Module->min_mem_pages)));
1519
1480 Globals->push_back(WasmMemory); 1520 Globals->push_back(WasmMemory);
1521 Globals->push_back(GlobalDataSize);
1522 Globals->push_back(GlobalNumPages);
1481 1523
1482 lowerGlobals(std::move(Globals)); 1524 lowerGlobals(std::move(Globals));
1483 } 1525 }
1484 1526
1485 // Translate each function. 1527 // Translate each function.
1486 for (const auto Fn : Module->functions) { 1528 for (const auto Fn : Module->functions) {
1487 const auto FnName = getFunctionName(Module, Fn.func_index); 1529 const auto FnName = getFunctionName(Module, Fn.func_index);
1488 1530
1489 LOG(out << " " << Fn.func_index << ": " << FnName << "..."); 1531 LOG(out << " " << Fn.func_index << ": " << FnName << "...");
1490 1532
1491 Body.sig = Fn.sig; 1533 Body.sig = Fn.sig;
1492 Body.base = Buffer.get(); 1534 Body.base = Buffer.get();
1493 Body.start = Buffer.get() + Fn.code_start_offset; 1535 Body.start = Buffer.get() + Fn.code_start_offset;
1494 Body.end = Buffer.get() + Fn.code_end_offset; 1536 Body.end = Buffer.get() + Fn.code_end_offset;
1495 1537
1496 auto Func = translateFunction(&Zone, Body); 1538 auto Func = translateFunction(&Zone, Body);
1497 Func->setFunctionName(Ctx->getGlobalString(FnName)); 1539 Func->setFunctionName(Ctx->getGlobalString(FnName));
1498 1540
1499 Ctx->optQueueBlockingPush(makeUnique<CfgOptWorkItem>(std::move(Func))); 1541 Ctx->optQueueBlockingPush(makeUnique<CfgOptWorkItem>(std::move(Func)));
1500 LOG(out << "done.\n"); 1542 LOG(out << "done.\n");
1501 } 1543 }
1502 1544
1503 return; 1545 return;
1504 } 1546 }
1505 1547
1506 #endif // ALLOW_WASM 1548 #endif // ALLOW_WASM
OLDNEW
« runtime/wasm-runtime.cpp ('K') | « runtime/wasm-runtime.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698