WarpBuilderShared.cpp (4418B)
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 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "jit/WarpBuilderShared.h" 8 9 #include "jit/MIRGenerator.h" 10 #include "jit/MIRGraph.h" 11 12 using namespace js; 13 using namespace js::jit; 14 15 WarpBuilderShared::WarpBuilderShared(WarpSnapshot& snapshot, 16 MIRGenerator& mirGen, 17 MBasicBlock* current_) 18 : snapshot_(snapshot), 19 mirGen_(mirGen), 20 alloc_(mirGen.alloc()), 21 current(current_) {} 22 23 bool WarpBuilderShared::resumeAfter(MInstruction* ins, BytecodeLocation loc) { 24 // resumeAfter should only be used with effectful instructions. The only 25 // exceptions are: 26 // 1. MInt64ToBigInt, which is used to convert the result of either a call 27 // into Wasm code or loading from a BigIntArray, so we attach the resume 28 // point to that instead of to the call resp. load. 29 // 2. MPostIntPtrConversion which is used after conversion from IntPtr. 30 MOZ_ASSERT(ins->isEffectful() || ins->isInt64ToBigInt() || 31 ins->isPostIntPtrConversion()); 32 MOZ_ASSERT(!ins->isMovable()); 33 34 MResumePoint* resumePoint = MResumePoint::New( 35 alloc(), ins->block(), loc.toRawBytecode(), ResumeMode::ResumeAfter); 36 if (!resumePoint) { 37 return false; 38 } 39 40 ins->setResumePoint(resumePoint); 41 return true; 42 } 43 44 MConstant* WarpBuilderShared::constant(const Value& v) { 45 MOZ_ASSERT_IF(v.isString(), v.toString()->isLinear()); 46 MOZ_ASSERT_IF(v.isGCThing(), !IsInsideNursery(v.toGCThing())); 47 48 MConstant* cst = MConstant::New(alloc(), v); 49 current->add(cst); 50 return cst; 51 } 52 53 void WarpBuilderShared::pushConstant(const Value& v) { 54 MConstant* cst = constant(v); 55 current->push(cst); 56 } 57 58 MDefinition* WarpBuilderShared::unboxObjectInfallible(MDefinition* def, 59 IsMovable movable) { 60 if (def->type() == MIRType::Object) { 61 return def; 62 } 63 64 if (def->type() != MIRType::Value) { 65 // Corner case: if the MIR node has a type other than Object or Value, this 66 // code isn't actually reachable and we expect an earlier guard to fail. 67 // Just insert a Box to satisfy MIR invariants. 68 MOZ_ASSERT(movable == IsMovable::No); 69 auto* box = MBox::New(alloc(), def); 70 current->add(box); 71 def = box; 72 } 73 74 auto* unbox = MUnbox::New(alloc(), def, MIRType::Object, MUnbox::Infallible); 75 if (movable == IsMovable::No) { 76 unbox->setNotMovable(); 77 } 78 current->add(unbox); 79 return unbox; 80 } 81 82 MCall* WarpBuilderShared::makeCall(CallInfo& callInfo, bool needsThisCheck, 83 WrappedFunction* target, bool isDOMCall, 84 gc::Heap initialHeap) { 85 auto addUndefined = [this]() -> MConstant* { 86 return constant(UndefinedValue()); 87 }; 88 89 return MakeCall(alloc(), addUndefined, callInfo, needsThisCheck, target, 90 isDOMCall, initialHeap); 91 } 92 93 MInstruction* WarpBuilderShared::makeSpreadCall(CallInfo& callInfo, 94 bool needsThisCheck, 95 bool isSameRealm, 96 WrappedFunction* target) { 97 MOZ_ASSERT(callInfo.argFormat() == CallInfo::ArgFormat::Array); 98 MOZ_ASSERT_IF(needsThisCheck, !target); 99 100 // Load dense elements of the argument array. 101 MElements* elements = MElements::New(alloc(), callInfo.arrayArg()); 102 current->add(elements); 103 104 if (callInfo.constructing()) { 105 auto* newTarget = unboxObjectInfallible(callInfo.getNewTarget()); 106 auto* construct = 107 MConstructArray::New(alloc(), target, callInfo.callee(), elements, 108 callInfo.thisArg(), newTarget); 109 if (isSameRealm) { 110 construct->setNotCrossRealm(); 111 } 112 if (needsThisCheck) { 113 construct->setNeedsThisCheck(); 114 } 115 return construct; 116 } 117 118 auto* apply = MApplyArray::New(alloc(), target, callInfo.callee(), elements, 119 callInfo.thisArg()); 120 121 if (callInfo.ignoresReturnValue()) { 122 apply->setIgnoresReturnValue(); 123 } 124 if (isSameRealm) { 125 apply->setNotCrossRealm(); 126 } 127 MOZ_ASSERT(!needsThisCheck); 128 return apply; 129 }