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

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: Code review feedback 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
« no previous file with comments | « 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 Ctx->getConstantZero(IceType_i32);
Jim Stichnoth 2016/04/23 16:23:04 Maybe use getPointerType() instead of IceType_i32,
Eric Holk 2016/04/25 19:53:03 Done.
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.
1167 //
1168 // TODO (eholk): Add a command line argument to control whether bounds
1169 // checks are inserted, and maybe add a way to duplicate bounds checks to
1170 // get a better sense of the overhead.
1159 if (!llvm::dyn_cast<ConstantInteger32>(Base)) { 1171 if (!llvm::dyn_cast<ConstantInteger32>(Base)) {
1160 auto *ClampedAddr = makeVariable(Ice::getPointerType()); 1172 // TODO (eholk): creating a new basic block on every memory access is
1173 // terrible (see https://goto.google.com/aqydy). Try adding a new
Jim Stichnoth 2016/04/23 16:23:04 Use a link that is externally viewable...
Eric Holk 2016/04/25 19:53:03 I thought goto was, but just to be safe, I switche
1174 // instruction that encapsulates this "abort if false" pattern.
1175 auto *CheckPassed = Func->makeNode();
1176 auto *CheckFailed = getAbortTarget();
1177
1178 auto *Check = makeVariable(IceType_i1);
1179 Control()->appendInst(InstIcmp::create(Func, InstIcmp::Ult, Check, Base,
1180 Ctx->getConstantInt32(MemSize)));
1161 Control()->appendInst( 1181 Control()->appendInst(
1162 InstArithmetic::create(Func, InstArithmetic::And, ClampedAddr, Base, 1182 InstBr::create(Func, Check, CheckPassed, CheckFailed));
1163 Ctx->getConstantInt32(MemSize - 1))); 1183
1164 Base = ClampedAddr; 1184 *ControlPtr = OperandNode(CheckPassed);
1165 } 1185 }
1166 1186
1167 Ice::Operand *RealAddr = nullptr; 1187 Ice::Operand *RealAddr = nullptr;
1168 auto MemBase = Ctx->getConstantSym(0, Ctx->getGlobalString("WASM_MEMORY")); 1188 auto MemBase = Ctx->getConstantSym(0, Ctx->getGlobalString("WASM_MEMORY"));
1169 if (!ConstZeroBase) { 1189 if (!ConstZeroBase) {
1170 auto RealAddrV = Func->makeVariable(Ice::getPointerType()); 1190 auto RealAddrV = Func->makeVariable(Ice::getPointerType());
1171 Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Add, 1191 Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Add,
1172 RealAddrV, Base, MemBase)); 1192 RealAddrV, Base, MemBase));
1173 1193
1174 RealAddr = RealAddrV; 1194 RealAddr = RealAddrV;
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
1254 void set_effect_ptr(Node *Effect) { this->EffectPtr = Effect; } 1274 void set_effect_ptr(Node *Effect) { this->EffectPtr = Effect; }
1255 1275
1256 private: 1276 private:
1257 wasm::ModuleEnv *Module; 1277 wasm::ModuleEnv *Module;
1258 Node *ControlPtr; 1278 Node *ControlPtr;
1259 Node *EffectPtr; 1279 Node *EffectPtr;
1260 1280
1261 class Cfg *Func; 1281 class Cfg *Func;
1262 GlobalContext *Ctx; 1282 GlobalContext *Ctx;
1263 1283
1284 CfgNode *AbortTarget = nullptr;
1285
1264 SizeT NextArg = 0; 1286 SizeT NextArg = 0;
1265 1287
1266 CfgUnorderedMap<Operand *, InstPhi *> PhiMap; 1288 CfgUnorderedMap<Operand *, InstPhi *> PhiMap;
1267 CfgUnorderedMap<Operand *, CfgNode *> DefNodeMap; 1289 CfgUnorderedMap<Operand *, CfgNode *> DefNodeMap;
1268 1290
1269 InstPhi *getDefiningInst(Operand *Op) const { 1291 InstPhi *getDefiningInst(Operand *Op) const {
1270 const auto &Iter = PhiMap.find(Op); 1292 const auto &Iter = PhiMap.find(Op);
1271 if (Iter == PhiMap.end()) { 1293 if (Iter == PhiMap.end()) {
1272 return nullptr; 1294 return nullptr;
1273 } 1295 }
(...skipping 16 matching lines...) Expand all
1290 } 1312 }
1291 1313
1292 CfgNode *getDefNode(Operand *Op) const { 1314 CfgNode *getDefNode(Operand *Op) const {
1293 const auto &Iter = DefNodeMap.find(Op); 1315 const auto &Iter = DefNodeMap.find(Op);
1294 if (Iter == DefNodeMap.end()) { 1316 if (Iter == DefNodeMap.end()) {
1295 return nullptr; 1317 return nullptr;
1296 } 1318 }
1297 return Iter->second; 1319 return Iter->second;
1298 } 1320 }
1299 1321
1322 CfgNode *getAbortTarget() {
1323 if (!AbortTarget) {
1324 AbortTarget = Func->makeNode();
1325 // TODO(eholk): This should probably actually call abort instead.
1326 AbortTarget->appendInst(InstUnreachable::create(Func));
1327 }
1328
1329 return AbortTarget;
1330 }
1331
1300 template <typename F = std::function<void(Ostream &)>> void log(F Fn) const { 1332 template <typename F = std::function<void(Ostream &)>> void log(F Fn) const {
1301 if (BuildDefs::dump() && (getFlags().getVerbose() & IceV_Wasm)) { 1333 if (BuildDefs::dump() && (getFlags().getVerbose() & IceV_Wasm)) {
1302 Fn(Ctx->getStrDump()); 1334 Fn(Ctx->getStrDump());
1303 Ctx->getStrDump().flush(); 1335 Ctx->getStrDump().flush();
1304 } 1336 }
1305 } 1337 }
1306 }; 1338 };
1307 1339
1308 std::unique_ptr<Cfg> WasmTranslator::translateFunction(Zone *Zone, 1340 std::unique_ptr<Cfg> WasmTranslator::translateFunction(Zone *Zone,
1309 FunctionBody &Body) { 1341 FunctionBody &Body) {
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after
1463 1495
1464 // Add the data 1496 // Add the data
1465 WasmMemory->addInitializer(VariableDeclaration::DataInitializer::create( 1497 WasmMemory->addInitializer(VariableDeclaration::DataInitializer::create(
1466 Globals.get(), reinterpret_cast<const char *>(Module->module_start) + 1498 Globals.get(), reinterpret_cast<const char *>(Module->module_start) +
1467 Seg.source_offset, 1499 Seg.source_offset,
1468 Seg.source_size)); 1500 Seg.source_size));
1469 1501
1470 WritePtr += Seg.source_size; 1502 WritePtr += Seg.source_size;
1471 } 1503 }
1472 1504
1505 // Save the size of the initialized data in a global variable so the runtime
1506 // can use it to determine the initial heap break.
1507 auto *GlobalDataSize = VariableDeclaration::createExternal(Globals.get());
1508 GlobalDataSize->setName(Ctx->getGlobalString("WASM_DATA_SIZE"));
1509 GlobalDataSize->addInitializer(VariableDeclaration::DataInitializer::create(
1510 Globals.get(), reinterpret_cast<const char *>(&WritePtr),
1511 sizeof(WritePtr)));
1512
1473 // Pad the rest with zeros 1513 // Pad the rest with zeros
1474 SizeT DataSize = Module->min_mem_pages * WASM_PAGE_SIZE; 1514 SizeT DataSize = Module->min_mem_pages * WASM_PAGE_SIZE;
1475 if (WritePtr < DataSize) { 1515 if (WritePtr < DataSize) {
1476 WasmMemory->addInitializer(VariableDeclaration::ZeroInitializer::create( 1516 WasmMemory->addInitializer(VariableDeclaration::ZeroInitializer::create(
1477 Globals.get(), DataSize - WritePtr)); 1517 Globals.get(), DataSize - WritePtr));
1478 } 1518 }
1479 1519
1520 // Save the number of pages for the runtime
1521 auto *GlobalNumPages = VariableDeclaration::createExternal(Globals.get());
1522 GlobalNumPages->setName(Ctx->getGlobalString("WASM_NUM_PAGES"));
1523 GlobalNumPages->addInitializer(VariableDeclaration::DataInitializer::create(
1524 Globals.get(), reinterpret_cast<const char *>(&Module->min_mem_pages),
1525 sizeof(Module->min_mem_pages)));
1526
1480 Globals->push_back(WasmMemory); 1527 Globals->push_back(WasmMemory);
1528 Globals->push_back(GlobalDataSize);
1529 Globals->push_back(GlobalNumPages);
1481 1530
1482 lowerGlobals(std::move(Globals)); 1531 lowerGlobals(std::move(Globals));
1483 } 1532 }
1484 1533
1485 // Translate each function. 1534 // Translate each function.
1486 for (const auto Fn : Module->functions) { 1535 for (const auto Fn : Module->functions) {
1487 const auto FnName = getFunctionName(Module, Fn.func_index); 1536 const auto FnName = getFunctionName(Module, Fn.func_index);
1488 1537
1489 LOG(out << " " << Fn.func_index << ": " << FnName << "..."); 1538 LOG(out << " " << Fn.func_index << ": " << FnName << "...");
1490 1539
1491 Body.sig = Fn.sig; 1540 Body.sig = Fn.sig;
1492 Body.base = Buffer.get(); 1541 Body.base = Buffer.get();
1493 Body.start = Buffer.get() + Fn.code_start_offset; 1542 Body.start = Buffer.get() + Fn.code_start_offset;
1494 Body.end = Buffer.get() + Fn.code_end_offset; 1543 Body.end = Buffer.get() + Fn.code_end_offset;
1495 1544
1496 auto Func = translateFunction(&Zone, Body); 1545 auto Func = translateFunction(&Zone, Body);
1497 Func->setFunctionName(Ctx->getGlobalString(FnName)); 1546 Func->setFunctionName(Ctx->getGlobalString(FnName));
1498 1547
1499 Ctx->optQueueBlockingPush(makeUnique<CfgOptWorkItem>(std::move(Func))); 1548 Ctx->optQueueBlockingPush(makeUnique<CfgOptWorkItem>(std::move(Func)));
1500 LOG(out << "done.\n"); 1549 LOG(out << "done.\n");
1501 } 1550 }
1502 1551
1503 return; 1552 return;
1504 } 1553 }
1505 1554
1506 #endif // ALLOW_WASM 1555 #endif // ALLOW_WASM
OLDNEW
« no previous file with comments | « runtime/wasm-runtime.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698