1 // Copyright 2015 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "src/signature.h" 6 7 #include "src/handles.h" 8 #include "src/v8.h" 9 #include "src/zone-containers.h" 10 11 #include "src/wasm/ast-decoder.h" 12 #include "src/wasm/encoder.h" 13 #include "src/wasm/wasm-module.h" 14 #include "src/wasm/wasm-opcodes.h" 15 16 #include "src/v8memory.h" 17 18 namespace v8 { 19 namespace internal { 20 namespace wasm { 21 22 /*TODO: add error cases for adding too many locals, too many functions and bad 23 indices in body */ 24 25 namespace { 26 void EmitUint8(byte** b, uint8_t x) { 27 Memory::uint8_at(*b) = x; 28 *b += 1; 29 } 30 31 32 void EmitUint16(byte** b, uint16_t x) { 33 Memory::uint16_at(*b) = x; 34 *b += 2; 35 } 36 37 38 void EmitUint32(byte** b, uint32_t x) { 39 Memory::uint32_at(*b) = x; 40 *b += 4; 41 } 42 43 44 void EmitVarInt(byte** b, size_t val) { 45 while (true) { 46 size_t next = val >> 7; 47 byte out = static_cast<byte>(val & 0x7f); 48 if (next) { 49 *((*b)++) = 0x80 | out; 50 val = next; 51 } else { 52 *((*b)++) = out; 53 break; 54 } 55 } 56 } 57 } // namespace 58 59 60 struct WasmFunctionBuilder::Type { 61 bool param_; 62 LocalType type_; 63 }; 64 65 66 WasmFunctionBuilder::WasmFunctionBuilder(Zone* zone) 67 : return_type_(kAstI32), 68 locals_(zone), 69 exported_(0), 70 external_(0), 71 body_(zone), 72 local_indices_(zone), 73 name_(zone) {} 74 75 76 uint16_t WasmFunctionBuilder::AddParam(LocalType type) { 77 return AddVar(type, true); 78 } 79 80 81 uint16_t WasmFunctionBuilder::AddLocal(LocalType type) { 82 return AddVar(type, false); 83 } 84 85 86 uint16_t WasmFunctionBuilder::AddVar(LocalType type, bool param) { 87 locals_.push_back({param, type}); 88 return static_cast<uint16_t>(locals_.size() - 1); 89 } 90 91 92 void WasmFunctionBuilder::ReturnType(LocalType type) { return_type_ = type; } 93 94 95 void WasmFunctionBuilder::EmitCode(const byte* code, uint32_t code_size) { 96 EmitCode(code, code_size, nullptr, 0); 97 } 98 99 100 void WasmFunctionBuilder::EmitCode(const byte* code, uint32_t code_size, 101 const uint32_t* local_indices, 102 uint32_t indices_size) { 103 size_t size = body_.size(); 104 for (size_t i = 0; i < code_size; i++) { 105 body_.push_back(code[i]); 106 } 107 for (size_t i = 0; i < indices_size; i++) { 108 local_indices_.push_back(local_indices[i] + static_cast<uint32_t>(size)); 109 } 110 } 111 112 113 void WasmFunctionBuilder::Emit(WasmOpcode opcode) { 114 body_.push_back(static_cast<byte>(opcode)); 115 } 116 117 118 void WasmFunctionBuilder::EmitWithU8(WasmOpcode opcode, const byte immediate) { 119 body_.push_back(static_cast<byte>(opcode)); 120 body_.push_back(immediate); 121 } 122 123 124 void WasmFunctionBuilder::EmitWithLocal(WasmOpcode opcode) { 125 body_.push_back(static_cast<byte>(opcode)); 126 local_indices_.push_back(static_cast<uint32_t>(body_.size()) - 1); 127 } 128 129 130 uint32_t WasmFunctionBuilder::EmitEditableImmediate(const byte immediate) { 131 body_.push_back(immediate); 132 return static_cast<uint32_t>(body_.size()) - 1; 133 } 134 135 136 void WasmFunctionBuilder::EditImmediate(uint32_t offset, const byte immediate) { 137 DCHECK(offset < body_.size()); 138 body_[offset] = immediate; 139 } 140 141 142 void WasmFunctionBuilder::Exported(uint8_t flag) { exported_ = flag; } 143 144 145 void WasmFunctionBuilder::External(uint8_t flag) { external_ = flag; } 146 147 void WasmFunctionBuilder::SetName(const unsigned char* name, int name_length) { 148 name_.clear(); 149 if (name_length > 0) { 150 for (int i = 0; i < name_length; i++) { 151 name_.push_back(*(name + i)); 152 } 153 name_.push_back('\0'); 154 } 155 } 156 157 158 WasmFunctionEncoder* WasmFunctionBuilder::Build(Zone* zone, 159 WasmModuleBuilder* mb) const { 160 WasmFunctionEncoder* e = 161 new (zone) WasmFunctionEncoder(zone, return_type_, exported_, external_); 162 uint16_t* var_index = zone->NewArray<uint16_t>(locals_.size()); 163 IndexVars(e, var_index); 164 if (body_.size() > 0) { 165 // TODO(titzer): iterate over local indexes, not the bytes. 166 const byte* start = &body_[0]; 167 const byte* end = start + body_.size(); 168 size_t local_index = 0; 169 for (size_t i = 0; i < body_.size();) { 170 if (local_index < local_indices_.size() && 171 i == local_indices_[local_index]) { 172 int length = 0; 173 uint32_t index; 174 ReadUnsignedLEB128Operand(start + i, end, &length, &index); 175 uint16_t new_index = var_index[index]; 176 const std::vector<uint8_t>& index_vec = UnsignedLEB128From(new_index); 177 for (size_t j = 0; j < index_vec.size(); j++) { 178 e->body_.push_back(index_vec.at(j)); 179 } 180 i += length; 181 local_index++; 182 } else { 183 e->body_.push_back(*(start + i)); 184 i++; 185 } 186 } 187 } 188 FunctionSig::Builder sig(zone, return_type_ == kAstStmt ? 0 : 1, 189 e->params_.size()); 190 if (return_type_ != kAstStmt) { 191 sig.AddReturn(static_cast<LocalType>(return_type_)); 192 } 193 for (size_t i = 0; i < e->params_.size(); i++) { 194 sig.AddParam(static_cast<LocalType>(e->params_[i])); 195 } 196 e->signature_index_ = mb->AddSignature(sig.Build()); 197 e->name_.insert(e->name_.begin(), name_.begin(), name_.end()); 198 return e; 199 } 200 201 202 void WasmFunctionBuilder::IndexVars(WasmFunctionEncoder* e, 203 uint16_t* var_index) const { 204 uint16_t param = 0; 205 uint16_t int32 = 0; 206 uint16_t int64 = 0; 207 uint16_t float32 = 0; 208 uint16_t float64 = 0; 209 for (size_t i = 0; i < locals_.size(); i++) { 210 if (locals_.at(i).param_) { 211 param++; 212 } else if (locals_.at(i).type_ == kAstI32) { 213 int32++; 214 } else if (locals_.at(i).type_ == kAstI64) { 215 int64++; 216 } else if (locals_.at(i).type_ == kAstF32) { 217 float32++; 218 } else if (locals_.at(i).type_ == kAstF64) { 219 float64++; 220 } 221 } 222 e->local_int32_count_ = int32; 223 e->local_int64_count_ = int64; 224 e->local_float32_count_ = float32; 225 e->local_float64_count_ = float64; 226 float64 = param + int32 + int64 + float32; 227 float32 = param + int32 + int64; 228 int64 = param + int32; 229 int32 = param; 230 param = 0; 231 for (size_t i = 0; i < locals_.size(); i++) { 232 if (locals_.at(i).param_) { 233 e->params_.push_back(locals_.at(i).type_); 234 var_index[i] = param++; 235 } else if (locals_.at(i).type_ == kAstI32) { 236 var_index[i] = int32++; 237 } else if (locals_.at(i).type_ == kAstI64) { 238 var_index[i] = int64++; 239 } else if (locals_.at(i).type_ == kAstF32) { 240 var_index[i] = float32++; 241 } else if (locals_.at(i).type_ == kAstF64) { 242 var_index[i] = float64++; 243 } 244 } 245 } 246 247 248 WasmFunctionEncoder::WasmFunctionEncoder(Zone* zone, LocalType return_type, 249 bool exported, bool external) 250 : params_(zone), 251 exported_(exported), 252 external_(external), 253 body_(zone), 254 name_(zone) {} 255 256 257 uint32_t WasmFunctionEncoder::HeaderSize() const { 258 uint32_t size = 3; 259 if (HasLocals()) size += 8; 260 if (!external_) size += 2; 261 if (HasName()) size += 4; 262 return size; 263 } 264 265 266 uint32_t WasmFunctionEncoder::BodySize(void) const { 267 return external_ ? 0 : static_cast<uint32_t>(body_.size()); 268 } 269 270 271 uint32_t WasmFunctionEncoder::NameSize() const { 272 return exported_ ? static_cast<uint32_t>(name_.size()) : 0; 273 } 274 275 276 void WasmFunctionEncoder::Serialize(byte* buffer, byte** header, 277 byte** body) const { 278 uint8_t decl_bits = (exported_ ? kDeclFunctionExport : 0) | 279 (external_ ? kDeclFunctionImport : 0) | 280 (HasLocals() ? kDeclFunctionLocals : 0) | 281 (HasName() ? kDeclFunctionName : 0); 282 283 EmitUint8(header, decl_bits); 284 EmitUint16(header, signature_index_); 285 286 if (HasName()) { 287 uint32_t name_offset = static_cast<uint32_t>(*body - buffer); 288 EmitUint32(header, name_offset); 289 std::memcpy(*body, &name_[0], name_.size()); 290 (*body) += name_.size(); 291 } 292 293 if (HasLocals()) { 294 EmitUint16(header, local_int32_count_); 295 EmitUint16(header, local_int64_count_); 296 EmitUint16(header, local_float32_count_); 297 EmitUint16(header, local_float64_count_); 298 } 299 300 if (!external_) { 301 EmitUint16(header, static_cast<uint16_t>(body_.size())); 302 if (body_.size() > 0) { 303 std::memcpy(*header, &body_[0], body_.size()); 304 (*header) += body_.size(); 305 } 306 } 307 } 308 309 310 WasmDataSegmentEncoder::WasmDataSegmentEncoder(Zone* zone, const byte* data, 311 uint32_t size, uint32_t dest) 312 : data_(zone), dest_(dest) { 313 for (size_t i = 0; i < size; i++) { 314 data_.push_back(data[i]); 315 } 316 } 317 318 319 uint32_t WasmDataSegmentEncoder::HeaderSize() const { 320 static const int kDataSegmentSize = 13; 321 return kDataSegmentSize; 322 } 323 324 325 uint32_t WasmDataSegmentEncoder::BodySize() const { 326 return static_cast<uint32_t>(data_.size()); 327 } 328 329 330 void WasmDataSegmentEncoder::Serialize(byte* buffer, byte** header, 331 byte** body) const { 332 uint32_t body_offset = static_cast<uint32_t>(*body - buffer); 333 EmitUint32(header, dest_); 334 EmitUint32(header, body_offset); 335 EmitUint32(header, static_cast<uint32_t>(data_.size())); 336 EmitUint8(header, 1); // init 337 338 std::memcpy(*body, &data_[0], data_.size()); 339 (*body) += data_.size(); 340 } 341 342 343 WasmModuleBuilder::WasmModuleBuilder(Zone* zone) 344 : zone_(zone), 345 signatures_(zone), 346 functions_(zone), 347 data_segments_(zone), 348 indirect_functions_(zone), 349 globals_(zone), 350 signature_map_(zone) {} 351 352 353 uint16_t WasmModuleBuilder::AddFunction() { 354 functions_.push_back(new (zone_) WasmFunctionBuilder(zone_)); 355 return static_cast<uint16_t>(functions_.size() - 1); 356 } 357 358 359 WasmFunctionBuilder* WasmModuleBuilder::FunctionAt(size_t index) { 360 if (functions_.size() > index) { 361 return functions_.at(index); 362 } else { 363 return nullptr; 364 } 365 } 366 367 368 void WasmModuleBuilder::AddDataSegment(WasmDataSegmentEncoder* data) { 369 data_segments_.push_back(data); 370 } 371 372 373 int WasmModuleBuilder::CompareFunctionSigs::operator()(FunctionSig* a, 374 FunctionSig* b) const { 375 if (a->return_count() < b->return_count()) return -1; 376 if (a->return_count() > b->return_count()) return 1; 377 if (a->parameter_count() < b->parameter_count()) return -1; 378 if (a->parameter_count() > b->parameter_count()) return 1; 379 for (size_t r = 0; r < a->return_count(); r++) { 380 if (a->GetReturn(r) < b->GetReturn(r)) return -1; 381 if (a->GetReturn(r) > b->GetReturn(r)) return 1; 382 } 383 for (size_t p = 0; p < a->parameter_count(); p++) { 384 if (a->GetParam(p) < b->GetParam(p)) return -1; 385 if (a->GetParam(p) > b->GetParam(p)) return 1; 386 } 387 return 0; 388 } 389 390 391 uint16_t WasmModuleBuilder::AddSignature(FunctionSig* sig) { 392 SignatureMap::iterator pos = signature_map_.find(sig); 393 if (pos != signature_map_.end()) { 394 return pos->second; 395 } else { 396 uint16_t index = static_cast<uint16_t>(signatures_.size()); 397 signature_map_[sig] = index; 398 signatures_.push_back(sig); 399 return index; 400 } 401 } 402 403 404 void WasmModuleBuilder::AddIndirectFunction(uint16_t index) { 405 indirect_functions_.push_back(index); 406 } 407 408 409 WasmModuleWriter* WasmModuleBuilder::Build(Zone* zone) { 410 WasmModuleWriter* writer = new (zone) WasmModuleWriter(zone); 411 for (auto function : functions_) { 412 writer->functions_.push_back(function->Build(zone, this)); 413 } 414 for (auto segment : data_segments_) { 415 writer->data_segments_.push_back(segment); 416 } 417 for (auto sig : signatures_) { 418 writer->signatures_.push_back(sig); 419 } 420 for (auto index : indirect_functions_) { 421 writer->indirect_functions_.push_back(index); 422 } 423 for (auto global : globals_) { 424 writer->globals_.push_back(global); 425 } 426 return writer; 427 } 428 429 430 uint32_t WasmModuleBuilder::AddGlobal(MachineType type, bool exported) { 431 globals_.push_back(std::make_pair(type, exported)); 432 return static_cast<uint32_t>(globals_.size() - 1); 433 } 434 435 436 WasmModuleWriter::WasmModuleWriter(Zone* zone) 437 : functions_(zone), 438 data_segments_(zone), 439 signatures_(zone), 440 indirect_functions_(zone), 441 globals_(zone) {} 442 443 444 struct Sizes { 445 size_t header_size; 446 size_t body_size; 447 448 size_t total() { return header_size + body_size; } 449 450 void Add(size_t header, size_t body) { 451 header_size += header; 452 body_size += body; 453 } 454 455 void AddSection(size_t size) { 456 if (size > 0) { 457 Add(1, 0); 458 while (size > 0) { 459 Add(1, 0); 460 size = size >> 7; 461 } 462 } 463 } 464 }; 465 466 467 WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const { 468 Sizes sizes = {0, 0}; 469 470 sizes.Add(1, 0); 471 sizes.Add(kDeclMemorySize, 0); 472 473 sizes.AddSection(signatures_.size()); 474 for (auto sig : signatures_) { 475 sizes.Add(2 + sig->parameter_count(), 0); 476 } 477 478 sizes.AddSection(globals_.size()); 479 if (globals_.size() > 0) { 480 sizes.Add(kDeclGlobalSize * globals_.size(), 0); 481 } 482 483 sizes.AddSection(functions_.size()); 484 for (auto function : functions_) { 485 sizes.Add(function->HeaderSize() + function->BodySize(), 486 function->NameSize()); 487 } 488 489 sizes.AddSection(data_segments_.size()); 490 for (auto segment : data_segments_) { 491 sizes.Add(segment->HeaderSize(), segment->BodySize()); 492 } 493 494 sizes.AddSection(indirect_functions_.size()); 495 sizes.Add(2 * static_cast<uint32_t>(indirect_functions_.size()), 0); 496 497 if (sizes.body_size > 0) sizes.Add(1, 0); 498 499 ZoneVector<uint8_t> buffer_vector(sizes.total(), zone); 500 byte* buffer = &buffer_vector[0]; 501 byte* header = buffer; 502 byte* body = buffer + sizes.header_size; 503 504 // -- emit memory declaration ------------------------------------------------ 505 EmitUint8(&header, kDeclMemory); 506 EmitUint8(&header, 16); // min memory size 507 EmitUint8(&header, 16); // max memory size 508 EmitUint8(&header, 0); // memory export 509 510 // -- emit globals ----------------------------------------------------------- 511 if (globals_.size() > 0) { 512 EmitUint8(&header, kDeclGlobals); 513 EmitVarInt(&header, globals_.size()); 514 515 for (auto global : globals_) { 516 EmitUint32(&header, 0); 517 EmitUint8(&header, WasmOpcodes::MemTypeCodeFor(global.first)); 518 EmitUint8(&header, global.second); 519 } 520 } 521 522 // -- emit signatures -------------------------------------------------------- 523 if (signatures_.size() > 0) { 524 EmitUint8(&header, kDeclSignatures); 525 EmitVarInt(&header, signatures_.size()); 526 527 for (FunctionSig* sig : signatures_) { 528 EmitUint8(&header, static_cast<byte>(sig->parameter_count())); 529 if (sig->return_count() > 0) { 530 EmitUint8(&header, WasmOpcodes::LocalTypeCodeFor(sig->GetReturn())); 531 } else { 532 EmitUint8(&header, kLocalVoid); 533 } 534 for (size_t j = 0; j < sig->parameter_count(); j++) { 535 EmitUint8(&header, WasmOpcodes::LocalTypeCodeFor(sig->GetParam(j))); 536 } 537 } 538 } 539 540 // -- emit functions --------------------------------------------------------- 541 if (functions_.size() > 0) { 542 EmitUint8(&header, kDeclFunctions); 543 EmitVarInt(&header, functions_.size()); 544 545 for (auto func : functions_) { 546 func->Serialize(buffer, &header, &body); 547 } 548 } 549 550 // -- emit data segments ----------------------------------------------------- 551 if (data_segments_.size() > 0) { 552 EmitUint8(&header, kDeclDataSegments); 553 EmitVarInt(&header, data_segments_.size()); 554 555 for (auto segment : data_segments_) { 556 segment->Serialize(buffer, &header, &body); 557 } 558 } 559 560 // -- emit function table ---------------------------------------------------- 561 if (indirect_functions_.size() > 0) { 562 EmitUint8(&header, kDeclFunctionTable); 563 EmitVarInt(&header, indirect_functions_.size()); 564 565 for (auto index : indirect_functions_) { 566 EmitUint16(&header, index); 567 } 568 } 569 570 if (sizes.body_size > 0) EmitUint8(&header, kDeclEnd); 571 572 return new (zone) WasmModuleIndex(buffer, buffer + sizes.total()); 573 } 574 575 576 std::vector<uint8_t> UnsignedLEB128From(uint32_t result) { 577 std::vector<uint8_t> output; 578 uint8_t next = 0; 579 int shift = 0; 580 do { 581 next = static_cast<uint8_t>(result >> shift); 582 if (((result >> shift) & 0xFFFFFF80) != 0) { 583 next = next | 0x80; 584 } 585 output.push_back(next); 586 shift += 7; 587 } while ((next & 0x80) != 0); 588 return output; 589 } 590 } // namespace wasm 591 } // namespace internal 592 } // namespace v8 593