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 |