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-containers.h" 10 11 #include "src/wasm/ast-decoder.h" 12 #include "src/wasm/encoder.h" 13 #include "src/wasm/leb-helper.h" 14 #include "src/wasm/wasm-macro-gen.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 name and the size as a padded varint that can be patched 34 // later. 35 size_t EmitSection(WasmSection::Code code, ZoneBuffer& buffer) { 36 // Emit the section name. 37 const char* name = WasmSection::getName(code); 38 TRACE("emit section: %s\n", name); 39 size_t length = WasmSection::getNameLength(code); 40 buffer.write_size(length); // Section name string size. 41 buffer.write(reinterpret_cast<const byte*>(name), length); 42 43 // Emit a placeholder for the length. 44 return buffer.reserve_u32v(); 45 } 46 47 // Patch the size of a section after it's finished. 48 void FixupSection(ZoneBuffer& buffer, size_t start) { 49 buffer.patch_u32v(start, static_cast<uint32_t>(buffer.offset() - start - 50 kPaddedVarInt32Size)); 51 } 52 53 WasmFunctionBuilder::WasmFunctionBuilder(WasmModuleBuilder* builder) 54 : builder_(builder), 55 locals_(builder->zone()), 56 signature_index_(0), 57 exported_(0), 58 body_(builder->zone()), 59 name_(builder->zone()) {} 60 61 void WasmFunctionBuilder::EmitVarInt(uint32_t val) { 62 byte buffer[8]; 63 byte* ptr = buffer; 64 LEBHelper::write_u32v(&ptr, val); 65 for (byte* p = buffer; p < ptr; p++) { 66 body_.push_back(*p); 67 } 68 } 69 70 void WasmFunctionBuilder::SetSignature(FunctionSig* sig) { 71 DCHECK(!locals_.has_sig()); 72 locals_.set_sig(sig); 73 signature_index_ = builder_->AddSignature(sig); 74 } 75 76 uint32_t WasmFunctionBuilder::AddLocal(LocalType type) { 77 DCHECK(locals_.has_sig()); 78 return locals_.AddLocals(1, type); 79 } 80 81 void WasmFunctionBuilder::EmitGetLocal(uint32_t local_index) { 82 EmitWithVarInt(kExprGetLocal, local_index); 83 } 84 85 void WasmFunctionBuilder::EmitSetLocal(uint32_t local_index) { 86 EmitWithVarInt(kExprSetLocal, local_index); 87 } 88 89 void WasmFunctionBuilder::EmitCode(const byte* code, uint32_t code_size) { 90 for (size_t i = 0; i < code_size; ++i) { 91 body_.push_back(code[i]); 92 } 93 } 94 95 void WasmFunctionBuilder::Emit(WasmOpcode opcode) { 96 body_.push_back(static_cast<byte>(opcode)); 97 } 98 99 void WasmFunctionBuilder::EmitWithU8(WasmOpcode opcode, const byte immediate) { 100 body_.push_back(static_cast<byte>(opcode)); 101 body_.push_back(immediate); 102 } 103 104 void WasmFunctionBuilder::EmitWithU8U8(WasmOpcode opcode, const byte imm1, 105 const byte imm2) { 106 body_.push_back(static_cast<byte>(opcode)); 107 body_.push_back(imm1); 108 body_.push_back(imm2); 109 } 110 111 void WasmFunctionBuilder::EmitWithVarInt(WasmOpcode opcode, 112 uint32_t immediate) { 113 body_.push_back(static_cast<byte>(opcode)); 114 EmitVarInt(immediate); 115 } 116 117 void WasmFunctionBuilder::EmitI32Const(int32_t value) { 118 // TODO(titzer): variable-length signed and unsigned i32 constants. 119 if (-128 <= value && value <= 127) { 120 EmitWithU8(kExprI8Const, static_cast<byte>(value)); 121 } else { 122 byte code[] = {WASM_I32V_5(value)}; 123 EmitCode(code, sizeof(code)); 124 } 125 } 126 127 void WasmFunctionBuilder::SetExported() { exported_ = true; } 128 129 void WasmFunctionBuilder::SetName(const char* name, int name_length) { 130 name_.clear(); 131 if (name_length > 0) { 132 for (int i = 0; i < name_length; ++i) { 133 name_.push_back(*(name + i)); 134 } 135 } 136 } 137 138 void WasmFunctionBuilder::WriteSignature(ZoneBuffer& buffer) const { 139 buffer.write_u32v(signature_index_); 140 } 141 142 void WasmFunctionBuilder::WriteExport(ZoneBuffer& buffer, 143 uint32_t func_index) const { 144 if (exported_) { 145 buffer.write_u32v(func_index); 146 buffer.write_size(name_.size()); 147 if (name_.size() > 0) { 148 buffer.write(reinterpret_cast<const byte*>(&name_[0]), name_.size()); 149 } 150 } 151 } 152 153 void WasmFunctionBuilder::WriteBody(ZoneBuffer& buffer) const { 154 size_t locals_size = locals_.Size(); 155 buffer.write_size(locals_size + body_.size()); 156 buffer.EnsureSpace(locals_size); 157 byte** ptr = buffer.pos_ptr(); 158 locals_.Emit(*ptr); 159 (*ptr) += locals_size; // UGLY: manual bump of position pointer 160 if (body_.size() > 0) { 161 buffer.write(&body_[0], body_.size()); 162 } 163 } 164 165 WasmDataSegmentEncoder::WasmDataSegmentEncoder(Zone* zone, const byte* data, 166 uint32_t size, uint32_t dest) 167 : data_(zone), dest_(dest) { 168 for (size_t i = 0; i < size; ++i) { 169 data_.push_back(data[i]); 170 } 171 } 172 173 void WasmDataSegmentEncoder::Write(ZoneBuffer& buffer) const { 174 buffer.write_u32v(dest_); 175 buffer.write_u32v(static_cast<uint32_t>(data_.size())); 176 buffer.write(&data_[0], data_.size()); 177 } 178 179 WasmModuleBuilder::WasmModuleBuilder(Zone* zone) 180 : zone_(zone), 181 signatures_(zone), 182 imports_(zone), 183 functions_(zone), 184 data_segments_(zone), 185 indirect_functions_(zone), 186 globals_(zone), 187 signature_map_(zone), 188 start_function_index_(-1) {} 189 190 uint32_t WasmModuleBuilder::AddFunction() { 191 functions_.push_back(new (zone_) WasmFunctionBuilder(this)); 192 return static_cast<uint32_t>(functions_.size() - 1); 193 } 194 195 WasmFunctionBuilder* WasmModuleBuilder::FunctionAt(size_t index) { 196 if (functions_.size() > index) { 197 return functions_.at(index); 198 } else { 199 return nullptr; 200 } 201 } 202 203 void WasmModuleBuilder::AddDataSegment(WasmDataSegmentEncoder* data) { 204 data_segments_.push_back(data); 205 } 206 207 bool WasmModuleBuilder::CompareFunctionSigs::operator()(FunctionSig* a, 208 FunctionSig* b) const { 209 if (a->return_count() < b->return_count()) return true; 210 if (a->return_count() > b->return_count()) return false; 211 if (a->parameter_count() < b->parameter_count()) return true; 212 if (a->parameter_count() > b->parameter_count()) return false; 213 for (size_t r = 0; r < a->return_count(); r++) { 214 if (a->GetReturn(r) < b->GetReturn(r)) return true; 215 if (a->GetReturn(r) > b->GetReturn(r)) return false; 216 } 217 for (size_t p = 0; p < a->parameter_count(); p++) { 218 if (a->GetParam(p) < b->GetParam(p)) return true; 219 if (a->GetParam(p) > b->GetParam(p)) return false; 220 } 221 return false; 222 } 223 224 uint32_t WasmModuleBuilder::AddSignature(FunctionSig* sig) { 225 SignatureMap::iterator pos = signature_map_.find(sig); 226 if (pos != signature_map_.end()) { 227 return pos->second; 228 } else { 229 uint32_t index = static_cast<uint32_t>(signatures_.size()); 230 signature_map_[sig] = index; 231 signatures_.push_back(sig); 232 return index; 233 } 234 } 235 236 void WasmModuleBuilder::AddIndirectFunction(uint32_t index) { 237 indirect_functions_.push_back(index); 238 } 239 240 uint32_t WasmModuleBuilder::AddImport(const char* name, int name_length, 241 FunctionSig* sig) { 242 imports_.push_back({AddSignature(sig), name, name_length}); 243 return static_cast<uint32_t>(imports_.size() - 1); 244 } 245 246 void WasmModuleBuilder::MarkStartFunction(uint32_t index) { 247 start_function_index_ = index; 248 } 249 250 uint32_t WasmModuleBuilder::AddGlobal(MachineType type, bool exported) { 251 globals_.push_back(std::make_pair(type, exported)); 252 return static_cast<uint32_t>(globals_.size() - 1); 253 } 254 255 void WasmModuleBuilder::WriteTo(ZoneBuffer& buffer) const { 256 uint32_t exports = 0; 257 258 // == Emit magic ============================================================= 259 TRACE("emit magic\n"); 260 buffer.write_u32(kWasmMagic); 261 buffer.write_u32(kWasmVersion); 262 263 // == Emit signatures ======================================================== 264 if (signatures_.size() > 0) { 265 size_t start = EmitSection(WasmSection::Code::Signatures, buffer); 266 buffer.write_size(signatures_.size()); 267 268 for (FunctionSig* sig : signatures_) { 269 buffer.write_u8(kWasmFunctionTypeForm); 270 buffer.write_size(sig->parameter_count()); 271 for (size_t j = 0; j < sig->parameter_count(); j++) { 272 buffer.write_u8(WasmOpcodes::LocalTypeCodeFor(sig->GetParam(j))); 273 } 274 buffer.write_size(sig->return_count()); 275 for (size_t j = 0; j < sig->return_count(); j++) { 276 buffer.write_u8(WasmOpcodes::LocalTypeCodeFor(sig->GetReturn(j))); 277 } 278 } 279 FixupSection(buffer, start); 280 } 281 282 // == Emit globals =========================================================== 283 if (globals_.size() > 0) { 284 size_t start = EmitSection(WasmSection::Code::Globals, buffer); 285 buffer.write_size(globals_.size()); 286 287 for (auto global : globals_) { 288 buffer.write_u32v(0); // Length of the global name. 289 buffer.write_u8(WasmOpcodes::MemTypeCodeFor(global.first)); 290 buffer.write_u8(global.second); 291 } 292 FixupSection(buffer, start); 293 } 294 295 // == Emit imports =========================================================== 296 if (imports_.size() > 0) { 297 size_t start = EmitSection(WasmSection::Code::ImportTable, buffer); 298 buffer.write_size(imports_.size()); 299 for (auto import : imports_) { 300 buffer.write_u32v(import.sig_index); 301 buffer.write_u32v(import.name_length); 302 buffer.write(reinterpret_cast<const byte*>(import.name), 303 import.name_length); 304 buffer.write_u32v(0); 305 } 306 FixupSection(buffer, start); 307 } 308 309 // == Emit function signatures =============================================== 310 if (functions_.size() > 0) { 311 size_t start = EmitSection(WasmSection::Code::FunctionSignatures, buffer); 312 buffer.write_size(functions_.size()); 313 for (auto function : functions_) { 314 function->WriteSignature(buffer); 315 if (function->exported()) exports++; 316 } 317 FixupSection(buffer, start); 318 } 319 320 // == emit function table ==================================================== 321 if (indirect_functions_.size() > 0) { 322 size_t start = EmitSection(WasmSection::Code::FunctionTable, buffer); 323 buffer.write_size(indirect_functions_.size()); 324 325 for (auto index : indirect_functions_) { 326 buffer.write_u32v(index); 327 } 328 FixupSection(buffer, start); 329 } 330 331 // == emit memory declaration ================================================ 332 { 333 size_t start = EmitSection(WasmSection::Code::Memory, buffer); 334 buffer.write_u32v(16); // min memory size 335 buffer.write_u32v(16); // max memory size 336 buffer.write_u8(0); // memory export 337 static_assert(kDeclMemorySize == 3, "memory size must match emit above"); 338 FixupSection(buffer, start); 339 } 340 341 // == emit exports =========================================================== 342 if (exports > 0) { 343 size_t start = EmitSection(WasmSection::Code::ExportTable, buffer); 344 buffer.write_u32v(exports); 345 uint32_t index = 0; 346 for (auto function : functions_) { 347 function->WriteExport(buffer, index++); 348 } 349 FixupSection(buffer, start); 350 } 351 352 // == emit start function index ============================================== 353 if (start_function_index_ >= 0) { 354 size_t start = EmitSection(WasmSection::Code::StartFunction, buffer); 355 buffer.write_u32v(start_function_index_); 356 FixupSection(buffer, start); 357 } 358 359 // == emit code ============================================================== 360 if (functions_.size() > 0) { 361 size_t start = EmitSection(WasmSection::Code::FunctionBodies, buffer); 362 buffer.write_size(functions_.size()); 363 for (auto function : functions_) { 364 function->WriteBody(buffer); 365 } 366 FixupSection(buffer, start); 367 } 368 369 // == emit data segments ===================================================== 370 if (data_segments_.size() > 0) { 371 size_t start = EmitSection(WasmSection::Code::DataSegments, buffer); 372 buffer.write_size(data_segments_.size()); 373 374 for (auto segment : data_segments_) { 375 segment->Write(buffer); 376 } 377 FixupSection(buffer, start); 378 } 379 } 380 } // namespace wasm 381 } // namespace internal 382 } // namespace v8 383