WasmOpIter.h (133443B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * 4 * Copyright 2016 Mozilla Foundation 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 #ifndef wasm_op_iter_h 20 #define wasm_op_iter_h 21 22 #include "mozilla/CompactPair.h" 23 24 #include <type_traits> 25 26 #include "js/Printf.h" 27 #include "wasm/WasmBinary.h" 28 #include "wasm/WasmBuiltinModule.h" 29 #include "wasm/WasmMetadata.h" 30 #include "wasm/WasmUtility.h" 31 32 namespace js { 33 namespace wasm { 34 35 // The kind of a control-flow stack item. 36 enum class LabelKind : uint8_t { 37 Body, 38 Block, 39 Loop, 40 Then, 41 Else, 42 Try, 43 Catch, 44 CatchAll, 45 TryTable, 46 }; 47 48 // The type of values on the operand stack during validation. This is either a 49 // ValType or the special type "Bottom". 50 51 class StackType { 52 PackedTypeCode tc_; 53 54 explicit StackType(PackedTypeCode tc) : tc_(tc) {} 55 56 public: 57 StackType() : tc_(PackedTypeCode::invalid()) {} 58 59 explicit StackType(const ValType& t) : tc_(t.packed()) { 60 MOZ_ASSERT(tc_.isValid()); 61 MOZ_ASSERT(!isStackBottom()); 62 } 63 64 static StackType bottom() { 65 return StackType(PackedTypeCode::pack(TypeCode::Limit)); 66 } 67 68 bool isStackBottom() const { 69 MOZ_ASSERT(tc_.isValid()); 70 return tc_.typeCode() == TypeCode::Limit; 71 } 72 73 // Returns whether this input is nullable when interpreted as an operand. 74 // When the type is bottom for unreachable code, this returns false as that 75 // is the most permissive option. 76 bool isNullableAsOperand() const { 77 MOZ_ASSERT(tc_.isValid()); 78 return isStackBottom() ? false : tc_.isNullable(); 79 } 80 81 ValType valType() const { 82 MOZ_ASSERT(tc_.isValid()); 83 MOZ_ASSERT(!isStackBottom()); 84 return ValType(tc_); 85 } 86 87 ValType valTypeOr(ValType ifBottom) const { 88 MOZ_ASSERT(tc_.isValid()); 89 if (isStackBottom()) { 90 return ifBottom; 91 } 92 return valType(); 93 } 94 95 ValType asNonNullable() const { 96 MOZ_ASSERT(tc_.isValid()); 97 MOZ_ASSERT(!isStackBottom()); 98 return ValType(tc_.withIsNullable(false)); 99 } 100 101 bool isValidForUntypedSelect() const { 102 MOZ_ASSERT(tc_.isValid()); 103 if (isStackBottom()) { 104 return true; 105 } 106 switch (valType().kind()) { 107 case ValType::I32: 108 case ValType::F32: 109 case ValType::I64: 110 case ValType::F64: 111 #ifdef ENABLE_WASM_SIMD 112 case ValType::V128: 113 #endif 114 return true; 115 default: 116 return false; 117 } 118 } 119 120 bool operator==(const StackType& that) const { 121 MOZ_ASSERT(tc_.isValid() && that.tc_.isValid()); 122 return tc_ == that.tc_; 123 } 124 125 bool operator!=(const StackType& that) const { 126 MOZ_ASSERT(tc_.isValid() && that.tc_.isValid()); 127 return tc_ != that.tc_; 128 } 129 }; 130 131 #ifdef DEBUG 132 // Families of opcodes that share a signature and validation logic. 133 enum class OpKind { 134 Block, 135 Loop, 136 Unreachable, 137 Drop, 138 I32Const, 139 I64Const, 140 F32Const, 141 F64Const, 142 V128Const, 143 Br, 144 BrIf, 145 BrTable, 146 Nop, 147 Unary, 148 Binary, 149 Ternary, 150 Comparison, 151 Conversion, 152 Load, 153 Store, 154 TeeStore, 155 MemorySize, 156 MemoryGrow, 157 Select, 158 GetLocal, 159 SetLocal, 160 TeeLocal, 161 GetGlobal, 162 SetGlobal, 163 TeeGlobal, 164 Call, 165 ReturnCall, 166 CallIndirect, 167 ReturnCallIndirect, 168 CallRef, 169 ReturnCallRef, 170 OldCallDirect, 171 OldCallIndirect, 172 Return, 173 If, 174 Else, 175 End, 176 Wait, 177 Notify, 178 Fence, 179 AtomicLoad, 180 AtomicStore, 181 AtomicRMW, 182 AtomicCmpXchg, 183 MemOrTableCopy, 184 DataOrElemDrop, 185 MemFill, 186 MemOrTableInit, 187 TableFill, 188 MemDiscard, 189 TableGet, 190 TableGrow, 191 TableSet, 192 TableSize, 193 RefNull, 194 RefFunc, 195 RefIsNull, 196 RefAsNonNull, 197 BrOnNull, 198 BrOnNonNull, 199 StructNew, 200 StructNewDefault, 201 StructGet, 202 StructSet, 203 ArrayNew, 204 ArrayNewFixed, 205 ArrayNewDefault, 206 ArrayNewData, 207 ArrayNewElem, 208 ArrayInitData, 209 ArrayInitElem, 210 ArrayGet, 211 ArraySet, 212 ArrayLen, 213 ArrayCopy, 214 ArrayFill, 215 RefTest, 216 RefCast, 217 BrOnCast, 218 RefConversion, 219 # ifdef ENABLE_WASM_SIMD 220 ExtractLane, 221 ReplaceLane, 222 LoadLane, 223 StoreLane, 224 VectorShift, 225 VectorShuffle, 226 # endif 227 Catch, 228 CatchAll, 229 Delegate, 230 Throw, 231 ThrowRef, 232 Rethrow, 233 Try, 234 TryTable, 235 CallBuiltinModuleFunc, 236 StackSwitch, 237 }; 238 239 // Return the OpKind for a given Op. This is used for sanity-checking that 240 // API users use the correct read function for a given Op. 241 OpKind Classify(OpBytes op); 242 #endif 243 244 // Common fields for linear memory access. 245 template <typename Value> 246 struct LinearMemoryAddress { 247 Value base; 248 uint32_t memoryIndex; 249 uint64_t offset; 250 uint32_t align; 251 252 LinearMemoryAddress() : memoryIndex(0), offset(0), align(0) {} 253 LinearMemoryAddress(Value base, uint32_t memoryIndex, uint64_t offset, 254 uint32_t align) 255 : base(base), memoryIndex(memoryIndex), offset(offset), align(align) {} 256 }; 257 258 template <typename ControlItem> 259 class ControlStackEntry { 260 // Use a pair to optimize away empty ControlItem. 261 mozilla::CompactPair<BlockType, ControlItem> typeAndItem_; 262 263 // The "base" of a control stack entry is valueStack_.length() minus 264 // type().params().length(), i.e., the size of the value stack "below" 265 // this block. 266 uint32_t valueStackBase_; 267 bool polymorphicBase_; 268 269 LabelKind kind_; 270 271 public: 272 ControlStackEntry(LabelKind kind, BlockType type, uint32_t valueStackBase) 273 : typeAndItem_(type, ControlItem()), 274 valueStackBase_(valueStackBase), 275 polymorphicBase_(false), 276 kind_(kind) { 277 MOZ_ASSERT(type != BlockType()); 278 } 279 280 LabelKind kind() const { return kind_; } 281 BlockType type() const { return typeAndItem_.first(); } 282 ResultType resultType() const { return type().results(); } 283 ResultType branchTargetType() const { 284 return kind_ == LabelKind::Loop ? type().params() : type().results(); 285 } 286 uint32_t valueStackBase() const { return valueStackBase_; } 287 ControlItem& controlItem() { return typeAndItem_.second(); } 288 const ControlItem& controlItem() const { return typeAndItem_.second(); } 289 void setPolymorphicBase() { polymorphicBase_ = true; } 290 bool polymorphicBase() const { return polymorphicBase_; } 291 292 void switchToElse() { 293 MOZ_ASSERT(kind() == LabelKind::Then); 294 kind_ = LabelKind::Else; 295 polymorphicBase_ = false; 296 } 297 298 void switchToCatch() { 299 MOZ_ASSERT(kind() == LabelKind::Try || kind() == LabelKind::Catch); 300 kind_ = LabelKind::Catch; 301 polymorphicBase_ = false; 302 } 303 304 void switchToCatchAll() { 305 MOZ_ASSERT(kind() == LabelKind::Try || kind() == LabelKind::Catch); 306 kind_ = LabelKind::CatchAll; 307 polymorphicBase_ = false; 308 } 309 }; 310 311 // Track state of the non-defaultable locals. Every time such local is 312 // initialized, the stack will record at what depth and which local was set. 313 // On a block end, the "unset" state will be rolled back to how it was before 314 // the block started. 315 // 316 // It is very likely only a few functions will have non-defaultable locals and 317 // very few locals will be non-defaultable. This class is optimized to be fast 318 // for this common case. 319 class UnsetLocalsState { 320 struct SetLocalEntry { 321 uint32_t depth; 322 uint32_t localUnsetIndex; 323 SetLocalEntry(uint32_t depth_, uint32_t localUnsetIndex_) 324 : depth(depth_), localUnsetIndex(localUnsetIndex_) {} 325 }; 326 using SetLocalsStack = Vector<SetLocalEntry, 16, SystemAllocPolicy>; 327 using UnsetLocals = Vector<uint32_t, 16, SystemAllocPolicy>; 328 329 static constexpr size_t WordSize = 4; 330 static constexpr size_t WordBits = WordSize * 8; 331 332 // Bit array of "unset" function locals. Stores only unset states of the 333 // locals that are declared after the first non-defaultable local. 334 UnsetLocals unsetLocals_; 335 // Stack of "set" operations. Contains pair where the first field is a depth, 336 // and the second field is local id (offset by firstNonDefaultLocal_). 337 SetLocalsStack setLocalsStack_; 338 uint32_t firstNonDefaultLocal_; 339 340 public: 341 UnsetLocalsState() : firstNonDefaultLocal_(UINT32_MAX) {} 342 343 [[nodiscard]] bool init(const ValTypeVector& locals, size_t numParams); 344 345 inline bool isUnset(uint32_t id) const { 346 if (MOZ_LIKELY(id < firstNonDefaultLocal_)) { 347 return false; 348 } 349 uint32_t localUnsetIndex = id - firstNonDefaultLocal_; 350 return unsetLocals_[localUnsetIndex / WordBits] & 351 (1 << (localUnsetIndex % WordBits)); 352 } 353 354 inline void set(uint32_t id, uint32_t depth) { 355 MOZ_ASSERT(isUnset(id)); 356 MOZ_ASSERT(id >= firstNonDefaultLocal_ && 357 (id - firstNonDefaultLocal_) / WordBits < unsetLocals_.length()); 358 uint32_t localUnsetIndex = id - firstNonDefaultLocal_; 359 unsetLocals_[localUnsetIndex / WordBits] ^= 1 360 << (localUnsetIndex % WordBits); 361 // The setLocalsStack_ is reserved upfront in the UnsetLocalsState::init. 362 // A SetLocalEntry will be pushed only once per local. 363 setLocalsStack_.infallibleEmplaceBack(depth, localUnsetIndex); 364 } 365 366 inline void resetToBlock(uint32_t controlDepth) { 367 while (MOZ_UNLIKELY(setLocalsStack_.length() > 0) && 368 setLocalsStack_.back().depth > controlDepth) { 369 uint32_t localUnsetIndex = setLocalsStack_.back().localUnsetIndex; 370 MOZ_ASSERT(!(unsetLocals_[localUnsetIndex / WordBits] & 371 (1 << (localUnsetIndex % WordBits)))); 372 unsetLocals_[localUnsetIndex / WordBits] |= 373 1 << (localUnsetIndex % WordBits); 374 setLocalsStack_.popBack(); 375 } 376 } 377 378 int empty() const { return setLocalsStack_.empty(); } 379 }; 380 381 template <typename Value> 382 class TypeAndValueT { 383 // Use a Pair to optimize away empty Value. 384 mozilla::CompactPair<StackType, Value> tv_; 385 386 public: 387 TypeAndValueT() : tv_(StackType::bottom(), Value()) {} 388 explicit TypeAndValueT(StackType type) : tv_(type, Value()) {} 389 explicit TypeAndValueT(ValType type) : tv_(StackType(type), Value()) {} 390 TypeAndValueT(StackType type, Value value) : tv_(type, value) {} 391 TypeAndValueT(ValType type, Value value) : tv_(StackType(type), value) {} 392 StackType type() const { return tv_.first(); } 393 void setType(StackType type) { tv_.first() = type; } 394 Value value() const { return tv_.second(); } 395 void setValue(Value value) { tv_.second() = value; } 396 }; 397 398 // An iterator over the bytes of a function body. It performs validation 399 // and unpacks the data into a usable form. 400 // 401 // The MOZ_STACK_CLASS attribute here is because of the use of DebugOnly. 402 // There's otherwise nothing inherent in this class which would require 403 // it to be used on the stack. 404 template <typename Policy> 405 class MOZ_STACK_CLASS OpIter : private Policy { 406 public: 407 using Value = typename Policy::Value; 408 using ValueVector = typename Policy::ValueVector; 409 using TypeAndValue = TypeAndValueT<Value>; 410 using TypeAndValueStack = Vector<TypeAndValue, 32, SystemAllocPolicy>; 411 using ControlItem = typename Policy::ControlItem; 412 using Control = ControlStackEntry<ControlItem>; 413 using ControlStack = Vector<Control, 16, SystemAllocPolicy>; 414 415 enum Kind { 416 Func, 417 InitExpr, 418 }; 419 420 private: 421 Kind kind_; 422 Decoder& d_; 423 const CodeMetadata& codeMeta_; 424 const ValTypeVector& locals_; 425 426 TypeAndValueStack valueStack_; 427 TypeAndValueStack elseParamStack_; 428 ControlStack controlStack_; 429 UnsetLocalsState unsetLocals_; 430 FeatureUsage featureUsage_; 431 uint32_t lastBranchHintIndex_; 432 BranchHintVector* branchHintVector_; 433 434 #ifdef DEBUG 435 OpBytes op_; 436 #endif 437 size_t offsetOfLastReadOp_; 438 439 [[nodiscard]] bool readFixedU8(uint8_t* out) { return d_.readFixedU8(out); } 440 [[nodiscard]] bool readFixedU32(uint32_t* out) { 441 return d_.readFixedU32(out); 442 } 443 [[nodiscard]] bool readVarS32(int32_t* out) { return d_.readVarS32(out); } 444 [[nodiscard]] bool readVarU32(uint32_t* out) { return d_.readVarU32(out); } 445 [[nodiscard]] bool readVarS64(int64_t* out) { return d_.readVarS64(out); } 446 [[nodiscard]] bool readVarU64(uint64_t* out) { return d_.readVarU64(out); } 447 [[nodiscard]] bool readFixedF32(float* out) { return d_.readFixedF32(out); } 448 [[nodiscard]] bool readFixedF64(double* out) { return d_.readFixedF64(out); } 449 450 [[nodiscard]] bool readLinearMemoryAddress(uint32_t byteSize, 451 LinearMemoryAddress<Value>* addr); 452 [[nodiscard]] bool readLinearMemoryAddressAligned( 453 uint32_t byteSize, LinearMemoryAddress<Value>* addr); 454 [[nodiscard]] bool readBlockType(BlockType* type); 455 [[nodiscard]] bool readGcTypeIndex(uint32_t* typeIndex); 456 [[nodiscard]] bool readStructTypeIndex(uint32_t* typeIndex); 457 [[nodiscard]] bool readArrayTypeIndex(uint32_t* typeIndex); 458 [[nodiscard]] bool readFuncTypeIndex(uint32_t* typeIndex); 459 [[nodiscard]] bool readFieldIndex(uint32_t* fieldIndex, 460 const StructType& structType); 461 462 [[nodiscard]] bool popCallArgs(const ValTypeVector& expectedTypes, 463 ValueVector* values); 464 465 [[nodiscard]] bool failEmptyStack(); 466 [[nodiscard]] bool popStackType(StackType* type, Value* value); 467 [[nodiscard]] bool popWithType(ValType expected, Value* value, 468 StackType* stackType); 469 [[nodiscard]] bool popWithType(ValType expected, Value* value); 470 [[nodiscard]] bool popWithType(ResultType expected, ValueVector* values); 471 template <typename ValTypeSpanT> 472 [[nodiscard]] bool popWithTypes(ValTypeSpanT expected, ValueVector* values); 473 [[nodiscard]] bool popWithRefType(Value* value, StackType* type); 474 // Check that the top of the value stack has type `expected`, bearing in 475 // mind that it may be a block type, hence involving multiple values. 476 // 477 // If the block's stack contains polymorphic values at its base (because we 478 // are in unreachable code) then suitable extra values are inserted into the 479 // value stack, as controlled by `rewriteStackTypes`: if this is true, 480 // polymorphic values have their types created/updated from `expected`. If 481 // it is false, such values are left as `StackType::bottom()`. 482 // 483 // If `values` is non-null, it is filled in with Value components of the 484 // relevant stack entries, including those of any new entries created. 485 [[nodiscard]] bool checkTopTypeMatches(ResultType expected, 486 ValueVector* values, 487 bool rewriteStackTypes); 488 489 [[nodiscard]] bool pushControl(LabelKind kind, BlockType type); 490 [[nodiscard]] bool checkStackAtEndOfBlock(ResultType* type, 491 ValueVector* values); 492 [[nodiscard]] bool getControl(uint32_t relativeDepth, Control** controlEntry); 493 [[nodiscard]] bool checkBranchValueAndPush(uint32_t relativeDepth, 494 ResultType* type, 495 ValueVector* values, 496 bool rewriteStackTypes); 497 [[nodiscard]] bool checkBrTableEntryAndPush(uint32_t* relativeDepth, 498 ResultType prevBranchType, 499 ResultType* branchType, 500 ValueVector* branchValues); 501 502 [[nodiscard]] bool push(StackType t) { return valueStack_.emplaceBack(t); } 503 [[nodiscard]] bool push(ValType t) { return valueStack_.emplaceBack(t); } 504 [[nodiscard]] bool push(TypeAndValue tv) { return valueStack_.append(tv); } 505 [[nodiscard]] bool push(ResultType t) { 506 for (size_t i = 0; i < t.length(); i++) { 507 if (!push(t[i])) { 508 return false; 509 } 510 } 511 return true; 512 } 513 void infalliblePush(StackType t) { valueStack_.infallibleEmplaceBack(t); } 514 void infalliblePush(ValType t) { 515 valueStack_.infallibleEmplaceBack(StackType(t)); 516 } 517 void infalliblePush(TypeAndValue tv) { valueStack_.infallibleAppend(tv); } 518 519 void afterUnconditionalBranch() { 520 valueStack_.shrinkTo(controlStack_.back().valueStackBase()); 521 controlStack_.back().setPolymorphicBase(); 522 } 523 524 inline bool checkIsSubtypeOf(StorageType actual, StorageType expected); 525 526 inline bool checkIsSubtypeOf(RefType actual, RefType expected) { 527 return checkIsSubtypeOf(ValType(actual).storageType(), 528 ValType(expected).storageType()); 529 } 530 inline bool checkIsSubtypeOf(ValType actual, ValType expected) { 531 return checkIsSubtypeOf(actual.storageType(), expected.storageType()); 532 } 533 534 inline bool checkIsSubtypeOf(ResultType params, ResultType results); 535 536 inline bool checkIsSubtypeOf(uint32_t actualTypeIndex, 537 uint32_t expectedTypeIndex); 538 539 public: 540 explicit OpIter(const CodeMetadata& codeMeta, Decoder& decoder, 541 const ValTypeVector& locals, Kind kind = OpIter::Func) 542 : kind_(kind), 543 d_(decoder), 544 codeMeta_(codeMeta), 545 locals_(locals), 546 featureUsage_(FeatureUsage::None), 547 branchHintVector_(nullptr), 548 #ifdef DEBUG 549 op_(OpBytes(Op::Limit)), 550 #endif 551 offsetOfLastReadOp_(0) { 552 } 553 554 FeatureUsage featureUsage() const { return featureUsage_; } 555 void addFeatureUsage(FeatureUsage featureUsage) { 556 featureUsage_ |= featureUsage; 557 } 558 559 // Return the decoding byte offset. 560 uint32_t currentOffset() const { return d_.currentOffset(); } 561 562 // Return the offset within the entire module of the last-read op. 563 size_t lastOpcodeOffset() const { 564 return offsetOfLastReadOp_ ? offsetOfLastReadOp_ : d_.currentOffset(); 565 } 566 567 // Return a BytecodeOffset describing where the current op should be reported 568 // to trap/call. 569 BytecodeOffset bytecodeOffset() const { 570 return BytecodeOffset(lastOpcodeOffset()); 571 } 572 573 // Test whether the iterator has reached the end of the buffer. 574 bool done() const { return d_.done(); } 575 576 // Return a pointer to the end of the buffer being decoded by this iterator. 577 const uint8_t* end() const { return d_.end(); } 578 579 // Report a general failure. 580 [[nodiscard]] bool fail(const char* msg) MOZ_COLD; 581 582 // Report a general failure with a context 583 [[nodiscard]] bool fail_ctx(const char* fmt, const char* context) MOZ_COLD; 584 585 // Report an unrecognized opcode. 586 [[nodiscard]] bool unrecognizedOpcode(const OpBytes* expr) MOZ_COLD; 587 588 // Return whether the innermost block has a polymorphic base of its stack. 589 // Ideally this accessor would be removed; consider using something else. 590 bool currentBlockHasPolymorphicBase() const { 591 return !controlStack_.empty() && controlStack_.back().polymorphicBase(); 592 } 593 594 // If it exists, return the BranchHint value from a function index and a 595 // branch offset. 596 // Branch hints are stored in a sorted vector. Because code in compiled in 597 // order, we keep track of the most recently accessed index. 598 // Retrieving branch hints is also done in order inside a function. 599 BranchHint getBranchHint(uint32_t funcIndex, uint32_t branchOffset) { 600 if (!codeMeta_.branchHintingEnabled()) { 601 return BranchHint::Invalid; 602 } 603 604 // Get the next hint in the collection 605 while (lastBranchHintIndex_ < branchHintVector_->length() && 606 (*branchHintVector_)[lastBranchHintIndex_].branchOffset < 607 branchOffset) { 608 lastBranchHintIndex_++; 609 } 610 611 // No hint found for this branch. 612 if (lastBranchHintIndex_ >= branchHintVector_->length()) { 613 return BranchHint::Invalid; 614 } 615 616 // The last index is saved, now return the hint. 617 return (*branchHintVector_)[lastBranchHintIndex_].value; 618 } 619 620 // ------------------------------------------------------------------------ 621 // Decoding and validation interface. 622 623 // Initialization and termination 624 625 [[nodiscard]] bool startFunction(uint32_t funcIndex); 626 [[nodiscard]] bool endFunction(const uint8_t* bodyEnd); 627 628 [[nodiscard]] bool startInitExpr(ValType expected); 629 [[nodiscard]] bool endInitExpr(); 630 631 // Value and reference types 632 633 [[nodiscard]] bool readValType(ValType* type); 634 [[nodiscard]] bool readHeapType(bool nullable, RefType* type); 635 636 // Instructions 637 638 [[nodiscard]] bool readOp(OpBytes* op); 639 [[nodiscard]] bool readReturn(ValueVector* values); 640 [[nodiscard]] bool readBlock(BlockType* type); 641 [[nodiscard]] bool readLoop(BlockType* type); 642 [[nodiscard]] bool readIf(BlockType* type, Value* condition); 643 [[nodiscard]] bool readElse(ResultType* paramType, ResultType* resultType, 644 ValueVector* thenResults); 645 [[nodiscard]] bool readEnd(LabelKind* kind, ResultType* type, 646 ValueVector* results, 647 ValueVector* resultsForEmptyElse); 648 void popEnd(); 649 [[nodiscard]] bool readBr(uint32_t* relativeDepth, ResultType* type, 650 ValueVector* values); 651 [[nodiscard]] bool readBrIf(uint32_t* relativeDepth, ResultType* type, 652 ValueVector* values, Value* condition); 653 [[nodiscard]] bool readBrTable(Uint32Vector* depths, uint32_t* defaultDepth, 654 ResultType* defaultBranchType, 655 ValueVector* branchValues, Value* index); 656 [[nodiscard]] bool readTry(BlockType* type); 657 [[nodiscard]] bool readTryTable(BlockType* type, 658 TryTableCatchVector* catches); 659 [[nodiscard]] bool readCatch(LabelKind* kind, uint32_t* tagIndex, 660 ResultType* paramType, ResultType* resultType, 661 ValueVector* tryResults); 662 [[nodiscard]] bool readCatchAll(LabelKind* kind, ResultType* paramType, 663 ResultType* resultType, 664 ValueVector* tryResults); 665 [[nodiscard]] bool readDelegate(uint32_t* relativeDepth, 666 ResultType* resultType, 667 ValueVector* tryResults); 668 void popDelegate(); 669 [[nodiscard]] bool readThrow(uint32_t* tagIndex, ValueVector* argValues); 670 [[nodiscard]] bool readThrowRef(Value* exnRef); 671 [[nodiscard]] bool readRethrow(uint32_t* relativeDepth); 672 [[nodiscard]] bool readUnreachable(); 673 [[nodiscard]] bool readDrop(); 674 [[nodiscard]] bool readUnary(ValType operandType, Value* input); 675 [[nodiscard]] bool readConversion(ValType operandType, ValType resultType, 676 Value* input); 677 [[nodiscard]] bool readBinary(ValType operandType, Value* lhs, Value* rhs); 678 [[nodiscard]] bool readComparison(ValType operandType, Value* lhs, 679 Value* rhs); 680 [[nodiscard]] bool readTernary(ValType operandType, Value* v0, Value* v1, 681 Value* v2); 682 [[nodiscard]] bool readLoad(ValType resultType, uint32_t byteSize, 683 LinearMemoryAddress<Value>* addr); 684 [[nodiscard]] bool readStore(ValType resultType, uint32_t byteSize, 685 LinearMemoryAddress<Value>* addr, Value* value); 686 [[nodiscard]] bool readTeeStore(ValType resultType, uint32_t byteSize, 687 LinearMemoryAddress<Value>* addr, 688 Value* value); 689 [[nodiscard]] bool readNop(); 690 [[nodiscard]] bool readMemorySize(uint32_t* memoryIndex); 691 [[nodiscard]] bool readMemoryGrow(uint32_t* memoryIndex, Value* input); 692 [[nodiscard]] bool readSelect(bool typed, StackType* type, Value* trueValue, 693 Value* falseValue, Value* condition); 694 [[nodiscard]] bool readGetLocal(uint32_t* id); 695 [[nodiscard]] bool readSetLocal(uint32_t* id, Value* value); 696 [[nodiscard]] bool readTeeLocal(uint32_t* id, Value* value); 697 [[nodiscard]] bool readGetGlobal(uint32_t* id); 698 [[nodiscard]] bool readSetGlobal(uint32_t* id, Value* value); 699 [[nodiscard]] bool readTeeGlobal(uint32_t* id, Value* value); 700 [[nodiscard]] bool readI32Const(int32_t* i32); 701 [[nodiscard]] bool readI64Const(int64_t* i64); 702 [[nodiscard]] bool readF32Const(float* f32); 703 [[nodiscard]] bool readF64Const(double* f64); 704 [[nodiscard]] bool readRefFunc(uint32_t* funcIndex); 705 [[nodiscard]] bool readRefNull(RefType* type); 706 [[nodiscard]] bool readRefIsNull(Value* input); 707 [[nodiscard]] bool readRefAsNonNull(Value* input); 708 [[nodiscard]] bool readBrOnNull(uint32_t* relativeDepth, ResultType* type, 709 ValueVector* values, Value* condition); 710 [[nodiscard]] bool readBrOnNonNull(uint32_t* relativeDepth, ResultType* type, 711 ValueVector* values, Value* condition); 712 [[nodiscard]] bool readCall(uint32_t* funcIndex, ValueVector* argValues); 713 [[nodiscard]] bool readCallIndirect(uint32_t* funcTypeIndex, 714 uint32_t* tableIndex, Value* callee, 715 ValueVector* argValues); 716 [[nodiscard]] bool readReturnCall(uint32_t* funcIndex, 717 ValueVector* argValues); 718 [[nodiscard]] bool readReturnCallIndirect(uint32_t* funcTypeIndex, 719 uint32_t* tableIndex, Value* callee, 720 ValueVector* argValues); 721 [[nodiscard]] bool readCallRef(uint32_t* funcTypeIndex, Value* callee, 722 ValueVector* argValues); 723 [[nodiscard]] bool readReturnCallRef(uint32_t* funcTypeIndex, Value* callee, 724 ValueVector* argValues); 725 [[nodiscard]] bool readOldCallDirect(uint32_t numFuncImports, 726 uint32_t* funcIndex, 727 ValueVector* argValues); 728 [[nodiscard]] bool readOldCallIndirect(uint32_t* funcTypeIndex, Value* callee, 729 ValueVector* argValues); 730 [[nodiscard]] bool readNotify(LinearMemoryAddress<Value>* addr, Value* count); 731 [[nodiscard]] bool readWait(LinearMemoryAddress<Value>* addr, 732 ValType valueType, uint32_t byteSize, 733 Value* value, Value* timeout); 734 [[nodiscard]] bool readFence(); 735 [[nodiscard]] bool readAtomicLoad(LinearMemoryAddress<Value>* addr, 736 ValType resultType, uint32_t byteSize); 737 [[nodiscard]] bool readAtomicStore(LinearMemoryAddress<Value>* addr, 738 ValType resultType, uint32_t byteSize, 739 Value* value); 740 [[nodiscard]] bool readAtomicRMW(LinearMemoryAddress<Value>* addr, 741 ValType resultType, uint32_t byteSize, 742 Value* value); 743 [[nodiscard]] bool readAtomicCmpXchg(LinearMemoryAddress<Value>* addr, 744 ValType resultType, uint32_t byteSize, 745 Value* oldValue, Value* newValue); 746 [[nodiscard]] bool readMemOrTableCopy(bool isMem, 747 uint32_t* dstMemOrTableIndex, 748 Value* dst, 749 uint32_t* srcMemOrTableIndex, 750 Value* src, Value* len); 751 [[nodiscard]] bool readDataOrElemDrop(bool isData, uint32_t* segIndex); 752 [[nodiscard]] bool readMemFill(uint32_t* memoryIndex, Value* start, 753 Value* val, Value* len); 754 [[nodiscard]] bool readMemOrTableInit(bool isMem, uint32_t* segIndex, 755 uint32_t* dstMemOrTableIndex, 756 Value* dst, Value* src, Value* len); 757 [[nodiscard]] bool readTableFill(uint32_t* tableIndex, Value* start, 758 Value* val, Value* len); 759 [[nodiscard]] bool readMemDiscard(uint32_t* memoryIndex, Value* start, 760 Value* len); 761 [[nodiscard]] bool readTableGet(uint32_t* tableIndex, Value* address); 762 [[nodiscard]] bool readTableGrow(uint32_t* tableIndex, Value* initValue, 763 Value* delta); 764 [[nodiscard]] bool readTableSet(uint32_t* tableIndex, Value* address, 765 Value* value); 766 767 [[nodiscard]] bool readTableSize(uint32_t* tableIndex); 768 769 [[nodiscard]] bool readStructNew(uint32_t* typeIndex, ValueVector* argValues); 770 [[nodiscard]] bool readStructNewDefault(uint32_t* typeIndex); 771 [[nodiscard]] bool readStructGet(uint32_t* typeIndex, uint32_t* fieldIndex, 772 FieldWideningOp wideningOp, Value* ptr); 773 [[nodiscard]] bool readStructSet(uint32_t* typeIndex, uint32_t* fieldIndex, 774 Value* ptr, Value* val); 775 [[nodiscard]] bool readArrayNew(uint32_t* typeIndex, Value* numElements, 776 Value* argValue); 777 [[nodiscard]] bool readArrayNewFixed(uint32_t* typeIndex, 778 uint32_t* numElements, 779 ValueVector* values); 780 [[nodiscard]] bool readArrayNewDefault(uint32_t* typeIndex, 781 Value* numElements); 782 [[nodiscard]] bool readArrayNewData(uint32_t* typeIndex, uint32_t* segIndex, 783 Value* offset, Value* numElements); 784 [[nodiscard]] bool readArrayNewElem(uint32_t* typeIndex, uint32_t* segIndex, 785 Value* offset, Value* numElements); 786 [[nodiscard]] bool readArrayInitData(uint32_t* typeIndex, uint32_t* segIndex, 787 Value* array, Value* arrayIndex, 788 Value* segOffset, Value* length); 789 [[nodiscard]] bool readArrayInitElem(uint32_t* typeIndex, uint32_t* segIndex, 790 Value* array, Value* arrayIndex, 791 Value* segOffset, Value* length); 792 [[nodiscard]] bool readArrayGet(uint32_t* typeIndex, 793 FieldWideningOp wideningOp, Value* index, 794 Value* ptr); 795 [[nodiscard]] bool readArraySet(uint32_t* typeIndex, Value* val, Value* index, 796 Value* ptr); 797 [[nodiscard]] bool readArrayLen(Value* ptr); 798 [[nodiscard]] bool readArrayCopy(uint32_t* dstArrayTypeIndex, 799 uint32_t* srcArrayTypeIndex, Value* dstArray, 800 Value* dstIndex, Value* srcArray, 801 Value* srcIndex, Value* numElements); 802 [[nodiscard]] bool readArrayFill(uint32_t* typeIndex, Value* array, 803 Value* index, Value* val, Value* length); 804 [[nodiscard]] bool readRefTest(bool nullable, RefType* sourceType, 805 RefType* destType, Value* ref); 806 [[nodiscard]] bool readRefCast(bool nullable, RefType* sourceType, 807 RefType* destType, Value* ref); 808 [[nodiscard]] bool readBrOnCast(bool onSuccess, uint32_t* labelRelativeDepth, 809 RefType* sourceType, RefType* destType, 810 ResultType* labelType, ValueVector* values); 811 [[nodiscard]] bool readRefConversion(RefType operandType, RefType resultType, 812 Value* operandValue); 813 814 #ifdef ENABLE_WASM_SIMD 815 [[nodiscard]] bool readLaneIndex(uint32_t inputLanes, uint32_t* laneIndex); 816 [[nodiscard]] bool readExtractLane(ValType resultType, uint32_t inputLanes, 817 uint32_t* laneIndex, Value* input); 818 [[nodiscard]] bool readReplaceLane(ValType operandType, uint32_t inputLanes, 819 uint32_t* laneIndex, Value* baseValue, 820 Value* operand); 821 [[nodiscard]] bool readVectorShift(Value* baseValue, Value* shift); 822 [[nodiscard]] bool readVectorShuffle(Value* v1, Value* v2, V128* selectMask); 823 [[nodiscard]] bool readV128Const(V128* value); 824 [[nodiscard]] bool readLoadSplat(uint32_t byteSize, 825 LinearMemoryAddress<Value>* addr); 826 [[nodiscard]] bool readLoadExtend(LinearMemoryAddress<Value>* addr); 827 [[nodiscard]] bool readLoadLane(uint32_t byteSize, 828 LinearMemoryAddress<Value>* addr, 829 uint32_t* laneIndex, Value* input); 830 [[nodiscard]] bool readStoreLane(uint32_t byteSize, 831 LinearMemoryAddress<Value>* addr, 832 uint32_t* laneIndex, Value* input); 833 #endif 834 835 [[nodiscard]] bool readCallBuiltinModuleFunc( 836 const BuiltinModuleFunc** builtinModuleFunc, ValueVector* params); 837 838 #ifdef ENABLE_WASM_JSPI 839 [[nodiscard]] bool readStackSwitch(StackSwitchKind* kind, Value* suspender, 840 Value* fn, Value* data); 841 #endif 842 843 // At a location where readOp is allowed, peek at the next opcode 844 // without consuming it or updating any internal state. 845 // Never fails: returns uint16_t(Op::Limit) in op->b0 if it can't read. 846 void peekOp(OpBytes* op); 847 848 // ------------------------------------------------------------------------ 849 // Stack management. 850 851 // Set the top N result values. 852 void setResults(size_t count, const ValueVector& values) { 853 MOZ_ASSERT(valueStack_.length() >= count); 854 size_t base = valueStack_.length() - count; 855 for (size_t i = 0; i < count; i++) { 856 valueStack_[base + i].setValue(values[i]); 857 } 858 } 859 860 bool getResults(size_t count, ValueVector* values) { 861 MOZ_ASSERT(valueStack_.length() >= count); 862 if (!values->resize(count)) { 863 return false; 864 } 865 size_t base = valueStack_.length() - count; 866 for (size_t i = 0; i < count; i++) { 867 (*values)[i] = valueStack_[base + i].value(); 868 } 869 return true; 870 } 871 872 // Set the result value of the current top-of-value-stack expression. 873 void setResult(Value value) { valueStack_.back().setValue(value); } 874 875 // Return the result value of the current top-of-value-stack expression. 876 Value getResult() { return valueStack_.back().value(); } 877 878 // Return a reference to the top of the control stack. 879 ControlItem& controlItem() { return controlStack_.back().controlItem(); } 880 881 // Return a reference to an element in the control stack. 882 ControlItem& controlItem(uint32_t relativeDepth) { 883 return controlStack_[controlStack_.length() - 1 - relativeDepth] 884 .controlItem(); 885 } 886 887 // Return the LabelKind of an element in the control stack. 888 LabelKind controlKind(uint32_t relativeDepth) { 889 return controlStack_[controlStack_.length() - 1 - relativeDepth].kind(); 890 } 891 892 // Return a reference to the outermost element on the control stack. 893 ControlItem& controlOutermost() { return controlStack_[0].controlItem(); } 894 895 // Test whether the control-stack is empty, meaning we've consumed the final 896 // end of the function body. 897 bool controlStackEmpty() const { return controlStack_.empty(); } 898 899 // Return the depth of the control stack. 900 size_t controlStackDepth() const { return controlStack_.length(); } 901 902 // Find the innermost control item matching a predicate, starting to search 903 // from a certain relative depth, and returning true if such innermost 904 // control item is found. The relative depth of the found item is returned 905 // via a parameter. 906 template <typename Predicate> 907 bool controlFindInnermostFrom(Predicate predicate, uint32_t fromRelativeDepth, 908 uint32_t* foundRelativeDepth) const { 909 int32_t fromAbsoluteDepth = controlStack_.length() - fromRelativeDepth - 1; 910 for (int32_t i = fromAbsoluteDepth; i >= 0; i--) { 911 if (predicate(controlStack_[i].kind(), controlStack_[i].controlItem())) { 912 *foundRelativeDepth = controlStack_.length() - 1 - i; 913 return true; 914 } 915 } 916 return false; 917 } 918 }; 919 920 template <typename Policy> 921 inline bool OpIter<Policy>::checkIsSubtypeOf(StorageType subType, 922 StorageType superType) { 923 return CheckIsSubtypeOf(d_, codeMeta_, lastOpcodeOffset(), subType, 924 superType); 925 } 926 927 template <typename Policy> 928 inline bool OpIter<Policy>::checkIsSubtypeOf(ResultType params, 929 ResultType results) { 930 return CheckIsSubtypeOf(d_, codeMeta_, lastOpcodeOffset(), params, results); 931 } 932 933 template <typename Policy> 934 inline bool OpIter<Policy>::checkIsSubtypeOf(uint32_t actualTypeIndex, 935 uint32_t expectedTypeIndex) { 936 const TypeDef& actualTypeDef = codeMeta_.types->type(actualTypeIndex); 937 const TypeDef& expectedTypeDef = codeMeta_.types->type(expectedTypeIndex); 938 return CheckIsSubtypeOf( 939 d_, codeMeta_, lastOpcodeOffset(), 940 ValType(RefType::fromTypeDef(&actualTypeDef, true)), 941 ValType(RefType::fromTypeDef(&expectedTypeDef, true))); 942 } 943 944 template <typename Policy> 945 inline bool OpIter<Policy>::unrecognizedOpcode(const OpBytes* expr) { 946 UniqueChars error(JS_smprintf("unrecognized opcode: %x %x", expr->b0, 947 IsPrefixByte(expr->b0) ? expr->b1 : 0)); 948 if (!error) { 949 return false; 950 } 951 952 return fail(error.get()); 953 } 954 955 template <typename Policy> 956 inline bool OpIter<Policy>::fail(const char* msg) { 957 return d_.fail(lastOpcodeOffset(), msg); 958 } 959 960 template <typename Policy> 961 inline bool OpIter<Policy>::fail_ctx(const char* fmt, const char* context) { 962 UniqueChars error(JS_smprintf(fmt, context)); 963 if (!error) { 964 return false; 965 } 966 return fail(error.get()); 967 } 968 969 template <typename Policy> 970 inline bool OpIter<Policy>::failEmptyStack() { 971 return valueStack_.empty() ? fail("popping value from empty stack") 972 : fail("popping value from outside block"); 973 } 974 975 // This function pops exactly one value from the stack, yielding Bottom types in 976 // various cases and therefore making it the caller's responsibility to do the 977 // right thing for StackType::Bottom. Prefer (pop|top)WithType. This is an 978 // optimization for the super-common case where the caller is statically 979 // expecting the resulttype `[valtype]`. 980 template <typename Policy> 981 inline bool OpIter<Policy>::popStackType(StackType* type, Value* value) { 982 Control& block = controlStack_.back(); 983 984 MOZ_ASSERT(valueStack_.length() >= block.valueStackBase()); 985 if (MOZ_UNLIKELY(valueStack_.length() == block.valueStackBase())) { 986 // If the base of this block's stack is polymorphic, then we can pop a 987 // dummy value of the bottom type; it won't be used since we're in 988 // unreachable code. 989 if (block.polymorphicBase()) { 990 *type = StackType::bottom(); 991 *value = Value(); 992 993 // Maintain the invariant that, after a pop, there is always memory 994 // reserved to push a value infallibly. 995 return valueStack_.reserve(valueStack_.length() + 1); 996 } 997 998 return failEmptyStack(); 999 } 1000 1001 TypeAndValue& tv = valueStack_.back(); 1002 *type = tv.type(); 1003 *value = tv.value(); 1004 valueStack_.popBack(); 1005 return true; 1006 } 1007 1008 // This function pops exactly one value from the stack, checking that it has the 1009 // expected type which can either be a specific value type or the bottom type. 1010 template <typename Policy> 1011 inline bool OpIter<Policy>::popWithType(ValType expectedType, Value* value, 1012 StackType* stackType) { 1013 if (!popStackType(stackType, value)) { 1014 return false; 1015 } 1016 1017 return stackType->isStackBottom() || 1018 checkIsSubtypeOf(stackType->valType(), expectedType); 1019 } 1020 1021 // This function pops exactly one value from the stack, checking that it has the 1022 // expected type which can either be a specific value type or the bottom type. 1023 template <typename Policy> 1024 inline bool OpIter<Policy>::popWithType(ValType expectedType, Value* value) { 1025 StackType stackType; 1026 return popWithType(expectedType, value, &stackType); 1027 } 1028 1029 template <typename Policy> 1030 inline bool OpIter<Policy>::popWithType(ResultType expected, 1031 ValueVector* values) { 1032 return popWithTypes(expected, values); 1033 } 1034 1035 // Pops each of the given expected types (in reverse, because it's a stack). 1036 template <typename Policy> 1037 template <typename ValTypeSpanT> 1038 inline bool OpIter<Policy>::popWithTypes(ValTypeSpanT expected, 1039 ValueVector* values) { 1040 size_t expectedLength = expected.size(); 1041 if (!values->resize(expectedLength)) { 1042 return false; 1043 } 1044 for (size_t i = 0; i < expectedLength; i++) { 1045 size_t reverseIndex = expectedLength - i - 1; 1046 ValType expectedType = expected[reverseIndex]; 1047 Value* value = &(*values)[reverseIndex]; 1048 if (!popWithType(expectedType, value)) { 1049 return false; 1050 } 1051 } 1052 return true; 1053 } 1054 1055 // This function pops exactly one value from the stack, checking that it is a 1056 // reference type. 1057 template <typename Policy> 1058 inline bool OpIter<Policy>::popWithRefType(Value* value, StackType* type) { 1059 if (!popStackType(type, value)) { 1060 return false; 1061 } 1062 1063 if (type->isStackBottom() || type->valType().isRefType()) { 1064 return true; 1065 } 1066 1067 UniqueChars actualText = ToString(type->valType(), codeMeta_.types); 1068 if (!actualText) { 1069 return false; 1070 } 1071 1072 UniqueChars error(JS_smprintf( 1073 "type mismatch: expression has type %s but expected a reference type", 1074 actualText.get())); 1075 if (!error) { 1076 return false; 1077 } 1078 1079 return fail(error.get()); 1080 } 1081 1082 template <typename Policy> 1083 inline bool OpIter<Policy>::checkTopTypeMatches(ResultType expected, 1084 ValueVector* values, 1085 bool rewriteStackTypes) { 1086 if (expected.empty()) { 1087 return true; 1088 } 1089 1090 Control& block = controlStack_.back(); 1091 1092 size_t expectedLength = expected.length(); 1093 if (values && !values->resize(expectedLength)) { 1094 return false; 1095 } 1096 1097 for (size_t i = 0; i != expectedLength; i++) { 1098 // We're iterating as-if we were popping each expected/actual type one by 1099 // one, which means iterating the array of expected results backwards. 1100 // The "current" value stack length refers to what the value stack length 1101 // would have been if we were popping it. 1102 size_t reverseIndex = expectedLength - i - 1; 1103 ValType expectedType = expected[reverseIndex]; 1104 auto collectValue = [&](const Value& v) { 1105 if (values) { 1106 (*values)[reverseIndex] = v; 1107 } 1108 }; 1109 1110 size_t currentValueStackLength = valueStack_.length() - i; 1111 1112 MOZ_ASSERT(currentValueStackLength >= block.valueStackBase()); 1113 if (currentValueStackLength == block.valueStackBase()) { 1114 if (!block.polymorphicBase()) { 1115 return failEmptyStack(); 1116 } 1117 1118 // If the base of this block's stack is polymorphic, then we can just 1119 // pull out as many fake values as we need to validate, and create dummy 1120 // stack entries accordingly; they won't be used since we're in 1121 // unreachable code. However, if `rewriteStackTypes` is true, we must 1122 // set the types on these new entries to whatever `expected` requires 1123 // them to be. 1124 TypeAndValue newTandV = 1125 rewriteStackTypes ? TypeAndValue(expectedType) : TypeAndValue(); 1126 if (!valueStack_.insert(valueStack_.begin() + currentValueStackLength, 1127 newTandV)) { 1128 return false; 1129 } 1130 1131 collectValue(Value()); 1132 } else { 1133 TypeAndValue& observed = valueStack_[currentValueStackLength - 1]; 1134 1135 if (observed.type().isStackBottom()) { 1136 collectValue(Value()); 1137 } else { 1138 if (!checkIsSubtypeOf(observed.type().valType(), expectedType)) { 1139 return false; 1140 } 1141 1142 collectValue(observed.value()); 1143 } 1144 1145 if (rewriteStackTypes) { 1146 observed.setType(StackType(expectedType)); 1147 } 1148 } 1149 } 1150 return true; 1151 } 1152 1153 template <typename Policy> 1154 inline bool OpIter<Policy>::pushControl(LabelKind kind, BlockType type) { 1155 ResultType paramType = type.params(); 1156 1157 ValueVector values; 1158 if (!checkTopTypeMatches(paramType, &values, /*rewriteStackTypes=*/true)) { 1159 return false; 1160 } 1161 MOZ_ASSERT(valueStack_.length() >= paramType.length()); 1162 uint32_t valueStackBase = valueStack_.length() - paramType.length(); 1163 return controlStack_.emplaceBack(kind, type, valueStackBase); 1164 } 1165 1166 template <typename Policy> 1167 inline bool OpIter<Policy>::checkStackAtEndOfBlock(ResultType* expectedType, 1168 ValueVector* values) { 1169 Control& block = controlStack_.back(); 1170 *expectedType = block.type().results(); 1171 1172 MOZ_ASSERT(valueStack_.length() >= block.valueStackBase()); 1173 if (expectedType->length() < valueStack_.length() - block.valueStackBase()) { 1174 return fail("unused values not explicitly dropped by end of block"); 1175 } 1176 1177 return checkTopTypeMatches(*expectedType, values, 1178 /*rewriteStackTypes=*/true); 1179 } 1180 1181 template <typename Policy> 1182 inline bool OpIter<Policy>::getControl(uint32_t relativeDepth, 1183 Control** controlEntry) { 1184 if (relativeDepth >= controlStack_.length()) { 1185 return fail("branch depth exceeds current nesting level"); 1186 } 1187 1188 *controlEntry = &controlStack_[controlStack_.length() - 1 - relativeDepth]; 1189 return true; 1190 } 1191 1192 template <typename Policy> 1193 inline bool OpIter<Policy>::readBlockType(BlockType* type) { 1194 uint8_t nextByte; 1195 if (!d_.peekByte(&nextByte)) { 1196 return fail("unable to read block type"); 1197 } 1198 1199 if (nextByte == uint8_t(TypeCode::BlockVoid)) { 1200 d_.uncheckedReadFixedU8(); 1201 *type = BlockType::VoidToVoid(); 1202 return true; 1203 } 1204 1205 if ((nextByte & SLEB128SignMask) == SLEB128SignBit) { 1206 ValType v; 1207 if (!readValType(&v)) { 1208 return false; 1209 } 1210 *type = BlockType::VoidToSingle(v); 1211 return true; 1212 } 1213 1214 int32_t x; 1215 if (!d_.readVarS32(&x) || x < 0 || uint32_t(x) >= codeMeta_.types->length()) { 1216 return fail("invalid block type type index"); 1217 } 1218 1219 const TypeDef* typeDef = &codeMeta_.types->type(x); 1220 if (!typeDef->isFuncType()) { 1221 return fail("block type type index must be func type"); 1222 } 1223 1224 *type = BlockType::Func(typeDef->funcType()); 1225 1226 return true; 1227 } 1228 1229 template <typename Policy> 1230 inline bool OpIter<Policy>::readOp(OpBytes* op) { 1231 MOZ_ASSERT(!controlStack_.empty()); 1232 1233 offsetOfLastReadOp_ = d_.currentOffset(); 1234 1235 if (MOZ_UNLIKELY(!d_.readOp(op))) { 1236 return fail("unable to read opcode"); 1237 } 1238 1239 #ifdef DEBUG 1240 op_ = *op; 1241 #endif 1242 1243 return true; 1244 } 1245 1246 template <typename Policy> 1247 inline void OpIter<Policy>::peekOp(OpBytes* op) { 1248 const uint8_t* pos = d_.currentPosition(); 1249 1250 if (MOZ_UNLIKELY(!d_.readOp(op))) { 1251 op->b0 = uint16_t(Op::Limit); 1252 } 1253 1254 d_.rollbackPosition(pos); 1255 } 1256 1257 template <typename Policy> 1258 inline bool OpIter<Policy>::startFunction(uint32_t funcIndex) { 1259 MOZ_ASSERT(kind_ == OpIter::Func); 1260 MOZ_ASSERT(elseParamStack_.empty()); 1261 MOZ_ASSERT(valueStack_.empty()); 1262 MOZ_ASSERT(controlStack_.empty()); 1263 MOZ_ASSERT(op_.b0 == uint16_t(Op::Limit)); 1264 BlockType type = BlockType::FuncResults(codeMeta_.getFuncType(funcIndex)); 1265 1266 // Initialize information related to branch hinting. 1267 lastBranchHintIndex_ = 0; 1268 if (codeMeta_.branchHintingEnabled()) { 1269 branchHintVector_ = &codeMeta_.branchHints.getHintVector(funcIndex); 1270 } 1271 1272 size_t numArgs = codeMeta_.getFuncType(funcIndex).args().length(); 1273 if (!unsetLocals_.init(locals_, numArgs)) { 1274 return false; 1275 } 1276 1277 return pushControl(LabelKind::Body, type); 1278 } 1279 1280 template <typename Policy> 1281 inline bool OpIter<Policy>::endFunction(const uint8_t* bodyEnd) { 1282 if (d_.currentPosition() != bodyEnd) { 1283 return fail("function body length mismatch"); 1284 } 1285 1286 if (!controlStack_.empty()) { 1287 return fail("unbalanced function body control flow"); 1288 } 1289 MOZ_ASSERT(elseParamStack_.empty()); 1290 MOZ_ASSERT(unsetLocals_.empty()); 1291 1292 #ifdef DEBUG 1293 op_ = OpBytes(Op::Limit); 1294 #endif 1295 valueStack_.clear(); 1296 return true; 1297 } 1298 1299 template <typename Policy> 1300 inline bool OpIter<Policy>::startInitExpr(ValType expected) { 1301 MOZ_ASSERT(kind_ == OpIter::InitExpr); 1302 MOZ_ASSERT(locals_.length() == 0); 1303 MOZ_ASSERT(elseParamStack_.empty()); 1304 MOZ_ASSERT(valueStack_.empty()); 1305 MOZ_ASSERT(controlStack_.empty()); 1306 MOZ_ASSERT(op_.b0 == uint16_t(Op::Limit)); 1307 lastBranchHintIndex_ = 0; 1308 1309 BlockType type = BlockType::VoidToSingle(expected); 1310 return pushControl(LabelKind::Body, type); 1311 } 1312 1313 template <typename Policy> 1314 inline bool OpIter<Policy>::endInitExpr() { 1315 MOZ_ASSERT(controlStack_.empty()); 1316 MOZ_ASSERT(elseParamStack_.empty()); 1317 1318 #ifdef DEBUG 1319 op_ = OpBytes(Op::Limit); 1320 #endif 1321 valueStack_.clear(); 1322 return true; 1323 } 1324 1325 template <typename Policy> 1326 inline bool OpIter<Policy>::readValType(ValType* type) { 1327 return d_.readValType(*codeMeta_.types, codeMeta_.features(), type); 1328 } 1329 1330 template <typename Policy> 1331 inline bool OpIter<Policy>::readHeapType(bool nullable, RefType* type) { 1332 return d_.readHeapType(*codeMeta_.types, codeMeta_.features(), nullable, 1333 type); 1334 } 1335 1336 template <typename Policy> 1337 inline bool OpIter<Policy>::readReturn(ValueVector* values) { 1338 MOZ_ASSERT(Classify(op_) == OpKind::Return); 1339 1340 Control& body = controlStack_[0]; 1341 MOZ_ASSERT(body.kind() == LabelKind::Body); 1342 1343 if (!popWithType(body.resultType(), values)) { 1344 return false; 1345 } 1346 1347 afterUnconditionalBranch(); 1348 return true; 1349 } 1350 1351 template <typename Policy> 1352 inline bool OpIter<Policy>::readBlock(BlockType* type) { 1353 MOZ_ASSERT(Classify(op_) == OpKind::Block); 1354 1355 if (!readBlockType(type)) { 1356 return false; 1357 } 1358 1359 return pushControl(LabelKind::Block, *type); 1360 } 1361 1362 template <typename Policy> 1363 inline bool OpIter<Policy>::readLoop(BlockType* type) { 1364 MOZ_ASSERT(Classify(op_) == OpKind::Loop); 1365 1366 if (!readBlockType(type)) { 1367 return false; 1368 } 1369 1370 return pushControl(LabelKind::Loop, *type); 1371 } 1372 1373 template <typename Policy> 1374 inline bool OpIter<Policy>::readIf(BlockType* type, Value* condition) { 1375 MOZ_ASSERT(Classify(op_) == OpKind::If); 1376 1377 if (!readBlockType(type)) { 1378 return false; 1379 } 1380 1381 if (!popWithType(ValType::I32, condition)) { 1382 return false; 1383 } 1384 1385 if (!pushControl(LabelKind::Then, *type)) { 1386 return false; 1387 } 1388 1389 size_t paramsLength = type->params().length(); 1390 return elseParamStack_.append(valueStack_.end() - paramsLength, paramsLength); 1391 } 1392 1393 template <typename Policy> 1394 inline bool OpIter<Policy>::readElse(ResultType* paramType, 1395 ResultType* resultType, 1396 ValueVector* thenResults) { 1397 MOZ_ASSERT(Classify(op_) == OpKind::Else); 1398 1399 Control& block = controlStack_.back(); 1400 if (block.kind() != LabelKind::Then) { 1401 return fail("else can only be used within an if"); 1402 } 1403 1404 *paramType = block.type().params(); 1405 if (!checkStackAtEndOfBlock(resultType, thenResults)) { 1406 return false; 1407 } 1408 1409 valueStack_.shrinkTo(block.valueStackBase()); 1410 1411 size_t nparams = block.type().params().length(); 1412 MOZ_ASSERT(elseParamStack_.length() >= nparams); 1413 valueStack_.infallibleAppend(elseParamStack_.end() - nparams, nparams); 1414 elseParamStack_.shrinkBy(nparams); 1415 1416 // Reset local state to the beginning of the 'if' block for the new block 1417 // started by 'else'. 1418 unsetLocals_.resetToBlock(controlStack_.length() - 1); 1419 1420 block.switchToElse(); 1421 return true; 1422 } 1423 1424 template <typename Policy> 1425 inline bool OpIter<Policy>::readEnd(LabelKind* kind, ResultType* type, 1426 ValueVector* results, 1427 ValueVector* resultsForEmptyElse) { 1428 MOZ_ASSERT(Classify(op_) == OpKind::End); 1429 1430 Control& block = controlStack_.back(); 1431 1432 if (!checkStackAtEndOfBlock(type, results)) { 1433 return false; 1434 } 1435 1436 if (block.kind() == LabelKind::Then) { 1437 ResultType params = block.type().params(); 1438 // If an `if` block ends with `end` instead of `else`, then the `else` block 1439 // implicitly passes the `if` parameters as the `else` results. In that 1440 // case, assert that the `if`'s param type matches the result type. 1441 if (!checkIsSubtypeOf(params, block.type().results())) { 1442 return fail( 1443 "the parameters to an if without an else must be compatible with the " 1444 "if's result type"); 1445 } 1446 1447 size_t nparams = params.length(); 1448 MOZ_ASSERT(elseParamStack_.length() >= nparams); 1449 if (!resultsForEmptyElse->resize(nparams)) { 1450 return false; 1451 } 1452 const TypeAndValue* elseParams = elseParamStack_.end() - nparams; 1453 for (size_t i = 0; i < nparams; i++) { 1454 (*resultsForEmptyElse)[i] = elseParams[i].value(); 1455 } 1456 elseParamStack_.shrinkBy(nparams); 1457 } 1458 1459 *kind = block.kind(); 1460 return true; 1461 } 1462 1463 template <typename Policy> 1464 inline void OpIter<Policy>::popEnd() { 1465 MOZ_ASSERT(Classify(op_) == OpKind::End); 1466 1467 controlStack_.popBack(); 1468 unsetLocals_.resetToBlock(controlStack_.length()); 1469 } 1470 1471 template <typename Policy> 1472 inline bool OpIter<Policy>::checkBranchValueAndPush(uint32_t relativeDepth, 1473 ResultType* type, 1474 ValueVector* values, 1475 bool rewriteStackTypes) { 1476 Control* block = nullptr; 1477 if (!getControl(relativeDepth, &block)) { 1478 return false; 1479 } 1480 1481 *type = block->branchTargetType(); 1482 return checkTopTypeMatches(*type, values, rewriteStackTypes); 1483 } 1484 1485 template <typename Policy> 1486 inline bool OpIter<Policy>::readBr(uint32_t* relativeDepth, ResultType* type, 1487 ValueVector* values) { 1488 MOZ_ASSERT(Classify(op_) == OpKind::Br); 1489 1490 if (!readVarU32(relativeDepth)) { 1491 return fail("unable to read br depth"); 1492 } 1493 1494 if (!checkBranchValueAndPush(*relativeDepth, type, values, 1495 /*rewriteStackTypes=*/false)) { 1496 return false; 1497 } 1498 1499 afterUnconditionalBranch(); 1500 return true; 1501 } 1502 1503 template <typename Policy> 1504 inline bool OpIter<Policy>::readBrIf(uint32_t* relativeDepth, ResultType* type, 1505 ValueVector* values, Value* condition) { 1506 MOZ_ASSERT(Classify(op_) == OpKind::BrIf); 1507 1508 if (!readVarU32(relativeDepth)) { 1509 return fail("unable to read br_if depth"); 1510 } 1511 1512 if (!popWithType(ValType::I32, condition)) { 1513 return false; 1514 } 1515 1516 return checkBranchValueAndPush(*relativeDepth, type, values, 1517 /*rewriteStackTypes=*/true); 1518 } 1519 1520 #define UNKNOWN_ARITY UINT32_MAX 1521 1522 template <typename Policy> 1523 inline bool OpIter<Policy>::checkBrTableEntryAndPush( 1524 uint32_t* relativeDepth, ResultType prevBranchType, ResultType* type, 1525 ValueVector* branchValues) { 1526 if (!readVarU32(relativeDepth)) { 1527 return fail("unable to read br_table depth"); 1528 } 1529 1530 Control* block = nullptr; 1531 if (!getControl(*relativeDepth, &block)) { 1532 return false; 1533 } 1534 1535 *type = block->branchTargetType(); 1536 1537 if (prevBranchType.valid()) { 1538 if (prevBranchType.length() != type->length()) { 1539 return fail("br_table targets must all have the same arity"); 1540 } 1541 1542 // Avoid re-collecting the same values for subsequent branch targets. 1543 branchValues = nullptr; 1544 } 1545 1546 return checkTopTypeMatches(*type, branchValues, /*rewriteStackTypes=*/false); 1547 } 1548 1549 template <typename Policy> 1550 inline bool OpIter<Policy>::readBrTable(Uint32Vector* depths, 1551 uint32_t* defaultDepth, 1552 ResultType* defaultBranchType, 1553 ValueVector* branchValues, 1554 Value* index) { 1555 MOZ_ASSERT(Classify(op_) == OpKind::BrTable); 1556 1557 uint32_t tableLength; 1558 if (!readVarU32(&tableLength)) { 1559 return fail("unable to read br_table table length"); 1560 } 1561 1562 if (tableLength > MaxBrTableElems) { 1563 return fail("br_table too big"); 1564 } 1565 1566 if (!popWithType(ValType::I32, index)) { 1567 return false; 1568 } 1569 1570 if (!depths->resize(tableLength)) { 1571 return false; 1572 } 1573 1574 ResultType prevBranchType; 1575 for (uint32_t i = 0; i < tableLength; i++) { 1576 ResultType branchType; 1577 if (!checkBrTableEntryAndPush(&(*depths)[i], prevBranchType, &branchType, 1578 branchValues)) { 1579 return false; 1580 } 1581 prevBranchType = branchType; 1582 } 1583 1584 if (!checkBrTableEntryAndPush(defaultDepth, prevBranchType, defaultBranchType, 1585 branchValues)) { 1586 return false; 1587 } 1588 1589 MOZ_ASSERT(defaultBranchType->valid()); 1590 1591 afterUnconditionalBranch(); 1592 return true; 1593 } 1594 1595 #undef UNKNOWN_ARITY 1596 1597 template <typename Policy> 1598 inline bool OpIter<Policy>::readTry(BlockType* type) { 1599 MOZ_ASSERT(Classify(op_) == OpKind::Try); 1600 featureUsage_ |= FeatureUsage::LegacyExceptions; 1601 1602 if (!readBlockType(type)) { 1603 return false; 1604 } 1605 1606 return pushControl(LabelKind::Try, *type); 1607 } 1608 1609 enum class TryTableCatchFlags : uint8_t { 1610 CaptureExnRef = 0x1, 1611 CatchAll = 0x1 << 1, 1612 AllowedMask = uint8_t(CaptureExnRef) | uint8_t(CatchAll), 1613 }; 1614 1615 template <typename Policy> 1616 inline bool OpIter<Policy>::readTryTable(BlockType* type, 1617 TryTableCatchVector* catches) { 1618 MOZ_ASSERT(Classify(op_) == OpKind::TryTable); 1619 1620 if (!readBlockType(type)) { 1621 return false; 1622 } 1623 1624 if (!pushControl(LabelKind::TryTable, *type)) { 1625 return false; 1626 } 1627 1628 uint32_t catchesLength; 1629 if (!readVarU32(&catchesLength)) { 1630 return fail("failed to read catches length"); 1631 } 1632 1633 if (catchesLength > MaxTryTableCatches) { 1634 return fail("too many catches"); 1635 } 1636 1637 if (!catches->reserve(catchesLength)) { 1638 return false; 1639 } 1640 1641 for (uint32_t i = 0; i < catchesLength; i++) { 1642 TryTableCatch tryTableCatch; 1643 1644 // Decode the flags 1645 uint8_t flags; 1646 if (!readFixedU8(&flags)) { 1647 return fail("expected flags"); 1648 } 1649 if ((flags & ~uint8_t(TryTableCatchFlags::AllowedMask)) != 0) { 1650 return fail("invalid try_table catch flags"); 1651 } 1652 1653 // Decode if this catch wants to capture an exnref 1654 tryTableCatch.captureExnRef = 1655 (flags & uint8_t(TryTableCatchFlags::CaptureExnRef)) != 0; 1656 1657 // Decode the tag, if any 1658 if ((flags & uint8_t(TryTableCatchFlags::CatchAll)) != 0) { 1659 tryTableCatch.tagIndex = CatchAllIndex; 1660 } else { 1661 if (!readVarU32(&tryTableCatch.tagIndex)) { 1662 return fail("expected tag index"); 1663 } 1664 if (tryTableCatch.tagIndex >= codeMeta_.tags.length()) { 1665 return fail("tag index out of range"); 1666 } 1667 } 1668 1669 // Decode the target branch and construct the type we need to compare 1670 // against the branch 1671 if (!readVarU32(&tryTableCatch.labelRelativeDepth)) { 1672 return fail("unable to read catch depth"); 1673 } 1674 1675 // The target branch depth is relative to the control labels outside of 1676 // this try_table. e.g. `0` is a branch to the control outside of this 1677 // try_table, not to the try_table itself. However, we've already pushed 1678 // the control block for the try_table, and users will read it after we've 1679 // returned, so we need to return the relative depth adjusted by 1 to 1680 // account for our own control block. 1681 if (tryTableCatch.labelRelativeDepth == UINT32_MAX) { 1682 return fail("catch depth out of range"); 1683 } 1684 tryTableCatch.labelRelativeDepth += 1; 1685 1686 // Tagged catches will unpack the exception package and pass it to the 1687 // branch 1688 if (tryTableCatch.tagIndex != CatchAllIndex) { 1689 const TagType& tagType = *codeMeta_.tags[tryTableCatch.tagIndex].type; 1690 ResultType tagResult = tagType.resultType(); 1691 if (!tagResult.cloneToVector(&tryTableCatch.labelType)) { 1692 return false; 1693 } 1694 } 1695 1696 // Any captured exnref is the final parameter 1697 if (tryTableCatch.captureExnRef && !tryTableCatch.labelType.append(ValType( 1698 RefType::exn().asNonNullable()))) { 1699 return false; 1700 } 1701 1702 Control* block; 1703 if (!getControl(tryTableCatch.labelRelativeDepth, &block)) { 1704 return false; 1705 } 1706 1707 ResultType blockTargetType = block->branchTargetType(); 1708 if (!checkIsSubtypeOf(ResultType::Vector(tryTableCatch.labelType), 1709 blockTargetType)) { 1710 return false; 1711 } 1712 1713 catches->infallibleAppend(std::move(tryTableCatch)); 1714 } 1715 1716 return true; 1717 } 1718 1719 template <typename Policy> 1720 inline bool OpIter<Policy>::readCatch(LabelKind* kind, uint32_t* tagIndex, 1721 ResultType* paramType, 1722 ResultType* resultType, 1723 ValueVector* tryResults) { 1724 MOZ_ASSERT(Classify(op_) == OpKind::Catch); 1725 1726 if (!readVarU32(tagIndex)) { 1727 return fail("expected tag index"); 1728 } 1729 if (*tagIndex >= codeMeta_.tags.length()) { 1730 return fail("tag index out of range"); 1731 } 1732 1733 Control& block = controlStack_.back(); 1734 if (block.kind() == LabelKind::CatchAll) { 1735 return fail("catch cannot follow a catch_all"); 1736 } 1737 if (block.kind() != LabelKind::Try && block.kind() != LabelKind::Catch) { 1738 return fail("catch can only be used within a try-catch"); 1739 } 1740 *kind = block.kind(); 1741 *paramType = block.type().params(); 1742 1743 if (!checkStackAtEndOfBlock(resultType, tryResults)) { 1744 return false; 1745 } 1746 1747 valueStack_.shrinkTo(block.valueStackBase()); 1748 block.switchToCatch(); 1749 // Reset local state to the beginning of the 'try' block. 1750 unsetLocals_.resetToBlock(controlStack_.length() - 1); 1751 1752 return push(codeMeta_.tags[*tagIndex].type->resultType()); 1753 } 1754 1755 template <typename Policy> 1756 inline bool OpIter<Policy>::readCatchAll(LabelKind* kind, ResultType* paramType, 1757 ResultType* resultType, 1758 ValueVector* tryResults) { 1759 MOZ_ASSERT(Classify(op_) == OpKind::CatchAll); 1760 1761 Control& block = controlStack_.back(); 1762 if (block.kind() != LabelKind::Try && block.kind() != LabelKind::Catch) { 1763 return fail("catch_all can only be used within a try-catch"); 1764 } 1765 *kind = block.kind(); 1766 *paramType = block.type().params(); 1767 1768 if (!checkStackAtEndOfBlock(resultType, tryResults)) { 1769 return false; 1770 } 1771 1772 valueStack_.shrinkTo(block.valueStackBase()); 1773 block.switchToCatchAll(); 1774 // Reset local state to the beginning of the 'try' block. 1775 unsetLocals_.resetToBlock(controlStack_.length() - 1); 1776 return true; 1777 } 1778 1779 template <typename Policy> 1780 inline bool OpIter<Policy>::readDelegate(uint32_t* relativeDepth, 1781 ResultType* resultType, 1782 ValueVector* tryResults) { 1783 MOZ_ASSERT(Classify(op_) == OpKind::Delegate); 1784 1785 Control& block = controlStack_.back(); 1786 if (block.kind() != LabelKind::Try) { 1787 return fail("delegate can only be used within a try"); 1788 } 1789 1790 uint32_t delegateDepth; 1791 if (!readVarU32(&delegateDepth)) { 1792 return fail("unable to read delegate depth"); 1793 } 1794 1795 // Depths for delegate start counting in the surrounding block. 1796 if (delegateDepth >= controlStack_.length() - 1) { 1797 return fail("delegate depth exceeds current nesting level"); 1798 } 1799 *relativeDepth = delegateDepth + 1; 1800 1801 // Because `delegate` acts like `end` and ends the block, we will check 1802 // the stack here. 1803 return checkStackAtEndOfBlock(resultType, tryResults); 1804 } 1805 1806 // We need popDelegate because readDelegate cannot pop the control stack 1807 // itself, as its caller may need to use the control item for delegate. 1808 template <typename Policy> 1809 inline void OpIter<Policy>::popDelegate() { 1810 MOZ_ASSERT(Classify(op_) == OpKind::Delegate); 1811 1812 controlStack_.popBack(); 1813 unsetLocals_.resetToBlock(controlStack_.length()); 1814 } 1815 1816 template <typename Policy> 1817 inline bool OpIter<Policy>::readThrow(uint32_t* tagIndex, 1818 ValueVector* argValues) { 1819 MOZ_ASSERT(Classify(op_) == OpKind::Throw); 1820 1821 if (!readVarU32(tagIndex)) { 1822 return fail("expected tag index"); 1823 } 1824 if (*tagIndex >= codeMeta_.tags.length()) { 1825 return fail("tag index out of range"); 1826 } 1827 1828 if (!popWithType(codeMeta_.tags[*tagIndex].type->resultType(), argValues)) { 1829 return false; 1830 } 1831 1832 afterUnconditionalBranch(); 1833 return true; 1834 } 1835 1836 template <typename Policy> 1837 inline bool OpIter<Policy>::readThrowRef(Value* exnRef) { 1838 MOZ_ASSERT(Classify(op_) == OpKind::ThrowRef); 1839 1840 if (!popWithType(ValType(RefType::exn()), exnRef)) { 1841 return false; 1842 } 1843 1844 afterUnconditionalBranch(); 1845 return true; 1846 } 1847 1848 template <typename Policy> 1849 inline bool OpIter<Policy>::readRethrow(uint32_t* relativeDepth) { 1850 MOZ_ASSERT(Classify(op_) == OpKind::Rethrow); 1851 1852 if (!readVarU32(relativeDepth)) { 1853 return fail("unable to read rethrow depth"); 1854 } 1855 1856 if (*relativeDepth >= controlStack_.length()) { 1857 return fail("rethrow depth exceeds current nesting level"); 1858 } 1859 LabelKind kind = controlKind(*relativeDepth); 1860 if (kind != LabelKind::Catch && kind != LabelKind::CatchAll) { 1861 return fail("rethrow target was not a catch block"); 1862 } 1863 1864 afterUnconditionalBranch(); 1865 return true; 1866 } 1867 1868 template <typename Policy> 1869 inline bool OpIter<Policy>::readUnreachable() { 1870 MOZ_ASSERT(Classify(op_) == OpKind::Unreachable); 1871 1872 afterUnconditionalBranch(); 1873 return true; 1874 } 1875 1876 template <typename Policy> 1877 inline bool OpIter<Policy>::readDrop() { 1878 MOZ_ASSERT(Classify(op_) == OpKind::Drop); 1879 StackType type; 1880 Value value; 1881 return popStackType(&type, &value); 1882 } 1883 1884 template <typename Policy> 1885 inline bool OpIter<Policy>::readUnary(ValType operandType, Value* input) { 1886 MOZ_ASSERT(Classify(op_) == OpKind::Unary); 1887 1888 if (!popWithType(operandType, input)) { 1889 return false; 1890 } 1891 1892 infalliblePush(operandType); 1893 1894 return true; 1895 } 1896 1897 template <typename Policy> 1898 inline bool OpIter<Policy>::readConversion(ValType operandType, 1899 ValType resultType, Value* input) { 1900 MOZ_ASSERT(Classify(op_) == OpKind::Conversion); 1901 1902 if (!popWithType(operandType, input)) { 1903 return false; 1904 } 1905 1906 infalliblePush(resultType); 1907 1908 return true; 1909 } 1910 1911 template <typename Policy> 1912 inline bool OpIter<Policy>::readBinary(ValType operandType, Value* lhs, 1913 Value* rhs) { 1914 MOZ_ASSERT(Classify(op_) == OpKind::Binary); 1915 1916 if (!popWithType(operandType, rhs)) { 1917 return false; 1918 } 1919 1920 if (!popWithType(operandType, lhs)) { 1921 return false; 1922 } 1923 1924 infalliblePush(operandType); 1925 1926 return true; 1927 } 1928 1929 template <typename Policy> 1930 inline bool OpIter<Policy>::readComparison(ValType operandType, Value* lhs, 1931 Value* rhs) { 1932 MOZ_ASSERT(Classify(op_) == OpKind::Comparison); 1933 1934 if (!popWithType(operandType, rhs)) { 1935 return false; 1936 } 1937 1938 if (!popWithType(operandType, lhs)) { 1939 return false; 1940 } 1941 1942 infalliblePush(ValType::I32); 1943 1944 return true; 1945 } 1946 1947 template <typename Policy> 1948 inline bool OpIter<Policy>::readTernary(ValType operandType, Value* v0, 1949 Value* v1, Value* v2) { 1950 MOZ_ASSERT(Classify(op_) == OpKind::Ternary); 1951 1952 if (!popWithType(operandType, v2)) { 1953 return false; 1954 } 1955 1956 if (!popWithType(operandType, v1)) { 1957 return false; 1958 } 1959 1960 if (!popWithType(operandType, v0)) { 1961 return false; 1962 } 1963 1964 infalliblePush(operandType); 1965 1966 return true; 1967 } 1968 1969 template <typename Policy> 1970 inline bool OpIter<Policy>::readLinearMemoryAddress( 1971 uint32_t byteSize, LinearMemoryAddress<Value>* addr) { 1972 uint32_t flags; 1973 if (!readVarU32(&flags)) { 1974 return fail("unable to read load alignment"); 1975 } 1976 1977 uint8_t alignLog2 = flags & ((1 << 6) - 1); 1978 uint8_t hasMemoryIndex = flags & (1 << 6); 1979 uint32_t undefinedBits = flags & ~((1 << 7) - 1); 1980 1981 if (undefinedBits != 0) { 1982 return fail("invalid memory flags"); 1983 } 1984 1985 if (hasMemoryIndex != 0) { 1986 if (!readVarU32(&addr->memoryIndex)) { 1987 return fail("unable to read memory index"); 1988 } 1989 } else { 1990 addr->memoryIndex = 0; 1991 } 1992 1993 if (addr->memoryIndex >= codeMeta_.numMemories()) { 1994 return fail("memory index out of range"); 1995 } 1996 1997 if (!readVarU64(&addr->offset)) { 1998 return fail("unable to read load offset"); 1999 } 2000 2001 AddressType at = codeMeta_.memories[addr->memoryIndex].addressType(); 2002 if (at == AddressType::I32 && addr->offset > UINT32_MAX) { 2003 return fail("offset too large for memory type"); 2004 } 2005 2006 if (alignLog2 >= 32 || (uint32_t(1) << alignLog2) > byteSize) { 2007 return fail("greater than natural alignment"); 2008 } 2009 2010 if (!popWithType(ToValType(at), &addr->base)) { 2011 return false; 2012 } 2013 2014 addr->align = uint32_t(1) << alignLog2; 2015 return true; 2016 } 2017 2018 template <typename Policy> 2019 inline bool OpIter<Policy>::readLinearMemoryAddressAligned( 2020 uint32_t byteSize, LinearMemoryAddress<Value>* addr) { 2021 if (!readLinearMemoryAddress(byteSize, addr)) { 2022 return false; 2023 } 2024 2025 if (addr->align != byteSize) { 2026 return fail("not natural alignment"); 2027 } 2028 2029 return true; 2030 } 2031 2032 template <typename Policy> 2033 inline bool OpIter<Policy>::readLoad(ValType resultType, uint32_t byteSize, 2034 LinearMemoryAddress<Value>* addr) { 2035 MOZ_ASSERT(Classify(op_) == OpKind::Load); 2036 2037 if (!readLinearMemoryAddress(byteSize, addr)) { 2038 return false; 2039 } 2040 2041 infalliblePush(resultType); 2042 2043 return true; 2044 } 2045 2046 template <typename Policy> 2047 inline bool OpIter<Policy>::readStore(ValType resultType, uint32_t byteSize, 2048 LinearMemoryAddress<Value>* addr, 2049 Value* value) { 2050 MOZ_ASSERT(Classify(op_) == OpKind::Store); 2051 2052 if (!popWithType(resultType, value)) { 2053 return false; 2054 } 2055 2056 return readLinearMemoryAddress(byteSize, addr); 2057 } 2058 2059 template <typename Policy> 2060 inline bool OpIter<Policy>::readTeeStore(ValType resultType, uint32_t byteSize, 2061 LinearMemoryAddress<Value>* addr, 2062 Value* value) { 2063 MOZ_ASSERT(Classify(op_) == OpKind::TeeStore); 2064 2065 if (!popWithType(resultType, value)) { 2066 return false; 2067 } 2068 2069 if (!readLinearMemoryAddress(byteSize, addr)) { 2070 return false; 2071 } 2072 2073 infalliblePush(TypeAndValue(resultType, *value)); 2074 return true; 2075 } 2076 2077 template <typename Policy> 2078 inline bool OpIter<Policy>::readNop() { 2079 MOZ_ASSERT(Classify(op_) == OpKind::Nop); 2080 2081 return true; 2082 } 2083 2084 template <typename Policy> 2085 inline bool OpIter<Policy>::readMemorySize(uint32_t* memoryIndex) { 2086 MOZ_ASSERT(Classify(op_) == OpKind::MemorySize); 2087 2088 if (!readVarU32(memoryIndex)) { 2089 return fail("failed to read memory flags"); 2090 } 2091 2092 if (*memoryIndex >= codeMeta_.numMemories()) { 2093 return fail("memory index out of range for memory.size"); 2094 } 2095 2096 ValType ptrType = ToValType(codeMeta_.memories[*memoryIndex].addressType()); 2097 return push(ptrType); 2098 } 2099 2100 template <typename Policy> 2101 inline bool OpIter<Policy>::readMemoryGrow(uint32_t* memoryIndex, 2102 Value* input) { 2103 MOZ_ASSERT(Classify(op_) == OpKind::MemoryGrow); 2104 2105 if (!readVarU32(memoryIndex)) { 2106 return fail("failed to read memory flags"); 2107 } 2108 2109 if (*memoryIndex >= codeMeta_.numMemories()) { 2110 return fail("memory index out of range for memory.grow"); 2111 } 2112 2113 ValType ptrType = ToValType(codeMeta_.memories[*memoryIndex].addressType()); 2114 if (!popWithType(ptrType, input)) { 2115 return false; 2116 } 2117 2118 infalliblePush(ptrType); 2119 2120 return true; 2121 } 2122 2123 template <typename Policy> 2124 inline bool OpIter<Policy>::readSelect(bool typed, StackType* type, 2125 Value* trueValue, Value* falseValue, 2126 Value* condition) { 2127 MOZ_ASSERT(Classify(op_) == OpKind::Select); 2128 2129 if (typed) { 2130 uint32_t length; 2131 if (!readVarU32(&length)) { 2132 return fail("unable to read select result length"); 2133 } 2134 if (length != 1) { 2135 return fail("bad number of results"); 2136 } 2137 ValType result; 2138 if (!readValType(&result)) { 2139 return fail("invalid result type for select"); 2140 } 2141 2142 if (!popWithType(ValType::I32, condition)) { 2143 return false; 2144 } 2145 if (!popWithType(result, falseValue)) { 2146 return false; 2147 } 2148 if (!popWithType(result, trueValue)) { 2149 return false; 2150 } 2151 2152 *type = StackType(result); 2153 infalliblePush(*type); 2154 return true; 2155 } 2156 2157 if (!popWithType(ValType::I32, condition)) { 2158 return false; 2159 } 2160 2161 StackType falseType; 2162 if (!popStackType(&falseType, falseValue)) { 2163 return false; 2164 } 2165 2166 StackType trueType; 2167 if (!popStackType(&trueType, trueValue)) { 2168 return false; 2169 } 2170 2171 if (!falseType.isValidForUntypedSelect() || 2172 !trueType.isValidForUntypedSelect()) { 2173 return fail("invalid types for untyped select"); 2174 } 2175 2176 if (falseType.isStackBottom()) { 2177 *type = trueType; 2178 } else if (trueType.isStackBottom() || falseType == trueType) { 2179 *type = falseType; 2180 } else { 2181 return fail("select operand types must match"); 2182 } 2183 2184 infalliblePush(*type); 2185 return true; 2186 } 2187 2188 template <typename Policy> 2189 inline bool OpIter<Policy>::readGetLocal(uint32_t* id) { 2190 MOZ_ASSERT(Classify(op_) == OpKind::GetLocal); 2191 2192 if (!readVarU32(id)) { 2193 return fail("unable to read local index"); 2194 } 2195 2196 if (*id >= locals_.length()) { 2197 return fail("local.get index out of range"); 2198 } 2199 2200 if (unsetLocals_.isUnset(*id)) { 2201 return fail("local.get read from unset local"); 2202 } 2203 2204 return push(locals_[*id]); 2205 } 2206 2207 template <typename Policy> 2208 inline bool OpIter<Policy>::readSetLocal(uint32_t* id, Value* value) { 2209 MOZ_ASSERT(Classify(op_) == OpKind::SetLocal); 2210 2211 if (!readVarU32(id)) { 2212 return fail("unable to read local index"); 2213 } 2214 2215 if (*id >= locals_.length()) { 2216 return fail("local.set index out of range"); 2217 } 2218 2219 if (unsetLocals_.isUnset(*id)) { 2220 unsetLocals_.set(*id, controlStackDepth()); 2221 } 2222 2223 return popWithType(locals_[*id], value); 2224 } 2225 2226 template <typename Policy> 2227 inline bool OpIter<Policy>::readTeeLocal(uint32_t* id, Value* value) { 2228 MOZ_ASSERT(Classify(op_) == OpKind::TeeLocal); 2229 2230 if (!readVarU32(id)) { 2231 return fail("unable to read local index"); 2232 } 2233 2234 if (*id >= locals_.length()) { 2235 return fail("local.set index out of range"); 2236 } 2237 2238 if (unsetLocals_.isUnset(*id)) { 2239 unsetLocals_.set(*id, controlStackDepth()); 2240 } 2241 2242 ValueVector single; 2243 if (!checkTopTypeMatches(ResultType::Single(locals_[*id]), &single, 2244 /*rewriteStackTypes=*/true)) { 2245 return false; 2246 } 2247 2248 *value = single[0]; 2249 return true; 2250 } 2251 2252 template <typename Policy> 2253 inline bool OpIter<Policy>::readGetGlobal(uint32_t* id) { 2254 MOZ_ASSERT(Classify(op_) == OpKind::GetGlobal); 2255 2256 if (!d_.readGlobalIndex(id)) { 2257 return false; 2258 } 2259 2260 if (*id >= codeMeta_.globals.length()) { 2261 return fail("global.get index out of range"); 2262 } 2263 2264 // Initializer expressions can only access previously-defined immutable 2265 // globals. 2266 if (kind_ == OpIter::InitExpr && codeMeta_.globals[*id].isMutable()) { 2267 return fail( 2268 "global.get in initializer expression must reference a " 2269 "previously-defined immutable global"); 2270 } 2271 2272 return push(codeMeta_.globals[*id].type()); 2273 } 2274 2275 template <typename Policy> 2276 inline bool OpIter<Policy>::readSetGlobal(uint32_t* id, Value* value) { 2277 MOZ_ASSERT(Classify(op_) == OpKind::SetGlobal); 2278 2279 if (!d_.readGlobalIndex(id)) { 2280 return false; 2281 } 2282 2283 if (*id >= codeMeta_.globals.length()) { 2284 return fail("global.set index out of range"); 2285 } 2286 2287 if (!codeMeta_.globals[*id].isMutable()) { 2288 return fail("can't write an immutable global"); 2289 } 2290 2291 return popWithType(codeMeta_.globals[*id].type(), value); 2292 } 2293 2294 template <typename Policy> 2295 inline bool OpIter<Policy>::readTeeGlobal(uint32_t* id, Value* value) { 2296 MOZ_ASSERT(Classify(op_) == OpKind::TeeGlobal); 2297 2298 if (!d_.readGlobalIndex(id)) { 2299 return false; 2300 } 2301 2302 if (*id >= codeMeta_.globals.length()) { 2303 return fail("global.set index out of range"); 2304 } 2305 2306 if (!codeMeta_.globals[*id].isMutable()) { 2307 return fail("can't write an immutable global"); 2308 } 2309 2310 ValueVector single; 2311 if (!checkTopTypeMatches(ResultType::Single(codeMeta_.globals[*id].type()), 2312 &single, 2313 /*rewriteStackTypes=*/true)) { 2314 return false; 2315 } 2316 2317 MOZ_ASSERT(single.length() == 1); 2318 *value = single[0]; 2319 return true; 2320 } 2321 2322 template <typename Policy> 2323 inline bool OpIter<Policy>::readI32Const(int32_t* i32) { 2324 MOZ_ASSERT(Classify(op_) == OpKind::I32Const); 2325 2326 if (!d_.readI32Const(i32)) { 2327 return false; 2328 } 2329 2330 return push(ValType::I32); 2331 } 2332 2333 template <typename Policy> 2334 inline bool OpIter<Policy>::readI64Const(int64_t* i64) { 2335 MOZ_ASSERT(Classify(op_) == OpKind::I64Const); 2336 2337 if (!d_.readI64Const(i64)) { 2338 return false; 2339 } 2340 2341 return push(ValType::I64); 2342 } 2343 2344 template <typename Policy> 2345 inline bool OpIter<Policy>::readF32Const(float* f32) { 2346 MOZ_ASSERT(Classify(op_) == OpKind::F32Const); 2347 2348 if (!d_.readF32Const(f32)) { 2349 return false; 2350 } 2351 2352 return push(ValType::F32); 2353 } 2354 2355 template <typename Policy> 2356 inline bool OpIter<Policy>::readF64Const(double* f64) { 2357 MOZ_ASSERT(Classify(op_) == OpKind::F64Const); 2358 2359 if (!d_.readF64Const(f64)) { 2360 return false; 2361 } 2362 2363 return push(ValType::F64); 2364 } 2365 2366 template <typename Policy> 2367 inline bool OpIter<Policy>::readRefFunc(uint32_t* funcIndex) { 2368 MOZ_ASSERT(Classify(op_) == OpKind::RefFunc); 2369 2370 if (!d_.readFuncIndex(funcIndex)) { 2371 return false; 2372 } 2373 if (*funcIndex >= codeMeta_.funcs.length()) { 2374 return fail("function index out of range"); 2375 } 2376 if (kind_ == OpIter::Func && !codeMeta_.funcs[*funcIndex].canRefFunc()) { 2377 return fail( 2378 "function index is not declared in a section before the code section"); 2379 } 2380 2381 const uint32_t typeIndex = codeMeta_.funcs[*funcIndex].typeIndex; 2382 const TypeDef& typeDef = codeMeta_.types->type(typeIndex); 2383 return push(RefType::fromTypeDef(&typeDef, false)); 2384 } 2385 2386 template <typename Policy> 2387 inline bool OpIter<Policy>::readRefNull(RefType* type) { 2388 MOZ_ASSERT(Classify(op_) == OpKind::RefNull); 2389 2390 if (!d_.readRefNull(*codeMeta_.types, codeMeta_.features(), type)) { 2391 return false; 2392 } 2393 return push(*type); 2394 } 2395 2396 template <typename Policy> 2397 inline bool OpIter<Policy>::readRefIsNull(Value* input) { 2398 MOZ_ASSERT(Classify(op_) == OpKind::RefIsNull); 2399 2400 StackType type; 2401 if (!popWithRefType(input, &type)) { 2402 return false; 2403 } 2404 return push(ValType::I32); 2405 } 2406 2407 template <typename Policy> 2408 inline bool OpIter<Policy>::readRefAsNonNull(Value* input) { 2409 MOZ_ASSERT(Classify(op_) == OpKind::RefAsNonNull); 2410 2411 StackType type; 2412 if (!popWithRefType(input, &type)) { 2413 return false; 2414 } 2415 2416 if (type.isStackBottom()) { 2417 infalliblePush(type); 2418 } else { 2419 infalliblePush(TypeAndValue(type.asNonNullable(), *input)); 2420 } 2421 return true; 2422 } 2423 2424 template <typename Policy> 2425 inline bool OpIter<Policy>::readBrOnNull(uint32_t* relativeDepth, 2426 ResultType* type, ValueVector* values, 2427 Value* condition) { 2428 MOZ_ASSERT(Classify(op_) == OpKind::BrOnNull); 2429 2430 if (!readVarU32(relativeDepth)) { 2431 return fail("unable to read br_on_null depth"); 2432 } 2433 2434 StackType refType; 2435 if (!popWithRefType(condition, &refType)) { 2436 return false; 2437 } 2438 2439 if (!checkBranchValueAndPush(*relativeDepth, type, values, 2440 /*rewriteStackTypes=*/true)) { 2441 return false; 2442 } 2443 2444 if (refType.isStackBottom()) { 2445 return push(refType); 2446 } 2447 return push(TypeAndValue(refType.asNonNullable(), *condition)); 2448 } 2449 2450 template <typename Policy> 2451 inline bool OpIter<Policy>::readBrOnNonNull(uint32_t* relativeDepth, 2452 ResultType* type, 2453 ValueVector* values, 2454 Value* condition) { 2455 MOZ_ASSERT(Classify(op_) == OpKind::BrOnNonNull); 2456 2457 if (!readVarU32(relativeDepth)) { 2458 return fail("unable to read br_on_non_null depth"); 2459 } 2460 2461 Control* block = nullptr; 2462 if (!getControl(*relativeDepth, &block)) { 2463 return false; 2464 } 2465 2466 *type = block->branchTargetType(); 2467 2468 // Check we at least have one type in the branch target type. 2469 if (type->length() < 1) { 2470 return fail("type mismatch: target block type expected to be [_, ref]"); 2471 } 2472 2473 // Pop the condition reference. 2474 StackType refType; 2475 if (!popWithRefType(condition, &refType)) { 2476 return false; 2477 } 2478 2479 // Push non-nullable version of condition reference on the stack, prior 2480 // checking the target type below. 2481 if (!(refType.isStackBottom() 2482 ? push(refType) 2483 : push(TypeAndValue(refType.asNonNullable(), *condition)))) { 2484 return false; 2485 } 2486 2487 // Check if the type stack matches the branch target type. 2488 if (!checkTopTypeMatches(*type, values, /*rewriteStackTypes=*/true)) { 2489 return false; 2490 } 2491 2492 // Pop the condition reference -- the null-branch does not receive the value. 2493 StackType unusedType; 2494 Value unusedValue; 2495 return popStackType(&unusedType, &unusedValue); 2496 } 2497 2498 template <typename Policy> 2499 inline bool OpIter<Policy>::popCallArgs(const ValTypeVector& expectedTypes, 2500 ValueVector* values) { 2501 // Iterate through the argument types backward so that pops occur in the 2502 // right order. 2503 2504 if (!values->resize(expectedTypes.length())) { 2505 return false; 2506 } 2507 2508 for (int32_t i = int32_t(expectedTypes.length()) - 1; i >= 0; i--) { 2509 if (!popWithType(expectedTypes[i], &(*values)[i])) { 2510 return false; 2511 } 2512 } 2513 2514 return true; 2515 } 2516 2517 template <typename Policy> 2518 inline bool OpIter<Policy>::readCall(uint32_t* funcIndex, 2519 ValueVector* argValues) { 2520 MOZ_ASSERT(Classify(op_) == OpKind::Call); 2521 2522 if (!readVarU32(funcIndex)) { 2523 return fail("unable to read call function index"); 2524 } 2525 2526 if (*funcIndex >= codeMeta_.funcs.length()) { 2527 return fail("callee index out of range"); 2528 } 2529 2530 const FuncType& funcType = codeMeta_.getFuncType(*funcIndex); 2531 2532 if (!popCallArgs(funcType.args(), argValues)) { 2533 return false; 2534 } 2535 2536 return push(ResultType::Vector(funcType.results())); 2537 } 2538 2539 template <typename Policy> 2540 inline bool OpIter<Policy>::readReturnCall(uint32_t* funcIndex, 2541 ValueVector* argValues) { 2542 MOZ_ASSERT(Classify(op_) == OpKind::ReturnCall); 2543 2544 featureUsage_ |= FeatureUsage::ReturnCall; 2545 2546 if (!readVarU32(funcIndex)) { 2547 return fail("unable to read call function index"); 2548 } 2549 2550 if (*funcIndex >= codeMeta_.funcs.length()) { 2551 return fail("callee index out of range"); 2552 } 2553 2554 const FuncType& funcType = codeMeta_.getFuncType(*funcIndex); 2555 2556 if (!popCallArgs(funcType.args(), argValues)) { 2557 return false; 2558 } 2559 2560 // Check if callee results are subtypes of caller's. 2561 Control& body = controlStack_[0]; 2562 MOZ_ASSERT(body.kind() == LabelKind::Body); 2563 if (!checkIsSubtypeOf(ResultType::Vector(funcType.results()), 2564 body.resultType())) { 2565 return false; 2566 } 2567 2568 afterUnconditionalBranch(); 2569 return true; 2570 } 2571 2572 template <typename Policy> 2573 inline bool OpIter<Policy>::readCallIndirect(uint32_t* funcTypeIndex, 2574 uint32_t* tableIndex, 2575 Value* callee, 2576 ValueVector* argValues) { 2577 MOZ_ASSERT(Classify(op_) == OpKind::CallIndirect); 2578 MOZ_ASSERT(funcTypeIndex != tableIndex); 2579 2580 if (!readVarU32(funcTypeIndex)) { 2581 return fail("unable to read call_indirect signature index"); 2582 } 2583 2584 if (*funcTypeIndex >= codeMeta_.numTypes()) { 2585 return fail("signature index out of range"); 2586 } 2587 2588 if (!readVarU32(tableIndex)) { 2589 return fail("unable to read call_indirect table index"); 2590 } 2591 if (*tableIndex >= codeMeta_.tables.length()) { 2592 // Special case this for improved user experience. 2593 if (!codeMeta_.tables.length()) { 2594 return fail("can't call_indirect without a table"); 2595 } 2596 return fail("table index out of range for call_indirect"); 2597 } 2598 if (!codeMeta_.tables[*tableIndex].elemType.isFuncHierarchy()) { 2599 return fail("indirect calls must go through a table of 'funcref'"); 2600 } 2601 2602 if (!popWithType(ToValType(codeMeta_.tables[*tableIndex].addressType()), 2603 callee)) { 2604 return false; 2605 } 2606 2607 const TypeDef& typeDef = codeMeta_.types->type(*funcTypeIndex); 2608 if (!typeDef.isFuncType()) { 2609 return fail("expected signature type"); 2610 } 2611 const FuncType& funcType = typeDef.funcType(); 2612 2613 if (!popCallArgs(funcType.args(), argValues)) { 2614 return false; 2615 } 2616 2617 return push(ResultType::Vector(funcType.results())); 2618 } 2619 2620 template <typename Policy> 2621 inline bool OpIter<Policy>::readReturnCallIndirect(uint32_t* funcTypeIndex, 2622 uint32_t* tableIndex, 2623 Value* callee, 2624 ValueVector* argValues) { 2625 MOZ_ASSERT(Classify(op_) == OpKind::ReturnCallIndirect); 2626 MOZ_ASSERT(funcTypeIndex != tableIndex); 2627 2628 featureUsage_ |= FeatureUsage::ReturnCall; 2629 2630 if (!readVarU32(funcTypeIndex)) { 2631 return fail("unable to read return_call_indirect signature index"); 2632 } 2633 if (*funcTypeIndex >= codeMeta_.numTypes()) { 2634 return fail("signature index out of range"); 2635 } 2636 2637 if (!readVarU32(tableIndex)) { 2638 return fail("unable to read return_call_indirect table index"); 2639 } 2640 if (*tableIndex >= codeMeta_.tables.length()) { 2641 // Special case this for improved user experience. 2642 if (!codeMeta_.tables.length()) { 2643 return fail("can't return_call_indirect without a table"); 2644 } 2645 return fail("table index out of range for return_call_indirect"); 2646 } 2647 if (!codeMeta_.tables[*tableIndex].elemType.isFuncHierarchy()) { 2648 return fail("indirect calls must go through a table of 'funcref'"); 2649 } 2650 2651 if (!popWithType(ToValType(codeMeta_.tables[*tableIndex].addressType()), 2652 callee)) { 2653 return false; 2654 } 2655 2656 const TypeDef& typeDef = codeMeta_.types->type(*funcTypeIndex); 2657 if (!typeDef.isFuncType()) { 2658 return fail("expected signature type"); 2659 } 2660 const FuncType& funcType = typeDef.funcType(); 2661 2662 if (!popCallArgs(funcType.args(), argValues)) { 2663 return false; 2664 } 2665 2666 // Check if callee results are subtypes of caller's. 2667 Control& body = controlStack_[0]; 2668 MOZ_ASSERT(body.kind() == LabelKind::Body); 2669 if (!checkIsSubtypeOf(ResultType::Vector(funcType.results()), 2670 body.resultType())) { 2671 return false; 2672 } 2673 2674 afterUnconditionalBranch(); 2675 return true; 2676 } 2677 2678 template <typename Policy> 2679 inline bool OpIter<Policy>::readCallRef(uint32_t* funcTypeIndex, Value* callee, 2680 ValueVector* argValues) { 2681 MOZ_ASSERT(Classify(op_) == OpKind::CallRef); 2682 2683 if (!readFuncTypeIndex(funcTypeIndex)) { 2684 return false; 2685 } 2686 2687 const TypeDef& typeDef = codeMeta_.types->type(*funcTypeIndex); 2688 const FuncType& funcType = typeDef.funcType(); 2689 2690 if (!popWithType(ValType(RefType::fromTypeDef(&typeDef, true)), callee)) { 2691 return false; 2692 } 2693 2694 if (!popCallArgs(funcType.args(), argValues)) { 2695 return false; 2696 } 2697 2698 return push(ResultType::Vector(funcType.results())); 2699 } 2700 2701 template <typename Policy> 2702 inline bool OpIter<Policy>::readReturnCallRef(uint32_t* funcTypeIndex, 2703 Value* callee, 2704 ValueVector* argValues) { 2705 MOZ_ASSERT(Classify(op_) == OpKind::ReturnCallRef); 2706 2707 featureUsage_ |= FeatureUsage::ReturnCall; 2708 2709 if (!readFuncTypeIndex(funcTypeIndex)) { 2710 return false; 2711 } 2712 2713 const TypeDef& typeDef = codeMeta_.types->type(*funcTypeIndex); 2714 const FuncType& funcType = typeDef.funcType(); 2715 2716 if (!popWithType(ValType(RefType::fromTypeDef(&typeDef, true)), callee)) { 2717 return false; 2718 } 2719 2720 if (!popCallArgs(funcType.args(), argValues)) { 2721 return false; 2722 } 2723 2724 // Check if callee results are subtypes of caller's. 2725 Control& body = controlStack_[0]; 2726 MOZ_ASSERT(body.kind() == LabelKind::Body); 2727 if (!checkIsSubtypeOf(ResultType::Vector(funcType.results()), 2728 body.resultType())) { 2729 return false; 2730 } 2731 2732 afterUnconditionalBranch(); 2733 return true; 2734 } 2735 2736 template <typename Policy> 2737 inline bool OpIter<Policy>::readOldCallDirect(uint32_t numFuncImports, 2738 uint32_t* funcIndex, 2739 ValueVector* argValues) { 2740 MOZ_ASSERT(Classify(op_) == OpKind::OldCallDirect); 2741 2742 uint32_t funcDefIndex; 2743 if (!readVarU32(&funcDefIndex)) { 2744 return fail("unable to read call function index"); 2745 } 2746 2747 if (UINT32_MAX - funcDefIndex < numFuncImports) { 2748 return fail("callee index out of range"); 2749 } 2750 2751 *funcIndex = numFuncImports + funcDefIndex; 2752 2753 if (*funcIndex >= codeMeta_.funcs.length()) { 2754 return fail("callee index out of range"); 2755 } 2756 2757 const FuncType& funcType = codeMeta_.getFuncType(*funcIndex); 2758 2759 if (!popCallArgs(funcType.args(), argValues)) { 2760 return false; 2761 } 2762 2763 return push(ResultType::Vector(funcType.results())); 2764 } 2765 2766 template <typename Policy> 2767 inline bool OpIter<Policy>::readOldCallIndirect(uint32_t* funcTypeIndex, 2768 Value* callee, 2769 ValueVector* argValues) { 2770 MOZ_ASSERT(Classify(op_) == OpKind::OldCallIndirect); 2771 2772 if (!readVarU32(funcTypeIndex)) { 2773 return fail("unable to read call_indirect signature index"); 2774 } 2775 2776 if (*funcTypeIndex >= codeMeta_.numTypes()) { 2777 return fail("signature index out of range"); 2778 } 2779 2780 const TypeDef& typeDef = codeMeta_.types->type(*funcTypeIndex); 2781 if (!typeDef.isFuncType()) { 2782 return fail("expected signature type"); 2783 } 2784 const FuncType& funcType = typeDef.funcType(); 2785 2786 if (!popCallArgs(funcType.args(), argValues)) { 2787 return false; 2788 } 2789 2790 if (!popWithType(ValType::I32, callee)) { 2791 return false; 2792 } 2793 2794 return push(ResultType::Vector(funcType.results())); 2795 } 2796 2797 template <typename Policy> 2798 inline bool OpIter<Policy>::readNotify(LinearMemoryAddress<Value>* addr, 2799 Value* count) { 2800 MOZ_ASSERT(Classify(op_) == OpKind::Notify); 2801 2802 if (!popWithType(ValType::I32, count)) { 2803 return false; 2804 } 2805 2806 uint32_t byteSize = 4; // Per spec; smallest WAIT is i32. 2807 2808 if (!readLinearMemoryAddressAligned(byteSize, addr)) { 2809 return false; 2810 } 2811 2812 infalliblePush(ValType::I32); 2813 return true; 2814 } 2815 2816 template <typename Policy> 2817 inline bool OpIter<Policy>::readWait(LinearMemoryAddress<Value>* addr, 2818 ValType valueType, uint32_t byteSize, 2819 Value* value, Value* timeout) { 2820 MOZ_ASSERT(Classify(op_) == OpKind::Wait); 2821 2822 if (!popWithType(ValType::I64, timeout)) { 2823 return false; 2824 } 2825 2826 if (!popWithType(valueType, value)) { 2827 return false; 2828 } 2829 2830 if (!readLinearMemoryAddressAligned(byteSize, addr)) { 2831 return false; 2832 } 2833 2834 infalliblePush(ValType::I32); 2835 return true; 2836 } 2837 2838 template <typename Policy> 2839 inline bool OpIter<Policy>::readFence() { 2840 MOZ_ASSERT(Classify(op_) == OpKind::Fence); 2841 uint8_t flags; 2842 if (!readFixedU8(&flags)) { 2843 return fail("expected memory order after fence"); 2844 } 2845 if (flags != 0) { 2846 return fail("non-zero memory order not supported yet"); 2847 } 2848 return true; 2849 } 2850 2851 template <typename Policy> 2852 inline bool OpIter<Policy>::readAtomicLoad(LinearMemoryAddress<Value>* addr, 2853 ValType resultType, 2854 uint32_t byteSize) { 2855 MOZ_ASSERT(Classify(op_) == OpKind::AtomicLoad); 2856 2857 if (!readLinearMemoryAddressAligned(byteSize, addr)) { 2858 return false; 2859 } 2860 2861 infalliblePush(resultType); 2862 return true; 2863 } 2864 2865 template <typename Policy> 2866 inline bool OpIter<Policy>::readAtomicStore(LinearMemoryAddress<Value>* addr, 2867 ValType resultType, 2868 uint32_t byteSize, Value* value) { 2869 MOZ_ASSERT(Classify(op_) == OpKind::AtomicStore); 2870 2871 if (!popWithType(resultType, value)) { 2872 return false; 2873 } 2874 2875 return readLinearMemoryAddressAligned(byteSize, addr); 2876 } 2877 2878 template <typename Policy> 2879 inline bool OpIter<Policy>::readAtomicRMW(LinearMemoryAddress<Value>* addr, 2880 ValType resultType, uint32_t byteSize, 2881 Value* value) { 2882 MOZ_ASSERT(Classify(op_) == OpKind::AtomicRMW); 2883 2884 if (!popWithType(resultType, value)) { 2885 return false; 2886 } 2887 2888 if (!readLinearMemoryAddressAligned(byteSize, addr)) { 2889 return false; 2890 } 2891 2892 infalliblePush(resultType); 2893 return true; 2894 } 2895 2896 template <typename Policy> 2897 inline bool OpIter<Policy>::readAtomicCmpXchg(LinearMemoryAddress<Value>* addr, 2898 ValType resultType, 2899 uint32_t byteSize, 2900 Value* oldValue, 2901 Value* newValue) { 2902 MOZ_ASSERT(Classify(op_) == OpKind::AtomicCmpXchg); 2903 2904 if (!popWithType(resultType, newValue)) { 2905 return false; 2906 } 2907 2908 if (!popWithType(resultType, oldValue)) { 2909 return false; 2910 } 2911 2912 if (!readLinearMemoryAddressAligned(byteSize, addr)) { 2913 return false; 2914 } 2915 2916 infalliblePush(resultType); 2917 return true; 2918 } 2919 2920 template <typename Policy> 2921 inline bool OpIter<Policy>::readMemOrTableCopy(bool isMem, 2922 uint32_t* dstMemOrTableIndex, 2923 Value* dst, 2924 uint32_t* srcMemOrTableIndex, 2925 Value* src, Value* len) { 2926 MOZ_ASSERT(Classify(op_) == OpKind::MemOrTableCopy); 2927 MOZ_ASSERT(dstMemOrTableIndex != srcMemOrTableIndex); 2928 2929 // Spec requires (dest, src) as of 2019-10-04. 2930 if (!readVarU32(dstMemOrTableIndex)) { 2931 return false; 2932 } 2933 if (!readVarU32(srcMemOrTableIndex)) { 2934 return false; 2935 } 2936 2937 if (isMem) { 2938 if (*srcMemOrTableIndex >= codeMeta_.memories.length() || 2939 *dstMemOrTableIndex >= codeMeta_.memories.length()) { 2940 return fail("memory index out of range for memory.copy"); 2941 } 2942 } else { 2943 if (*dstMemOrTableIndex >= codeMeta_.tables.length() || 2944 *srcMemOrTableIndex >= codeMeta_.tables.length()) { 2945 return fail("table index out of range for table.copy"); 2946 } 2947 ValType dstElemType = codeMeta_.tables[*dstMemOrTableIndex].elemType; 2948 ValType srcElemType = codeMeta_.tables[*srcMemOrTableIndex].elemType; 2949 if (!checkIsSubtypeOf(srcElemType, dstElemType)) { 2950 return false; 2951 } 2952 } 2953 2954 ValType dstPtrType; 2955 ValType srcPtrType; 2956 ValType lenType; 2957 if (isMem) { 2958 dstPtrType = 2959 ToValType(codeMeta_.memories[*dstMemOrTableIndex].addressType()); 2960 srcPtrType = 2961 ToValType(codeMeta_.memories[*srcMemOrTableIndex].addressType()); 2962 } else { 2963 dstPtrType = ToValType(codeMeta_.tables[*dstMemOrTableIndex].addressType()); 2964 srcPtrType = ToValType(codeMeta_.tables[*srcMemOrTableIndex].addressType()); 2965 } 2966 if (dstPtrType == ValType::I64 && srcPtrType == ValType::I64) { 2967 lenType = ValType::I64; 2968 } else { 2969 lenType = ValType::I32; 2970 } 2971 2972 if (!popWithType(lenType, len)) { 2973 return false; 2974 } 2975 2976 if (!popWithType(srcPtrType, src)) { 2977 return false; 2978 } 2979 2980 return popWithType(dstPtrType, dst); 2981 } 2982 2983 template <typename Policy> 2984 inline bool OpIter<Policy>::readDataOrElemDrop(bool isData, 2985 uint32_t* segIndex) { 2986 MOZ_ASSERT(Classify(op_) == OpKind::DataOrElemDrop); 2987 2988 if (!readVarU32(segIndex)) { 2989 return fail("unable to read segment index"); 2990 } 2991 2992 if (isData) { 2993 if (codeMeta_.dataCount.isNothing()) { 2994 return fail("data.drop requires a DataCount section"); 2995 } 2996 if (*segIndex >= *codeMeta_.dataCount) { 2997 return fail("data.drop segment index out of range"); 2998 } 2999 } else { 3000 if (*segIndex >= codeMeta_.elemSegmentTypes.length()) { 3001 return fail("element segment index out of range for elem.drop"); 3002 } 3003 } 3004 3005 return true; 3006 } 3007 3008 template <typename Policy> 3009 inline bool OpIter<Policy>::readMemFill(uint32_t* memoryIndex, Value* start, 3010 Value* val, Value* len) { 3011 MOZ_ASSERT(Classify(op_) == OpKind::MemFill); 3012 3013 if (!readVarU32(memoryIndex)) { 3014 return fail("failed to read memory index"); 3015 } 3016 3017 if (*memoryIndex >= codeMeta_.numMemories()) { 3018 return fail("memory index out of range for memory.fill"); 3019 } 3020 3021 ValType ptrType = ToValType(codeMeta_.memories[*memoryIndex].addressType()); 3022 3023 if (!popWithType(ptrType, len)) { 3024 return false; 3025 } 3026 3027 if (!popWithType(ValType::I32, val)) { 3028 return false; 3029 } 3030 3031 return popWithType(ptrType, start); 3032 } 3033 3034 template <typename Policy> 3035 inline bool OpIter<Policy>::readMemOrTableInit(bool isMem, uint32_t* segIndex, 3036 uint32_t* dstMemOrTableIndex, 3037 Value* dst, Value* src, 3038 Value* len) { 3039 MOZ_ASSERT(Classify(op_) == OpKind::MemOrTableInit); 3040 MOZ_ASSERT(segIndex != dstMemOrTableIndex); 3041 3042 if (!readVarU32(segIndex)) { 3043 return fail("unable to read segment index"); 3044 } 3045 3046 uint32_t memOrTableIndex = 0; 3047 if (!readVarU32(&memOrTableIndex)) { 3048 return false; 3049 } 3050 3051 if (isMem) { 3052 if (memOrTableIndex >= codeMeta_.memories.length()) { 3053 return fail("memory index out of range for memory.init"); 3054 } 3055 *dstMemOrTableIndex = memOrTableIndex; 3056 3057 if (codeMeta_.dataCount.isNothing()) { 3058 return fail("memory.init requires a DataCount section"); 3059 } 3060 if (*segIndex >= *codeMeta_.dataCount) { 3061 return fail("memory.init segment index out of range"); 3062 } 3063 } else { 3064 if (memOrTableIndex >= codeMeta_.tables.length()) { 3065 return fail("table index out of range for table.init"); 3066 } 3067 *dstMemOrTableIndex = memOrTableIndex; 3068 3069 if (*segIndex >= codeMeta_.elemSegmentTypes.length()) { 3070 return fail("table.init segment index out of range"); 3071 } 3072 if (!checkIsSubtypeOf(codeMeta_.elemSegmentTypes[*segIndex], 3073 codeMeta_.tables[*dstMemOrTableIndex].elemType)) { 3074 return false; 3075 } 3076 } 3077 3078 if (!popWithType(ValType::I32, len)) { 3079 return false; 3080 } 3081 3082 if (!popWithType(ValType::I32, src)) { 3083 return false; 3084 } 3085 3086 ValType ptrType = 3087 isMem ? ToValType(codeMeta_.memories[*dstMemOrTableIndex].addressType()) 3088 : ToValType(codeMeta_.tables[*dstMemOrTableIndex].addressType()); 3089 return popWithType(ptrType, dst); 3090 } 3091 3092 template <typename Policy> 3093 inline bool OpIter<Policy>::readTableFill(uint32_t* tableIndex, Value* start, 3094 Value* val, Value* len) { 3095 MOZ_ASSERT(Classify(op_) == OpKind::TableFill); 3096 3097 if (!readVarU32(tableIndex)) { 3098 return fail("unable to read table index"); 3099 } 3100 if (*tableIndex >= codeMeta_.tables.length()) { 3101 return fail("table index out of range for table.fill"); 3102 } 3103 3104 const TableDesc& table = codeMeta_.tables[*tableIndex]; 3105 3106 if (!popWithType(ToValType(table.addressType()), len)) { 3107 return false; 3108 } 3109 if (!popWithType(table.elemType, val)) { 3110 return false; 3111 } 3112 return popWithType(ToValType(table.addressType()), start); 3113 } 3114 3115 template <typename Policy> 3116 inline bool OpIter<Policy>::readMemDiscard(uint32_t* memoryIndex, Value* start, 3117 Value* len) { 3118 MOZ_ASSERT(Classify(op_) == OpKind::MemDiscard); 3119 3120 if (!readVarU32(memoryIndex)) { 3121 return fail("failed to read memory index"); 3122 } 3123 if (*memoryIndex >= codeMeta_.memories.length()) { 3124 return fail("memory index out of range for memory.discard"); 3125 } 3126 3127 ValType ptrType = ToValType(codeMeta_.memories[*memoryIndex].addressType()); 3128 3129 if (!popWithType(ptrType, len)) { 3130 return false; 3131 } 3132 3133 return popWithType(ptrType, start); 3134 } 3135 3136 template <typename Policy> 3137 inline bool OpIter<Policy>::readTableGet(uint32_t* tableIndex, Value* address) { 3138 MOZ_ASSERT(Classify(op_) == OpKind::TableGet); 3139 3140 if (!readVarU32(tableIndex)) { 3141 return fail("unable to read table index"); 3142 } 3143 if (*tableIndex >= codeMeta_.tables.length()) { 3144 return fail("table index out of range for table.get"); 3145 } 3146 3147 const TableDesc& table = codeMeta_.tables[*tableIndex]; 3148 3149 if (!popWithType(ToValType(table.addressType()), address)) { 3150 return false; 3151 } 3152 3153 infalliblePush(table.elemType); 3154 return true; 3155 } 3156 3157 template <typename Policy> 3158 inline bool OpIter<Policy>::readTableGrow(uint32_t* tableIndex, 3159 Value* initValue, Value* delta) { 3160 MOZ_ASSERT(Classify(op_) == OpKind::TableGrow); 3161 3162 if (!readVarU32(tableIndex)) { 3163 return fail("unable to read table index"); 3164 } 3165 if (*tableIndex >= codeMeta_.tables.length()) { 3166 return fail("table index out of range for table.grow"); 3167 } 3168 3169 const TableDesc& table = codeMeta_.tables[*tableIndex]; 3170 3171 if (!popWithType(ToValType(table.addressType()), delta)) { 3172 return false; 3173 } 3174 if (!popWithType(table.elemType, initValue)) { 3175 return false; 3176 } 3177 3178 infalliblePush(ToValType(table.addressType())); 3179 return true; 3180 } 3181 3182 template <typename Policy> 3183 inline bool OpIter<Policy>::readTableSet(uint32_t* tableIndex, Value* address, 3184 Value* value) { 3185 MOZ_ASSERT(Classify(op_) == OpKind::TableSet); 3186 3187 if (!readVarU32(tableIndex)) { 3188 return fail("unable to read table index"); 3189 } 3190 if (*tableIndex >= codeMeta_.tables.length()) { 3191 return fail("table index out of range for table.set"); 3192 } 3193 3194 const TableDesc& table = codeMeta_.tables[*tableIndex]; 3195 3196 if (!popWithType(table.elemType, value)) { 3197 return false; 3198 } 3199 3200 return popWithType(ToValType(table.addressType()), address); 3201 } 3202 3203 template <typename Policy> 3204 inline bool OpIter<Policy>::readTableSize(uint32_t* tableIndex) { 3205 MOZ_ASSERT(Classify(op_) == OpKind::TableSize); 3206 3207 *tableIndex = 0; 3208 3209 if (!readVarU32(tableIndex)) { 3210 return fail("unable to read table index"); 3211 } 3212 if (*tableIndex >= codeMeta_.tables.length()) { 3213 return fail("table index out of range for table.size"); 3214 } 3215 3216 return push(ToValType(codeMeta_.tables[*tableIndex].addressType())); 3217 } 3218 3219 template <typename Policy> 3220 inline bool OpIter<Policy>::readGcTypeIndex(uint32_t* typeIndex) { 3221 if (!d_.readTypeIndex(typeIndex)) { 3222 return false; 3223 } 3224 3225 if (*typeIndex >= codeMeta_.types->length()) { 3226 return fail("type index out of range"); 3227 } 3228 3229 if (!codeMeta_.types->type(*typeIndex).isStructType() && 3230 !codeMeta_.types->type(*typeIndex).isArrayType()) { 3231 return fail("not a gc type"); 3232 } 3233 3234 return true; 3235 } 3236 3237 template <typename Policy> 3238 inline bool OpIter<Policy>::readStructTypeIndex(uint32_t* typeIndex) { 3239 if (!readVarU32(typeIndex)) { 3240 return fail("unable to read type index"); 3241 } 3242 3243 if (*typeIndex >= codeMeta_.types->length()) { 3244 return fail("type index out of range"); 3245 } 3246 3247 if (!codeMeta_.types->type(*typeIndex).isStructType()) { 3248 return fail("not a struct type"); 3249 } 3250 3251 return true; 3252 } 3253 3254 template <typename Policy> 3255 inline bool OpIter<Policy>::readArrayTypeIndex(uint32_t* typeIndex) { 3256 if (!readVarU32(typeIndex)) { 3257 return fail("unable to read type index"); 3258 } 3259 3260 if (*typeIndex >= codeMeta_.types->length()) { 3261 return fail("type index out of range"); 3262 } 3263 3264 if (!codeMeta_.types->type(*typeIndex).isArrayType()) { 3265 return fail("not an array type"); 3266 } 3267 3268 return true; 3269 } 3270 3271 template <typename Policy> 3272 inline bool OpIter<Policy>::readFuncTypeIndex(uint32_t* typeIndex) { 3273 if (!readVarU32(typeIndex)) { 3274 return fail("unable to read type index"); 3275 } 3276 3277 if (*typeIndex >= codeMeta_.types->length()) { 3278 return fail("type index out of range"); 3279 } 3280 3281 if (!codeMeta_.types->type(*typeIndex).isFuncType()) { 3282 return fail("not an func type"); 3283 } 3284 3285 return true; 3286 } 3287 3288 template <typename Policy> 3289 inline bool OpIter<Policy>::readFieldIndex(uint32_t* fieldIndex, 3290 const StructType& structType) { 3291 if (!readVarU32(fieldIndex)) { 3292 return fail("unable to read field index"); 3293 } 3294 3295 if (structType.fields_.length() <= *fieldIndex) { 3296 return fail("field index out of range"); 3297 } 3298 3299 return true; 3300 } 3301 3302 template <typename Policy> 3303 inline bool OpIter<Policy>::readStructNew(uint32_t* typeIndex, 3304 ValueVector* argValues) { 3305 MOZ_ASSERT(Classify(op_) == OpKind::StructNew); 3306 3307 if (!readStructTypeIndex(typeIndex)) { 3308 return false; 3309 } 3310 3311 const TypeDef& typeDef = codeMeta_.types->type(*typeIndex); 3312 const StructType& structType = typeDef.structType(); 3313 3314 if (!argValues->resize(structType.fields_.length())) { 3315 return false; 3316 } 3317 3318 static_assert(MaxStructFields <= INT32_MAX, "Or we iloop below"); 3319 3320 for (int32_t i = structType.fields_.length() - 1; i >= 0; i--) { 3321 if (!popWithType(structType.fields_[i].type.widenToValType(), 3322 &(*argValues)[i])) { 3323 return false; 3324 } 3325 } 3326 3327 return push(RefType::fromTypeDef(&typeDef, false)); 3328 } 3329 3330 template <typename Policy> 3331 inline bool OpIter<Policy>::readStructNewDefault(uint32_t* typeIndex) { 3332 MOZ_ASSERT(Classify(op_) == OpKind::StructNewDefault); 3333 3334 if (!readStructTypeIndex(typeIndex)) { 3335 return false; 3336 } 3337 3338 const TypeDef& typeDef = codeMeta_.types->type(*typeIndex); 3339 const StructType& structType = typeDef.structType(); 3340 3341 if (!structType.isDefaultable()) { 3342 return fail("struct must be defaultable"); 3343 } 3344 3345 return push(RefType::fromTypeDef(&typeDef, false)); 3346 } 3347 3348 template <typename Policy> 3349 inline bool OpIter<Policy>::readStructGet(uint32_t* typeIndex, 3350 uint32_t* fieldIndex, 3351 FieldWideningOp wideningOp, 3352 Value* ptr) { 3353 MOZ_ASSERT(typeIndex != fieldIndex); 3354 MOZ_ASSERT(Classify(op_) == OpKind::StructGet); 3355 3356 if (!readStructTypeIndex(typeIndex)) { 3357 return false; 3358 } 3359 3360 const TypeDef& typeDef = codeMeta_.types->type(*typeIndex); 3361 const StructType& structType = typeDef.structType(); 3362 3363 if (!readFieldIndex(fieldIndex, structType)) { 3364 return false; 3365 } 3366 3367 if (!popWithType(RefType::fromTypeDef(&typeDef, true), ptr)) { 3368 return false; 3369 } 3370 3371 StorageType StorageType = structType.fields_[*fieldIndex].type; 3372 3373 if (StorageType.isValType() && wideningOp != FieldWideningOp::None) { 3374 return fail("must not specify signedness for unpacked field type"); 3375 } 3376 3377 if (!StorageType.isValType() && wideningOp == FieldWideningOp::None) { 3378 return fail("must specify signedness for packed field type"); 3379 } 3380 3381 return push(StorageType.widenToValType()); 3382 } 3383 3384 template <typename Policy> 3385 inline bool OpIter<Policy>::readStructSet(uint32_t* typeIndex, 3386 uint32_t* fieldIndex, Value* ptr, 3387 Value* val) { 3388 MOZ_ASSERT(typeIndex != fieldIndex); 3389 MOZ_ASSERT(Classify(op_) == OpKind::StructSet); 3390 3391 if (!readStructTypeIndex(typeIndex)) { 3392 return false; 3393 } 3394 3395 const TypeDef& typeDef = codeMeta_.types->type(*typeIndex); 3396 const StructType& structType = typeDef.structType(); 3397 3398 if (!readFieldIndex(fieldIndex, structType)) { 3399 return false; 3400 } 3401 3402 if (!popWithType(structType.fields_[*fieldIndex].type.widenToValType(), 3403 val)) { 3404 return false; 3405 } 3406 3407 if (!structType.fields_[*fieldIndex].isMutable) { 3408 return fail("field is not mutable"); 3409 } 3410 3411 return popWithType(RefType::fromTypeDef(&typeDef, true), ptr); 3412 } 3413 3414 template <typename Policy> 3415 inline bool OpIter<Policy>::readArrayNew(uint32_t* typeIndex, 3416 Value* numElements, Value* argValue) { 3417 MOZ_ASSERT(Classify(op_) == OpKind::ArrayNew); 3418 3419 if (!readArrayTypeIndex(typeIndex)) { 3420 return false; 3421 } 3422 3423 const TypeDef& typeDef = codeMeta_.types->type(*typeIndex); 3424 const ArrayType& arrayType = typeDef.arrayType(); 3425 3426 if (!popWithType(ValType::I32, numElements)) { 3427 return false; 3428 } 3429 3430 if (!popWithType(arrayType.elementType().widenToValType(), argValue)) { 3431 return false; 3432 } 3433 3434 return push(RefType::fromTypeDef(&typeDef, false)); 3435 } 3436 3437 template <typename Policy> 3438 inline bool OpIter<Policy>::readArrayNewFixed(uint32_t* typeIndex, 3439 uint32_t* numElements, 3440 ValueVector* values) { 3441 MOZ_ASSERT(Classify(op_) == OpKind::ArrayNewFixed); 3442 MOZ_ASSERT(values->length() == 0); 3443 3444 if (!readArrayTypeIndex(typeIndex)) { 3445 return false; 3446 } 3447 3448 const TypeDef& typeDef = codeMeta_.types->type(*typeIndex); 3449 const ArrayType& arrayType = typeDef.arrayType(); 3450 3451 if (!readVarU32(numElements)) { 3452 return false; 3453 } 3454 3455 if (*numElements > MaxArrayNewFixedElements) { 3456 return fail("too many array.new_fixed elements"); 3457 } 3458 3459 if (!values->reserve(*numElements)) { 3460 return false; 3461 } 3462 3463 ValType widenedElementType = arrayType.elementType().widenToValType(); 3464 for (uint32_t i = 0; i < *numElements; i++) { 3465 Value v; 3466 if (!popWithType(widenedElementType, &v)) { 3467 return false; 3468 } 3469 values->infallibleAppend(v); 3470 } 3471 3472 return push(RefType::fromTypeDef(&typeDef, false)); 3473 } 3474 3475 template <typename Policy> 3476 inline bool OpIter<Policy>::readArrayNewDefault(uint32_t* typeIndex, 3477 Value* numElements) { 3478 MOZ_ASSERT(Classify(op_) == OpKind::ArrayNewDefault); 3479 3480 if (!readArrayTypeIndex(typeIndex)) { 3481 return false; 3482 } 3483 3484 const TypeDef& typeDef = codeMeta_.types->type(*typeIndex); 3485 const ArrayType& arrayType = typeDef.arrayType(); 3486 3487 if (!popWithType(ValType::I32, numElements)) { 3488 return false; 3489 } 3490 3491 if (!arrayType.elementType().isDefaultable()) { 3492 return fail("array must be defaultable"); 3493 } 3494 3495 return push(RefType::fromTypeDef(&typeDef, false)); 3496 } 3497 3498 template <typename Policy> 3499 inline bool OpIter<Policy>::readArrayNewData(uint32_t* typeIndex, 3500 uint32_t* segIndex, Value* offset, 3501 Value* numElements) { 3502 MOZ_ASSERT(Classify(op_) == OpKind::ArrayNewData); 3503 3504 if (!readArrayTypeIndex(typeIndex)) { 3505 return false; 3506 } 3507 3508 if (!readVarU32(segIndex)) { 3509 return fail("unable to read segment index"); 3510 } 3511 3512 const TypeDef& typeDef = codeMeta_.types->type(*typeIndex); 3513 const ArrayType& arrayType = typeDef.arrayType(); 3514 StorageType elemType = arrayType.elementType(); 3515 if (!elemType.isNumber() && !elemType.isPacked() && !elemType.isVector()) { 3516 return fail("element type must be i8/i16/i32/i64/f32/f64/v128"); 3517 } 3518 if (codeMeta_.dataCount.isNothing()) { 3519 return fail("datacount section missing"); 3520 } 3521 if (*segIndex >= *codeMeta_.dataCount) { 3522 return fail("segment index is out of range"); 3523 } 3524 3525 if (!popWithType(ValType::I32, numElements)) { 3526 return false; 3527 } 3528 if (!popWithType(ValType::I32, offset)) { 3529 return false; 3530 } 3531 3532 return push(RefType::fromTypeDef(&typeDef, false)); 3533 } 3534 3535 template <typename Policy> 3536 inline bool OpIter<Policy>::readArrayNewElem(uint32_t* typeIndex, 3537 uint32_t* segIndex, Value* offset, 3538 Value* numElements) { 3539 MOZ_ASSERT(Classify(op_) == OpKind::ArrayNewElem); 3540 3541 if (!readArrayTypeIndex(typeIndex)) { 3542 return false; 3543 } 3544 3545 if (!readVarU32(segIndex)) { 3546 return fail("unable to read segment index"); 3547 } 3548 3549 const TypeDef& typeDef = codeMeta_.types->type(*typeIndex); 3550 const ArrayType& arrayType = typeDef.arrayType(); 3551 StorageType dstElemType = arrayType.elementType(); 3552 if (!dstElemType.isRefType()) { 3553 return fail("element type is not a reftype"); 3554 } 3555 if (*segIndex >= codeMeta_.elemSegmentTypes.length()) { 3556 return fail("segment index is out of range"); 3557 } 3558 3559 RefType srcElemType = codeMeta_.elemSegmentTypes[*segIndex]; 3560 // srcElemType needs to be a subtype (child) of dstElemType 3561 if (!checkIsSubtypeOf(srcElemType, dstElemType.refType())) { 3562 return fail("incompatible element types"); 3563 } 3564 3565 if (!popWithType(ValType::I32, numElements)) { 3566 return false; 3567 } 3568 if (!popWithType(ValType::I32, offset)) { 3569 return false; 3570 } 3571 3572 return push(RefType::fromTypeDef(&typeDef, false)); 3573 } 3574 3575 template <typename Policy> 3576 inline bool OpIter<Policy>::readArrayInitData(uint32_t* typeIndex, 3577 uint32_t* segIndex, Value* array, 3578 Value* arrayIndex, 3579 Value* segOffset, Value* length) { 3580 MOZ_ASSERT(Classify(op_) == OpKind::ArrayInitData); 3581 3582 if (!readArrayTypeIndex(typeIndex)) { 3583 return false; 3584 } 3585 3586 if (!readVarU32(segIndex)) { 3587 return fail("unable to read segment index"); 3588 } 3589 3590 const TypeDef& typeDef = codeMeta_.types->type(*typeIndex); 3591 const ArrayType& arrayType = typeDef.arrayType(); 3592 StorageType elemType = arrayType.elementType(); 3593 if (!elemType.isNumber() && !elemType.isPacked() && !elemType.isVector()) { 3594 return fail("element type must be i8/i16/i32/i64/f32/f64/v128"); 3595 } 3596 if (!arrayType.isMutable()) { 3597 return fail("destination array is not mutable"); 3598 } 3599 if (codeMeta_.dataCount.isNothing()) { 3600 return fail("datacount section missing"); 3601 } 3602 if (*segIndex >= *codeMeta_.dataCount) { 3603 return fail("segment index is out of range"); 3604 } 3605 3606 if (!popWithType(ValType::I32, length)) { 3607 return false; 3608 } 3609 if (!popWithType(ValType::I32, segOffset)) { 3610 return false; 3611 } 3612 if (!popWithType(ValType::I32, arrayIndex)) { 3613 return false; 3614 } 3615 return popWithType(RefType::fromTypeDef(&typeDef, true), array); 3616 } 3617 3618 template <typename Policy> 3619 inline bool OpIter<Policy>::readArrayInitElem(uint32_t* typeIndex, 3620 uint32_t* segIndex, Value* array, 3621 Value* arrayIndex, 3622 Value* segOffset, Value* length) { 3623 MOZ_ASSERT(Classify(op_) == OpKind::ArrayInitElem); 3624 3625 if (!readArrayTypeIndex(typeIndex)) { 3626 return false; 3627 } 3628 3629 if (!readVarU32(segIndex)) { 3630 return fail("unable to read segment index"); 3631 } 3632 3633 const TypeDef& typeDef = codeMeta_.types->type(*typeIndex); 3634 const ArrayType& arrayType = typeDef.arrayType(); 3635 StorageType dstElemType = arrayType.elementType(); 3636 if (!arrayType.isMutable()) { 3637 return fail("destination array is not mutable"); 3638 } 3639 if (!dstElemType.isRefType()) { 3640 return fail("element type is not a reftype"); 3641 } 3642 if (*segIndex >= codeMeta_.elemSegmentTypes.length()) { 3643 return fail("segment index is out of range"); 3644 } 3645 3646 RefType srcElemType = codeMeta_.elemSegmentTypes[*segIndex]; 3647 // srcElemType needs to be a subtype (child) of dstElemType 3648 if (!checkIsSubtypeOf(srcElemType, dstElemType.refType())) { 3649 return fail("incompatible element types"); 3650 } 3651 3652 if (!popWithType(ValType::I32, length)) { 3653 return false; 3654 } 3655 if (!popWithType(ValType::I32, segOffset)) { 3656 return false; 3657 } 3658 if (!popWithType(ValType::I32, arrayIndex)) { 3659 return false; 3660 } 3661 return popWithType(RefType::fromTypeDef(&typeDef, true), array); 3662 } 3663 3664 template <typename Policy> 3665 inline bool OpIter<Policy>::readArrayGet(uint32_t* typeIndex, 3666 FieldWideningOp wideningOp, 3667 Value* index, Value* ptr) { 3668 MOZ_ASSERT(Classify(op_) == OpKind::ArrayGet); 3669 3670 if (!readArrayTypeIndex(typeIndex)) { 3671 return false; 3672 } 3673 3674 const TypeDef& typeDef = codeMeta_.types->type(*typeIndex); 3675 const ArrayType& arrayType = typeDef.arrayType(); 3676 3677 if (!popWithType(ValType::I32, index)) { 3678 return false; 3679 } 3680 3681 if (!popWithType(RefType::fromTypeDef(&typeDef, true), ptr)) { 3682 return false; 3683 } 3684 3685 StorageType elementType = arrayType.elementType(); 3686 3687 if (elementType.isValType() && wideningOp != FieldWideningOp::None) { 3688 return fail("must not specify signedness for unpacked element type"); 3689 } 3690 3691 if (!elementType.isValType() && wideningOp == FieldWideningOp::None) { 3692 return fail("must specify signedness for packed element type"); 3693 } 3694 3695 return push(elementType.widenToValType()); 3696 } 3697 3698 template <typename Policy> 3699 inline bool OpIter<Policy>::readArraySet(uint32_t* typeIndex, Value* val, 3700 Value* index, Value* ptr) { 3701 MOZ_ASSERT(Classify(op_) == OpKind::ArraySet); 3702 3703 if (!readArrayTypeIndex(typeIndex)) { 3704 return false; 3705 } 3706 3707 const TypeDef& typeDef = codeMeta_.types->type(*typeIndex); 3708 const ArrayType& arrayType = typeDef.arrayType(); 3709 3710 if (!arrayType.isMutable()) { 3711 return fail("array is not mutable"); 3712 } 3713 3714 if (!popWithType(arrayType.elementType().widenToValType(), val)) { 3715 return false; 3716 } 3717 3718 if (!popWithType(ValType::I32, index)) { 3719 return false; 3720 } 3721 3722 return popWithType(RefType::fromTypeDef(&typeDef, true), ptr); 3723 } 3724 3725 template <typename Policy> 3726 inline bool OpIter<Policy>::readArrayLen(Value* ptr) { 3727 MOZ_ASSERT(Classify(op_) == OpKind::ArrayLen); 3728 3729 if (!popWithType(RefType::array(), ptr)) { 3730 return false; 3731 } 3732 3733 return push(ValType::I32); 3734 } 3735 3736 template <typename Policy> 3737 inline bool OpIter<Policy>::readArrayCopy(uint32_t* dstArrayTypeIndex, 3738 uint32_t* srcArrayTypeIndex, 3739 Value* dstArray, Value* dstIndex, 3740 Value* srcArray, Value* srcIndex, 3741 Value* numElements) { 3742 MOZ_ASSERT(Classify(op_) == OpKind::ArrayCopy); 3743 3744 if (!readArrayTypeIndex(dstArrayTypeIndex)) { 3745 return false; 3746 } 3747 if (!readArrayTypeIndex(srcArrayTypeIndex)) { 3748 return false; 3749 } 3750 3751 // `dstArrayTypeIndex`/`srcArrayTypeIndex` are ensured by the above to both be 3752 // array types. Reject if: 3753 // * the dst array is not of mutable type 3754 // * the element types are incompatible 3755 const TypeDef& dstTypeDef = codeMeta_.types->type(*dstArrayTypeIndex); 3756 const ArrayType& dstArrayType = dstTypeDef.arrayType(); 3757 const TypeDef& srcTypeDef = codeMeta_.types->type(*srcArrayTypeIndex); 3758 const ArrayType& srcArrayType = srcTypeDef.arrayType(); 3759 StorageType dstElemType = dstArrayType.elementType(); 3760 StorageType srcElemType = srcArrayType.elementType(); 3761 if (!dstArrayType.isMutable()) { 3762 return fail("destination array is not mutable"); 3763 } 3764 3765 if (!checkIsSubtypeOf(srcElemType, dstElemType)) { 3766 return fail("incompatible element types"); 3767 } 3768 MOZ_ASSERT(dstElemType.isRefType() == srcElemType.isRefType()); 3769 3770 if (!popWithType(ValType::I32, numElements)) { 3771 return false; 3772 } 3773 if (!popWithType(ValType::I32, srcIndex)) { 3774 return false; 3775 } 3776 if (!popWithType(RefType::fromTypeDef(&srcTypeDef, true), srcArray)) { 3777 return false; 3778 } 3779 if (!popWithType(ValType::I32, dstIndex)) { 3780 return false; 3781 } 3782 3783 return popWithType(RefType::fromTypeDef(&dstTypeDef, true), dstArray); 3784 } 3785 3786 template <typename Policy> 3787 inline bool OpIter<Policy>::readArrayFill(uint32_t* typeIndex, Value* array, 3788 Value* index, Value* val, 3789 Value* length) { 3790 MOZ_ASSERT(Classify(op_) == OpKind::ArrayFill); 3791 3792 if (!readArrayTypeIndex(typeIndex)) { 3793 return false; 3794 } 3795 3796 const TypeDef& typeDef = codeMeta_.types->type(*typeIndex); 3797 const ArrayType& arrayType = typeDef.arrayType(); 3798 if (!arrayType.isMutable()) { 3799 return fail("destination array is not mutable"); 3800 } 3801 3802 if (!popWithType(ValType::I32, length)) { 3803 return false; 3804 } 3805 if (!popWithType(arrayType.elementType().widenToValType(), val)) { 3806 return false; 3807 } 3808 if (!popWithType(ValType::I32, index)) { 3809 return false; 3810 } 3811 3812 return popWithType(RefType::fromTypeDef(&typeDef, true), array); 3813 } 3814 3815 template <typename Policy> 3816 inline bool OpIter<Policy>::readRefTest(bool nullable, RefType* sourceType, 3817 RefType* destType, Value* ref) { 3818 MOZ_ASSERT(Classify(op_) == OpKind::RefTest); 3819 3820 if (!readHeapType(nullable, destType)) { 3821 return false; 3822 } 3823 3824 StackType inputType; 3825 if (!popWithType(destType->topType(), ref, &inputType)) { 3826 return false; 3827 } 3828 *sourceType = inputType.valTypeOr(RefType::any()).refType(); 3829 3830 return push(ValType(ValType::I32)); 3831 } 3832 3833 template <typename Policy> 3834 inline bool OpIter<Policy>::readRefCast(bool nullable, RefType* sourceType, 3835 RefType* destType, Value* ref) { 3836 MOZ_ASSERT(Classify(op_) == OpKind::RefCast); 3837 3838 if (!readHeapType(nullable, destType)) { 3839 return false; 3840 } 3841 3842 StackType inputType; 3843 if (!popWithType(destType->topType(), ref, &inputType)) { 3844 return false; 3845 } 3846 *sourceType = inputType.valTypeOr(RefType::any()).refType(); 3847 3848 return push(*destType); 3849 } 3850 3851 // `br_on_cast <flags> <labelRelativeDepth> <rt1> <rt2>` 3852 // branches if a reference has a given heap type. 3853 // 3854 // V6 spec text follows - note that br_on_cast and br_on_cast_fail are both 3855 // handled by this function (disambiguated by a flag). 3856 // 3857 // * `br_on_cast <labelidx> <reftype> <reftype>` branches if a reference has a 3858 // given type 3859 // - `br_on_cast $l rt1 rt2 : [t0* rt1] -> [t0* rt1\rt2]` 3860 // - iff `$l : [t0* rt2]` 3861 // - and `rt2 <: rt1` 3862 // - passes operand along with branch under target type, plus possible extra 3863 // args 3864 // - if `rt2` contains `null`, branches on null, otherwise does not 3865 // * `br_on_cast_fail <labelidx> <reftype> <reftype>` branches if a reference 3866 // does not have a given type 3867 // - `br_on_cast_fail $l rt1 rt2 : [t0* rt1] -> [t0* rt2]` 3868 // - iff `$l : [t0* rt1\rt2]` 3869 // - and `rt2 <: rt1` 3870 // - passes operand along with branch, plus possible extra args 3871 // - if `rt2` contains `null`, does not branch on null, otherwise does 3872 // where: 3873 // - `(ref null1? ht1)\(ref null ht2) = (ref ht1)` 3874 // - `(ref null1? ht1)\(ref ht2) = (ref null1? ht1)` 3875 // 3876 // The `rt1\rt2` syntax is a "diff" - it is basically rt1 minus rt2, because a 3877 // successful cast to rt2 will branch away. So if rt2 allows null, the result 3878 // after a non-branch will be non-null; on the other hand, if rt2 is 3879 // non-nullable, the cast will have nothing to say about nullability and the 3880 // nullability of rt1 will be preserved. 3881 // 3882 // `values` will be nonempty after the call, and its last entry will be the 3883 // type that causes a branch (rt1\rt2 or rt2, depending). 3884 3885 enum class BrOnCastFlags : uint8_t { 3886 SourceNullable = 0x1, 3887 DestNullable = 0x1 << 1, 3888 AllowedMask = uint8_t(SourceNullable) | uint8_t(DestNullable), 3889 }; 3890 3891 template <typename Policy> 3892 inline bool OpIter<Policy>::readBrOnCast(bool onSuccess, 3893 uint32_t* labelRelativeDepth, 3894 RefType* sourceType, RefType* destType, 3895 ResultType* labelType, 3896 ValueVector* values) { 3897 MOZ_ASSERT(Classify(op_) == OpKind::BrOnCast); 3898 3899 uint8_t flags; 3900 if (!readFixedU8(&flags)) { 3901 return fail("unable to read br_on_cast flags"); 3902 } 3903 if ((flags & ~uint8_t(BrOnCastFlags::AllowedMask)) != 0) { 3904 return fail("invalid br_on_cast flags"); 3905 } 3906 bool sourceNullable = flags & uint8_t(BrOnCastFlags::SourceNullable); 3907 bool destNullable = flags & uint8_t(BrOnCastFlags::DestNullable); 3908 3909 if (!readVarU32(labelRelativeDepth)) { 3910 return fail("unable to read br_on_cast depth"); 3911 } 3912 3913 // This is distinct from the actual source type we pop from the stack, which 3914 // can be more specific and allow for better optimizations. 3915 RefType immediateSourceType; 3916 if (!readHeapType(sourceNullable, &immediateSourceType)) { 3917 return fail("unable to read br_on_cast source type"); 3918 } 3919 3920 if (!readHeapType(destNullable, destType)) { 3921 return fail("unable to read br_on_cast dest type"); 3922 } 3923 3924 // Check that source and destination types are compatible 3925 if (!checkIsSubtypeOf(*destType, immediateSourceType)) { 3926 return fail( 3927 "type mismatch: source and destination types for cast are " 3928 "incompatible"); 3929 } 3930 3931 RefType typeOnSuccess = *destType; 3932 // This is rt1\rt2 3933 RefType typeOnFail = 3934 destNullable ? immediateSourceType.asNonNullable() : immediateSourceType; 3935 RefType typeOnBranch = onSuccess ? typeOnSuccess : typeOnFail; 3936 RefType typeOnFallthrough = onSuccess ? typeOnFail : typeOnSuccess; 3937 3938 // Get the branch target type, which will also determine the type of extra 3939 // values that are passed along on branch. 3940 Control* block = nullptr; 3941 if (!getControl(*labelRelativeDepth, &block)) { 3942 return false; 3943 } 3944 *labelType = block->branchTargetType(); 3945 3946 // Check we have at least one value slot in the branch target type, so as to 3947 // receive the casted or non-casted type when we branch. 3948 const size_t labelTypeNumValues = labelType->length(); 3949 if (labelTypeNumValues < 1) { 3950 return fail("type mismatch: branch target type has no value types"); 3951 } 3952 3953 // The last value slot in the branch target type is what is being cast. 3954 // This slot is guaranteed to exist by the above check. 3955 3956 // Check that the branch target type can accept typeOnBranch. 3957 if (!checkIsSubtypeOf(typeOnBranch, (*labelType)[labelTypeNumValues - 1])) { 3958 return false; 3959 } 3960 3961 // Replace the top operand with the result of falling through. Even branching 3962 // on success can change the type on top of the stack on fallthrough. 3963 Value inputValue; 3964 StackType inputType; 3965 if (!popWithType(immediateSourceType, &inputValue, &inputType)) { 3966 return false; 3967 } 3968 *sourceType = inputType.valTypeOr(immediateSourceType).refType(); 3969 infalliblePush(TypeAndValue(typeOnFallthrough, inputValue)); 3970 3971 // Create a copy of the branch target type, with the relevant value slot 3972 // replaced by typeOnFallthrough. 3973 ValTypeVector fallthroughTypes; 3974 if (!labelType->cloneToVector(&fallthroughTypes)) { 3975 return false; 3976 } 3977 fallthroughTypes[labelTypeNumValues - 1] = typeOnFallthrough; 3978 3979 return checkTopTypeMatches(ResultType::Vector(fallthroughTypes), values, 3980 /*rewriteStackTypes=*/true); 3981 } 3982 3983 template <typename Policy> 3984 inline bool OpIter<Policy>::readRefConversion(RefType operandType, 3985 RefType resultType, 3986 Value* operandValue) { 3987 MOZ_ASSERT(Classify(op_) == OpKind::RefConversion); 3988 3989 StackType actualOperandType; 3990 if (!popWithType(ValType(operandType), operandValue, &actualOperandType)) { 3991 return false; 3992 } 3993 3994 // The result nullability is the same as the operand nullability 3995 bool outputNullable = actualOperandType.isNullableAsOperand(); 3996 infalliblePush(ValType(resultType.withIsNullable(outputNullable))); 3997 return true; 3998 } 3999 4000 #ifdef ENABLE_WASM_SIMD 4001 4002 template <typename Policy> 4003 inline bool OpIter<Policy>::readLaneIndex(uint32_t inputLanes, 4004 uint32_t* laneIndex) { 4005 uint8_t tmp; 4006 if (!readFixedU8(&tmp)) { 4007 return false; // Caller signals error 4008 } 4009 if (tmp >= inputLanes) { 4010 return false; 4011 } 4012 *laneIndex = tmp; 4013 return true; 4014 } 4015 4016 template <typename Policy> 4017 inline bool OpIter<Policy>::readExtractLane(ValType resultType, 4018 uint32_t inputLanes, 4019 uint32_t* laneIndex, Value* input) { 4020 MOZ_ASSERT(Classify(op_) == OpKind::ExtractLane); 4021 4022 if (!readLaneIndex(inputLanes, laneIndex)) { 4023 return fail("missing or invalid extract_lane lane index"); 4024 } 4025 4026 if (!popWithType(ValType::V128, input)) { 4027 return false; 4028 } 4029 4030 infalliblePush(resultType); 4031 4032 return true; 4033 } 4034 4035 template <typename Policy> 4036 inline bool OpIter<Policy>::readReplaceLane(ValType operandType, 4037 uint32_t inputLanes, 4038 uint32_t* laneIndex, 4039 Value* baseValue, Value* operand) { 4040 MOZ_ASSERT(Classify(op_) == OpKind::ReplaceLane); 4041 4042 if (!readLaneIndex(inputLanes, laneIndex)) { 4043 return fail("missing or invalid replace_lane lane index"); 4044 } 4045 4046 if (!popWithType(operandType, operand)) { 4047 return false; 4048 } 4049 4050 if (!popWithType(ValType::V128, baseValue)) { 4051 return false; 4052 } 4053 4054 infalliblePush(ValType::V128); 4055 4056 return true; 4057 } 4058 4059 template <typename Policy> 4060 inline bool OpIter<Policy>::readVectorShift(Value* baseValue, Value* shift) { 4061 MOZ_ASSERT(Classify(op_) == OpKind::VectorShift); 4062 4063 if (!popWithType(ValType::I32, shift)) { 4064 return false; 4065 } 4066 4067 if (!popWithType(ValType::V128, baseValue)) { 4068 return false; 4069 } 4070 4071 infalliblePush(ValType::V128); 4072 4073 return true; 4074 } 4075 4076 template <typename Policy> 4077 inline bool OpIter<Policy>::readVectorShuffle(Value* v1, Value* v2, 4078 V128* selectMask) { 4079 MOZ_ASSERT(Classify(op_) == OpKind::VectorShuffle); 4080 4081 for (unsigned char& byte : selectMask->bytes) { 4082 uint8_t tmp; 4083 if (!readFixedU8(&tmp)) { 4084 return fail("unable to read shuffle index"); 4085 } 4086 if (tmp > 31) { 4087 return fail("shuffle index out of range"); 4088 } 4089 byte = tmp; 4090 } 4091 4092 if (!popWithType(ValType::V128, v2)) { 4093 return false; 4094 } 4095 4096 if (!popWithType(ValType::V128, v1)) { 4097 return false; 4098 } 4099 4100 infalliblePush(ValType::V128); 4101 4102 return true; 4103 } 4104 4105 template <typename Policy> 4106 inline bool OpIter<Policy>::readV128Const(V128* value) { 4107 MOZ_ASSERT(Classify(op_) == OpKind::V128Const); 4108 4109 if (!d_.readV128Const(value)) { 4110 return false; 4111 } 4112 4113 return push(ValType::V128); 4114 } 4115 4116 template <typename Policy> 4117 inline bool OpIter<Policy>::readLoadSplat(uint32_t byteSize, 4118 LinearMemoryAddress<Value>* addr) { 4119 MOZ_ASSERT(Classify(op_) == OpKind::Load); 4120 4121 if (!readLinearMemoryAddress(byteSize, addr)) { 4122 return false; 4123 } 4124 4125 infalliblePush(ValType::V128); 4126 4127 return true; 4128 } 4129 4130 template <typename Policy> 4131 inline bool OpIter<Policy>::readLoadExtend(LinearMemoryAddress<Value>* addr) { 4132 MOZ_ASSERT(Classify(op_) == OpKind::Load); 4133 4134 if (!readLinearMemoryAddress(/*byteSize=*/8, addr)) { 4135 return false; 4136 } 4137 4138 infalliblePush(ValType::V128); 4139 4140 return true; 4141 } 4142 4143 template <typename Policy> 4144 inline bool OpIter<Policy>::readLoadLane(uint32_t byteSize, 4145 LinearMemoryAddress<Value>* addr, 4146 uint32_t* laneIndex, Value* input) { 4147 MOZ_ASSERT(Classify(op_) == OpKind::LoadLane); 4148 4149 if (!popWithType(ValType::V128, input)) { 4150 return false; 4151 } 4152 4153 if (!readLinearMemoryAddress(byteSize, addr)) { 4154 return false; 4155 } 4156 4157 uint32_t inputLanes = 16 / byteSize; 4158 if (!readLaneIndex(inputLanes, laneIndex)) { 4159 return fail("missing or invalid load_lane lane index"); 4160 } 4161 4162 infalliblePush(ValType::V128); 4163 4164 return true; 4165 } 4166 4167 template <typename Policy> 4168 inline bool OpIter<Policy>::readStoreLane(uint32_t byteSize, 4169 LinearMemoryAddress<Value>* addr, 4170 uint32_t* laneIndex, Value* input) { 4171 MOZ_ASSERT(Classify(op_) == OpKind::StoreLane); 4172 4173 if (!popWithType(ValType::V128, input)) { 4174 return false; 4175 } 4176 4177 if (!readLinearMemoryAddress(byteSize, addr)) { 4178 return false; 4179 } 4180 4181 uint32_t inputLanes = 16 / byteSize; 4182 if (!readLaneIndex(inputLanes, laneIndex)) { 4183 return fail("missing or invalid store_lane lane index"); 4184 } 4185 4186 return true; 4187 } 4188 4189 #endif // ENABLE_WASM_SIMD 4190 4191 #ifdef ENABLE_WASM_JSPI 4192 template <typename Policy> 4193 inline bool OpIter<Policy>::readStackSwitch(StackSwitchKind* kind, 4194 Value* suspender, Value* fn, 4195 Value* data) { 4196 MOZ_ASSERT(Classify(op_) == OpKind::StackSwitch); 4197 MOZ_ASSERT(codeMeta_.jsPromiseIntegrationEnabled()); 4198 uint32_t kind_; 4199 if (!d_.readVarU32(&kind_)) { 4200 return false; 4201 } 4202 *kind = StackSwitchKind(kind_); 4203 if (!popWithType(ValType(RefType::any()), data)) { 4204 return false; 4205 } 4206 StackType stackType; 4207 if (!popWithType(ValType(RefType::func()), fn, &stackType)) { 4208 return false; 4209 } 4210 # if DEBUG 4211 // Verify that the function takes suspender and data as parameters. 4212 MOZ_ASSERT((*kind == StackSwitchKind::ContinueOnSuspendable) == 4213 stackType.isNullableAsOperand()); 4214 if (!stackType.isNullableAsOperand()) { 4215 ValType valType = stackType.valType(); 4216 MOZ_ASSERT(valType.isRefType() && valType.typeDef()->isFuncType()); 4217 const FuncType& func = valType.typeDef()->funcType(); 4218 MOZ_ASSERT(func.args().length() == 2 && func.arg(0).isExternRef() && 4219 ValType::isSubTypeOf(func.arg(1), RefType::any())); 4220 MOZ_ASSERT_IF(*kind != StackSwitchKind::SwitchToMain, 4221 func.results().empty()); 4222 MOZ_ASSERT_IF(*kind == StackSwitchKind::SwitchToMain, 4223 func.results().length() == 1 && func.result(0).isAnyRef()); 4224 } 4225 # endif 4226 if (!popWithType(ValType(RefType::extern_()), suspender)) { 4227 return false; 4228 } 4229 // Returns a value only for SwitchToMain. 4230 if (*kind == StackSwitchKind::SwitchToMain) { 4231 return push(RefType::extern_()); 4232 } 4233 return true; 4234 } 4235 #endif 4236 4237 template <typename Policy> 4238 inline bool OpIter<Policy>::readCallBuiltinModuleFunc( 4239 const BuiltinModuleFunc** builtinModuleFunc, ValueVector* params) { 4240 MOZ_ASSERT(Classify(op_) == OpKind::CallBuiltinModuleFunc); 4241 4242 uint32_t id; 4243 if (!d_.readVarU32(&id)) { 4244 return false; 4245 } 4246 4247 if (id >= uint32_t(BuiltinModuleFuncId::Limit)) { 4248 return fail("index out of range"); 4249 } 4250 4251 *builtinModuleFunc = &BuiltinModuleFuncs::getFromId(BuiltinModuleFuncId(id)); 4252 4253 if ((*builtinModuleFunc)->usesMemory() && codeMeta_.numMemories() == 0) { 4254 return fail("can't touch memory without memory"); 4255 } 4256 4257 const FuncType& funcType = *(*builtinModuleFunc)->funcType(); 4258 if (!popCallArgs(funcType.args(), params)) { 4259 return false; 4260 } 4261 4262 return push(ResultType::Vector(funcType.results())); 4263 } 4264 4265 } // namespace wasm 4266 } // namespace js 4267 4268 static_assert(std::is_trivially_copyable< 4269 js::wasm::TypeAndValueT<mozilla::Nothing>>::value, 4270 "Must be trivially copyable"); 4271 static_assert(std::is_trivially_destructible< 4272 js::wasm::TypeAndValueT<mozilla::Nothing>>::value, 4273 "Must be trivially destructible"); 4274 4275 static_assert(std::is_trivially_copyable< 4276 js::wasm::ControlStackEntry<mozilla::Nothing>>::value, 4277 "Must be trivially copyable"); 4278 static_assert(std::is_trivially_destructible< 4279 js::wasm::ControlStackEntry<mozilla::Nothing>>::value, 4280 "Must be trivially destructible"); 4281 4282 #endif // wasm_op_iter_h