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/objects-inl.h" 9 #include "src/v8.h" 10 #include "src/zone/zone-containers.h" 11 12 #include "src/wasm/function-body-decoder.h" 13 #include "src/wasm/leb-helper.h" 14 #include "src/wasm/module-decoder.h" 15 #include "src/wasm/wasm-macro-gen.h" 16 #include "src/wasm/wasm-module-builder.h" 17 #include "src/wasm/wasm-module.h" 18 #include "src/wasm/wasm-opcodes.h" 19 20 #include "src/v8memory.h" 21 22 #if DEBUG 23 #define TRACE(...) \ 24 do { \ 25 if (FLAG_trace_wasm_encoder) PrintF(__VA_ARGS__); \ 26 } while (false) 27 #else 28 #define TRACE(...) 29 #endif 30 31 namespace v8 { 32 namespace internal { 33 namespace wasm { 34 35 // Emit a section code and the size as a padded varint that can be patched 36 // later. 37 size_t EmitSection(WasmSectionCode code, ZoneBuffer& buffer) { 38 // Emit the section code. 39 buffer.write_u8(code); 40 41 // Emit a placeholder for the length. 42 return buffer.reserve_u32v(); 43 } 44 45 // Patch the size of a section after it's finished. 46 void FixupSection(ZoneBuffer& buffer, size_t start) { 47 buffer.patch_u32v(start, static_cast<uint32_t>(buffer.offset() - start - 48 kPaddedVarInt32Size)); 49 } 50 51 WasmFunctionBuilder::WasmFunctionBuilder(WasmModuleBuilder* builder) 52 : builder_(builder), 53 locals_(builder->zone()), 54 signature_index_(0), 55 func_index_(static_cast<uint32_t>(builder->functions_.size())), 56 body_(builder->zone()), 57 name_(builder->zone()), 58 exported_names_(builder->zone()), 59 i32_temps_(builder->zone()), 60 i64_temps_(builder->zone()), 61 f32_temps_(builder->zone()), 62 f64_temps_(builder->zone()), 63 direct_calls_(builder->zone()), 64 asm_offsets_(builder->zone(), 8) {} 65 66 void WasmFunctionBuilder::EmitVarInt(int32_t val) { 67 byte buffer[5]; 68 byte* ptr = buffer; 69 LEBHelper::write_i32v(&ptr, val); 70 DCHECK_GE(5, ptr - buffer); 71 body_.insert(body_.end(), buffer, ptr); 72 } 73 74 void WasmFunctionBuilder::EmitVarUint(uint32_t val) { 75 byte buffer[5]; 76 byte* ptr = buffer; 77 LEBHelper::write_u32v(&ptr, val); 78 DCHECK_GE(5, ptr - buffer); 79 body_.insert(body_.end(), buffer, ptr); 80 } 81 82 void WasmFunctionBuilder::SetSignature(FunctionSig* sig) { 83 DCHECK(!locals_.has_sig()); 84 locals_.set_sig(sig); 85 signature_index_ = builder_->AddSignature(sig); 86 } 87 88 uint32_t WasmFunctionBuilder::AddLocal(ValueType type) { 89 DCHECK(locals_.has_sig()); 90 return locals_.AddLocals(1, type); 91 } 92 93 void WasmFunctionBuilder::EmitGetLocal(uint32_t local_index) { 94 EmitWithVarUint(kExprGetLocal, local_index); 95 } 96 97 void WasmFunctionBuilder::EmitSetLocal(uint32_t local_index) { 98 EmitWithVarUint(kExprSetLocal, local_index); 99 } 100 101 void WasmFunctionBuilder::EmitTeeLocal(uint32_t local_index) { 102 EmitWithVarUint(kExprTeeLocal, local_index); 103 } 104 105 void WasmFunctionBuilder::EmitCode(const byte* code, uint32_t code_size) { 106 for (size_t i = 0; i < code_size; ++i) { 107 body_.push_back(code[i]); 108 } 109 } 110 111 void WasmFunctionBuilder::Emit(WasmOpcode opcode) { 112 body_.push_back(static_cast<byte>(opcode)); 113 } 114 115 void WasmFunctionBuilder::EmitWithU8(WasmOpcode opcode, const byte immediate) { 116 body_.push_back(static_cast<byte>(opcode)); 117 body_.push_back(immediate); 118 } 119 120 void WasmFunctionBuilder::EmitWithU8U8(WasmOpcode opcode, const byte imm1, 121 const byte imm2) { 122 body_.push_back(static_cast<byte>(opcode)); 123 body_.push_back(imm1); 124 body_.push_back(imm2); 125 } 126 127 void WasmFunctionBuilder::EmitWithVarInt(WasmOpcode opcode, int32_t immediate) { 128 body_.push_back(static_cast<byte>(opcode)); 129 EmitVarInt(immediate); 130 } 131 132 void WasmFunctionBuilder::EmitWithVarUint(WasmOpcode opcode, 133 uint32_t immediate) { 134 body_.push_back(static_cast<byte>(opcode)); 135 EmitVarUint(immediate); 136 } 137 138 void WasmFunctionBuilder::EmitI32Const(int32_t value) { 139 EmitWithVarInt(kExprI32Const, value); 140 } 141 142 void WasmFunctionBuilder::EmitDirectCallIndex(uint32_t index) { 143 DirectCallIndex call; 144 call.offset = body_.size(); 145 call.direct_index = index; 146 direct_calls_.push_back(call); 147 byte code[] = {U32V_5(0)}; 148 EmitCode(code, sizeof(code)); 149 } 150 151 void WasmFunctionBuilder::ExportAs(Vector<const char> name) { 152 exported_names_.push_back(ZoneVector<char>( 153 name.start(), name.start() + name.length(), builder_->zone())); 154 } 155 156 void WasmFunctionBuilder::SetName(Vector<const char> name) { 157 name_.resize(name.length()); 158 memcpy(name_.data(), name.start(), name.length()); 159 } 160 161 void WasmFunctionBuilder::AddAsmWasmOffset(int call_position, 162 int to_number_position) { 163 // We only want to emit one mapping per byte offset. 164 DCHECK(asm_offsets_.size() == 0 || body_.size() > last_asm_byte_offset_); 165 166 DCHECK_LE(body_.size(), kMaxUInt32); 167 uint32_t byte_offset = static_cast<uint32_t>(body_.size()); 168 asm_offsets_.write_u32v(byte_offset - last_asm_byte_offset_); 169 last_asm_byte_offset_ = byte_offset; 170 171 DCHECK_GE(call_position, 0); 172 asm_offsets_.write_i32v(call_position - last_asm_source_position_); 173 174 DCHECK_GE(to_number_position, 0); 175 asm_offsets_.write_i32v(to_number_position - call_position); 176 last_asm_source_position_ = to_number_position; 177 } 178 179 void WasmFunctionBuilder::SetAsmFunctionStartPosition(int position) { 180 DCHECK_EQ(0, asm_func_start_source_position_); 181 DCHECK_LE(0, position); 182 // Must be called before emitting any asm.js source position. 183 DCHECK_EQ(0, asm_offsets_.size()); 184 asm_func_start_source_position_ = position; 185 last_asm_source_position_ = position; 186 } 187 188 void WasmFunctionBuilder::WriteSignature(ZoneBuffer& buffer) const { 189 buffer.write_u32v(signature_index_); 190 } 191 192 void WasmFunctionBuilder::WriteExports(ZoneBuffer& buffer) const { 193 for (auto name : exported_names_) { 194 buffer.write_size(name.size()); 195 buffer.write(reinterpret_cast<const byte*>(name.data()), name.size()); 196 buffer.write_u8(kExternalFunction); 197 buffer.write_u32v(func_index_ + 198 static_cast<uint32_t>(builder_->imports_.size())); 199 } 200 } 201 202 void WasmFunctionBuilder::WriteBody(ZoneBuffer& buffer) const { 203 size_t locals_size = locals_.Size(); 204 buffer.write_size(locals_size + body_.size()); 205 buffer.EnsureSpace(locals_size); 206 byte** ptr = buffer.pos_ptr(); 207 locals_.Emit(*ptr); 208 (*ptr) += locals_size; // UGLY: manual bump of position pointer 209 if (body_.size() > 0) { 210 size_t base = buffer.offset(); 211 buffer.write(&body_[0], body_.size()); 212 for (DirectCallIndex call : direct_calls_) { 213 buffer.patch_u32v( 214 base + call.offset, 215 call.direct_index + static_cast<uint32_t>(builder_->imports_.size())); 216 } 217 } 218 } 219 220 void WasmFunctionBuilder::WriteAsmWasmOffsetTable(ZoneBuffer& buffer) const { 221 if (asm_func_start_source_position_ == 0 && asm_offsets_.size() == 0) { 222 buffer.write_size(0); 223 return; 224 } 225 size_t locals_enc_size = LEBHelper::sizeof_u32v(locals_.Size()); 226 size_t func_start_size = 227 LEBHelper::sizeof_u32v(asm_func_start_source_position_); 228 buffer.write_size(asm_offsets_.size() + locals_enc_size + func_start_size); 229 // Offset of the recorded byte offsets. 230 DCHECK_GE(kMaxUInt32, locals_.Size()); 231 buffer.write_u32v(static_cast<uint32_t>(locals_.Size())); 232 // Start position of the function. 233 buffer.write_u32v(asm_func_start_source_position_); 234 buffer.write(asm_offsets_.begin(), asm_offsets_.size()); 235 } 236 237 WasmModuleBuilder::WasmModuleBuilder(Zone* zone) 238 : zone_(zone), 239 signatures_(zone), 240 imports_(zone), 241 functions_(zone), 242 data_segments_(zone), 243 indirect_functions_(zone), 244 globals_(zone), 245 signature_map_(zone), 246 start_function_index_(-1) {} 247 248 WasmFunctionBuilder* WasmModuleBuilder::AddFunction(FunctionSig* sig) { 249 functions_.push_back(new (zone_) WasmFunctionBuilder(this)); 250 // Add the signature if one was provided here. 251 if (sig) functions_.back()->SetSignature(sig); 252 return functions_.back(); 253 } 254 255 void WasmModuleBuilder::AddDataSegment(const byte* data, uint32_t size, 256 uint32_t dest) { 257 data_segments_.push_back({ZoneVector<byte>(zone()), dest}); 258 ZoneVector<byte>& vec = data_segments_.back().data; 259 for (uint32_t i = 0; i < size; i++) { 260 vec.push_back(data[i]); 261 } 262 } 263 264 bool WasmModuleBuilder::CompareFunctionSigs::operator()(FunctionSig* a, 265 FunctionSig* b) const { 266 if (a->return_count() < b->return_count()) return true; 267 if (a->return_count() > b->return_count()) return false; 268 if (a->parameter_count() < b->parameter_count()) return true; 269 if (a->parameter_count() > b->parameter_count()) return false; 270 for (size_t r = 0; r < a->return_count(); r++) { 271 if (a->GetReturn(r) < b->GetReturn(r)) return true; 272 if (a->GetReturn(r) > b->GetReturn(r)) return false; 273 } 274 for (size_t p = 0; p < a->parameter_count(); p++) { 275 if (a->GetParam(p) < b->GetParam(p)) return true; 276 if (a->GetParam(p) > b->GetParam(p)) return false; 277 } 278 return false; 279 } 280 281 uint32_t WasmModuleBuilder::AddSignature(FunctionSig* sig) { 282 SignatureMap::iterator pos = signature_map_.find(sig); 283 if (pos != signature_map_.end()) { 284 return pos->second; 285 } else { 286 uint32_t index = static_cast<uint32_t>(signatures_.size()); 287 signature_map_[sig] = index; 288 signatures_.push_back(sig); 289 return index; 290 } 291 } 292 293 uint32_t WasmModuleBuilder::AllocateIndirectFunctions(uint32_t count) { 294 uint32_t ret = static_cast<uint32_t>(indirect_functions_.size()); 295 indirect_functions_.resize(indirect_functions_.size() + count); 296 return ret; 297 } 298 299 void WasmModuleBuilder::SetIndirectFunction(uint32_t indirect, 300 uint32_t direct) { 301 indirect_functions_[indirect] = direct; 302 } 303 304 uint32_t WasmModuleBuilder::AddImport(const char* name, int name_length, 305 FunctionSig* sig) { 306 imports_.push_back({AddSignature(sig), name, name_length}); 307 return static_cast<uint32_t>(imports_.size() - 1); 308 } 309 310 void WasmModuleBuilder::MarkStartFunction(WasmFunctionBuilder* function) { 311 start_function_index_ = function->func_index(); 312 } 313 314 uint32_t WasmModuleBuilder::AddGlobal(ValueType type, bool exported, 315 bool mutability, 316 const WasmInitExpr& init) { 317 globals_.push_back({type, exported, mutability, init}); 318 return static_cast<uint32_t>(globals_.size() - 1); 319 } 320 321 void WasmModuleBuilder::WriteTo(ZoneBuffer& buffer) const { 322 uint32_t exports = 0; 323 324 // == Emit magic ============================================================= 325 TRACE("emit magic\n"); 326 buffer.write_u32(kWasmMagic); 327 buffer.write_u32(kWasmVersion); 328 329 // == Emit signatures ======================================================== 330 if (signatures_.size() > 0) { 331 size_t start = EmitSection(kTypeSectionCode, buffer); 332 buffer.write_size(signatures_.size()); 333 334 for (FunctionSig* sig : signatures_) { 335 buffer.write_u8(kWasmFunctionTypeForm); 336 buffer.write_size(sig->parameter_count()); 337 for (size_t j = 0; j < sig->parameter_count(); j++) { 338 buffer.write_u8(WasmOpcodes::ValueTypeCodeFor(sig->GetParam(j))); 339 } 340 buffer.write_size(sig->return_count()); 341 for (size_t j = 0; j < sig->return_count(); j++) { 342 buffer.write_u8(WasmOpcodes::ValueTypeCodeFor(sig->GetReturn(j))); 343 } 344 } 345 FixupSection(buffer, start); 346 } 347 348 // == Emit imports =========================================================== 349 if (imports_.size() > 0) { 350 size_t start = EmitSection(kImportSectionCode, buffer); 351 buffer.write_size(imports_.size()); 352 for (auto import : imports_) { 353 buffer.write_u32v(0); // module name length 354 buffer.write_u32v(import.name_length); // field name length 355 buffer.write(reinterpret_cast<const byte*>(import.name), // field name 356 import.name_length); 357 buffer.write_u8(kExternalFunction); 358 buffer.write_u32v(import.sig_index); 359 } 360 FixupSection(buffer, start); 361 } 362 363 // == Emit function signatures =============================================== 364 bool has_names = false; 365 if (functions_.size() > 0) { 366 size_t start = EmitSection(kFunctionSectionCode, buffer); 367 buffer.write_size(functions_.size()); 368 for (auto function : functions_) { 369 function->WriteSignature(buffer); 370 exports += function->exported_names_.size(); 371 if (function->name_.size() > 0) has_names = true; 372 } 373 FixupSection(buffer, start); 374 } 375 376 // == emit function table ==================================================== 377 if (indirect_functions_.size() > 0) { 378 size_t start = EmitSection(kTableSectionCode, buffer); 379 buffer.write_u8(1); // table count 380 buffer.write_u8(kWasmAnyFunctionTypeForm); 381 buffer.write_u8(kResizableMaximumFlag); 382 buffer.write_size(indirect_functions_.size()); 383 buffer.write_size(indirect_functions_.size()); 384 FixupSection(buffer, start); 385 } 386 387 // == emit memory declaration ================================================ 388 { 389 size_t start = EmitSection(kMemorySectionCode, buffer); 390 buffer.write_u8(1); // memory count 391 buffer.write_u32v(kResizableMaximumFlag); 392 buffer.write_u32v(16); // min memory size 393 buffer.write_u32v(32); // max memory size 394 FixupSection(buffer, start); 395 } 396 397 // == Emit globals =========================================================== 398 if (globals_.size() > 0) { 399 size_t start = EmitSection(kGlobalSectionCode, buffer); 400 buffer.write_size(globals_.size()); 401 402 for (auto global : globals_) { 403 buffer.write_u8(WasmOpcodes::ValueTypeCodeFor(global.type)); 404 buffer.write_u8(global.mutability ? 1 : 0); 405 switch (global.init.kind) { 406 case WasmInitExpr::kI32Const: { 407 DCHECK_EQ(kWasmI32, global.type); 408 const byte code[] = {WASM_I32V_5(global.init.val.i32_const)}; 409 buffer.write(code, sizeof(code)); 410 break; 411 } 412 case WasmInitExpr::kI64Const: { 413 DCHECK_EQ(kWasmI64, global.type); 414 const byte code[] = {WASM_I64V_10(global.init.val.i64_const)}; 415 buffer.write(code, sizeof(code)); 416 break; 417 } 418 case WasmInitExpr::kF32Const: { 419 DCHECK_EQ(kWasmF32, global.type); 420 const byte code[] = {WASM_F32(global.init.val.f32_const)}; 421 buffer.write(code, sizeof(code)); 422 break; 423 } 424 case WasmInitExpr::kF64Const: { 425 DCHECK_EQ(kWasmF64, global.type); 426 const byte code[] = {WASM_F64(global.init.val.f64_const)}; 427 buffer.write(code, sizeof(code)); 428 break; 429 } 430 case WasmInitExpr::kGlobalIndex: { 431 const byte code[] = {kExprGetGlobal, 432 U32V_5(global.init.val.global_index)}; 433 buffer.write(code, sizeof(code)); 434 break; 435 } 436 default: { 437 // No initializer, emit a default value. 438 switch (global.type) { 439 case kWasmI32: { 440 const byte code[] = {WASM_I32V_1(0)}; 441 buffer.write(code, sizeof(code)); 442 break; 443 } 444 case kWasmI64: { 445 const byte code[] = {WASM_I64V_1(0)}; 446 buffer.write(code, sizeof(code)); 447 break; 448 } 449 case kWasmF32: { 450 const byte code[] = {WASM_F32(0.0)}; 451 buffer.write(code, sizeof(code)); 452 break; 453 } 454 case kWasmF64: { 455 const byte code[] = {WASM_F64(0.0)}; 456 buffer.write(code, sizeof(code)); 457 break; 458 } 459 default: 460 UNREACHABLE(); 461 } 462 } 463 } 464 buffer.write_u8(kExprEnd); 465 } 466 FixupSection(buffer, start); 467 } 468 469 // == emit exports =========================================================== 470 if (exports > 0) { 471 size_t start = EmitSection(kExportSectionCode, buffer); 472 buffer.write_u32v(exports); 473 for (auto function : functions_) function->WriteExports(buffer); 474 FixupSection(buffer, start); 475 } 476 477 // == emit start function index ============================================== 478 if (start_function_index_ >= 0) { 479 size_t start = EmitSection(kStartSectionCode, buffer); 480 buffer.write_u32v(start_function_index_ + 481 static_cast<uint32_t>(imports_.size())); 482 FixupSection(buffer, start); 483 } 484 485 // == emit function table elements =========================================== 486 if (indirect_functions_.size() > 0) { 487 size_t start = EmitSection(kElementSectionCode, buffer); 488 buffer.write_u8(1); // count of entries 489 buffer.write_u8(0); // table index 490 buffer.write_u8(kExprI32Const); // offset 491 buffer.write_u32v(0); 492 buffer.write_u8(kExprEnd); 493 buffer.write_size(indirect_functions_.size()); // element count 494 495 for (auto index : indirect_functions_) { 496 buffer.write_u32v(index + static_cast<uint32_t>(imports_.size())); 497 } 498 499 FixupSection(buffer, start); 500 } 501 502 // == emit code ============================================================== 503 if (functions_.size() > 0) { 504 size_t start = EmitSection(kCodeSectionCode, buffer); 505 buffer.write_size(functions_.size()); 506 for (auto function : functions_) { 507 function->WriteBody(buffer); 508 } 509 FixupSection(buffer, start); 510 } 511 512 // == emit data segments ===================================================== 513 if (data_segments_.size() > 0) { 514 size_t start = EmitSection(kDataSectionCode, buffer); 515 buffer.write_size(data_segments_.size()); 516 517 for (auto segment : data_segments_) { 518 buffer.write_u8(0); // linear memory segment 519 buffer.write_u8(kExprI32Const); // initializer expression for dest 520 buffer.write_u32v(segment.dest); 521 buffer.write_u8(kExprEnd); 522 buffer.write_u32v(static_cast<uint32_t>(segment.data.size())); 523 buffer.write(&segment.data[0], segment.data.size()); 524 } 525 FixupSection(buffer, start); 526 } 527 528 // == Emit names ============================================================= 529 if (has_names) { 530 // Emit the section code. 531 buffer.write_u8(kUnknownSectionCode); 532 // Emit a placeholder for the length. 533 size_t start = buffer.reserve_u32v(); 534 // Emit the section string. 535 buffer.write_size(4); 536 buffer.write(reinterpret_cast<const byte*>("name"), 4); 537 // Emit the names. 538 size_t count = functions_.size() + imports_.size(); 539 buffer.write_size(count); 540 for (size_t i = 0; i < imports_.size(); i++) { 541 buffer.write_u8(0); // empty name for import 542 buffer.write_u8(0); // no local variables 543 } 544 for (auto function : functions_) { 545 buffer.write_size(function->name_.size()); 546 buffer.write(reinterpret_cast<const byte*>(function->name_.data()), 547 function->name_.size()); 548 buffer.write_u8(0); 549 } 550 FixupSection(buffer, start); 551 } 552 } 553 554 void WasmModuleBuilder::WriteAsmJsOffsetTable(ZoneBuffer& buffer) const { 555 // == Emit asm.js offset table =============================================== 556 buffer.write_size(functions_.size()); 557 // Emit the offset table per function. 558 for (auto function : functions_) { 559 function->WriteAsmWasmOffsetTable(buffer); 560 } 561 // Append a 0 to indicate that this is an encoded table. 562 buffer.write_u8(0); 563 } 564 } // namespace wasm 565 } // namespace internal 566 } // namespace v8 567