| OLD | NEW |
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/signature.h" | 5 #include "src/signature.h" |
| 6 | 6 |
| 7 #include "src/handles.h" | 7 #include "src/handles.h" |
| 8 #include "src/v8.h" | 8 #include "src/v8.h" |
| 9 #include "src/zone-containers.h" | 9 #include "src/zone-containers.h" |
| 10 | 10 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 47 | 47 |
| 48 void EmitUint32(byte** b, uint32_t x) { | 48 void EmitUint32(byte** b, uint32_t x) { |
| 49 WriteUnalignedUInt32(*b, x); | 49 WriteUnalignedUInt32(*b, x); |
| 50 *b += 4; | 50 *b += 4; |
| 51 } | 51 } |
| 52 | 52 |
| 53 // Sections all start with a size, but it's unknown at the start. | 53 // Sections all start with a size, but it's unknown at the start. |
| 54 // We generate a large varint which we then fixup later when the size is known. | 54 // We generate a large varint which we then fixup later when the size is known. |
| 55 // | 55 // |
| 56 // TODO(jfb) Not strictly necessary since sizes are calculated ahead of time. | 56 // TODO(jfb) Not strictly necessary since sizes are calculated ahead of time. |
| 57 const size_t padded_varint = 5; | 57 const size_t kPaddedVarintSize = 5; |
| 58 | 58 |
| 59 void EmitVarInt(byte** b, size_t val) { | 59 void EmitVarInt(byte** b, size_t val) { |
| 60 while (true) { | 60 while (true) { |
| 61 size_t next = val >> 7; | 61 size_t next = val >> 7; |
| 62 byte out = static_cast<byte>(val & 0x7f); | 62 byte out = static_cast<byte>(val & 0x7f); |
| 63 if (next) { | 63 if (next) { |
| 64 *((*b)++) = 0x80 | out; | 64 *((*b)++) = 0x80 | out; |
| 65 val = next; | 65 val = next; |
| 66 } else { | 66 } else { |
| 67 *((*b)++) = out; | 67 *((*b)++) = out; |
| 68 break; | 68 break; |
| 69 } | 69 } |
| 70 } | 70 } |
| 71 } | 71 } |
| 72 | 72 |
| 73 size_t SizeOfVarInt(size_t value) { | 73 size_t SizeOfVarInt(size_t value) { |
| 74 size_t size = 0; | 74 size_t size = 0; |
| 75 do { | 75 do { |
| 76 size++; | 76 size++; |
| 77 value = value >> 7; | 77 value = value >> 7; |
| 78 } while (value > 0); | 78 } while (value > 0); |
| 79 return size; | 79 return size; |
| 80 } | 80 } |
| 81 | 81 |
| 82 void FixupSection(byte* start, byte* end) { | 82 void FixupSection(byte* start, byte* end) { |
| 83 // Same as EmitVarInt, but fixed-width with zeroes in the MSBs. | 83 // Same as EmitVarInt, but fixed-width with zeroes in the MSBs. |
| 84 size_t val = end - start - padded_varint; | 84 size_t val = end - start - kPaddedVarintSize; |
| 85 TRACE(" fixup %u\n", (unsigned)val); | 85 TRACE(" fixup %u\n", (unsigned)val); |
| 86 for (size_t pos = 0; pos != padded_varint; ++pos) { | 86 for (size_t pos = 0; pos != kPaddedVarintSize; ++pos) { |
| 87 size_t next = val >> 7; | 87 size_t next = val >> 7; |
| 88 byte out = static_cast<byte>(val & 0x7f); | 88 byte out = static_cast<byte>(val & 0x7f); |
| 89 if (pos != padded_varint - 1) { | 89 if (pos != kPaddedVarintSize - 1) { |
| 90 *(start++) = 0x80 | out; | 90 *(start++) = 0x80 | out; |
| 91 val = next; | 91 val = next; |
| 92 } else { | 92 } else { |
| 93 *(start++) = out; | 93 *(start++) = out; |
| 94 // TODO(jfb) check that the pre-allocated fixup size isn't overflowed. | 94 // TODO(jfb) check that the pre-allocated fixup size isn't overflowed. |
| 95 } | 95 } |
| 96 } | 96 } |
| 97 } | 97 } |
| 98 | 98 |
| 99 // Returns the start of the section, where the section VarInt size is. | 99 // Returns the start of the section, where the section VarInt size is. |
| 100 byte* EmitSection(WasmSection::Code code, byte** b) { | 100 byte* EmitSection(WasmSection::Code code, byte** b) { |
| 101 // Emit a placeholder for the length. |
| 101 byte* start = *b; | 102 byte* start = *b; |
| 102 const char* name = WasmSection::getName(code); | 103 for (size_t padding = 0; padding != kPaddedVarintSize; ++padding) { |
| 103 size_t length = WasmSection::getNameLength(code); | |
| 104 TRACE("emit section: %s\n", name); | |
| 105 for (size_t padding = 0; padding != padded_varint; ++padding) { | |
| 106 EmitUint8(b, 0xff); // Will get fixed up later. | 104 EmitUint8(b, 0xff); // Will get fixed up later. |
| 107 } | 105 } |
| 106 // Emit the section name. |
| 107 const char* name = WasmSection::getName(code); |
| 108 TRACE("emit section: %s\n", name); |
| 109 size_t length = WasmSection::getNameLength(code); |
| 108 EmitVarInt(b, length); // Section name string size. | 110 EmitVarInt(b, length); // Section name string size. |
| 109 for (size_t i = 0; i != length; ++i) EmitUint8(b, name[i]); | 111 for (size_t i = 0; i != length; ++i) EmitUint8(b, name[i]); |
| 112 |
| 110 return start; | 113 return start; |
| 111 } | 114 } |
| 112 } // namespace | 115 } // namespace |
| 113 | 116 |
| 114 struct WasmFunctionBuilder::Type { | 117 struct WasmFunctionBuilder::Type { |
| 115 bool param_; | 118 bool param_; |
| 116 LocalType type_; | 119 LocalType type_; |
| 117 }; | 120 }; |
| 118 | 121 |
| 119 | 122 |
| (...skipping 424 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 544 size_t body_size; | 547 size_t body_size; |
| 545 | 548 |
| 546 size_t total() { return header_size + body_size; } | 549 size_t total() { return header_size + body_size; } |
| 547 | 550 |
| 548 void Add(size_t header, size_t body) { | 551 void Add(size_t header, size_t body) { |
| 549 header_size += header; | 552 header_size += header; |
| 550 body_size += body; | 553 body_size += body; |
| 551 } | 554 } |
| 552 | 555 |
| 553 void AddSection(WasmSection::Code code, size_t other_size) { | 556 void AddSection(WasmSection::Code code, size_t other_size) { |
| 554 Add(padded_varint + SizeOfVarInt(WasmSection::getNameLength(code)) + | 557 Add(kPaddedVarintSize + SizeOfVarInt(WasmSection::getNameLength(code)) + |
| 555 WasmSection::getNameLength(code), | 558 WasmSection::getNameLength(code), |
| 556 0); | 559 0); |
| 557 if (other_size) Add(SizeOfVarInt(other_size), 0); | 560 if (other_size) Add(SizeOfVarInt(other_size), 0); |
| 558 } | 561 } |
| 559 }; | 562 }; |
| 560 | 563 |
| 561 WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const { | 564 WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const { |
| 562 Sizes sizes = {0, 0}; | 565 Sizes sizes = {0, 0}; |
| 563 | 566 |
| 564 sizes.Add(2 * sizeof(uint32_t), 0); // header | 567 sizes.Add(2 * sizeof(uint32_t), 0); // header |
| 565 | 568 |
| 566 sizes.AddSection(WasmSection::Code::Memory, 0); | |
| 567 sizes.Add(kDeclMemorySize, 0); | |
| 568 TRACE("Size after memory: %u, %u\n", (unsigned)sizes.header_size, | |
| 569 (unsigned)sizes.body_size); | |
| 570 | |
| 571 if (globals_.size() > 0) { | 569 if (globals_.size() > 0) { |
| 572 sizes.AddSection(WasmSection::Code::Globals, globals_.size()); | 570 sizes.AddSection(WasmSection::Code::Globals, globals_.size()); |
| 573 /* These globals never have names, so are always 3 bytes. */ | 571 /* These globals never have names, so are always 3 bytes. */ |
| 574 sizes.Add(3 * globals_.size(), 0); | 572 sizes.Add(3 * globals_.size(), 0); |
| 575 TRACE("Size after globals: %u, %u\n", (unsigned)sizes.header_size, | 573 TRACE("Size after globals: %u, %u\n", (unsigned)sizes.header_size, |
| 576 (unsigned)sizes.body_size); | 574 (unsigned)sizes.body_size); |
| 577 } | 575 } |
| 578 | 576 |
| 579 if (signatures_.size() > 0) { | 577 if (signatures_.size() > 0) { |
| 580 sizes.AddSection(WasmSection::Code::Signatures, signatures_.size()); | 578 sizes.AddSection(WasmSection::Code::Signatures, signatures_.size()); |
| 581 for (auto sig : signatures_) { | 579 for (auto sig : signatures_) { |
| 582 sizes.Add( | 580 sizes.Add( |
| 583 1 + SizeOfVarInt(sig->parameter_count()) + sig->parameter_count(), 0); | 581 1 + SizeOfVarInt(sig->parameter_count()) + sig->parameter_count(), 0); |
| 584 } | 582 } |
| 585 TRACE("Size after signatures: %u, %u\n", (unsigned)sizes.header_size, | 583 TRACE("Size after signatures: %u, %u\n", (unsigned)sizes.header_size, |
| 586 (unsigned)sizes.body_size); | 584 (unsigned)sizes.body_size); |
| 587 } | 585 } |
| 588 | 586 |
| 589 if (functions_.size() > 0) { | 587 if (functions_.size() > 0) { |
| 590 sizes.AddSection(WasmSection::Code::Functions, functions_.size()); | 588 sizes.AddSection(WasmSection::Code::Functions, functions_.size()); |
| 591 for (auto function : functions_) { | 589 for (auto function : functions_) { |
| 592 sizes.Add(function->HeaderSize() + function->BodySize(), | 590 sizes.Add(function->HeaderSize() + function->BodySize(), |
| 593 function->NameSize()); | 591 function->NameSize()); |
| 594 } | 592 } |
| 595 TRACE("Size after functions: %u, %u\n", (unsigned)sizes.header_size, | 593 TRACE("Size after functions: %u, %u\n", (unsigned)sizes.header_size, |
| 596 (unsigned)sizes.body_size); | 594 (unsigned)sizes.body_size); |
| 597 } | 595 } |
| 598 | 596 |
| 597 if (indirect_functions_.size() > 0) { |
| 598 sizes.AddSection(WasmSection::Code::FunctionTable, |
| 599 indirect_functions_.size()); |
| 600 for (auto function_index : indirect_functions_) { |
| 601 sizes.Add(SizeOfVarInt(function_index), 0); |
| 602 } |
| 603 TRACE("Size after indirect functions: %u, %u\n", |
| 604 (unsigned)sizes.header_size, (unsigned)sizes.body_size); |
| 605 } |
| 606 |
| 607 sizes.AddSection(WasmSection::Code::Memory, 0); |
| 608 sizes.Add(kDeclMemorySize, 0); |
| 609 TRACE("Size after memory: %u, %u\n", (unsigned)sizes.header_size, |
| 610 (unsigned)sizes.body_size); |
| 611 |
| 599 if (start_function_index_ >= 0) { | 612 if (start_function_index_ >= 0) { |
| 600 sizes.AddSection(WasmSection::Code::StartFunction, 0); | 613 sizes.AddSection(WasmSection::Code::StartFunction, 0); |
| 601 sizes.Add(SizeOfVarInt(start_function_index_), 0); | 614 sizes.Add(SizeOfVarInt(start_function_index_), 0); |
| 602 TRACE("Size after start: %u, %u\n", (unsigned)sizes.header_size, | 615 TRACE("Size after start: %u, %u\n", (unsigned)sizes.header_size, |
| 603 (unsigned)sizes.body_size); | 616 (unsigned)sizes.body_size); |
| 604 } | 617 } |
| 605 | 618 |
| 606 if (data_segments_.size() > 0) { | 619 if (data_segments_.size() > 0) { |
| 607 sizes.AddSection(WasmSection::Code::DataSegments, data_segments_.size()); | 620 sizes.AddSection(WasmSection::Code::DataSegments, data_segments_.size()); |
| 608 for (auto segment : data_segments_) { | 621 for (auto segment : data_segments_) { |
| 609 sizes.Add(segment->HeaderSize(), segment->BodySize()); | 622 sizes.Add(segment->HeaderSize(), segment->BodySize()); |
| 610 } | 623 } |
| 611 TRACE("Size after data segments: %u, %u\n", (unsigned)sizes.header_size, | 624 TRACE("Size after data segments: %u, %u\n", (unsigned)sizes.header_size, |
| 612 (unsigned)sizes.body_size); | 625 (unsigned)sizes.body_size); |
| 613 } | 626 } |
| 614 | 627 |
| 615 if (indirect_functions_.size() > 0) { | |
| 616 sizes.AddSection(WasmSection::Code::FunctionTable, | |
| 617 indirect_functions_.size()); | |
| 618 for (auto function_index : indirect_functions_) { | |
| 619 sizes.Add(SizeOfVarInt(function_index), 0); | |
| 620 } | |
| 621 TRACE("Size after indirect functions: %u, %u\n", | |
| 622 (unsigned)sizes.header_size, (unsigned)sizes.body_size); | |
| 623 } | |
| 624 | |
| 625 if (sizes.body_size > 0) { | 628 if (sizes.body_size > 0) { |
| 626 sizes.AddSection(WasmSection::Code::End, 0); | 629 sizes.AddSection(WasmSection::Code::End, 0); |
| 627 TRACE("Size after end: %u, %u\n", (unsigned)sizes.header_size, | 630 TRACE("Size after end: %u, %u\n", (unsigned)sizes.header_size, |
| 628 (unsigned)sizes.body_size); | 631 (unsigned)sizes.body_size); |
| 629 } | 632 } |
| 630 | 633 |
| 631 ZoneVector<uint8_t> buffer_vector(sizes.total(), zone); | 634 ZoneVector<uint8_t> buffer_vector(sizes.total(), zone); |
| 632 byte* buffer = &buffer_vector[0]; | 635 byte* buffer = &buffer_vector[0]; |
| 633 byte* header = buffer; | 636 byte* header = buffer; |
| 634 byte* body = buffer + sizes.header_size; | 637 byte* body = buffer + sizes.header_size; |
| 635 | 638 |
| 636 // -- emit magic ------------------------------------------------------------- | 639 // -- emit magic ------------------------------------------------------------- |
| 637 TRACE("emit magic\n"); | 640 TRACE("emit magic\n"); |
| 638 EmitUint32(&header, kWasmMagic); | 641 EmitUint32(&header, kWasmMagic); |
| 639 EmitUint32(&header, kWasmVersion); | 642 EmitUint32(&header, kWasmVersion); |
| 640 | 643 |
| 641 // -- emit memory declaration ------------------------------------------------ | |
| 642 { | |
| 643 byte* section = EmitSection(WasmSection::Code::Memory, &header); | |
| 644 EmitVarInt(&header, 16); // min memory size | |
| 645 EmitVarInt(&header, 16); // max memory size | |
| 646 EmitUint8(&header, 0); // memory export | |
| 647 static_assert(kDeclMemorySize == 3, "memory size must match emit above"); | |
| 648 FixupSection(section, header); | |
| 649 } | |
| 650 | |
| 651 // -- emit globals ----------------------------------------------------------- | 644 // -- emit globals ----------------------------------------------------------- |
| 652 if (globals_.size() > 0) { | 645 if (globals_.size() > 0) { |
| 653 byte* section = EmitSection(WasmSection::Code::Globals, &header); | 646 byte* section = EmitSection(WasmSection::Code::Globals, &header); |
| 654 EmitVarInt(&header, globals_.size()); | 647 EmitVarInt(&header, globals_.size()); |
| 655 | 648 |
| 656 for (auto global : globals_) { | 649 for (auto global : globals_) { |
| 657 EmitVarInt(&header, 0); // Length of the global name. | 650 EmitVarInt(&header, 0); // Length of the global name. |
| 658 EmitUint8(&header, WasmOpcodes::MemTypeCodeFor(global.first)); | 651 EmitUint8(&header, WasmOpcodes::MemTypeCodeFor(global.first)); |
| 659 EmitUint8(&header, global.second); | 652 EmitUint8(&header, global.second); |
| 660 } | 653 } |
| (...skipping 23 matching lines...) Expand all Loading... |
| 684 if (functions_.size() > 0) { | 677 if (functions_.size() > 0) { |
| 685 byte* section = EmitSection(WasmSection::Code::Functions, &header); | 678 byte* section = EmitSection(WasmSection::Code::Functions, &header); |
| 686 EmitVarInt(&header, functions_.size()); | 679 EmitVarInt(&header, functions_.size()); |
| 687 | 680 |
| 688 for (auto func : functions_) { | 681 for (auto func : functions_) { |
| 689 func->Serialize(buffer, &header, &body); | 682 func->Serialize(buffer, &header, &body); |
| 690 } | 683 } |
| 691 FixupSection(section, header); | 684 FixupSection(section, header); |
| 692 } | 685 } |
| 693 | 686 |
| 687 // -- emit function table ---------------------------------------------------- |
| 688 if (indirect_functions_.size() > 0) { |
| 689 byte* section = EmitSection(WasmSection::Code::FunctionTable, &header); |
| 690 EmitVarInt(&header, indirect_functions_.size()); |
| 691 |
| 692 for (auto index : indirect_functions_) { |
| 693 EmitVarInt(&header, index); |
| 694 } |
| 695 FixupSection(section, header); |
| 696 } |
| 697 |
| 698 // -- emit memory declaration ------------------------------------------------ |
| 699 { |
| 700 byte* section = EmitSection(WasmSection::Code::Memory, &header); |
| 701 EmitVarInt(&header, 16); // min memory size |
| 702 EmitVarInt(&header, 16); // max memory size |
| 703 EmitUint8(&header, 0); // memory export |
| 704 static_assert(kDeclMemorySize == 3, "memory size must match emit above"); |
| 705 FixupSection(section, header); |
| 706 } |
| 707 |
| 694 // -- emit start function index ---------------------------------------------- | 708 // -- emit start function index ---------------------------------------------- |
| 695 if (start_function_index_ >= 0) { | 709 if (start_function_index_ >= 0) { |
| 696 byte* section = EmitSection(WasmSection::Code::StartFunction, &header); | 710 byte* section = EmitSection(WasmSection::Code::StartFunction, &header); |
| 697 EmitVarInt(&header, start_function_index_); | 711 EmitVarInt(&header, start_function_index_); |
| 698 FixupSection(section, header); | 712 FixupSection(section, header); |
| 699 } | 713 } |
| 700 | 714 |
| 701 // -- emit data segments ----------------------------------------------------- | 715 // -- emit data segments ----------------------------------------------------- |
| 702 if (data_segments_.size() > 0) { | 716 if (data_segments_.size() > 0) { |
| 703 byte* section = EmitSection(WasmSection::Code::DataSegments, &header); | 717 byte* section = EmitSection(WasmSection::Code::DataSegments, &header); |
| 704 EmitVarInt(&header, data_segments_.size()); | 718 EmitVarInt(&header, data_segments_.size()); |
| 705 | 719 |
| 706 for (auto segment : data_segments_) { | 720 for (auto segment : data_segments_) { |
| 707 segment->Serialize(buffer, &header, &body); | 721 segment->Serialize(buffer, &header, &body); |
| 708 } | 722 } |
| 709 FixupSection(section, header); | 723 FixupSection(section, header); |
| 710 } | 724 } |
| 711 | 725 |
| 712 // -- emit function table ---------------------------------------------------- | |
| 713 if (indirect_functions_.size() > 0) { | |
| 714 byte* section = EmitSection(WasmSection::Code::FunctionTable, &header); | |
| 715 EmitVarInt(&header, indirect_functions_.size()); | |
| 716 | |
| 717 for (auto index : indirect_functions_) { | |
| 718 EmitVarInt(&header, index); | |
| 719 } | |
| 720 FixupSection(section, header); | |
| 721 } | |
| 722 | |
| 723 if (sizes.body_size > 0) { | 726 if (sizes.body_size > 0) { |
| 724 byte* section = EmitSection(WasmSection::Code::End, &header); | 727 byte* section = EmitSection(WasmSection::Code::End, &header); |
| 725 FixupSection(section, header); | 728 FixupSection(section, header); |
| 726 } | 729 } |
| 727 | 730 |
| 728 return new (zone) WasmModuleIndex(buffer, buffer + sizes.total()); | 731 return new (zone) WasmModuleIndex(buffer, buffer + sizes.total()); |
| 729 } | 732 } |
| 730 | 733 |
| 731 | 734 |
| 732 std::vector<uint8_t> UnsignedLEB128From(uint32_t result) { | 735 std::vector<uint8_t> UnsignedLEB128From(uint32_t result) { |
| 733 std::vector<uint8_t> output; | 736 std::vector<uint8_t> output; |
| 734 uint8_t next = 0; | 737 uint8_t next = 0; |
| 735 int shift = 0; | 738 int shift = 0; |
| 736 do { | 739 do { |
| 737 next = static_cast<uint8_t>(result >> shift); | 740 next = static_cast<uint8_t>(result >> shift); |
| 738 if (((result >> shift) & 0xFFFFFF80) != 0) { | 741 if (((result >> shift) & 0xFFFFFF80) != 0) { |
| 739 next = next | 0x80; | 742 next = next | 0x80; |
| 740 } | 743 } |
| 741 output.push_back(next); | 744 output.push_back(next); |
| 742 shift += 7; | 745 shift += 7; |
| 743 } while ((next & 0x80) != 0); | 746 } while ((next & 0x80) != 0); |
| 744 return output; | 747 return output; |
| 745 } | 748 } |
| 746 } // namespace wasm | 749 } // namespace wasm |
| 747 } // namespace internal | 750 } // namespace internal |
| 748 } // namespace v8 | 751 } // namespace v8 |
| OLD | NEW |