Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(144)

Unified Diff: src/wasm/encoder.cc

Issue 1504713014: Initial import of v8-native WASM. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/wasm/encoder.h ('k') | src/wasm/module-decoder.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/wasm/encoder.cc
diff --git a/src/wasm/encoder.cc b/src/wasm/encoder.cc
new file mode 100644
index 0000000000000000000000000000000000000000..cde09720062a0bfbf6880bb9fd0a40adeace5a49
--- /dev/null
+++ b/src/wasm/encoder.cc
@@ -0,0 +1,588 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/signature.h"
+
+#include "src/handles.h"
+#include "src/v8.h"
+#include "src/zone-containers.h"
+
+#include "src/wasm/ast-decoder.h"
+#include "src/wasm/encoder.h"
+#include "src/wasm/wasm-module.h"
+#include "src/wasm/wasm-opcodes.h"
+
+#include "src/v8memory.h"
+
+namespace v8 {
+namespace internal {
+namespace wasm {
+
+/*TODO: add error cases for adding too many locals, too many functions and bad
+ indices in body */
+
+namespace {
+void EmitUint8(byte** b, uint8_t x) {
+ Memory::uint8_at(*b) = x;
+ *b += 1;
+}
+
+
+void EmitUint16(byte** b, uint16_t x) {
+ Memory::uint16_at(*b) = x;
+ *b += 2;
+}
+
+
+void EmitUint32(byte** b, uint32_t x) {
+ Memory::uint32_at(*b) = x;
+ *b += 4;
+}
+
+
+void EmitVarInt(byte** b, size_t val) {
+ while (true) {
+ size_t next = val >> 7;
+ byte out = static_cast<byte>(val & 0x7f);
+ if (next) {
+ *((*b)++) = 0x80 | out;
+ val = next;
+ } else {
+ *((*b)++) = out;
+ break;
+ }
+ }
+}
+} // namespace
+
+
+struct WasmFunctionBuilder::Type {
+ bool param_;
+ LocalType type_;
+};
+
+
+WasmFunctionBuilder::WasmFunctionBuilder(Zone* zone, const unsigned char* name,
+ int name_length)
+ : return_type_(kAstI32),
+ locals_(zone),
+ exported_(0),
+ external_(0),
+ body_(zone),
+ local_indices_(zone),
+ name_(zone) {
+ if (name_length > 0) {
+ for (int i = 0; i < name_length; i++) {
+ name_.push_back(*(name + i));
+ }
+ name_.push_back('\0');
+ }
+}
+
+
+uint16_t WasmFunctionBuilder::AddParam(LocalType type) {
+ return AddVar(type, true);
+}
+
+
+uint16_t WasmFunctionBuilder::AddLocal(LocalType type) {
+ return AddVar(type, false);
+}
+
+
+uint16_t WasmFunctionBuilder::AddVar(LocalType type, bool param) {
+ locals_.push_back({param, type});
+ return static_cast<uint16_t>(locals_.size() - 1);
+}
+
+
+void WasmFunctionBuilder::ReturnType(LocalType type) { return_type_ = type; }
+
+
+void WasmFunctionBuilder::EmitCode(const byte* code, uint32_t code_size) {
+ EmitCode(code, code_size, NULL, 0);
+}
+
+
+void WasmFunctionBuilder::EmitCode(const byte* code, uint32_t code_size,
+ const uint32_t* local_indices,
+ uint32_t indices_size) {
+ size_t size = body_.size();
+ for (size_t i = 0; i < code_size; i++) {
+ body_.push_back(code[i]);
+ }
+ for (size_t i = 0; i < indices_size; i++) {
+ local_indices_.push_back(local_indices[i] + static_cast<uint32_t>(size));
+ }
+}
+
+
+void WasmFunctionBuilder::Emit(WasmOpcode opcode) {
+ body_.push_back(static_cast<byte>(opcode));
+}
+
+
+void WasmFunctionBuilder::EmitWithU8(WasmOpcode opcode, const byte immediate) {
+ body_.push_back(static_cast<byte>(opcode));
+ body_.push_back(immediate);
+}
+
+
+void WasmFunctionBuilder::EmitWithLocal(WasmOpcode opcode) {
+ body_.push_back(static_cast<byte>(opcode));
+ local_indices_.push_back(static_cast<uint32_t>(body_.size()) - 1);
+}
+
+
+uint32_t WasmFunctionBuilder::EmitEditableImmediate(const byte immediate) {
+ body_.push_back(immediate);
+ return static_cast<uint32_t>(body_.size()) - 1;
+}
+
+
+void WasmFunctionBuilder::EditImmediate(uint32_t offset, const byte immediate) {
+ DCHECK(offset < body_.size());
+ body_[offset] = immediate;
+}
+
+
+void WasmFunctionBuilder::Exported(uint8_t flag) { exported_ = flag; }
+
+
+void WasmFunctionBuilder::External(uint8_t flag) { external_ = flag; }
+
+
+WasmFunctionEncoder* WasmFunctionBuilder::Build(Zone* zone,
+ WasmModuleBuilder* mb) const {
+ WasmFunctionEncoder* e =
+ new (zone) WasmFunctionEncoder(zone, return_type_, exported_, external_);
+ auto var_index = new uint16_t[locals_.size()];
+ IndexVars(e, var_index);
+ const byte* start = body_.data();
+ const byte* end = start + body_.size();
+ size_t local_index = 0;
+ for (size_t i = 0; i < body_.size();) {
+ if (local_index < local_indices_.size() &&
+ i == local_indices_[local_index]) {
+ int length = 0;
+ uint32_t index;
+ ReadUnsignedLEB128Operand(start + i, end, &length, &index);
+ uint16_t new_index = var_index[index];
+ const std::vector<uint8_t>& index_vec = UnsignedLEB128From(new_index);
+ for (size_t j = 0; j < index_vec.size(); j++) {
+ e->body_.push_back(index_vec.at(j));
+ }
+ i += length;
+ local_index++;
+ } else {
+ e->body_.push_back(*(start + i));
+ i++;
+ }
+ }
+ FunctionSig::Builder sig(zone, return_type_ == kAstStmt ? 0 : 1,
+ e->params_.size());
+ if (return_type_ != kAstStmt) {
+ sig.AddReturn(static_cast<LocalType>(return_type_));
+ }
+ for (size_t i = 0; i < e->params_.size(); i++) {
+ sig.AddParam(static_cast<LocalType>(e->params_[i]));
+ }
+ e->signature_index_ = mb->AddSignature(sig.Build());
+ delete[] var_index;
+ e->name_.insert(e->name_.begin(), name_.begin(), name_.end());
+ return e;
+}
+
+
+void WasmFunctionBuilder::IndexVars(WasmFunctionEncoder* e,
+ uint16_t* var_index) const {
+ uint16_t param = 0;
+ uint16_t int32 = 0;
+ uint16_t int64 = 0;
+ uint16_t float32 = 0;
+ uint16_t float64 = 0;
+ for (size_t i = 0; i < locals_.size(); i++) {
+ if (locals_.at(i).param_) {
+ param++;
+ } else if (locals_.at(i).type_ == kAstI32) {
+ int32++;
+ } else if (locals_.at(i).type_ == kAstI64) {
+ int64++;
+ } else if (locals_.at(i).type_ == kAstF32) {
+ float32++;
+ } else if (locals_.at(i).type_ == kAstF64) {
+ float64++;
+ }
+ }
+ e->local_int32_count_ = int32;
+ e->local_int64_count_ = int64;
+ e->local_float32_count_ = float32;
+ e->local_float64_count_ = float64;
+ float64 = param + int32 + int64 + float32;
+ float32 = param + int32 + int64;
+ int64 = param + int32;
+ int32 = param;
+ param = 0;
+ for (size_t i = 0; i < locals_.size(); i++) {
+ if (locals_.at(i).param_) {
+ e->params_.push_back(locals_.at(i).type_);
+ var_index[i] = param++;
+ } else if (locals_.at(i).type_ == kAstI32) {
+ var_index[i] = int32++;
+ } else if (locals_.at(i).type_ == kAstI64) {
+ var_index[i] = int64++;
+ } else if (locals_.at(i).type_ == kAstF32) {
+ var_index[i] = float32++;
+ } else if (locals_.at(i).type_ == kAstF64) {
+ var_index[i] = float64++;
+ }
+ }
+}
+
+
+WasmFunctionEncoder::WasmFunctionEncoder(Zone* zone, LocalType return_type,
+ bool exported, bool external)
+ : params_(zone),
+ exported_(exported),
+ external_(external),
+ body_(zone),
+ name_(zone) {}
+
+
+uint32_t WasmFunctionEncoder::HeaderSize() const {
+ uint32_t size = 3;
+ if (HasLocals()) size += 8;
+ if (!external_) size += 2;
+ if (HasName()) size += 4;
+ return size;
+}
+
+
+uint32_t WasmFunctionEncoder::BodySize(void) const {
+ return external_ ? 0 : static_cast<uint32_t>(body_.size());
+}
+
+
+uint32_t WasmFunctionEncoder::NameSize() const {
+ return exported_ ? static_cast<uint32_t>(name_.size()) : 0;
+}
+
+
+void WasmFunctionEncoder::Serialize(byte* buffer, byte** header,
+ byte** body) const {
+ uint8_t decl_bits = (exported_ ? kDeclFunctionExport : 0) |
+ (external_ ? kDeclFunctionImport : 0) |
+ (HasLocals() ? kDeclFunctionLocals : 0) |
+ (HasName() ? kDeclFunctionName : 0);
+
+ EmitUint8(header, decl_bits);
+ EmitUint16(header, signature_index_);
+
+ if (HasName()) {
+ uint32_t name_offset = static_cast<uint32_t>(*body - buffer);
+ EmitUint32(header, name_offset);
+ std::memcpy(*body, name_.data(), name_.size());
+ (*body) += name_.size();
+ }
+
+ if (HasLocals()) {
+ EmitUint16(header, local_int32_count_);
+ EmitUint16(header, local_int64_count_);
+ EmitUint16(header, local_float32_count_);
+ EmitUint16(header, local_float64_count_);
+ }
+
+ if (!external_) {
+ EmitUint16(header, static_cast<uint16_t>(body_.size()));
+ std::memcpy(*header, body_.data(), body_.size());
+ (*header) += body_.size();
+ }
+}
+
+
+WasmDataSegmentEncoder::WasmDataSegmentEncoder(Zone* zone, const byte* data,
+ uint32_t size, uint32_t dest)
+ : data_(zone), dest_(dest) {
+ for (size_t i = 0; i < size; i++) {
+ data_.push_back(data[i]);
+ }
+}
+
+
+uint32_t WasmDataSegmentEncoder::HeaderSize() const {
+ static const int kDataSegmentSize = 13;
+ return kDataSegmentSize;
+}
+
+
+uint32_t WasmDataSegmentEncoder::BodySize() const {
+ return static_cast<uint32_t>(data_.size());
+}
+
+
+void WasmDataSegmentEncoder::Serialize(byte* buffer, byte** header,
+ byte** body) const {
+ uint32_t body_offset = static_cast<uint32_t>(*body - buffer);
+ EmitUint32(header, dest_);
+ EmitUint32(header, body_offset);
+ EmitUint32(header, static_cast<uint32_t>(data_.size()));
+ EmitUint8(header, 1); // init
+
+ std::memcpy(*body, data_.data(), data_.size());
+ (*body) += data_.size();
+}
+
+
+WasmModuleBuilder::WasmModuleBuilder(Zone* zone)
+ : zone_(zone),
+ signatures_(zone),
+ functions_(zone),
+ data_segments_(zone),
+ indirect_functions_(zone),
+ globals_(zone),
+ signature_map_(zone) {}
+
+
+uint16_t WasmModuleBuilder::AddFunction(const unsigned char* name,
+ int name_length) {
+ functions_.push_back(new (zone_)
+ WasmFunctionBuilder(zone_, name, name_length));
+ return static_cast<uint16_t>(functions_.size() - 1);
+}
+
+
+WasmFunctionBuilder* WasmModuleBuilder::FunctionAt(size_t index) {
+ if (functions_.size() > index) {
+ return functions_.at(index);
+ } else {
+ return nullptr;
+ }
+}
+
+
+void WasmModuleBuilder::AddDataSegment(WasmDataSegmentEncoder* data) {
+ data_segments_.push_back(data);
+}
+
+
+int WasmModuleBuilder::CompareFunctionSigs::operator()(FunctionSig* a,
+ FunctionSig* b) {
+ if (a->return_count() < b->return_count()) return -1;
+ if (a->return_count() > b->return_count()) return 1;
+ if (a->parameter_count() < b->parameter_count()) return -1;
+ if (a->parameter_count() > b->parameter_count()) return 1;
+ for (size_t r = 0; r < a->return_count(); r++) {
+ if (a->GetReturn(r) < b->GetReturn(r)) return -1;
+ if (a->GetReturn(r) > b->GetReturn(r)) return 1;
+ }
+ for (size_t p = 0; p < a->parameter_count(); p++) {
+ if (a->GetParam(p) < b->GetParam(p)) return -1;
+ if (a->GetParam(p) > b->GetParam(p)) return 1;
+ }
+ return 0;
+}
+
+
+uint16_t WasmModuleBuilder::AddSignature(FunctionSig* sig) {
+ SignatureMap::iterator pos = signature_map_.find(sig);
+ if (pos != signature_map_.end()) {
+ return pos->second;
+ } else {
+ uint16_t index = static_cast<uint16_t>(signatures_.size());
+ signature_map_[sig] = index;
+ signatures_.push_back(sig);
+ return index;
+ }
+}
+
+
+void WasmModuleBuilder::AddIndirectFunction(uint16_t index) {
+ indirect_functions_.push_back(index);
+}
+
+
+WasmModuleWriter* WasmModuleBuilder::Build(Zone* zone) {
+ WasmModuleWriter* writer = new (zone) WasmModuleWriter(zone);
+ for (auto function : functions_) {
+ writer->functions_.push_back(function->Build(zone, this));
+ }
+ for (auto segment : data_segments_) {
+ writer->data_segments_.push_back(segment);
+ }
+ for (auto sig : signatures_) {
+ writer->signatures_.push_back(sig);
+ }
+ for (auto index : indirect_functions_) {
+ writer->indirect_functions_.push_back(index);
+ }
+ for (auto global : globals_) {
+ writer->globals_.push_back(global);
+ }
+ return writer;
+}
+
+
+uint32_t WasmModuleBuilder::AddGlobal(MachineType type, bool exported) {
+ globals_.push_back(std::make_pair(type, exported));
+ return static_cast<uint32_t>(globals_.size() - 1);
+}
+
+
+WasmModuleWriter::WasmModuleWriter(Zone* zone)
+ : functions_(zone),
+ data_segments_(zone),
+ signatures_(zone),
+ indirect_functions_(zone),
+ globals_(zone) {}
+
+
+struct Sizes {
+ size_t header_size;
+ size_t body_size;
+
+ size_t total() { return header_size + body_size; }
+
+ void Add(size_t header, size_t body) {
+ header_size += header;
+ body_size += body;
+ }
+
+ void AddSection(size_t size) {
+ if (size > 0) {
+ Add(1, 0);
+ while (size > 0) {
+ Add(1, 0);
+ size = size >> 7;
+ }
+ }
+ }
+};
+
+
+WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const {
+ Sizes sizes = {0, 0};
+
+ sizes.Add(1, 0);
+ sizes.Add(kDeclMemorySize, 0);
+
+ sizes.AddSection(signatures_.size());
+ for (auto sig : signatures_) {
+ sizes.Add(2 + sig->parameter_count(), 0);
+ }
+
+ sizes.AddSection(globals_.size());
+ if (globals_.size() > 0) {
+ sizes.Add(kDeclGlobalSize * globals_.size(), 0);
+ }
+
+ sizes.AddSection(functions_.size());
+ for (auto function : functions_) {
+ sizes.Add(function->HeaderSize() + function->BodySize(),
+ function->NameSize());
+ }
+
+ sizes.AddSection(data_segments_.size());
+ for (auto segment : data_segments_) {
+ sizes.Add(segment->HeaderSize(), segment->BodySize());
+ }
+
+ sizes.AddSection(indirect_functions_.size());
+ sizes.Add(2 * static_cast<uint32_t>(indirect_functions_.size()), 0);
+
+ if (sizes.body_size > 0) sizes.Add(1, 0);
+
+ ZoneVector<uint8_t> buffer_vector(sizes.total(), zone);
+ byte* buffer = buffer_vector.data();
+ byte* header = buffer;
+ byte* body = buffer + sizes.header_size;
+
+ // -- emit memory declaration ------------------------------------------------
+ EmitUint8(&header, kDeclMemory);
+ EmitUint8(&header, 16); // min memory size
+ EmitUint8(&header, 16); // max memory size
+ EmitUint8(&header, 0); // memory export
+
+ // -- emit globals -----------------------------------------------------------
+ if (globals_.size() > 0) {
+ EmitUint8(&header, kDeclGlobals);
+ EmitVarInt(&header, globals_.size());
+
+ for (auto global : globals_) {
+ EmitUint32(&header, 0);
+ EmitUint8(&header, WasmOpcodes::MemTypeCodeFor(global.first));
+ EmitUint8(&header, global.second);
+ }
+ }
+
+ // -- emit signatures --------------------------------------------------------
+ if (signatures_.size() > 0) {
+ EmitUint8(&header, kDeclSignatures);
+ EmitVarInt(&header, signatures_.size());
+
+ for (FunctionSig* sig : signatures_) {
+ EmitUint8(&header, static_cast<byte>(sig->parameter_count()));
+ if (sig->return_count() > 0) {
+ EmitUint8(&header, WasmOpcodes::LocalTypeCodeFor(sig->GetReturn()));
+ } else {
+ EmitUint8(&header, kLocalVoid);
+ }
+ for (size_t j = 0; j < sig->parameter_count(); j++) {
+ EmitUint8(&header, WasmOpcodes::LocalTypeCodeFor(sig->GetParam(j)));
+ }
+ }
+ }
+
+ // -- emit functions ---------------------------------------------------------
+ if (functions_.size() > 0) {
+ EmitUint8(&header, kDeclFunctions);
+ EmitVarInt(&header, functions_.size());
+
+ for (auto func : functions_) {
+ func->Serialize(buffer, &header, &body);
+ }
+ }
+
+ // -- emit data segments -----------------------------------------------------
+ if (data_segments_.size() > 0) {
+ EmitUint8(&header, kDeclDataSegments);
+ EmitVarInt(&header, data_segments_.size());
+
+ for (auto segment : data_segments_) {
+ segment->Serialize(buffer, &header, &body);
+ }
+ }
+
+ // -- emit function table ----------------------------------------------------
+ if (indirect_functions_.size() > 0) {
+ EmitUint8(&header, kDeclFunctionTable);
+ EmitVarInt(&header, indirect_functions_.size());
+
+ for (auto index : indirect_functions_) {
+ EmitUint16(&header, index);
+ }
+ }
+
+ if (sizes.body_size > 0) EmitUint8(&header, kDeclEnd);
+
+ return new (zone) WasmModuleIndex(buffer, buffer + sizes.total());
+}
+
+
+std::vector<uint8_t> UnsignedLEB128From(uint32_t result) {
+ std::vector<uint8_t> output;
+ uint8_t next = 0;
+ int shift = 0;
+ do {
+ next = static_cast<uint8_t>(result >> shift);
+ if (((result >> shift) & 0xFFFFFF80) != 0) {
+ next = next | 0x80;
+ }
+ output.push_back(next);
+ shift += 7;
+ } while ((next & 0x80) != 0);
+ return output;
+}
+} // namespace wasm
+} // namespace internal
+} // namespace v8
« no previous file with comments | « src/wasm/encoder.h ('k') | src/wasm/module-decoder.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698