1// Copyright 2018 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/wasm/graph-builder-interface.h" 6 7#include "src/compiler/wasm-compiler.h" 8#include "src/flags/flags.h" 9#include "src/handles/handles.h" 10#include "src/objects/objects-inl.h" 11#include "src/utils/ostreams.h" 12#include "src/wasm/branch-hint-map.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/value-type.h" 17#include "src/wasm/wasm-limits.h" 18#include "src/wasm/wasm-linkage.h" 19#include "src/wasm/wasm-module.h" 20#include "src/wasm/wasm-opcodes-inl.h" 21 22namespace v8 { 23namespace internal { 24namespace wasm { 25 26namespace { 27 28// An SsaEnv environment carries the current local variable renaming 29// as well as the current effect and control dependency in the TF graph. 30// It maintains a control state that tracks whether the environment 31// is reachable, has reached a control end, or has been merged. 32struct SsaEnv : public ZoneObject { 33 enum State { kUnreachable, kReached, kMerged }; 34 35 State state; 36 TFNode* control; 37 TFNode* effect; 38 compiler::WasmInstanceCacheNodes instance_cache; 39 ZoneVector<TFNode*> locals; 40 41 SsaEnv(Zone* zone, State state, TFNode* control, TFNode* effect, 42 uint32_t locals_size) 43 : state(state), 44 control(control), 45 effect(effect), 46 locals(locals_size, zone) {} 47 48 SsaEnv(const SsaEnv& other) V8_NOEXCEPT = default; 49 SsaEnv(SsaEnv&& other) V8_NOEXCEPT : state(other.state), 50 control(other.control), 51 effect(other.effect), 52 instance_cache(other.instance_cache), 53 locals(std::move(other.locals)) { 54 other.Kill(); 55 } 56 57 void Kill() { 58 state = kUnreachable; 59 for (TFNode*& local : locals) { 60 local = nullptr; 61 } 62 control = nullptr; 63 effect = nullptr; 64 instance_cache = {}; 65 } 66 void SetNotMerged() { 67 if (state == kMerged) state = kReached; 68 } 69}; 70 71class WasmGraphBuildingInterface { 72 public: 73 static constexpr Decoder::ValidateFlag validate = Decoder::kFullValidation; 74 using FullDecoder = WasmFullDecoder<validate, WasmGraphBuildingInterface>; 75 using CheckForNull = compiler::WasmGraphBuilder::CheckForNull; 76 77 struct Value : public ValueBase<validate> { 78 TFNode* node = nullptr; 79 80 template <typename... Args> 81 explicit Value(Args&&... args) V8_NOEXCEPT 82 : ValueBase(std::forward<Args>(args)...) {} 83 }; 84 using ValueVector = base::SmallVector<Value, 8>; 85 using NodeVector = base::SmallVector<TFNode*, 8>; 86 87 struct TryInfo : public ZoneObject { 88 SsaEnv* catch_env; 89 TFNode* exception = nullptr; 90 91 bool might_throw() const { return exception != nullptr; } 92 93 MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(TryInfo); 94 95 explicit TryInfo(SsaEnv* c) : catch_env(c) {} 96 }; 97 98 struct Control : public ControlBase<Value, validate> { 99 SsaEnv* merge_env = nullptr; // merge environment for the construct. 100 SsaEnv* false_env = nullptr; // false environment (only for if). 101 TryInfo* try_info = nullptr; // information about try statements. 102 int32_t previous_catch = -1; // previous Control with a catch. 103 BitVector* loop_assignments = nullptr; // locals assigned in this loop. 104 TFNode* loop_node = nullptr; // loop header of this loop. 105 MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(Control); 106 107 template <typename... Args> 108 explicit Control(Args&&... args) V8_NOEXCEPT 109 : ControlBase(std::forward<Args>(args)...) {} 110 }; 111 112 WasmGraphBuildingInterface(compiler::WasmGraphBuilder* builder, 113 int func_index, InlinedStatus inlined_status) 114 : builder_(builder), 115 func_index_(func_index), 116 inlined_status_(inlined_status) {} 117 118 void StartFunction(FullDecoder* decoder) { 119 // Get the branch hints map and type feedback for this function (if 120 // available). 121 if (decoder->module_) { 122 auto branch_hints_it = decoder->module_->branch_hints.find(func_index_); 123 if (branch_hints_it != decoder->module_->branch_hints.end()) { 124 branch_hints_ = &branch_hints_it->second; 125 } 126 TypeFeedbackStorage& feedbacks = decoder->module_->type_feedback; 127 base::MutexGuard mutex_guard(&feedbacks.mutex); 128 auto feedback = feedbacks.feedback_for_function.find(func_index_); 129 if (feedback != feedbacks.feedback_for_function.end()) { 130 type_feedback_ = feedback->second.feedback_vector; 131 // We need to keep the feedback in the module to inline later. However, 132 // this means we are stuck with it forever. 133 // TODO(jkummerow): Reconsider our options here. 134 } 135 } 136 // The first '+ 1' is needed by TF Start node, the second '+ 1' is for the 137 // instance parameter. 138 builder_->Start(static_cast<int>(decoder->sig_->parameter_count() + 1 + 1)); 139 uint32_t num_locals = decoder->num_locals(); 140 SsaEnv* ssa_env = decoder->zone()->New<SsaEnv>( 141 decoder->zone(), SsaEnv::kReached, effect(), control(), num_locals); 142 SetEnv(ssa_env); 143 144 // Initialize local variables. Parameters are shifted by 1 because of the 145 // the instance parameter. 146 uint32_t index = 0; 147 for (; index < decoder->sig_->parameter_count(); ++index) { 148 ssa_env->locals[index] = builder_->Param(index + 1); 149 } 150 while (index < num_locals) { 151 ValueType type = decoder->local_type(index); 152 TFNode* node; 153 if ((decoder->enabled_.has_nn_locals() || 154 decoder->enabled_.has_unsafe_nn_locals()) && 155 !type.is_defaultable()) { 156 DCHECK(type.is_reference()); 157 // TODO(jkummerow): Consider using "the hole" instead, to make any 158 // illegal uses more obvious. 159 node = builder_->RefNull(); 160 } else { 161 node = DefaultValue(type); 162 } 163 while (index < num_locals && decoder->local_type(index) == type) { 164 // Do a whole run of like-typed locals at a time. 165 ssa_env->locals[index++] = node; 166 } 167 } 168 LoadContextIntoSsa(ssa_env); 169 170 if (FLAG_trace_wasm && inlined_status_ == kRegularFunction) { 171 builder_->TraceFunctionEntry(decoder->position()); 172 } 173 } 174 175 // Reload the instance cache entries into the Ssa Environment. 176 void LoadContextIntoSsa(SsaEnv* ssa_env) { 177 if (ssa_env) builder_->InitInstanceCache(&ssa_env->instance_cache); 178 } 179 180 void StartFunctionBody(FullDecoder* decoder, Control* block) {} 181 182 void FinishFunction(FullDecoder*) { 183 if (inlined_status_ == kRegularFunction) { 184 builder_->PatchInStackCheckIfNeeded(); 185 } 186 } 187 188 void OnFirstError(FullDecoder*) {} 189 190 void NextInstruction(FullDecoder*, WasmOpcode) {} 191 192 void Block(FullDecoder* decoder, Control* block) { 193 // The branch environment is the outer environment. 194 block->merge_env = ssa_env_; 195 SetEnv(Steal(decoder->zone(), ssa_env_)); 196 } 197 198 void Loop(FullDecoder* decoder, Control* block) { 199 // This is the merge environment at the beginning of the loop. 200 SsaEnv* merge_env = Steal(decoder->zone(), ssa_env_); 201 block->merge_env = merge_env; 202 SetEnv(merge_env); 203 204 ssa_env_->state = SsaEnv::kMerged; 205 206 TFNode* loop_node = builder_->Loop(control()); 207 208 if (emit_loop_exits()) { 209 uint32_t nesting_depth = 0; 210 for (uint32_t depth = 1; depth < decoder->control_depth(); depth++) { 211 if (decoder->control_at(depth)->is_loop()) { 212 nesting_depth++; 213 } 214 } 215 // If this loop is nested, the parent loop's can_be_innermost field needs 216 // to be false. If the last loop in loop_infos_ has less depth, it has to 217 // be the parent loop. If it does not, it means another loop has been 218 // found within the parent loop, and that loop will have set the parent's 219 // can_be_innermost to false, so we do not need to do anything. 220 if (nesting_depth > 0 && 221 loop_infos_.back().nesting_depth < nesting_depth) { 222 loop_infos_.back().can_be_innermost = false; 223 } 224 loop_infos_.emplace_back(loop_node, nesting_depth, true); 225 } 226 227 builder_->SetControl(loop_node); 228 decoder->control_at(0)->loop_node = loop_node; 229 230 TFNode* effect_inputs[] = {effect(), control()}; 231 builder_->SetEffect(builder_->EffectPhi(1, effect_inputs)); 232 builder_->TerminateLoop(effect(), control()); 233 // Doing a preprocessing pass to analyze loop assignments seems to pay off 234 // compared to reallocating Nodes when rearranging Phis in Goto. 235 BitVector* assigned = WasmDecoder<validate>::AnalyzeLoopAssignment( 236 decoder, decoder->pc(), decoder->num_locals(), decoder->zone()); 237 if (decoder->failed()) return; 238 int instance_cache_index = decoder->num_locals(); 239 // If the module has shared memory, the stack guard might reallocate the 240 // shared memory. We have to assume the instance cache will be updated. 241 if (decoder->module_->has_shared_memory) { 242 assigned->Add(instance_cache_index); 243 } 244 DCHECK_NOT_NULL(assigned); 245 decoder->control_at(0)->loop_assignments = assigned; 246 247 // Only introduce phis for variables assigned in this loop. 248 for (int i = decoder->num_locals() - 1; i >= 0; i--) { 249 if (!assigned->Contains(i)) continue; 250 TFNode* inputs[] = {ssa_env_->locals[i], control()}; 251 ssa_env_->locals[i] = builder_->Phi(decoder->local_type(i), 1, inputs); 252 } 253 // Introduce phis for instance cache pointers if necessary. 254 if (assigned->Contains(instance_cache_index)) { 255 builder_->PrepareInstanceCacheForLoop(&ssa_env_->instance_cache, 256 control()); 257 } 258 259 // Now we setup a new environment for the inside of the loop. 260 SetEnv(Split(decoder->zone(), ssa_env_)); 261 builder_->StackCheck(decoder->module_->has_shared_memory 262 ? &ssa_env_->instance_cache 263 : nullptr, 264 decoder->position()); 265 ssa_env_->SetNotMerged(); 266 267 // Wrap input merge into phis. 268 for (uint32_t i = 0; i < block->start_merge.arity; ++i) { 269 Value& val = block->start_merge[i]; 270 TFNode* inputs[] = {val.node, block->merge_env->control}; 271 val.node = builder_->Phi(val.type, 1, inputs); 272 } 273 } 274 275 void Try(FullDecoder* decoder, Control* block) { 276 SsaEnv* outer_env = ssa_env_; 277 SsaEnv* catch_env = Split(decoder->zone(), outer_env); 278 // Mark catch environment as unreachable, since only accessable 279 // through catch unwinding (i.e. landing pads). 280 catch_env->state = SsaEnv::kUnreachable; 281 SsaEnv* try_env = Steal(decoder->zone(), outer_env); 282 SetEnv(try_env); 283 TryInfo* try_info = decoder->zone()->New<TryInfo>(catch_env); 284 block->merge_env = outer_env; 285 block->try_info = try_info; 286 } 287 288 void If(FullDecoder* decoder, const Value& cond, Control* if_block) { 289 TFNode* if_true = nullptr; 290 TFNode* if_false = nullptr; 291 WasmBranchHint hint = WasmBranchHint::kNoHint; 292 if (branch_hints_) { 293 hint = branch_hints_->GetHintFor(decoder->pc_relative_offset()); 294 } 295 switch (hint) { 296 case WasmBranchHint::kNoHint: 297 builder_->BranchNoHint(cond.node, &if_true, &if_false); 298 break; 299 case WasmBranchHint::kUnlikely: 300 builder_->BranchExpectFalse(cond.node, &if_true, &if_false); 301 break; 302 case WasmBranchHint::kLikely: 303 builder_->BranchExpectTrue(cond.node, &if_true, &if_false); 304 break; 305 } 306 SsaEnv* merge_env = ssa_env_; 307 SsaEnv* false_env = Split(decoder->zone(), ssa_env_); 308 false_env->control = if_false; 309 SsaEnv* true_env = Steal(decoder->zone(), ssa_env_); 310 true_env->control = if_true; 311 if_block->merge_env = merge_env; 312 if_block->false_env = false_env; 313 SetEnv(true_env); 314 } 315 316 void FallThruTo(FullDecoder* decoder, Control* c) { 317 DCHECK(!c->is_loop()); 318 MergeValuesInto(decoder, c, &c->end_merge); 319 } 320 321 void PopControl(FullDecoder* decoder, Control* block) { 322 // A loop just continues with the end environment. There is no merge. 323 // However, if loop unrolling is enabled, we must create a loop exit and 324 // wrap the fallthru values on the stack. 325 if (block->is_loop()) { 326 if (emit_loop_exits() && block->reachable()) { 327 BuildLoopExits(decoder, block); 328 WrapLocalsAtLoopExit(decoder, block); 329 uint32_t arity = block->end_merge.arity; 330 if (arity > 0) { 331 Value* stack_base = decoder->stack_value(arity); 332 for (uint32_t i = 0; i < arity; i++) { 333 Value* val = stack_base + i; 334 val->node = builder_->LoopExitValue( 335 val->node, val->type.machine_representation()); 336 } 337 } 338 } 339 return; 340 } 341 // Any other block falls through to the parent block. 342 if (block->reachable()) FallThruTo(decoder, block); 343 if (block->is_onearmed_if()) { 344 // Merge the else branch into the end merge. 345 SetEnv(block->false_env); 346 DCHECK_EQ(block->start_merge.arity, block->end_merge.arity); 347 Value* values = 348 block->start_merge.arity > 0 ? &block->start_merge[0] : nullptr; 349 MergeValuesInto(decoder, block, &block->end_merge, values); 350 } 351 // Now continue with the merged environment. 352 SetEnv(block->merge_env); 353 } 354 355 void UnOp(FullDecoder* decoder, WasmOpcode opcode, const Value& value, 356 Value* result) { 357 result->node = builder_->Unop(opcode, value.node, decoder->position()); 358 } 359 360 void BinOp(FullDecoder* decoder, WasmOpcode opcode, const Value& lhs, 361 const Value& rhs, Value* result) { 362 TFNode* node = 363 builder_->Binop(opcode, lhs.node, rhs.node, decoder->position()); 364 if (result) result->node = node; 365 } 366 367 void I32Const(FullDecoder* decoder, Value* result, int32_t value) { 368 result->node = builder_->Int32Constant(value); 369 } 370 371 void I64Const(FullDecoder* decoder, Value* result, int64_t value) { 372 result->node = builder_->Int64Constant(value); 373 } 374 375 void F32Const(FullDecoder* decoder, Value* result, float value) { 376 result->node = builder_->Float32Constant(value); 377 } 378 379 void F64Const(FullDecoder* decoder, Value* result, double value) { 380 result->node = builder_->Float64Constant(value); 381 } 382 383 void S128Const(FullDecoder* decoder, const Simd128Immediate<validate>& imm, 384 Value* result) { 385 result->node = builder_->Simd128Constant(imm.value); 386 } 387 388 void RefNull(FullDecoder* decoder, ValueType type, Value* result) { 389 result->node = builder_->RefNull(); 390 } 391 392 void RefFunc(FullDecoder* decoder, uint32_t function_index, Value* result) { 393 result->node = builder_->RefFunc(function_index); 394 } 395 396 void RefAsNonNull(FullDecoder* decoder, const Value& arg, Value* result) { 397 result->node = builder_->RefAsNonNull(arg.node, decoder->position()); 398 } 399 400 void Drop(FullDecoder* decoder) {} 401 402 void LocalGet(FullDecoder* decoder, Value* result, 403 const IndexImmediate<validate>& imm) { 404 result->node = ssa_env_->locals[imm.index]; 405 } 406 407 void LocalSet(FullDecoder* decoder, const Value& value, 408 const IndexImmediate<validate>& imm) { 409 ssa_env_->locals[imm.index] = value.node; 410 } 411 412 void LocalTee(FullDecoder* decoder, const Value& value, Value* result, 413 const IndexImmediate<validate>& imm) { 414 result->node = value.node; 415 ssa_env_->locals[imm.index] = value.node; 416 } 417 418 void AllocateLocals(FullDecoder* decoder, base::Vector<Value> local_values) { 419 ZoneVector<TFNode*>* locals = &ssa_env_->locals; 420 locals->insert(locals->begin(), local_values.size(), nullptr); 421 for (uint32_t i = 0; i < local_values.size(); i++) { 422 (*locals)[i] = local_values[i].node; 423 } 424 } 425 426 void DeallocateLocals(FullDecoder* decoder, uint32_t count) { 427 ZoneVector<TFNode*>* locals = &ssa_env_->locals; 428 locals->erase(locals->begin(), locals->begin() + count); 429 } 430 431 void GlobalGet(FullDecoder* decoder, Value* result, 432 const GlobalIndexImmediate<validate>& imm) { 433 result->node = builder_->GlobalGet(imm.index); 434 } 435 436 void GlobalSet(FullDecoder* decoder, const Value& value, 437 const GlobalIndexImmediate<validate>& imm) { 438 builder_->GlobalSet(imm.index, value.node); 439 } 440 441 void TableGet(FullDecoder* decoder, const Value& index, Value* result, 442 const IndexImmediate<validate>& imm) { 443 result->node = 444 builder_->TableGet(imm.index, index.node, decoder->position()); 445 } 446 447 void TableSet(FullDecoder* decoder, const Value& index, const Value& value, 448 const IndexImmediate<validate>& imm) { 449 builder_->TableSet(imm.index, index.node, value.node, decoder->position()); 450 } 451 452 void Trap(FullDecoder* decoder, TrapReason reason) { 453 builder_->Trap(reason, decoder->position()); 454 } 455 456 void AssertNull(FullDecoder* decoder, const Value& obj, Value* result) { 457 builder_->TrapIfFalse( 458 wasm::TrapReason::kTrapIllegalCast, 459 builder_->Binop(kExprRefEq, obj.node, builder_->RefNull(), 460 decoder->position()), 461 decoder->position()); 462 result->node = obj.node; 463 } 464 465 void NopForTestingUnsupportedInLiftoff(FullDecoder* decoder) {} 466 467 void Select(FullDecoder* decoder, const Value& cond, const Value& fval, 468 const Value& tval, Value* result) { 469 result->node = 470 builder_->Select(cond.node, tval.node, fval.node, result->type); 471 } 472 473 ValueVector CopyStackValues(FullDecoder* decoder, uint32_t count, 474 uint32_t drop_values) { 475 Value* stack_base = 476 count > 0 ? decoder->stack_value(count + drop_values) : nullptr; 477 ValueVector stack_values(count); 478 for (uint32_t i = 0; i < count; i++) { 479 stack_values[i] = stack_base[i]; 480 } 481 return stack_values; 482 } 483 484 void DoReturn(FullDecoder* decoder, uint32_t drop_values) { 485 uint32_t ret_count = static_cast<uint32_t>(decoder->sig_->return_count()); 486 NodeVector values(ret_count); 487 SsaEnv* internal_env = ssa_env_; 488 if (emit_loop_exits()) { 489 SsaEnv* exit_env = Split(decoder->zone(), ssa_env_); 490 SetEnv(exit_env); 491 auto stack_values = CopyStackValues(decoder, ret_count, drop_values); 492 BuildNestedLoopExits(decoder, decoder->control_depth() - 1, false, 493 stack_values); 494 GetNodes(values.begin(), base::VectorOf(stack_values)); 495 } else { 496 Value* stack_base = ret_count == 0 497 ? nullptr 498 : decoder->stack_value(ret_count + drop_values); 499 GetNodes(values.begin(), stack_base, ret_count); 500 } 501 if (FLAG_trace_wasm && inlined_status_ == kRegularFunction) { 502 builder_->TraceFunctionExit(base::VectorOf(values), decoder->position()); 503 } 504 builder_->Return(base::VectorOf(values)); 505 SetEnv(internal_env); 506 } 507 508 void BrOrRet(FullDecoder* decoder, uint32_t depth, uint32_t drop_values) { 509 if (depth == decoder->control_depth() - 1) { 510 DoReturn(decoder, drop_values); 511 } else { 512 Control* target = decoder->control_at(depth); 513 if (emit_loop_exits()) { 514 SsaEnv* internal_env = ssa_env_; 515 SsaEnv* exit_env = Split(decoder->zone(), ssa_env_); 516 SetEnv(exit_env); 517 uint32_t value_count = target->br_merge()->arity; 518 auto stack_values = CopyStackValues(decoder, value_count, drop_values); 519 BuildNestedLoopExits(decoder, depth, true, stack_values); 520 MergeValuesInto(decoder, target, target->br_merge(), 521 stack_values.data()); 522 SetEnv(internal_env); 523 } else { 524 MergeValuesInto(decoder, target, target->br_merge(), drop_values); 525 } 526 } 527 } 528 529 void BrIf(FullDecoder* decoder, const Value& cond, uint32_t depth) { 530 SsaEnv* fenv = ssa_env_; 531 SsaEnv* tenv = Split(decoder->zone(), fenv); 532 fenv->SetNotMerged(); 533 WasmBranchHint hint = WasmBranchHint::kNoHint; 534 if (branch_hints_) { 535 hint = branch_hints_->GetHintFor(decoder->pc_relative_offset()); 536 } 537 switch (hint) { 538 case WasmBranchHint::kNoHint: 539 builder_->BranchNoHint(cond.node, &tenv->control, &fenv->control); 540 break; 541 case WasmBranchHint::kUnlikely: 542 builder_->BranchExpectFalse(cond.node, &tenv->control, &fenv->control); 543 break; 544 case WasmBranchHint::kLikely: 545 builder_->BranchExpectTrue(cond.node, &tenv->control, &fenv->control); 546 break; 547 } 548 builder_->SetControl(fenv->control); 549 SetEnv(tenv); 550 BrOrRet(decoder, depth, 1); 551 SetEnv(fenv); 552 } 553 554 void BrTable(FullDecoder* decoder, const BranchTableImmediate<validate>& imm, 555 const Value& key) { 556 if (imm.table_count == 0) { 557 // Only a default target. Do the equivalent of br. 558 uint32_t target = BranchTableIterator<validate>(decoder, imm).next(); 559 BrOrRet(decoder, target, 1); 560 return; 561 } 562 563 SsaEnv* branch_env = ssa_env_; 564 // Build branches to the various blocks based on the table. 565 TFNode* sw = builder_->Switch(imm.table_count + 1, key.node); 566 567 SsaEnv* copy = Steal(decoder->zone(), branch_env); 568 SetEnv(copy); 569 BranchTableIterator<validate> iterator(decoder, imm); 570 while (iterator.has_next()) { 571 uint32_t i = iterator.cur_index(); 572 uint32_t target = iterator.next(); 573 SetEnv(Split(decoder->zone(), copy)); 574 builder_->SetControl(i == imm.table_count ? builder_->IfDefault(sw) 575 : builder_->IfValue(i, sw)); 576 BrOrRet(decoder, target, 1); 577 } 578 DCHECK(decoder->ok()); 579 SetEnv(branch_env); 580 } 581 582 void Else(FullDecoder* decoder, Control* if_block) { 583 if (if_block->reachable()) { 584 // Merge the if branch into the end merge. 585 MergeValuesInto(decoder, if_block, &if_block->end_merge); 586 } 587 SetEnv(if_block->false_env); 588 } 589 590 void LoadMem(FullDecoder* decoder, LoadType type, 591 const MemoryAccessImmediate<validate>& imm, const Value& index, 592 Value* result) { 593 result->node = 594 builder_->LoadMem(type.value_type(), type.mem_type(), index.node, 595 imm.offset, imm.alignment, decoder->position()); 596 } 597 598 void LoadTransform(FullDecoder* decoder, LoadType type, 599 LoadTransformationKind transform, 600 const MemoryAccessImmediate<validate>& imm, 601 const Value& index, Value* result) { 602 result->node = builder_->LoadTransform(type.value_type(), type.mem_type(), 603 transform, index.node, imm.offset, 604 imm.alignment, decoder->position()); 605 } 606 607 void LoadLane(FullDecoder* decoder, LoadType type, const Value& value, 608 const Value& index, const MemoryAccessImmediate<validate>& imm, 609 const uint8_t laneidx, Value* result) { 610 result->node = builder_->LoadLane( 611 type.value_type(), type.mem_type(), value.node, index.node, imm.offset, 612 imm.alignment, laneidx, decoder->position()); 613 } 614 615 void StoreMem(FullDecoder* decoder, StoreType type, 616 const MemoryAccessImmediate<validate>& imm, const Value& index, 617 const Value& value) { 618 builder_->StoreMem(type.mem_rep(), index.node, imm.offset, imm.alignment, 619 value.node, decoder->position(), type.value_type()); 620 } 621 622 void StoreLane(FullDecoder* decoder, StoreType type, 623 const MemoryAccessImmediate<validate>& imm, const Value& index, 624 const Value& value, const uint8_t laneidx) { 625 builder_->StoreLane(type.mem_rep(), index.node, imm.offset, imm.alignment, 626 value.node, laneidx, decoder->position(), 627 type.value_type()); 628 } 629 630 void CurrentMemoryPages(FullDecoder* decoder, Value* result) { 631 result->node = builder_->CurrentMemoryPages(); 632 } 633 634 void MemoryGrow(FullDecoder* decoder, const Value& value, Value* result) { 635 result->node = builder_->MemoryGrow(value.node); 636 // Always reload the instance cache after growing memory. 637 LoadContextIntoSsa(ssa_env_); 638 } 639 640 void CallDirect(FullDecoder* decoder, 641 const CallFunctionImmediate<validate>& imm, 642 const Value args[], Value returns[]) { 643 if (FLAG_wasm_speculative_inlining && type_feedback_.size() > 0) { 644 DCHECK_LT(feedback_instruction_index_, type_feedback_.size()); 645 feedback_instruction_index_++; 646 } 647 DoCall(decoder, CallInfo::CallDirect(imm.index), imm.sig, args, returns); 648 } 649 650 void ReturnCall(FullDecoder* decoder, 651 const CallFunctionImmediate<validate>& imm, 652 const Value args[]) { 653 if (FLAG_wasm_speculative_inlining && type_feedback_.size() > 0) { 654 DCHECK_LT(feedback_instruction_index_, type_feedback_.size()); 655 feedback_instruction_index_++; 656 } 657 DoReturnCall(decoder, CallInfo::CallDirect(imm.index), imm.sig, args); 658 } 659 660 void CallIndirect(FullDecoder* decoder, const Value& index, 661 const CallIndirectImmediate<validate>& imm, 662 const Value args[], Value returns[]) { 663 DoCall( 664 decoder, 665 CallInfo::CallIndirect(index, imm.table_imm.index, imm.sig_imm.index), 666 imm.sig, args, returns); 667 } 668 669 void ReturnCallIndirect(FullDecoder* decoder, const Value& index, 670 const CallIndirectImmediate<validate>& imm, 671 const Value args[]) { 672 DoReturnCall( 673 decoder, 674 CallInfo::CallIndirect(index, imm.table_imm.index, imm.sig_imm.index), 675 imm.sig, args); 676 } 677 678 void CallRef(FullDecoder* decoder, const Value& func_ref, 679 const FunctionSig* sig, uint32_t sig_index, const Value args[], 680 Value returns[]) { 681 int maybe_feedback = -1; 682 if (FLAG_wasm_speculative_inlining && type_feedback_.size() > 0) { 683 DCHECK_LT(feedback_instruction_index_, type_feedback_.size()); 684 maybe_feedback = 685 type_feedback_[feedback_instruction_index_].function_index; 686 feedback_instruction_index_++; 687 } 688 if (maybe_feedback == -1) { 689 DoCall(decoder, CallInfo::CallRef(func_ref, NullCheckFor(func_ref.type)), 690 sig, args, returns); 691 return; 692 } 693 694 // Check for equality against a function at a specific index, and if 695 // successful, just emit a direct call. 696 DCHECK_GE(maybe_feedback, 0); 697 const uint32_t expected_function_index = maybe_feedback; 698 699 if (FLAG_trace_wasm_speculative_inlining) { 700 PrintF("[Function #%d call #%d: graph support for inlining target #%d]\n", 701 func_index_, feedback_instruction_index_ - 1, 702 expected_function_index); 703 } 704 705 TFNode* success_control; 706 TFNode* failure_control; 707 builder_->CompareToInternalFunctionAtIndex( 708 func_ref.node, expected_function_index, &success_control, 709 &failure_control); 710 TFNode* initial_effect = effect(); 711 712 builder_->SetControl(success_control); 713 ssa_env_->control = success_control; 714 Value* returns_direct = 715 decoder->zone()->NewArray<Value>(sig->return_count()); 716 DoCall(decoder, CallInfo::CallDirect(expected_function_index), 717 decoder->module_->signature(sig_index), args, returns_direct); 718 TFNode* control_direct = control(); 719 TFNode* effect_direct = effect(); 720 721 builder_->SetEffectControl(initial_effect, failure_control); 722 ssa_env_->effect = initial_effect; 723 ssa_env_->control = failure_control; 724 Value* returns_ref = decoder->zone()->NewArray<Value>(sig->return_count()); 725 DoCall(decoder, CallInfo::CallRef(func_ref, NullCheckFor(func_ref.type)), 726 sig, args, returns_ref); 727 728 TFNode* control_ref = control(); 729 TFNode* effect_ref = effect(); 730 731 TFNode* control_args[] = {control_direct, control_ref}; 732 TFNode* control = builder_->Merge(2, control_args); 733 734 TFNode* effect_args[] = {effect_direct, effect_ref, control}; 735 TFNode* effect = builder_->EffectPhi(2, effect_args); 736 737 ssa_env_->control = control; 738 ssa_env_->effect = effect; 739 builder_->SetEffectControl(effect, control); 740 741 for (uint32_t i = 0; i < sig->return_count(); i++) { 742 TFNode* phi_args[] = {returns_direct[i].node, returns_ref[i].node, 743 control}; 744 returns[i].node = builder_->Phi(sig->GetReturn(i), 2, phi_args); 745 } 746 } 747 748 void ReturnCallRef(FullDecoder* decoder, const Value& func_ref, 749 const FunctionSig* sig, uint32_t sig_index, 750 const Value args[]) { 751 int maybe_feedback = -1; 752 if (FLAG_wasm_speculative_inlining && type_feedback_.size() > 0) { 753 DCHECK_LT(feedback_instruction_index_, type_feedback_.size()); 754 maybe_feedback = 755 type_feedback_[feedback_instruction_index_].function_index; 756 feedback_instruction_index_++; 757 } 758 if (maybe_feedback == -1) { 759 DoReturnCall(decoder, 760 CallInfo::CallRef(func_ref, NullCheckFor(func_ref.type)), 761 sig, args); 762 return; 763 } 764 765 // Check for equality against a function at a specific index, and if 766 // successful, just emit a direct call. 767 DCHECK_GE(maybe_feedback, 0); 768 const uint32_t expected_function_index = maybe_feedback; 769 770 if (FLAG_trace_wasm_speculative_inlining) { 771 PrintF("[Function #%d call #%d: graph support for inlining target #%d]\n", 772 func_index_, feedback_instruction_index_ - 1, 773 expected_function_index); 774 } 775 776 TFNode* success_control; 777 TFNode* failure_control; 778 builder_->CompareToInternalFunctionAtIndex( 779 func_ref.node, expected_function_index, &success_control, 780 &failure_control); 781 TFNode* initial_effect = effect(); 782 783 builder_->SetControl(success_control); 784 ssa_env_->control = success_control; 785 DoReturnCall(decoder, CallInfo::CallDirect(expected_function_index), sig, 786 args); 787 788 builder_->SetEffectControl(initial_effect, failure_control); 789 ssa_env_->effect = initial_effect; 790 ssa_env_->control = failure_control; 791 DoReturnCall(decoder, 792 CallInfo::CallRef(func_ref, NullCheckFor(func_ref.type)), sig, 793 args); 794 } 795 796 void BrOnNull(FullDecoder* decoder, const Value& ref_object, uint32_t depth, 797 bool pass_null_along_branch, Value* result_on_fallthrough) { 798 SsaEnv* false_env = ssa_env_; 799 SsaEnv* true_env = Split(decoder->zone(), false_env); 800 false_env->SetNotMerged(); 801 builder_->BrOnNull(ref_object.node, &true_env->control, 802 &false_env->control); 803 builder_->SetControl(false_env->control); 804 SetEnv(true_env); 805 BrOrRet(decoder, depth, pass_null_along_branch ? 0 : 1); 806 SetEnv(false_env); 807 result_on_fallthrough->node = ref_object.node; 808 } 809 810 void BrOnNonNull(FullDecoder* decoder, const Value& ref_object, 811 uint32_t depth) { 812 SsaEnv* false_env = ssa_env_; 813 SsaEnv* true_env = Split(decoder->zone(), false_env); 814 false_env->SetNotMerged(); 815 builder_->BrOnNull(ref_object.node, &false_env->control, 816 &true_env->control); 817 builder_->SetControl(false_env->control); 818 SetEnv(true_env); 819 BrOrRet(decoder, depth, 0); 820 SetEnv(false_env); 821 } 822 823 void SimdOp(FullDecoder* decoder, WasmOpcode opcode, base::Vector<Value> args, 824 Value* result) { 825 NodeVector inputs(args.size()); 826 GetNodes(inputs.begin(), args); 827 TFNode* node = builder_->SimdOp(opcode, inputs.begin()); 828 if (result) result->node = node; 829 } 830 831 void SimdLaneOp(FullDecoder* decoder, WasmOpcode opcode, 832 const SimdLaneImmediate<validate>& imm, 833 base::Vector<Value> inputs, Value* result) { 834 NodeVector nodes(inputs.size()); 835 GetNodes(nodes.begin(), inputs); 836 result->node = builder_->SimdLaneOp(opcode, imm.lane, nodes.begin()); 837 } 838 839 void Simd8x16ShuffleOp(FullDecoder* decoder, 840 const Simd128Immediate<validate>& imm, 841 const Value& input0, const Value& input1, 842 Value* result) { 843 TFNode* input_nodes[] = {input0.node, input1.node}; 844 result->node = builder_->Simd8x16ShuffleOp(imm.value, input_nodes); 845 } 846 847 void Throw(FullDecoder* decoder, const TagIndexImmediate<validate>& imm, 848 const base::Vector<Value>& value_args) { 849 int count = value_args.length(); 850 ZoneVector<TFNode*> args(count, decoder->zone()); 851 for (int i = 0; i < count; ++i) { 852 args[i] = value_args[i].node; 853 } 854 CheckForException(decoder, 855 builder_->Throw(imm.index, imm.tag, base::VectorOf(args), 856 decoder->position())); 857 builder_->TerminateThrow(effect(), control()); 858 } 859 860 void Rethrow(FullDecoder* decoder, Control* block) { 861 DCHECK(block->is_try_catchall() || block->is_try_catch()); 862 TFNode* exception = block->try_info->exception; 863 DCHECK_NOT_NULL(exception); 864 CheckForException(decoder, builder_->Rethrow(exception)); 865 builder_->TerminateThrow(effect(), control()); 866 } 867 868 void CatchException(FullDecoder* decoder, 869 const TagIndexImmediate<validate>& imm, Control* block, 870 base::Vector<Value> values) { 871 DCHECK(block->is_try_catch()); 872 // The catch block is unreachable if no possible throws in the try block 873 // exist. We only build a landing pad if some node in the try block can 874 // (possibly) throw. Otherwise the catch environments remain empty. 875 if (!block->try_info->might_throw()) { 876 block->reachability = kSpecOnlyReachable; 877 return; 878 } 879 880 TFNode* exception = block->try_info->exception; 881 SetEnv(block->try_info->catch_env); 882 883 TFNode* if_catch = nullptr; 884 TFNode* if_no_catch = nullptr; 885 886 // Get the exception tag and see if it matches the expected one. 887 TFNode* caught_tag = builder_->GetExceptionTag(exception); 888 TFNode* exception_tag = builder_->LoadTagFromTable(imm.index); 889 TFNode* compare = builder_->ExceptionTagEqual(caught_tag, exception_tag); 890 builder_->BranchNoHint(compare, &if_catch, &if_no_catch); 891 892 // If the tags don't match we continue with the next tag by setting the 893 // false environment as the new {TryInfo::catch_env} here. 894 SsaEnv* if_no_catch_env = Split(decoder->zone(), ssa_env_); 895 if_no_catch_env->control = if_no_catch; 896 SsaEnv* if_catch_env = Steal(decoder->zone(), ssa_env_); 897 if_catch_env->control = if_catch; 898 block->try_info->catch_env = if_no_catch_env; 899 900 // If the tags match we extract the values from the exception object and 901 // push them onto the operand stack using the passed {values} vector. 902 SetEnv(if_catch_env); 903 NodeVector caught_values(values.size()); 904 base::Vector<TFNode*> caught_vector = base::VectorOf(caught_values); 905 builder_->GetExceptionValues(exception, imm.tag, caught_vector); 906 for (size_t i = 0, e = values.size(); i < e; ++i) { 907 values[i].node = caught_values[i]; 908 } 909 } 910 911 void Delegate(FullDecoder* decoder, uint32_t depth, Control* block) { 912 DCHECK_EQ(decoder->control_at(0), block); 913 DCHECK(block->is_incomplete_try()); 914 915 if (block->try_info->might_throw()) { 916 // Merge the current env into the target handler's env. 917 SetEnv(block->try_info->catch_env); 918 if (depth == decoder->control_depth() - 1) { 919 // We just throw to the caller here, so no need to generate IfSuccess 920 // and IfFailure nodes. 921 builder_->Rethrow(block->try_info->exception); 922 builder_->TerminateThrow(effect(), control()); 923 return; 924 } 925 DCHECK(decoder->control_at(depth)->is_try()); 926 TryInfo* target_try = decoder->control_at(depth)->try_info; 927 if (emit_loop_exits()) { 928 ValueVector stack_values; 929 BuildNestedLoopExits(decoder, depth, true, stack_values, 930 &block->try_info->exception); 931 } 932 Goto(decoder, target_try->catch_env); 933 934 // Create or merge the exception. 935 if (target_try->catch_env->state == SsaEnv::kReached) { 936 target_try->exception = block->try_info->exception; 937 } else { 938 DCHECK_EQ(target_try->catch_env->state, SsaEnv::kMerged); 939 target_try->exception = builder_->CreateOrMergeIntoPhi( 940 MachineRepresentation::kTagged, target_try->catch_env->control, 941 target_try->exception, block->try_info->exception); 942 } 943 } 944 } 945 946 void CatchAll(FullDecoder* decoder, Control* block) { 947 DCHECK(block->is_try_catchall() || block->is_try_catch()); 948 DCHECK_EQ(decoder->control_at(0), block); 949 950 // The catch block is unreachable if no possible throws in the try block 951 // exist. We only build a landing pad if some node in the try block can 952 // (possibly) throw. Otherwise the catch environments remain empty. 953 if (!block->try_info->might_throw()) { 954 decoder->SetSucceedingCodeDynamicallyUnreachable(); 955 return; 956 } 957 958 SetEnv(block->try_info->catch_env); 959 } 960 961 void AtomicOp(FullDecoder* decoder, WasmOpcode opcode, 962 base::Vector<Value> args, 963 const MemoryAccessImmediate<validate>& imm, Value* result) { 964 NodeVector inputs(args.size()); 965 GetNodes(inputs.begin(), args); 966 TFNode* node = builder_->AtomicOp(opcode, inputs.begin(), imm.alignment, 967 imm.offset, decoder->position()); 968 if (result) result->node = node; 969 } 970 971 void AtomicFence(FullDecoder* decoder) { builder_->AtomicFence(); } 972 973 void MemoryInit(FullDecoder* decoder, 974 const MemoryInitImmediate<validate>& imm, const Value& dst, 975 const Value& src, const Value& size) { 976 builder_->MemoryInit(imm.data_segment.index, dst.node, src.node, size.node, 977 decoder->position()); 978 } 979 980 void DataDrop(FullDecoder* decoder, const IndexImmediate<validate>& imm) { 981 builder_->DataDrop(imm.index, decoder->position()); 982 } 983 984 void MemoryCopy(FullDecoder* decoder, 985 const MemoryCopyImmediate<validate>& imm, const Value& dst, 986 const Value& src, const Value& size) { 987 builder_->MemoryCopy(dst.node, src.node, size.node, decoder->position()); 988 } 989 990 void MemoryFill(FullDecoder* decoder, 991 const MemoryIndexImmediate<validate>& imm, const Value& dst, 992 const Value& value, const Value& size) { 993 builder_->MemoryFill(dst.node, value.node, size.node, decoder->position()); 994 } 995 996 void TableInit(FullDecoder* decoder, const TableInitImmediate<validate>& imm, 997 base::Vector<Value> args) { 998 builder_->TableInit(imm.table.index, imm.element_segment.index, 999 args[0].node, args[1].node, args[2].node, 1000 decoder->position()); 1001 } 1002 1003 void ElemDrop(FullDecoder* decoder, const IndexImmediate<validate>& imm) { 1004 builder_->ElemDrop(imm.index, decoder->position()); 1005 } 1006 1007 void TableCopy(FullDecoder* decoder, const TableCopyImmediate<validate>& imm, 1008 base::Vector<Value> args) { 1009 builder_->TableCopy(imm.table_dst.index, imm.table_src.index, args[0].node, 1010 args[1].node, args[2].node, decoder->position()); 1011 } 1012 1013 void TableGrow(FullDecoder* decoder, const IndexImmediate<validate>& imm, 1014 const Value& value, const Value& delta, Value* result) { 1015 result->node = builder_->TableGrow(imm.index, value.node, delta.node); 1016 } 1017 1018 void TableSize(FullDecoder* decoder, const IndexImmediate<validate>& imm, 1019 Value* result) { 1020 result->node = builder_->TableSize(imm.index); 1021 } 1022 1023 void TableFill(FullDecoder* decoder, const IndexImmediate<validate>& imm, 1024 const Value& start, const Value& value, const Value& count) { 1025 builder_->TableFill(imm.index, start.node, value.node, count.node); 1026 } 1027 1028 void StructNewWithRtt(FullDecoder* decoder, 1029 const StructIndexImmediate<validate>& imm, 1030 const Value& rtt, const Value args[], Value* result) { 1031 uint32_t field_count = imm.struct_type->field_count(); 1032 NodeVector arg_nodes(field_count); 1033 for (uint32_t i = 0; i < field_count; i++) { 1034 arg_nodes[i] = args[i].node; 1035 } 1036 result->node = builder_->StructNewWithRtt( 1037 imm.index, imm.struct_type, rtt.node, base::VectorOf(arg_nodes)); 1038 } 1039 void StructNewDefault(FullDecoder* decoder, 1040 const StructIndexImmediate<validate>& imm, 1041 const Value& rtt, Value* result) { 1042 uint32_t field_count = imm.struct_type->field_count(); 1043 NodeVector arg_nodes(field_count); 1044 for (uint32_t i = 0; i < field_count; i++) { 1045 arg_nodes[i] = DefaultValue(imm.struct_type->field(i)); 1046 } 1047 result->node = builder_->StructNewWithRtt( 1048 imm.index, imm.struct_type, rtt.node, base::VectorOf(arg_nodes)); 1049 } 1050 1051 void StructGet(FullDecoder* decoder, const Value& struct_object, 1052 const FieldImmediate<validate>& field, bool is_signed, 1053 Value* result) { 1054 result->node = builder_->StructGet( 1055 struct_object.node, field.struct_imm.struct_type, field.field_imm.index, 1056 NullCheckFor(struct_object.type), is_signed, decoder->position()); 1057 } 1058 1059 void StructSet(FullDecoder* decoder, const Value& struct_object, 1060 const FieldImmediate<validate>& field, 1061 const Value& field_value) { 1062 builder_->StructSet(struct_object.node, field.struct_imm.struct_type, 1063 field.field_imm.index, field_value.node, 1064 NullCheckFor(struct_object.type), decoder->position()); 1065 } 1066 1067 void ArrayNewWithRtt(FullDecoder* decoder, 1068 const ArrayIndexImmediate<validate>& imm, 1069 const Value& length, const Value& initial_value, 1070 const Value& rtt, Value* result) { 1071 result->node = builder_->ArrayNewWithRtt(imm.index, imm.array_type, 1072 length.node, initial_value.node, 1073 rtt.node, decoder->position()); 1074 // array.new_with_rtt introduces a loop. Therefore, we have to mark the 1075 // immediately nesting loop (if any) as non-innermost. 1076 if (!loop_infos_.empty()) loop_infos_.back().can_be_innermost = false; 1077 } 1078 1079 void ArrayNewDefault(FullDecoder* decoder, 1080 const ArrayIndexImmediate<validate>& imm, 1081 const Value& length, const Value& rtt, Value* result) { 1082 // This will cause the default value to be chosen automatically based 1083 // on the element type. 1084 TFNode* initial_value = nullptr; 1085 result->node = 1086 builder_->ArrayNewWithRtt(imm.index, imm.array_type, length.node, 1087 initial_value, rtt.node, decoder->position()); 1088 } 1089 1090 void ArrayGet(FullDecoder* decoder, const Value& array_obj, 1091 const ArrayIndexImmediate<validate>& imm, const Value& index, 1092 bool is_signed, Value* result) { 1093 result->node = builder_->ArrayGet(array_obj.node, imm.array_type, 1094 index.node, NullCheckFor(array_obj.type), 1095 is_signed, decoder->position()); 1096 } 1097 1098 void ArraySet(FullDecoder* decoder, const Value& array_obj, 1099 const ArrayIndexImmediate<validate>& imm, const Value& index, 1100 const Value& value) { 1101 builder_->ArraySet(array_obj.node, imm.array_type, index.node, value.node, 1102 NullCheckFor(array_obj.type), decoder->position()); 1103 } 1104 1105 void ArrayLen(FullDecoder* decoder, const Value& array_obj, Value* result) { 1106 result->node = builder_->ArrayLen( 1107 array_obj.node, NullCheckFor(array_obj.type), decoder->position()); 1108 } 1109 1110 void ArrayCopy(FullDecoder* decoder, const Value& dst, const Value& dst_index, 1111 const Value& src, const Value& src_index, 1112 const Value& length) { 1113 builder_->ArrayCopy(dst.node, dst_index.node, NullCheckFor(dst.type), 1114 src.node, src_index.node, NullCheckFor(src.type), 1115 length.node, decoder->position()); 1116 } 1117 1118 void ArrayInit(FullDecoder* decoder, const ArrayIndexImmediate<validate>& imm, 1119 const base::Vector<Value>& elements, const Value& rtt, 1120 Value* result) { 1121 NodeVector element_nodes(elements.size()); 1122 for (uint32_t i = 0; i < elements.size(); i++) { 1123 element_nodes[i] = elements[i].node; 1124 } 1125 result->node = 1126 builder_->ArrayInit(imm.array_type, rtt.node, VectorOf(element_nodes)); 1127 } 1128 1129 void ArrayInitFromData(FullDecoder* decoder, 1130 const ArrayIndexImmediate<validate>& array_imm, 1131 const IndexImmediate<validate>& data_segment, 1132 const Value& offset, const Value& length, 1133 const Value& rtt, Value* result) { 1134 result->node = builder_->ArrayInitFromData( 1135 array_imm.array_type, data_segment.index, offset.node, length.node, 1136 rtt.node, decoder->position()); 1137 } 1138 1139 void I31New(FullDecoder* decoder, const Value& input, Value* result) { 1140 result->node = builder_->I31New(input.node); 1141 } 1142 1143 void I31GetS(FullDecoder* decoder, const Value& input, Value* result) { 1144 result->node = builder_->I31GetS(input.node); 1145 } 1146 1147 void I31GetU(FullDecoder* decoder, const Value& input, Value* result) { 1148 result->node = builder_->I31GetU(input.node); 1149 } 1150 1151 void RttCanon(FullDecoder* decoder, uint32_t type_index, Value* result) { 1152 result->node = builder_->RttCanon(type_index); 1153 } 1154 1155 using StaticKnowledge = compiler::WasmGraphBuilder::ObjectReferenceKnowledge; 1156 1157 StaticKnowledge ComputeStaticKnowledge(ValueType object_type, 1158 ValueType rtt_type, 1159 const WasmModule* module) { 1160 StaticKnowledge result; 1161 result.object_can_be_null = object_type.is_nullable(); 1162 DCHECK(object_type.is_object_reference()); // Checked by validation. 1163 // In the bottom case, the result is irrelevant. 1164 result.rtt_depth = rtt_type.is_bottom() 1165 ? 0 /* unused */ 1166 : static_cast<uint8_t>(GetSubtypingDepth( 1167 module, rtt_type.ref_index())); 1168 return result; 1169 } 1170 1171 void RefTest(FullDecoder* decoder, const Value& object, const Value& rtt, 1172 Value* result) { 1173 StaticKnowledge config = 1174 ComputeStaticKnowledge(object.type, rtt.type, decoder->module_); 1175 result->node = builder_->RefTest(object.node, rtt.node, config); 1176 } 1177 1178 void RefCast(FullDecoder* decoder, const Value& object, const Value& rtt, 1179 Value* result) { 1180 StaticKnowledge config = 1181 ComputeStaticKnowledge(object.type, rtt.type, decoder->module_); 1182 result->node = 1183 builder_->RefCast(object.node, rtt.node, config, decoder->position()); 1184 } 1185 1186 template <void (compiler::WasmGraphBuilder::*branch_function)( 1187 TFNode*, TFNode*, StaticKnowledge, TFNode**, TFNode**, TFNode**, 1188 TFNode**)> 1189 void BrOnCastAbs(FullDecoder* decoder, const Value& object, const Value& rtt, 1190 Value* forwarding_value, uint32_t br_depth, 1191 bool branch_on_match) { 1192 StaticKnowledge config = 1193 ComputeStaticKnowledge(object.type, rtt.type, decoder->module_); 1194 SsaEnv* branch_env = Split(decoder->zone(), ssa_env_); 1195 SsaEnv* no_branch_env = Steal(decoder->zone(), ssa_env_); 1196 no_branch_env->SetNotMerged(); 1197 SsaEnv* match_env = branch_on_match ? branch_env : no_branch_env; 1198 SsaEnv* no_match_env = branch_on_match ? no_branch_env : branch_env; 1199 (builder_->*branch_function)(object.node, rtt.node, config, 1200 &match_env->control, &match_env->effect, 1201 &no_match_env->control, &no_match_env->effect); 1202 builder_->SetControl(no_branch_env->control); 1203 SetEnv(branch_env); 1204 forwarding_value->node = object.node; 1205 // Currently, br_on_* instructions modify the value stack before calling 1206 // the interface function, so we don't need to drop any values here. 1207 BrOrRet(decoder, br_depth, 0); 1208 SetEnv(no_branch_env); 1209 } 1210 1211 void BrOnCast(FullDecoder* decoder, const Value& object, const Value& rtt, 1212 Value* value_on_branch, uint32_t br_depth) { 1213 BrOnCastAbs<&compiler::WasmGraphBuilder::BrOnCast>( 1214 decoder, object, rtt, value_on_branch, br_depth, true); 1215 } 1216 1217 void BrOnCastFail(FullDecoder* decoder, const Value& object, const Value& rtt, 1218 Value* value_on_fallthrough, uint32_t br_depth) { 1219 BrOnCastAbs<&compiler::WasmGraphBuilder::BrOnCast>( 1220 decoder, object, rtt, value_on_fallthrough, br_depth, false); 1221 } 1222 1223 void RefIsData(FullDecoder* decoder, const Value& object, Value* result) { 1224 result->node = builder_->RefIsData(object.node, object.type.is_nullable()); 1225 } 1226 1227 void RefAsData(FullDecoder* decoder, const Value& object, Value* result) { 1228 result->node = builder_->RefAsData(object.node, object.type.is_nullable(), 1229 decoder->position()); 1230 } 1231 1232 void BrOnData(FullDecoder* decoder, const Value& object, 1233 Value* value_on_branch, uint32_t br_depth) { 1234 BrOnCastAbs<&compiler::WasmGraphBuilder::BrOnData>( 1235 decoder, object, Value{nullptr, kWasmBottom}, value_on_branch, br_depth, 1236 true); 1237 } 1238 1239 void BrOnNonData(FullDecoder* decoder, const Value& object, 1240 Value* value_on_fallthrough, uint32_t br_depth) { 1241 BrOnCastAbs<&compiler::WasmGraphBuilder::BrOnData>( 1242 decoder, object, Value{nullptr, kWasmBottom}, value_on_fallthrough, 1243 br_depth, false); 1244 } 1245 1246 void RefIsFunc(FullDecoder* decoder, const Value& object, Value* result) { 1247 result->node = builder_->RefIsFunc(object.node, object.type.is_nullable()); 1248 } 1249 1250 void RefAsFunc(FullDecoder* decoder, const Value& object, Value* result) { 1251 result->node = builder_->RefAsFunc(object.node, object.type.is_nullable(), 1252 decoder->position()); 1253 } 1254 1255 void BrOnFunc(FullDecoder* decoder, const Value& object, 1256 Value* value_on_branch, uint32_t br_depth) { 1257 BrOnCastAbs<&compiler::WasmGraphBuilder::BrOnFunc>( 1258 decoder, object, Value{nullptr, kWasmBottom}, value_on_branch, br_depth, 1259 true); 1260 } 1261 1262 void BrOnNonFunc(FullDecoder* decoder, const Value& object, 1263 Value* value_on_fallthrough, uint32_t br_depth) { 1264 BrOnCastAbs<&compiler::WasmGraphBuilder::BrOnFunc>( 1265 decoder, object, Value{nullptr, kWasmBottom}, value_on_fallthrough, 1266 br_depth, false); 1267 } 1268 1269 void RefIsArray(FullDecoder* decoder, const Value& object, Value* result) { 1270 result->node = builder_->RefIsArray(object.node, object.type.is_nullable()); 1271 } 1272 1273 void RefAsArray(FullDecoder* decoder, const Value& object, Value* result) { 1274 result->node = builder_->RefAsArray(object.node, object.type.is_nullable(), 1275 decoder->position()); 1276 } 1277 1278 void BrOnArray(FullDecoder* decoder, const Value& object, 1279 Value* value_on_branch, uint32_t br_depth) { 1280 BrOnCastAbs<&compiler::WasmGraphBuilder::BrOnArray>( 1281 decoder, object, Value{nullptr, kWasmBottom}, value_on_branch, br_depth, 1282 true); 1283 } 1284 1285 void BrOnNonArray(FullDecoder* decoder, const Value& object, 1286 Value* value_on_fallthrough, uint32_t br_depth) { 1287 BrOnCastAbs<&compiler::WasmGraphBuilder::BrOnArray>( 1288 decoder, object, Value{nullptr, kWasmBottom}, value_on_fallthrough, 1289 br_depth, false); 1290 } 1291 1292 void RefIsI31(FullDecoder* decoder, const Value& object, Value* result) { 1293 result->node = builder_->RefIsI31(object.node); 1294 } 1295 1296 void RefAsI31(FullDecoder* decoder, const Value& object, Value* result) { 1297 result->node = builder_->RefAsI31(object.node, decoder->position()); 1298 } 1299 1300 void BrOnI31(FullDecoder* decoder, const Value& object, 1301 Value* value_on_branch, uint32_t br_depth) { 1302 BrOnCastAbs<&compiler::WasmGraphBuilder::BrOnI31>( 1303 decoder, object, Value{nullptr, kWasmBottom}, value_on_branch, br_depth, 1304 true); 1305 } 1306 1307 void BrOnNonI31(FullDecoder* decoder, const Value& object, 1308 Value* value_on_fallthrough, uint32_t br_depth) { 1309 BrOnCastAbs<&compiler::WasmGraphBuilder::BrOnI31>( 1310 decoder, object, Value{nullptr, kWasmBottom}, value_on_fallthrough, 1311 br_depth, false); 1312 } 1313 1314 void Forward(FullDecoder* decoder, const Value& from, Value* to) { 1315 to->node = from.node; 1316 } 1317 1318 std::vector<compiler::WasmLoopInfo> loop_infos() { return loop_infos_; } 1319 1320 private: 1321 SsaEnv* ssa_env_ = nullptr; 1322 compiler::WasmGraphBuilder* builder_; 1323 int func_index_; 1324 const BranchHintMap* branch_hints_ = nullptr; 1325 // Tracks loop data for loop unrolling. 1326 std::vector<compiler::WasmLoopInfo> loop_infos_; 1327 InlinedStatus inlined_status_; 1328 // The entries in {type_feedback_} are indexed by the position of feedback- 1329 // consuming instructions (currently only call_ref). 1330 int feedback_instruction_index_ = 0; 1331 std::vector<CallSiteFeedback> type_feedback_; 1332 1333 TFNode* effect() { return builder_->effect(); } 1334 1335 TFNode* control() { return builder_->control(); } 1336 1337 TryInfo* current_try_info(FullDecoder* decoder) { 1338 DCHECK_LT(decoder->current_catch(), decoder->control_depth()); 1339 return decoder->control_at(decoder->control_depth_of_current_catch()) 1340 ->try_info; 1341 } 1342 1343 // If {emit_loop_exits()} returns true, we need to emit LoopExit, 1344 // LoopExitEffect, and LoopExit nodes whenever a control resp. effect resp. 1345 // value escapes a loop. We emit loop exits in the following cases: 1346 // - When popping the control of a loop. 1347 // - At some nodes which connect to the graph's end. We do not always need to 1348 // emit loop exits for such nodes, since the wasm loop analysis algorithm 1349 // can handle a loop body which connects directly to the graph's end. 1350 // However, we need to emit them anyway for nodes that may be rewired to 1351 // different nodes during inlining. These are Return and TailCall nodes. 1352 // - After IfFailure nodes. 1353 // - When exiting a loop through Delegate. 1354 bool emit_loop_exits() { 1355 return FLAG_wasm_loop_unrolling || FLAG_wasm_loop_peeling; 1356 } 1357 1358 void GetNodes(TFNode** nodes, Value* values, size_t count) { 1359 for (size_t i = 0; i < count; ++i) { 1360 nodes[i] = values[i].node; 1361 } 1362 } 1363 1364 void GetNodes(TFNode** nodes, base::Vector<Value> values) { 1365 GetNodes(nodes, values.begin(), values.size()); 1366 } 1367 1368 void SetEnv(SsaEnv* env) { 1369 if (FLAG_trace_wasm_decoder) { 1370 char state = 'X'; 1371 if (env) { 1372 switch (env->state) { 1373 case SsaEnv::kReached: 1374 state = 'R'; 1375 break; 1376 case SsaEnv::kUnreachable: 1377 state = 'U'; 1378 break; 1379 case SsaEnv::kMerged: 1380 state = 'M'; 1381 break; 1382 } 1383 } 1384 PrintF("{set_env = %p, state = %c", env, state); 1385 if (env && env->control) { 1386 PrintF(", control = "); 1387 compiler::WasmGraphBuilder::PrintDebugName(env->control); 1388 } 1389 PrintF("}\n"); 1390 } 1391 if (ssa_env_) { 1392 ssa_env_->control = control(); 1393 ssa_env_->effect = effect(); 1394 } 1395 ssa_env_ = env; 1396 builder_->SetEffectControl(env->effect, env->control); 1397 builder_->set_instance_cache(&env->instance_cache); 1398 } 1399 1400 TFNode* CheckForException(FullDecoder* decoder, TFNode* node) { 1401 DCHECK_NOT_NULL(node); 1402 1403 // We need to emit IfSuccess/IfException nodes if this node throws and has 1404 // an exception handler. An exception handler can either be a try-scope 1405 // around this node, or if this function is being inlined, the IfException 1406 // output of the inlined Call node. 1407 const bool inside_try_scope = decoder->current_catch() != -1; 1408 if (inlined_status_ != kInlinedHandledCall && !inside_try_scope) { 1409 return node; 1410 } 1411 1412 TFNode* if_success = nullptr; 1413 TFNode* if_exception = nullptr; 1414 if (!builder_->ThrowsException(node, &if_success, &if_exception)) { 1415 return node; 1416 } 1417 1418 SsaEnv* success_env = Steal(decoder->zone(), ssa_env_); 1419 success_env->control = if_success; 1420 1421 SsaEnv* exception_env = Split(decoder->zone(), success_env); 1422 exception_env->control = if_exception; 1423 exception_env->effect = if_exception; 1424 SetEnv(exception_env); 1425 1426 if (emit_loop_exits()) { 1427 ValueVector values; 1428 BuildNestedLoopExits(decoder, 1429 inside_try_scope 1430 ? decoder->control_depth_of_current_catch() 1431 : decoder->control_depth() - 1, 1432 true, values, &if_exception); 1433 } 1434 if (inside_try_scope) { 1435 TryInfo* try_info = current_try_info(decoder); 1436 Goto(decoder, try_info->catch_env); 1437 if (try_info->exception == nullptr) { 1438 DCHECK_EQ(SsaEnv::kReached, try_info->catch_env->state); 1439 try_info->exception = if_exception; 1440 } else { 1441 DCHECK_EQ(SsaEnv::kMerged, try_info->catch_env->state); 1442 try_info->exception = builder_->CreateOrMergeIntoPhi( 1443 MachineRepresentation::kTaggedPointer, try_info->catch_env->control, 1444 try_info->exception, if_exception); 1445 } 1446 } else { 1447 DCHECK_EQ(inlined_status_, kInlinedHandledCall); 1448 // Leave the IfException/LoopExit node dangling. We will connect it during 1449 // inlining to the handler of the inlined call. 1450 // Note: We have to generate the handler now since we have no way of 1451 // generating a LoopExit if needed in the inlining code. 1452 } 1453 1454 SetEnv(success_env); 1455 return node; 1456 } 1457 1458 TFNode* DefaultValue(ValueType type) { 1459 DCHECK(type.is_defaultable()); 1460 switch (type.kind()) { 1461 case kI8: 1462 case kI16: 1463 case kI32: 1464 return builder_->Int32Constant(0); 1465 case kI64: 1466 return builder_->Int64Constant(0); 1467 case kF32: 1468 return builder_->Float32Constant(0); 1469 case kF64: 1470 return builder_->Float64Constant(0); 1471 case kS128: 1472 return builder_->S128Zero(); 1473 case kOptRef: 1474 return builder_->RefNull(); 1475 case kRtt: 1476 case kVoid: 1477 case kBottom: 1478 case kRef: 1479 UNREACHABLE(); 1480 } 1481 } 1482 1483 void MergeValuesInto(FullDecoder* decoder, Control* c, Merge<Value>* merge, 1484 Value* values) { 1485 DCHECK(merge == &c->start_merge || merge == &c->end_merge); 1486 1487 SsaEnv* target = c->merge_env; 1488 // This has to be computed before calling Goto(). 1489 const bool first = target->state == SsaEnv::kUnreachable; 1490 1491 Goto(decoder, target); 1492 1493 if (merge->arity == 0) return; 1494 1495 for (uint32_t i = 0; i < merge->arity; ++i) { 1496 Value& val = values[i]; 1497 Value& old = (*merge)[i]; 1498 DCHECK_NOT_NULL(val.node); 1499 DCHECK(val.type == kWasmBottom || val.type.machine_representation() == 1500 old.type.machine_representation()); 1501 old.node = first ? val.node 1502 : builder_->CreateOrMergeIntoPhi( 1503 old.type.machine_representation(), target->control, 1504 old.node, val.node); 1505 } 1506 } 1507 1508 void MergeValuesInto(FullDecoder* decoder, Control* c, Merge<Value>* merge, 1509 uint32_t drop_values = 0) { 1510#ifdef DEBUG 1511 uint32_t avail = decoder->stack_size() - 1512 decoder->control_at(0)->stack_depth - drop_values; 1513 DCHECK_GE(avail, merge->arity); 1514#endif 1515 Value* stack_values = merge->arity > 0 1516 ? decoder->stack_value(merge->arity + drop_values) 1517 : nullptr; 1518 MergeValuesInto(decoder, c, merge, stack_values); 1519 } 1520 1521 void Goto(FullDecoder* decoder, SsaEnv* to) { 1522 DCHECK_NOT_NULL(to); 1523 switch (to->state) { 1524 case SsaEnv::kUnreachable: { // Overwrite destination. 1525 to->state = SsaEnv::kReached; 1526 // There might be an offset in the locals due to a 'let'. 1527 DCHECK_EQ(ssa_env_->locals.size(), decoder->num_locals()); 1528 DCHECK_GE(ssa_env_->locals.size(), to->locals.size()); 1529 uint32_t local_count_diff = 1530 static_cast<uint32_t>(ssa_env_->locals.size() - to->locals.size()); 1531 to->locals = ssa_env_->locals; 1532 to->locals.erase(to->locals.begin(), 1533 to->locals.begin() + local_count_diff); 1534 to->control = control(); 1535 to->effect = effect(); 1536 to->instance_cache = ssa_env_->instance_cache; 1537 break; 1538 } 1539 case SsaEnv::kReached: { // Create a new merge. 1540 to->state = SsaEnv::kMerged; 1541 // Merge control. 1542 TFNode* controls[] = {to->control, control()}; 1543 TFNode* merge = builder_->Merge(2, controls); 1544 to->control = merge; 1545 // Merge effects. 1546 TFNode* old_effect = effect(); 1547 if (old_effect != to->effect) { 1548 TFNode* inputs[] = {to->effect, old_effect, merge}; 1549 to->effect = builder_->EffectPhi(2, inputs); 1550 } 1551 // Merge locals. 1552 // There might be an offset in the locals due to a 'let'. 1553 DCHECK_EQ(ssa_env_->locals.size(), decoder->num_locals()); 1554 DCHECK_GE(ssa_env_->locals.size(), to->locals.size()); 1555 uint32_t local_count_diff = 1556 static_cast<uint32_t>(ssa_env_->locals.size() - to->locals.size()); 1557 for (uint32_t i = 0; i < to->locals.size(); i++) { 1558 TFNode* a = to->locals[i]; 1559 TFNode* b = ssa_env_->locals[i + local_count_diff]; 1560 if (a != b) { 1561 TFNode* inputs[] = {a, b, merge}; 1562 to->locals[i] = builder_->Phi( 1563 decoder->local_type(i + local_count_diff), 2, inputs); 1564 } 1565 } 1566 // Start a new merge from the instance cache. 1567 builder_->NewInstanceCacheMerge(&to->instance_cache, 1568 &ssa_env_->instance_cache, merge); 1569 break; 1570 } 1571 case SsaEnv::kMerged: { 1572 TFNode* merge = to->control; 1573 // Extend the existing merge control node. 1574 builder_->AppendToMerge(merge, control()); 1575 // Merge effects. 1576 to->effect = 1577 builder_->CreateOrMergeIntoEffectPhi(merge, to->effect, effect()); 1578 // Merge locals. 1579 // There might be an offset in the locals due to a 'let'. 1580 DCHECK_EQ(ssa_env_->locals.size(), decoder->num_locals()); 1581 DCHECK_GE(ssa_env_->locals.size(), to->locals.size()); 1582 uint32_t local_count_diff = 1583 static_cast<uint32_t>(ssa_env_->locals.size() - to->locals.size()); 1584 for (uint32_t i = 0; i < to->locals.size(); i++) { 1585 to->locals[i] = builder_->CreateOrMergeIntoPhi( 1586 decoder->local_type(i + local_count_diff) 1587 .machine_representation(), 1588 merge, to->locals[i], ssa_env_->locals[i + local_count_diff]); 1589 } 1590 // Merge the instance caches. 1591 builder_->MergeInstanceCacheInto(&to->instance_cache, 1592 &ssa_env_->instance_cache, merge); 1593 break; 1594 } 1595 default: 1596 UNREACHABLE(); 1597 } 1598 } 1599 1600 // Create a complete copy of {from}. 1601 SsaEnv* Split(Zone* zone, SsaEnv* from) { 1602 DCHECK_NOT_NULL(from); 1603 if (from == ssa_env_) { 1604 ssa_env_->control = control(); 1605 ssa_env_->effect = effect(); 1606 } 1607 SsaEnv* result = zone->New<SsaEnv>(*from); 1608 result->state = SsaEnv::kReached; 1609 return result; 1610 } 1611 1612 // Create a copy of {from} that steals its state and leaves {from} 1613 // unreachable. 1614 SsaEnv* Steal(Zone* zone, SsaEnv* from) { 1615 DCHECK_NOT_NULL(from); 1616 if (from == ssa_env_) { 1617 ssa_env_->control = control(); 1618 ssa_env_->effect = effect(); 1619 } 1620 SsaEnv* result = zone->New<SsaEnv>(std::move(*from)); 1621 // Restore the length of {from->locals} after applying move-constructor. 1622 from->locals.resize(result->locals.size()); 1623 result->state = SsaEnv::kReached; 1624 return result; 1625 } 1626 1627 class CallInfo { 1628 public: 1629 enum CallMode { kCallDirect, kCallIndirect, kCallRef }; 1630 1631 static CallInfo CallDirect(uint32_t callee_index) { 1632 return {kCallDirect, callee_index, nullptr, 0, 1633 CheckForNull::kWithoutNullCheck}; 1634 } 1635 1636 static CallInfo CallIndirect(const Value& index_value, uint32_t table_index, 1637 uint32_t sig_index) { 1638 return {kCallIndirect, sig_index, &index_value, table_index, 1639 CheckForNull::kWithoutNullCheck}; 1640 } 1641 1642 static CallInfo CallRef(const Value& funcref_value, 1643 CheckForNull null_check) { 1644 return {kCallRef, 0, &funcref_value, 0, null_check}; 1645 } 1646 1647 CallMode call_mode() { return call_mode_; } 1648 1649 uint32_t sig_index() { 1650 DCHECK_EQ(call_mode_, kCallIndirect); 1651 return callee_or_sig_index_; 1652 } 1653 1654 uint32_t callee_index() { 1655 DCHECK_EQ(call_mode_, kCallDirect); 1656 return callee_or_sig_index_; 1657 } 1658 1659 CheckForNull null_check() { 1660 DCHECK_EQ(call_mode_, kCallRef); 1661 return null_check_; 1662 } 1663 1664 const Value* index_or_callee_value() { 1665 DCHECK_NE(call_mode_, kCallDirect); 1666 return index_or_callee_value_; 1667 } 1668 1669 uint32_t table_index() { 1670 DCHECK_EQ(call_mode_, kCallIndirect); 1671 return table_index_; 1672 } 1673 1674 private: 1675 CallInfo(CallMode call_mode, uint32_t callee_or_sig_index, 1676 const Value* index_or_callee_value, uint32_t table_index, 1677 CheckForNull null_check) 1678 : call_mode_(call_mode), 1679 callee_or_sig_index_(callee_or_sig_index), 1680 index_or_callee_value_(index_or_callee_value), 1681 table_index_(table_index), 1682 null_check_(null_check) {} 1683 CallMode call_mode_; 1684 uint32_t callee_or_sig_index_; 1685 const Value* index_or_callee_value_; 1686 uint32_t table_index_; 1687 CheckForNull null_check_; 1688 }; 1689 1690 void DoCall(FullDecoder* decoder, CallInfo call_info, const FunctionSig* sig, 1691 const Value args[], Value returns[]) { 1692 size_t param_count = sig->parameter_count(); 1693 size_t return_count = sig->return_count(); 1694 1695 // Construct a function signature based on the real function parameters. 1696 FunctionSig::Builder real_sig_builder(builder_->graph_zone(), return_count, 1697 param_count); 1698 for (size_t i = 0; i < param_count; i++) { 1699 real_sig_builder.AddParam(args[i].type); 1700 } 1701 for (size_t i = 0; i < return_count; i++) { 1702 real_sig_builder.AddReturn(sig->GetReturn(i)); 1703 } 1704 FunctionSig* real_sig = real_sig_builder.Build(); 1705 1706 NodeVector arg_nodes(param_count + 1); 1707 base::SmallVector<TFNode*, 1> return_nodes(return_count); 1708 arg_nodes[0] = (call_info.call_mode() == CallInfo::kCallDirect) 1709 ? nullptr 1710 : call_info.index_or_callee_value()->node; 1711 1712 for (size_t i = 0; i < param_count; ++i) { 1713 arg_nodes[i + 1] = args[i].node; 1714 } 1715 switch (call_info.call_mode()) { 1716 case CallInfo::kCallIndirect: 1717 CheckForException( 1718 decoder, builder_->CallIndirect( 1719 call_info.table_index(), call_info.sig_index(), 1720 real_sig, base::VectorOf(arg_nodes), 1721 base::VectorOf(return_nodes), decoder->position())); 1722 break; 1723 case CallInfo::kCallDirect: 1724 CheckForException( 1725 decoder, builder_->CallDirect(call_info.callee_index(), real_sig, 1726 base::VectorOf(arg_nodes), 1727 base::VectorOf(return_nodes), 1728 decoder->position())); 1729 break; 1730 case CallInfo::kCallRef: 1731 CheckForException( 1732 decoder, 1733 builder_->CallRef(real_sig, base::VectorOf(arg_nodes), 1734 base::VectorOf(return_nodes), 1735 call_info.null_check(), decoder->position())); 1736 break; 1737 } 1738 for (size_t i = 0; i < return_count; ++i) { 1739 returns[i].node = return_nodes[i]; 1740 } 1741 if (decoder->module_->initial_pages != decoder->module_->maximum_pages) { 1742 // The invoked function could have used grow_memory, so we need to 1743 // reload mem_size and mem_start. 1744 LoadContextIntoSsa(ssa_env_); 1745 } 1746 } 1747 1748 void DoReturnCall(FullDecoder* decoder, CallInfo call_info, 1749 const FunctionSig* sig, const Value args[]) { 1750 size_t arg_count = sig->parameter_count(); 1751 1752 // Construct a function signature based on the real function parameters. 1753 FunctionSig::Builder real_sig_builder(builder_->graph_zone(), 1754 sig->return_count(), arg_count); 1755 for (size_t i = 0; i < arg_count; i++) { 1756 real_sig_builder.AddParam(args[i].type); 1757 } 1758 for (size_t i = 0; i < sig->return_count(); i++) { 1759 real_sig_builder.AddReturn(sig->GetReturn(i)); 1760 } 1761 FunctionSig* real_sig = real_sig_builder.Build(); 1762 1763 ValueVector arg_values(arg_count + 1); 1764 if (call_info.call_mode() == CallInfo::kCallDirect) { 1765 arg_values[0].node = nullptr; 1766 } else { 1767 arg_values[0] = *call_info.index_or_callee_value(); 1768 // This is not done by copy assignment. 1769 arg_values[0].node = call_info.index_or_callee_value()->node; 1770 } 1771 if (arg_count > 0) { 1772 std::memcpy(arg_values.data() + 1, args, arg_count * sizeof(Value)); 1773 } 1774 1775 if (emit_loop_exits()) { 1776 BuildNestedLoopExits(decoder, decoder->control_depth(), false, 1777 arg_values); 1778 } 1779 1780 NodeVector arg_nodes(arg_count + 1); 1781 GetNodes(arg_nodes.data(), base::VectorOf(arg_values)); 1782 1783 switch (call_info.call_mode()) { 1784 case CallInfo::kCallIndirect: 1785 builder_->ReturnCallIndirect( 1786 call_info.table_index(), call_info.sig_index(), real_sig, 1787 base::VectorOf(arg_nodes), decoder->position()); 1788 break; 1789 case CallInfo::kCallDirect: 1790 builder_->ReturnCall(call_info.callee_index(), real_sig, 1791 base::VectorOf(arg_nodes), decoder->position()); 1792 break; 1793 case CallInfo::kCallRef: 1794 builder_->ReturnCallRef(real_sig, base::VectorOf(arg_nodes), 1795 call_info.null_check(), decoder->position()); 1796 break; 1797 } 1798 } 1799 1800 void BuildLoopExits(FullDecoder* decoder, Control* loop) { 1801 builder_->LoopExit(loop->loop_node); 1802 ssa_env_->control = control(); 1803 ssa_env_->effect = effect(); 1804 } 1805 1806 void WrapLocalsAtLoopExit(FullDecoder* decoder, Control* loop) { 1807 for (uint32_t index = 0; index < decoder->num_locals(); index++) { 1808 if (loop->loop_assignments->Contains(static_cast<int>(index))) { 1809 ssa_env_->locals[index] = builder_->LoopExitValue( 1810 ssa_env_->locals[index], 1811 decoder->local_type(index).machine_representation()); 1812 } 1813 } 1814 if (loop->loop_assignments->Contains(decoder->num_locals())) { 1815#define WRAP_CACHE_FIELD(field) \ 1816 if (ssa_env_->instance_cache.field != nullptr) { \ 1817 ssa_env_->instance_cache.field = builder_->LoopExitValue( \ 1818 ssa_env_->instance_cache.field, MachineType::PointerRepresentation()); \ 1819 } 1820 1821 WRAP_CACHE_FIELD(mem_start); 1822 WRAP_CACHE_FIELD(mem_size); 1823#undef WRAP_CACHE_FIELD 1824 } 1825 } 1826 1827 void BuildNestedLoopExits(FullDecoder* decoder, uint32_t depth_limit, 1828 bool wrap_exit_values, ValueVector& stack_values, 1829 TFNode** exception_value = nullptr) { 1830 DCHECK(emit_loop_exits()); 1831 Control* control = nullptr; 1832 // We are only interested in exits from the innermost loop. 1833 for (uint32_t i = 0; i < depth_limit; i++) { 1834 Control* c = decoder->control_at(i); 1835 if (c->is_loop()) { 1836 control = c; 1837 break; 1838 } 1839 } 1840 if (control != nullptr) { 1841 BuildLoopExits(decoder, control); 1842 for (Value& value : stack_values) { 1843 if (value.node != nullptr) { 1844 value.node = builder_->LoopExitValue( 1845 value.node, value.type.machine_representation()); 1846 } 1847 } 1848 if (exception_value != nullptr) { 1849 *exception_value = builder_->LoopExitValue( 1850 *exception_value, MachineRepresentation::kWord32); 1851 } 1852 if (wrap_exit_values) { 1853 WrapLocalsAtLoopExit(decoder, control); 1854 } 1855 } 1856 } 1857 1858 CheckForNull NullCheckFor(ValueType type) { 1859 DCHECK(type.is_object_reference()); 1860 return (!FLAG_experimental_wasm_skip_null_checks && type.is_nullable()) 1861 ? CheckForNull::kWithNullCheck 1862 : CheckForNull::kWithoutNullCheck; 1863 } 1864}; 1865 1866} // namespace 1867 1868DecodeResult BuildTFGraph(AccountingAllocator* allocator, 1869 const WasmFeatures& enabled, const WasmModule* module, 1870 compiler::WasmGraphBuilder* builder, 1871 WasmFeatures* detected, const FunctionBody& body, 1872 std::vector<compiler::WasmLoopInfo>* loop_infos, 1873 compiler::NodeOriginTable* node_origins, 1874 int func_index, InlinedStatus inlined_status) { 1875 Zone zone(allocator, ZONE_NAME); 1876 WasmFullDecoder<Decoder::kFullValidation, WasmGraphBuildingInterface> decoder( 1877 &zone, module, enabled, detected, body, builder, func_index, 1878 inlined_status); 1879 if (node_origins) { 1880 builder->AddBytecodePositionDecorator(node_origins, &decoder); 1881 } 1882 decoder.Decode(); 1883 if (node_origins) { 1884 builder->RemoveBytecodePositionDecorator(); 1885 } 1886 *loop_infos = decoder.interface().loop_infos(); 1887 1888 return decoder.toResult(nullptr); 1889} 1890 1891} // namespace wasm 1892} // namespace internal 1893} // namespace v8 1894