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