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/base/platform/elapsed-timer.h" 8 #include "src/compiler/wasm-compiler.h" 9 #include "src/flags.h" 10 #include "src/handles.h" 11 #include "src/objects-inl.h" 12 #include "src/ostreams.h" 13 #include "src/wasm/decoder.h" 14 #include "src/wasm/function-body-decoder-impl.h" 15 #include "src/wasm/function-body-decoder.h" 16 #include "src/wasm/wasm-limits.h" 17 #include "src/wasm/wasm-linkage.h" 18 #include "src/wasm/wasm-module.h" 19 #include "src/wasm/wasm-opcodes.h" 20 21 namespace v8 { 22 namespace internal { 23 namespace wasm { 24 25 namespace { 26 27 // An SsaEnv environment carries the current local variable renaming 28 // as well as the current effect and control dependency in the TF graph. 29 // It maintains a control state that tracks whether the environment 30 // is reachable, has reached a control end, or has been merged. 31 struct SsaEnv { 32 enum State { kControlEnd, kUnreachable, kReached, kMerged }; 33 34 State state; 35 TFNode* control; 36 TFNode* effect; 37 compiler::WasmInstanceCacheNodes instance_cache; 38 TFNode** locals; 39 40 bool go() { return state >= kReached; } 41 void Kill(State new_state = kControlEnd) { 42 state = new_state; 43 locals = nullptr; 44 control = nullptr; 45 effect = nullptr; 46 instance_cache = {}; 47 } 48 void SetNotMerged() { 49 if (state == kMerged) state = kReached; 50 } 51 }; 52 53 #define BUILD(func, ...) \ 54 ([&] { \ 55 DCHECK(ssa_env_->go()); \ 56 DCHECK(decoder->ok()); \ 57 return CheckForException(decoder, builder_->func(__VA_ARGS__)); \ 58 })() 59 60 constexpr uint32_t kNullCatch = static_cast<uint32_t>(-1); 61 62 class WasmGraphBuildingInterface { 63 public: 64 static constexpr Decoder::ValidateFlag validate = Decoder::kValidate; 65 using FullDecoder = WasmFullDecoder<validate, WasmGraphBuildingInterface>; 66 67 struct Value : public ValueWithNamedConstructors<Value> { 68 TFNode* node; 69 }; 70 71 struct TryInfo : public ZoneObject { 72 SsaEnv* catch_env; 73 TFNode* exception = nullptr; 74 75 explicit TryInfo(SsaEnv* c) : catch_env(c) {} 76 }; 77 78 struct Control : public ControlWithNamedConstructors<Control, Value> { 79 SsaEnv* end_env; // end environment for the construct. 80 SsaEnv* false_env; // false environment (only for if). 81 TryInfo* try_info; // information used for compiling try statements. 82 int32_t previous_catch; // previous Control (on the stack) with a catch. 83 }; 84 85 explicit WasmGraphBuildingInterface(TFBuilder* builder) : builder_(builder) {} 86 87 void StartFunction(FullDecoder* decoder) { 88 SsaEnv* ssa_env = 89 reinterpret_cast<SsaEnv*>(decoder->zone()->New(sizeof(SsaEnv))); 90 uint32_t num_locals = decoder->NumLocals(); 91 uint32_t env_count = num_locals; 92 size_t size = sizeof(TFNode*) * env_count; 93 ssa_env->state = SsaEnv::kReached; 94 ssa_env->locals = 95 size > 0 ? reinterpret_cast<TFNode**>(decoder->zone()->New(size)) 96 : nullptr; 97 98 // The first '+ 1' is needed by TF Start node, the second '+ 1' is for the 99 // instance parameter. 100 TFNode* start = builder_->Start( 101 static_cast<int>(decoder->sig_->parameter_count() + 1 + 1)); 102 // Initialize the instance parameter (index 0). 103 builder_->set_instance_node(builder_->Param(kWasmInstanceParameterIndex)); 104 // Initialize local variables. Parameters are shifted by 1 because of the 105 // the instance parameter. 106 uint32_t index = 0; 107 for (; index < decoder->sig_->parameter_count(); ++index) { 108 ssa_env->locals[index] = builder_->Param(index + 1); 109 } 110 while (index < num_locals) { 111 ValueType type = decoder->GetLocalType(index); 112 TFNode* node = DefaultValue(type); 113 while (index < num_locals && decoder->GetLocalType(index) == type) { 114 // Do a whole run of like-typed locals at a time. 115 ssa_env->locals[index++] = node; 116 } 117 } 118 ssa_env->effect = start; 119 ssa_env->control = start; 120 // Initialize effect and control before loading the context. 121 builder_->set_effect_ptr(&ssa_env->effect); 122 builder_->set_control_ptr(&ssa_env->control); 123 LoadContextIntoSsa(ssa_env); 124 SetEnv(ssa_env); 125 } 126 127 // Reload the instance cache entries into the Ssa Environment. 128 void LoadContextIntoSsa(SsaEnv* ssa_env) { 129 if (!ssa_env || !ssa_env->go()) return; 130 builder_->InitInstanceCache(&ssa_env->instance_cache); 131 } 132 133 void StartFunctionBody(FullDecoder* decoder, Control* block) { 134 SsaEnv* break_env = ssa_env_; 135 SetEnv(Steal(decoder->zone(), break_env)); 136 block->end_env = break_env; 137 } 138 139 void FinishFunction(FullDecoder*) { builder_->PatchInStackCheckIfNeeded(); } 140 141 void OnFirstError(FullDecoder*) {} 142 143 void NextInstruction(FullDecoder*, WasmOpcode) {} 144 145 void Block(FullDecoder* decoder, Control* block) { 146 // The break environment is the outer environment. 147 block->end_env = ssa_env_; 148 SetEnv(Steal(decoder->zone(), ssa_env_)); 149 } 150 151 void Loop(FullDecoder* decoder, Control* block) { 152 SsaEnv* finish_try_env = Steal(decoder->zone(), ssa_env_); 153 block->end_env = finish_try_env; 154 // The continue environment is the inner environment. 155 SetEnv(PrepareForLoop(decoder, finish_try_env)); 156 ssa_env_->SetNotMerged(); 157 if (!decoder->ok()) return; 158 // Wrap input merge into phis. 159 for (unsigned i = 0; i < block->start_merge.arity; ++i) { 160 Value& val = block->start_merge[i]; 161 val.node = builder_->Phi(val.type, 1, &val.node, block->end_env->control); 162 } 163 } 164 165 void Try(FullDecoder* decoder, Control* block) { 166 SsaEnv* outer_env = ssa_env_; 167 SsaEnv* catch_env = Split(decoder, outer_env); 168 // Mark catch environment as unreachable, since only accessable 169 // through catch unwinding (i.e. landing pads). 170 catch_env->state = SsaEnv::kUnreachable; 171 SsaEnv* try_env = Steal(decoder->zone(), outer_env); 172 SetEnv(try_env); 173 TryInfo* try_info = new (decoder->zone()) TryInfo(catch_env); 174 block->end_env = outer_env; 175 block->try_info = try_info; 176 block->previous_catch = current_catch_; 177 current_catch_ = static_cast<int32_t>(decoder->control_depth() - 1); 178 } 179 180 void If(FullDecoder* decoder, const Value& cond, Control* if_block) { 181 TFNode* if_true = nullptr; 182 TFNode* if_false = nullptr; 183 if (ssa_env_->go()) BUILD(BranchNoHint, cond.node, &if_true, &if_false); 184 SsaEnv* end_env = ssa_env_; 185 SsaEnv* false_env = Split(decoder, ssa_env_); 186 false_env->control = if_false; 187 SsaEnv* true_env = Steal(decoder->zone(), ssa_env_); 188 true_env->control = if_true; 189 if_block->end_env = end_env; 190 if_block->false_env = false_env; 191 SetEnv(true_env); 192 } 193 194 void FallThruTo(FullDecoder* decoder, Control* c) { 195 DCHECK(!c->is_loop()); 196 MergeValuesInto(decoder, c, &c->end_merge); 197 } 198 199 void PopControl(FullDecoder* decoder, Control* block) { 200 if (!block->is_loop()) SetEnv(block->end_env); 201 } 202 203 void EndControl(FullDecoder* decoder, Control* block) { ssa_env_->Kill(); } 204 205 void UnOp(FullDecoder* decoder, WasmOpcode opcode, FunctionSig* sig, 206 const Value& value, Value* result) { 207 result->node = BUILD(Unop, opcode, value.node, decoder->position()); 208 } 209 210 void BinOp(FullDecoder* decoder, WasmOpcode opcode, FunctionSig* sig, 211 const Value& lhs, const Value& rhs, Value* result) { 212 auto node = BUILD(Binop, opcode, lhs.node, rhs.node, decoder->position()); 213 if (result) result->node = node; 214 } 215 216 void I32Const(FullDecoder* decoder, Value* result, int32_t value) { 217 result->node = builder_->Int32Constant(value); 218 } 219 220 void I64Const(FullDecoder* decoder, Value* result, int64_t value) { 221 result->node = builder_->Int64Constant(value); 222 } 223 224 void F32Const(FullDecoder* decoder, Value* result, float value) { 225 result->node = builder_->Float32Constant(value); 226 } 227 228 void F64Const(FullDecoder* decoder, Value* result, double value) { 229 result->node = builder_->Float64Constant(value); 230 } 231 232 void RefNull(FullDecoder* decoder, Value* result) { 233 result->node = builder_->RefNull(); 234 } 235 236 void Drop(FullDecoder* decoder, const Value& value) {} 237 238 void DoReturn(FullDecoder* decoder, Vector<Value> values, bool implicit) { 239 if (implicit) { 240 DCHECK_EQ(1, decoder->control_depth()); 241 SetEnv(decoder->control_at(0)->end_env); 242 } 243 size_t num_values = values.size(); 244 TFNode** buffer = GetNodes(values); 245 for (size_t i = 0; i < num_values; ++i) { 246 buffer[i] = values[i].node; 247 } 248 BUILD(Return, static_cast<unsigned>(values.size()), buffer); 249 } 250 251 void GetLocal(FullDecoder* decoder, Value* result, 252 const LocalIndexImmediate<validate>& imm) { 253 if (!ssa_env_->locals) return; // unreachable 254 result->node = ssa_env_->locals[imm.index]; 255 } 256 257 void SetLocal(FullDecoder* decoder, const Value& value, 258 const LocalIndexImmediate<validate>& imm) { 259 if (!ssa_env_->locals) return; // unreachable 260 ssa_env_->locals[imm.index] = value.node; 261 } 262 263 void TeeLocal(FullDecoder* decoder, const Value& value, Value* result, 264 const LocalIndexImmediate<validate>& imm) { 265 result->node = value.node; 266 if (!ssa_env_->locals) return; // unreachable 267 ssa_env_->locals[imm.index] = value.node; 268 } 269 270 void GetGlobal(FullDecoder* decoder, Value* result, 271 const GlobalIndexImmediate<validate>& imm) { 272 result->node = BUILD(GetGlobal, imm.index); 273 } 274 275 void SetGlobal(FullDecoder* decoder, const Value& value, 276 const GlobalIndexImmediate<validate>& imm) { 277 BUILD(SetGlobal, imm.index, value.node); 278 } 279 280 void Unreachable(FullDecoder* decoder) { 281 BUILD(Unreachable, decoder->position()); 282 } 283 284 void Select(FullDecoder* decoder, const Value& cond, const Value& fval, 285 const Value& tval, Value* result) { 286 TFNode* controls[2]; 287 BUILD(BranchNoHint, cond.node, &controls[0], &controls[1]); 288 TFNode* merge = BUILD(Merge, 2, controls); 289 TFNode* vals[2] = {tval.node, fval.node}; 290 TFNode* phi = BUILD(Phi, tval.type, 2, vals, merge); 291 result->node = phi; 292 ssa_env_->control = merge; 293 } 294 295 void Br(FullDecoder* decoder, Control* target) { 296 MergeValuesInto(decoder, target, target->br_merge()); 297 } 298 299 void BrIf(FullDecoder* decoder, const Value& cond, Control* target) { 300 SsaEnv* fenv = ssa_env_; 301 SsaEnv* tenv = Split(decoder, fenv); 302 fenv->SetNotMerged(); 303 BUILD(BranchNoHint, cond.node, &tenv->control, &fenv->control); 304 ssa_env_ = tenv; 305 Br(decoder, target); 306 ssa_env_ = fenv; 307 } 308 309 void BrTable(FullDecoder* decoder, const BranchTableImmediate<validate>& imm, 310 const Value& key) { 311 if (imm.table_count == 0) { 312 // Only a default target. Do the equivalent of br. 313 uint32_t target = BranchTableIterator<validate>(decoder, imm).next(); 314 Br(decoder, decoder->control_at(target)); 315 return; 316 } 317 318 SsaEnv* break_env = ssa_env_; 319 // Build branches to the various blocks based on the table. 320 TFNode* sw = BUILD(Switch, imm.table_count + 1, key.node); 321 322 SsaEnv* copy = Steal(decoder->zone(), break_env); 323 ssa_env_ = copy; 324 BranchTableIterator<validate> iterator(decoder, imm); 325 while (iterator.has_next()) { 326 uint32_t i = iterator.cur_index(); 327 uint32_t target = iterator.next(); 328 ssa_env_ = Split(decoder, copy); 329 ssa_env_->control = 330 (i == imm.table_count) ? BUILD(IfDefault, sw) : BUILD(IfValue, i, sw); 331 Br(decoder, decoder->control_at(target)); 332 } 333 DCHECK(decoder->ok()); 334 ssa_env_ = break_env; 335 } 336 337 void Else(FullDecoder* decoder, Control* if_block) { 338 SetEnv(if_block->false_env); 339 } 340 341 void LoadMem(FullDecoder* decoder, LoadType type, 342 const MemoryAccessImmediate<validate>& imm, const Value& index, 343 Value* result) { 344 result->node = 345 BUILD(LoadMem, type.value_type(), type.mem_type(), index.node, 346 imm.offset, imm.alignment, decoder->position()); 347 } 348 349 void StoreMem(FullDecoder* decoder, StoreType type, 350 const MemoryAccessImmediate<validate>& imm, const Value& index, 351 const Value& value) { 352 BUILD(StoreMem, type.mem_rep(), index.node, imm.offset, imm.alignment, 353 value.node, decoder->position(), type.value_type()); 354 } 355 356 void CurrentMemoryPages(FullDecoder* decoder, Value* result) { 357 result->node = BUILD(CurrentMemoryPages); 358 } 359 360 void GrowMemory(FullDecoder* decoder, const Value& value, Value* result) { 361 result->node = BUILD(GrowMemory, value.node); 362 // Always reload the instance cache after growing memory. 363 LoadContextIntoSsa(ssa_env_); 364 } 365 366 void CallDirect(FullDecoder* decoder, 367 const CallFunctionImmediate<validate>& imm, 368 const Value args[], Value returns[]) { 369 DoCall(decoder, nullptr, imm.sig, imm.index, args, returns); 370 } 371 372 void CallIndirect(FullDecoder* decoder, const Value& index, 373 const CallIndirectImmediate<validate>& imm, 374 const Value args[], Value returns[]) { 375 DoCall(decoder, index.node, imm.sig, imm.sig_index, args, returns); 376 } 377 378 void SimdOp(FullDecoder* decoder, WasmOpcode opcode, Vector<Value> args, 379 Value* result) { 380 TFNode** inputs = GetNodes(args); 381 TFNode* node = BUILD(SimdOp, opcode, inputs); 382 if (result) result->node = node; 383 } 384 385 void SimdLaneOp(FullDecoder* decoder, WasmOpcode opcode, 386 const SimdLaneImmediate<validate> imm, Vector<Value> inputs, 387 Value* result) { 388 TFNode** nodes = GetNodes(inputs); 389 result->node = BUILD(SimdLaneOp, opcode, imm.lane, nodes); 390 } 391 392 void SimdShiftOp(FullDecoder* decoder, WasmOpcode opcode, 393 const SimdShiftImmediate<validate> imm, const Value& input, 394 Value* result) { 395 TFNode* inputs[] = {input.node}; 396 result->node = BUILD(SimdShiftOp, opcode, imm.shift, inputs); 397 } 398 399 void Simd8x16ShuffleOp(FullDecoder* decoder, 400 const Simd8x16ShuffleImmediate<validate>& imm, 401 const Value& input0, const Value& input1, 402 Value* result) { 403 TFNode* input_nodes[] = {input0.node, input1.node}; 404 result->node = BUILD(Simd8x16ShuffleOp, imm.shuffle, input_nodes); 405 } 406 407 TFNode* GetExceptionTag(FullDecoder* decoder, 408 const ExceptionIndexImmediate<validate>& imm) { 409 // TODO(kschimpf): Need to get runtime exception tag values. This 410 // code only handles non-imported/exported exceptions. 411 return BUILD(Int32Constant, imm.index); 412 } 413 414 void Throw(FullDecoder* decoder, const ExceptionIndexImmediate<validate>& imm, 415 Control* block, const Vector<Value>& value_args) { 416 int count = value_args.length(); 417 ZoneVector<TFNode*> args(count, decoder->zone()); 418 for (int i = 0; i < count; ++i) { 419 args[i] = value_args[i].node; 420 } 421 BUILD(Throw, imm.index, imm.exception, vec2vec(args)); 422 Unreachable(decoder); 423 EndControl(decoder, block); 424 } 425 426 void CatchException(FullDecoder* decoder, 427 const ExceptionIndexImmediate<validate>& imm, 428 Control* block, Vector<Value> values) { 429 DCHECK(block->is_try_catch()); 430 current_catch_ = block->previous_catch; 431 SsaEnv* catch_env = block->try_info->catch_env; 432 SetEnv(catch_env); 433 434 TFNode* compare_i32 = nullptr; 435 if (block->try_info->exception == nullptr) { 436 // Catch not applicable, no possible throws in the try 437 // block. Create dummy code so that body of catch still 438 // compiles. Note: This only happens because the current 439 // implementation only builds a landing pad if some node in the 440 // try block can (possibly) throw. 441 // 442 // TODO(kschimpf): Always generate a landing pad for a try block. 443 compare_i32 = BUILD(Int32Constant, 0); 444 } else { 445 // Get the exception and see if wanted exception. 446 TFNode* caught_tag = BUILD(GetExceptionRuntimeId); 447 TFNode* exception_tag = BUILD(ConvertExceptionTagToRuntimeId, imm.index); 448 compare_i32 = BUILD(Binop, kExprI32Eq, caught_tag, exception_tag); 449 } 450 451 TFNode* if_catch = nullptr; 452 TFNode* if_no_catch = nullptr; 453 BUILD(BranchNoHint, compare_i32, &if_catch, &if_no_catch); 454 455 SsaEnv* if_no_catch_env = Split(decoder, ssa_env_); 456 if_no_catch_env->control = if_no_catch; 457 SsaEnv* if_catch_env = Steal(decoder->zone(), ssa_env_); 458 if_catch_env->control = if_catch; 459 460 // TODO(kschimpf): Generalize to allow more catches. Will force 461 // moving no_catch code to END opcode. 462 SetEnv(if_no_catch_env); 463 BUILD(Rethrow); 464 Unreachable(decoder); 465 EndControl(decoder, block); 466 467 SetEnv(if_catch_env); 468 469 if (block->try_info->exception == nullptr) { 470 // No caught value, make up filler nodes so that catch block still 471 // compiles. 472 for (Value& value : values) { 473 value.node = DefaultValue(value.type); 474 } 475 } else { 476 // TODO(kschimpf): Can't use BUILD() here, GetExceptionValues() returns 477 // TFNode** rather than TFNode*. Fix to add landing pads. 478 TFNode** caught_values = builder_->GetExceptionValues(imm.exception); 479 for (size_t i = 0, e = values.size(); i < e; ++i) { 480 values[i].node = caught_values[i]; 481 } 482 } 483 } 484 485 void AtomicOp(FullDecoder* decoder, WasmOpcode opcode, Vector<Value> args, 486 const MemoryAccessImmediate<validate>& imm, Value* result) { 487 TFNode** inputs = GetNodes(args); 488 TFNode* node = BUILD(AtomicOp, opcode, inputs, imm.alignment, imm.offset, 489 decoder->position()); 490 if (result) result->node = node; 491 } 492 493 private: 494 SsaEnv* ssa_env_; 495 TFBuilder* builder_; 496 uint32_t current_catch_ = kNullCatch; 497 498 TryInfo* current_try_info(FullDecoder* decoder) { 499 return decoder->control_at(decoder->control_depth() - 1 - current_catch_) 500 ->try_info; 501 } 502 503 TFNode** GetNodes(Value* values, size_t count) { 504 TFNode** nodes = builder_->Buffer(count); 505 for (size_t i = 0; i < count; ++i) { 506 nodes[i] = values[i].node; 507 } 508 return nodes; 509 } 510 511 TFNode** GetNodes(Vector<Value> values) { 512 return GetNodes(values.start(), values.size()); 513 } 514 515 void SetEnv(SsaEnv* env) { 516 #if DEBUG 517 if (FLAG_trace_wasm_decoder) { 518 char state = 'X'; 519 if (env) { 520 switch (env->state) { 521 case SsaEnv::kReached: 522 state = 'R'; 523 break; 524 case SsaEnv::kUnreachable: 525 state = 'U'; 526 break; 527 case SsaEnv::kMerged: 528 state = 'M'; 529 break; 530 case SsaEnv::kControlEnd: 531 state = 'E'; 532 break; 533 } 534 } 535 PrintF("{set_env = %p, state = %c", static_cast<void*>(env), state); 536 if (env && env->control) { 537 PrintF(", control = "); 538 compiler::WasmGraphBuilder::PrintDebugName(env->control); 539 } 540 PrintF("}\n"); 541 } 542 #endif 543 ssa_env_ = env; 544 // TODO(wasm): combine the control and effect pointers with instance cache. 545 builder_->set_control_ptr(&env->control); 546 builder_->set_effect_ptr(&env->effect); 547 builder_->set_instance_cache(&env->instance_cache); 548 } 549 550 TFNode* CheckForException(FullDecoder* decoder, TFNode* node) { 551 if (node == nullptr) return nullptr; 552 553 const bool inside_try_scope = current_catch_ != kNullCatch; 554 555 if (!inside_try_scope) return node; 556 557 TFNode* if_success = nullptr; 558 TFNode* if_exception = nullptr; 559 if (!builder_->ThrowsException(node, &if_success, &if_exception)) { 560 return node; 561 } 562 563 SsaEnv* success_env = Steal(decoder->zone(), ssa_env_); 564 success_env->control = if_success; 565 566 SsaEnv* exception_env = Split(decoder, success_env); 567 exception_env->control = if_exception; 568 TryInfo* try_info = current_try_info(decoder); 569 Goto(decoder, exception_env, try_info->catch_env); 570 TFNode* exception = try_info->exception; 571 if (exception == nullptr) { 572 DCHECK_EQ(SsaEnv::kReached, try_info->catch_env->state); 573 try_info->exception = if_exception; 574 } else { 575 DCHECK_EQ(SsaEnv::kMerged, try_info->catch_env->state); 576 try_info->exception = builder_->CreateOrMergeIntoPhi( 577 MachineRepresentation::kWord32, try_info->catch_env->control, 578 try_info->exception, if_exception); 579 } 580 581 SetEnv(success_env); 582 return node; 583 } 584 585 TFNode* DefaultValue(ValueType type) { 586 switch (type) { 587 case kWasmI32: 588 return builder_->Int32Constant(0); 589 case kWasmI64: 590 return builder_->Int64Constant(0); 591 case kWasmF32: 592 return builder_->Float32Constant(0); 593 case kWasmF64: 594 return builder_->Float64Constant(0); 595 case kWasmS128: 596 return builder_->S128Zero(); 597 default: 598 UNREACHABLE(); 599 } 600 } 601 602 void MergeValuesInto(FullDecoder* decoder, Control* c, Merge<Value>* merge) { 603 DCHECK(merge == &c->start_merge || merge == &c->end_merge); 604 if (!ssa_env_->go()) return; 605 606 SsaEnv* target = c->end_env; 607 const bool first = target->state == SsaEnv::kUnreachable; 608 Goto(decoder, ssa_env_, target); 609 610 uint32_t avail = 611 decoder->stack_size() - decoder->control_at(0)->stack_depth; 612 uint32_t start = avail >= merge->arity ? 0 : merge->arity - avail; 613 for (uint32_t i = start; i < merge->arity; ++i) { 614 auto& val = decoder->GetMergeValueFromStack(c, merge, i); 615 auto& old = (*merge)[i]; 616 DCHECK_NOT_NULL(val.node); 617 DCHECK(val.type == old.type || val.type == kWasmVar); 618 old.node = first ? val.node 619 : builder_->CreateOrMergeIntoPhi( 620 ValueTypes::MachineRepresentationFor(old.type), 621 target->control, old.node, val.node); 622 } 623 } 624 625 void Goto(FullDecoder* decoder, SsaEnv* from, SsaEnv* to) { 626 DCHECK_NOT_NULL(to); 627 if (!from->go()) return; 628 switch (to->state) { 629 case SsaEnv::kUnreachable: { // Overwrite destination. 630 to->state = SsaEnv::kReached; 631 to->locals = from->locals; 632 to->control = from->control; 633 to->effect = from->effect; 634 to->instance_cache = from->instance_cache; 635 break; 636 } 637 case SsaEnv::kReached: { // Create a new merge. 638 to->state = SsaEnv::kMerged; 639 // Merge control. 640 TFNode* controls[] = {to->control, from->control}; 641 TFNode* merge = builder_->Merge(2, controls); 642 to->control = merge; 643 // Merge effects. 644 if (from->effect != to->effect) { 645 TFNode* effects[] = {to->effect, from->effect, merge}; 646 to->effect = builder_->EffectPhi(2, effects, merge); 647 } 648 // Merge SSA values. 649 for (int i = decoder->NumLocals() - 1; i >= 0; i--) { 650 TFNode* a = to->locals[i]; 651 TFNode* b = from->locals[i]; 652 if (a != b) { 653 TFNode* vals[] = {a, b}; 654 to->locals[i] = 655 builder_->Phi(decoder->GetLocalType(i), 2, vals, merge); 656 } 657 } 658 // Start a new merge from the instance cache. 659 builder_->NewInstanceCacheMerge(&to->instance_cache, 660 &from->instance_cache, merge); 661 break; 662 } 663 case SsaEnv::kMerged: { 664 TFNode* merge = to->control; 665 // Extend the existing merge control node. 666 builder_->AppendToMerge(merge, from->control); 667 // Merge effects. 668 to->effect = builder_->CreateOrMergeIntoEffectPhi(merge, to->effect, 669 from->effect); 670 // Merge locals. 671 for (int i = decoder->NumLocals() - 1; i >= 0; i--) { 672 to->locals[i] = builder_->CreateOrMergeIntoPhi( 673 ValueTypes::MachineRepresentationFor(decoder->GetLocalType(i)), 674 merge, to->locals[i], from->locals[i]); 675 } 676 // Merge the instance caches. 677 builder_->MergeInstanceCacheInto(&to->instance_cache, 678 &from->instance_cache, merge); 679 break; 680 } 681 default: 682 UNREACHABLE(); 683 } 684 return from->Kill(); 685 } 686 687 SsaEnv* PrepareForLoop(FullDecoder* decoder, SsaEnv* env) { 688 if (!env->go()) return Split(decoder, env); 689 env->state = SsaEnv::kMerged; 690 691 env->control = builder_->Loop(env->control); 692 env->effect = builder_->EffectPhi(1, &env->effect, env->control); 693 builder_->Terminate(env->effect, env->control); 694 // The '+ 1' here is to be able to set the instance cache as assigned. 695 BitVector* assigned = WasmDecoder<validate>::AnalyzeLoopAssignment( 696 decoder, decoder->pc(), decoder->total_locals() + 1, decoder->zone()); 697 if (decoder->failed()) return env; 698 if (assigned != nullptr) { 699 // Only introduce phis for variables assigned in this loop. 700 int instance_cache_index = decoder->total_locals(); 701 for (int i = decoder->NumLocals() - 1; i >= 0; i--) { 702 if (!assigned->Contains(i)) continue; 703 env->locals[i] = builder_->Phi(decoder->GetLocalType(i), 1, 704 &env->locals[i], env->control); 705 } 706 // Introduce phis for instance cache pointers if necessary. 707 if (assigned->Contains(instance_cache_index)) { 708 builder_->PrepareInstanceCacheForLoop(&env->instance_cache, 709 env->control); 710 } 711 712 SsaEnv* loop_body_env = Split(decoder, env); 713 builder_->StackCheck(decoder->position(), &(loop_body_env->effect), 714 &(loop_body_env->control)); 715 return loop_body_env; 716 } 717 718 // Conservatively introduce phis for all local variables. 719 for (int i = decoder->NumLocals() - 1; i >= 0; i--) { 720 env->locals[i] = builder_->Phi(decoder->GetLocalType(i), 1, 721 &env->locals[i], env->control); 722 } 723 724 // Conservatively introduce phis for instance cache. 725 builder_->PrepareInstanceCacheForLoop(&env->instance_cache, env->control); 726 727 SsaEnv* loop_body_env = Split(decoder, env); 728 builder_->StackCheck(decoder->position(), &loop_body_env->effect, 729 &loop_body_env->control); 730 return loop_body_env; 731 } 732 733 // Create a complete copy of {from}. 734 SsaEnv* Split(FullDecoder* decoder, SsaEnv* from) { 735 DCHECK_NOT_NULL(from); 736 SsaEnv* result = 737 reinterpret_cast<SsaEnv*>(decoder->zone()->New(sizeof(SsaEnv))); 738 size_t size = sizeof(TFNode*) * decoder->NumLocals(); 739 result->control = from->control; 740 result->effect = from->effect; 741 742 if (from->go()) { 743 result->state = SsaEnv::kReached; 744 result->locals = 745 size > 0 ? reinterpret_cast<TFNode**>(decoder->zone()->New(size)) 746 : nullptr; 747 memcpy(result->locals, from->locals, size); 748 result->instance_cache = from->instance_cache; 749 } else { 750 result->state = SsaEnv::kUnreachable; 751 result->locals = nullptr; 752 result->instance_cache = {}; 753 } 754 755 return result; 756 } 757 758 // Create a copy of {from} that steals its state and leaves {from} 759 // unreachable. 760 SsaEnv* Steal(Zone* zone, SsaEnv* from) { 761 DCHECK_NOT_NULL(from); 762 if (!from->go()) return UnreachableEnv(zone); 763 SsaEnv* result = reinterpret_cast<SsaEnv*>(zone->New(sizeof(SsaEnv))); 764 result->state = SsaEnv::kReached; 765 result->locals = from->locals; 766 result->control = from->control; 767 result->effect = from->effect; 768 result->instance_cache = from->instance_cache; 769 from->Kill(SsaEnv::kUnreachable); 770 return result; 771 } 772 773 // Create an unreachable environment. 774 SsaEnv* UnreachableEnv(Zone* zone) { 775 SsaEnv* result = reinterpret_cast<SsaEnv*>(zone->New(sizeof(SsaEnv))); 776 result->state = SsaEnv::kUnreachable; 777 result->control = nullptr; 778 result->effect = nullptr; 779 result->locals = nullptr; 780 result->instance_cache = {}; 781 return result; 782 } 783 784 void DoCall(FullDecoder* decoder, TFNode* index_node, FunctionSig* sig, 785 uint32_t index, const Value args[], Value returns[]) { 786 int param_count = static_cast<int>(sig->parameter_count()); 787 TFNode** arg_nodes = builder_->Buffer(param_count + 1); 788 TFNode** return_nodes = nullptr; 789 arg_nodes[0] = index_node; 790 for (int i = 0; i < param_count; ++i) { 791 arg_nodes[i + 1] = args[i].node; 792 } 793 if (index_node) { 794 builder_->CallIndirect(index, arg_nodes, &return_nodes, 795 decoder->position()); 796 } else { 797 builder_->CallDirect(index, arg_nodes, &return_nodes, 798 decoder->position()); 799 } 800 int return_count = static_cast<int>(sig->return_count()); 801 for (int i = 0; i < return_count; ++i) { 802 returns[i].node = return_nodes[i]; 803 } 804 // The invoked function could have used grow_memory, so we need to 805 // reload mem_size and mem_start. 806 LoadContextIntoSsa(ssa_env_); 807 } 808 }; 809 810 } // namespace 811 812 bool DecodeLocalDecls(const WasmFeatures& enabled, BodyLocalDecls* decls, 813 const byte* start, const byte* end) { 814 Decoder decoder(start, end); 815 if (WasmDecoder<Decoder::kValidate>::DecodeLocals(enabled, &decoder, nullptr, 816 &decls->type_list)) { 817 DCHECK(decoder.ok()); 818 decls->encoded_size = decoder.pc_offset(); 819 return true; 820 } 821 return false; 822 } 823 824 BytecodeIterator::BytecodeIterator(const byte* start, const byte* end, 825 BodyLocalDecls* decls) 826 : Decoder(start, end) { 827 if (decls != nullptr) { 828 if (DecodeLocalDecls(kAllWasmFeatures, decls, start, end)) { 829 pc_ += decls->encoded_size; 830 if (pc_ > end_) pc_ = end_; 831 } 832 } 833 } 834 835 DecodeResult VerifyWasmCode(AccountingAllocator* allocator, 836 const WasmFeatures& enabled, 837 const WasmModule* module, WasmFeatures* detected, 838 FunctionBody& body) { 839 Zone zone(allocator, ZONE_NAME); 840 WasmFullDecoder<Decoder::kValidate, EmptyInterface> decoder( 841 &zone, module, enabled, detected, body); 842 decoder.Decode(); 843 return decoder.toResult(nullptr); 844 } 845 846 DecodeResult BuildTFGraph(AccountingAllocator* allocator, 847 const WasmFeatures& enabled, 848 const wasm::WasmModule* module, TFBuilder* builder, 849 WasmFeatures* detected, FunctionBody& body, 850 compiler::NodeOriginTable* node_origins) { 851 Zone zone(allocator, ZONE_NAME); 852 WasmFullDecoder<Decoder::kValidate, WasmGraphBuildingInterface> decoder( 853 &zone, module, enabled, detected, body, builder); 854 if (node_origins) { 855 builder->AddBytecodePositionDecorator(node_origins, &decoder); 856 } 857 decoder.Decode(); 858 if (node_origins) { 859 builder->RemoveBytecodePositionDecorator(); 860 } 861 return decoder.toResult(nullptr); 862 } 863 864 unsigned OpcodeLength(const byte* pc, const byte* end) { 865 Decoder decoder(pc, end); 866 return WasmDecoder<Decoder::kNoValidate>::OpcodeLength(&decoder, pc); 867 } 868 869 std::pair<uint32_t, uint32_t> StackEffect(const WasmModule* module, 870 FunctionSig* sig, const byte* pc, 871 const byte* end) { 872 WasmFeatures unused_detected_features; 873 WasmDecoder<Decoder::kNoValidate> decoder( 874 module, kAllWasmFeatures, &unused_detected_features, sig, pc, end); 875 return decoder.StackEffect(pc); 876 } 877 878 void PrintRawWasmCode(const byte* start, const byte* end) { 879 AccountingAllocator allocator; 880 PrintRawWasmCode(&allocator, FunctionBody{nullptr, 0, start, end}, nullptr, 881 kPrintLocals); 882 } 883 884 namespace { 885 const char* RawOpcodeName(WasmOpcode opcode) { 886 switch (opcode) { 887 #define DECLARE_NAME_CASE(name, opcode, sig) \ 888 case kExpr##name: \ 889 return "kExpr" #name; 890 FOREACH_OPCODE(DECLARE_NAME_CASE) 891 #undef DECLARE_NAME_CASE 892 default: 893 break; 894 } 895 return "Unknown"; 896 } 897 } // namespace 898 899 bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body, 900 const WasmModule* module, PrintLocals print_locals) { 901 StdoutStream os; 902 return PrintRawWasmCode(allocator, body, module, print_locals, os); 903 } 904 905 bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body, 906 const WasmModule* module, PrintLocals print_locals, 907 std::ostream& os, std::vector<int>* line_numbers) { 908 Zone zone(allocator, ZONE_NAME); 909 WasmFeatures unused_detected_features; 910 WasmDecoder<Decoder::kNoValidate> decoder(module, kAllWasmFeatures, 911 &unused_detected_features, body.sig, 912 body.start, body.end); 913 int line_nr = 0; 914 constexpr int kNoByteCode = -1; 915 916 // Print the function signature. 917 if (body.sig) { 918 os << "// signature: " << *body.sig << std::endl; 919 if (line_numbers) line_numbers->push_back(kNoByteCode); 920 ++line_nr; 921 } 922 923 // Print the local declarations. 924 BodyLocalDecls decls(&zone); 925 BytecodeIterator i(body.start, body.end, &decls); 926 if (body.start != i.pc() && print_locals == kPrintLocals) { 927 os << "// locals: "; 928 if (!decls.type_list.empty()) { 929 ValueType type = decls.type_list[0]; 930 uint32_t count = 0; 931 for (size_t pos = 0; pos < decls.type_list.size(); ++pos) { 932 if (decls.type_list[pos] == type) { 933 ++count; 934 } else { 935 os << " " << count << " " << ValueTypes::TypeName(type); 936 type = decls.type_list[pos]; 937 count = 1; 938 } 939 } 940 } 941 os << std::endl; 942 if (line_numbers) line_numbers->push_back(kNoByteCode); 943 ++line_nr; 944 945 for (const byte* locals = body.start; locals < i.pc(); locals++) { 946 os << (locals == body.start ? "0x" : " 0x") << AsHex(*locals, 2) << ","; 947 } 948 os << std::endl; 949 if (line_numbers) line_numbers->push_back(kNoByteCode); 950 ++line_nr; 951 } 952 953 os << "// body: " << std::endl; 954 if (line_numbers) line_numbers->push_back(kNoByteCode); 955 ++line_nr; 956 unsigned control_depth = 0; 957 for (; i.has_next(); i.next()) { 958 unsigned length = 959 WasmDecoder<Decoder::kNoValidate>::OpcodeLength(&decoder, i.pc()); 960 961 WasmOpcode opcode = i.current(); 962 if (line_numbers) line_numbers->push_back(i.position()); 963 if (opcode == kExprElse) control_depth--; 964 965 int num_whitespaces = control_depth < 32 ? 2 * control_depth : 64; 966 967 // 64 whitespaces 968 const char* padding = 969 " "; 970 os.write(padding, num_whitespaces); 971 972 os << RawOpcodeName(opcode) << ","; 973 974 if (opcode == kExprLoop || opcode == kExprIf || opcode == kExprBlock || 975 opcode == kExprTry) { 976 DCHECK_EQ(2, length); 977 978 switch (i.pc()[1]) { 979 #define CASE_LOCAL_TYPE(local_name, type_name) \ 980 case kLocal##local_name: \ 981 os << " kWasm" #type_name ","; \ 982 break; 983 984 CASE_LOCAL_TYPE(I32, I32) 985 CASE_LOCAL_TYPE(I64, I64) 986 CASE_LOCAL_TYPE(F32, F32) 987 CASE_LOCAL_TYPE(F64, F64) 988 CASE_LOCAL_TYPE(S128, S128) 989 CASE_LOCAL_TYPE(Void, Stmt) 990 default: 991 os << " 0x" << AsHex(i.pc()[1], 2) << ","; 992 break; 993 } 994 #undef CASE_LOCAL_TYPE 995 } else { 996 for (unsigned j = 1; j < length; ++j) { 997 os << " 0x" << AsHex(i.pc()[j], 2) << ","; 998 } 999 } 1000 1001 switch (opcode) { 1002 case kExprElse: 1003 os << " // @" << i.pc_offset(); 1004 control_depth++; 1005 break; 1006 case kExprLoop: 1007 case kExprIf: 1008 case kExprBlock: 1009 case kExprTry: { 1010 BlockTypeImmediate<Decoder::kNoValidate> imm(kAllWasmFeatures, &i, 1011 i.pc()); 1012 os << " // @" << i.pc_offset(); 1013 if (decoder.Complete(imm)) { 1014 for (unsigned i = 0; i < imm.out_arity(); i++) { 1015 os << " " << ValueTypes::TypeName(imm.out_type(i)); 1016 } 1017 } 1018 control_depth++; 1019 break; 1020 } 1021 case kExprEnd: 1022 os << " // @" << i.pc_offset(); 1023 control_depth--; 1024 break; 1025 case kExprBr: { 1026 BreakDepthImmediate<Decoder::kNoValidate> imm(&i, i.pc()); 1027 os << " // depth=" << imm.depth; 1028 break; 1029 } 1030 case kExprBrIf: { 1031 BreakDepthImmediate<Decoder::kNoValidate> imm(&i, i.pc()); 1032 os << " // depth=" << imm.depth; 1033 break; 1034 } 1035 case kExprBrTable: { 1036 BranchTableImmediate<Decoder::kNoValidate> imm(&i, i.pc()); 1037 os << " // entries=" << imm.table_count; 1038 break; 1039 } 1040 case kExprCallIndirect: { 1041 CallIndirectImmediate<Decoder::kNoValidate> imm(&i, i.pc()); 1042 os << " // sig #" << imm.sig_index; 1043 if (decoder.Complete(i.pc(), imm)) { 1044 os << ": " << *imm.sig; 1045 } 1046 break; 1047 } 1048 case kExprCallFunction: { 1049 CallFunctionImmediate<Decoder::kNoValidate> imm(&i, i.pc()); 1050 os << " // function #" << imm.index; 1051 if (decoder.Complete(i.pc(), imm)) { 1052 os << ": " << *imm.sig; 1053 } 1054 break; 1055 } 1056 default: 1057 break; 1058 } 1059 os << std::endl; 1060 ++line_nr; 1061 } 1062 DCHECK(!line_numbers || line_numbers->size() == static_cast<size_t>(line_nr)); 1063 1064 return decoder.ok(); 1065 } 1066 1067 BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals, 1068 const byte* start, const byte* end) { 1069 Decoder decoder(start, end); 1070 return WasmDecoder<Decoder::kValidate>::AnalyzeLoopAssignment( 1071 &decoder, start, static_cast<uint32_t>(num_locals), zone); 1072 } 1073 1074 #undef BUILD 1075 1076 } // namespace wasm 1077 } // namespace internal 1078 } // namespace v8 1079