no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / js / src / wasm / WasmCodegenTypes.cpp
blob59de47dd75127d802efb5a4e07fbfc3e5baf604c
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:
4 * Copyright 2021 Mozilla Foundation
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "wasm/WasmCodegenTypes.h"
21 #include "wasm/WasmExprType.h"
22 #include "wasm/WasmStubs.h"
23 #include "wasm/WasmTypeDef.h"
24 #include "wasm/WasmValidate.h"
25 #include "wasm/WasmValue.h"
27 using mozilla::MakeEnumeratedRange;
28 using mozilla::PodZero;
30 using namespace js;
31 using namespace js::wasm;
33 ArgTypeVector::ArgTypeVector(const FuncType& funcType)
34 : args_(funcType.args()),
35 hasStackResults_(ABIResultIter::HasStackResults(
36 ResultType::Vector(funcType.results()))) {}
38 bool TrapSiteVectorArray::empty() const {
39 for (Trap trap : MakeEnumeratedRange(Trap::Limit)) {
40 if (!(*this)[trap].empty()) {
41 return false;
45 return true;
48 #ifdef DEBUG
49 const char* js::wasm::NameOfTrap(Trap trap) {
50 switch (trap) {
51 case Trap::Unreachable:
52 return "Unreachable";
53 case Trap::IntegerOverflow:
54 return "IntegerOverflow";
55 case Trap::InvalidConversionToInteger:
56 return "InvalidConversionToInteger";
57 case Trap::IntegerDivideByZero:
58 return "IntegerDivideByZero";
59 case Trap::OutOfBounds:
60 return "OutOfBounds";
61 case Trap::UnalignedAccess:
62 return "UnalignedAccess";
63 case Trap::IndirectCallToNull:
64 return "IndirectCallToNull";
65 case Trap::IndirectCallBadSig:
66 return "IndirectCallBadSig";
67 case Trap::NullPointerDereference:
68 return "NullPointerDereference";
69 case Trap::BadCast:
70 return "BadCast";
71 case Trap::StackOverflow:
72 return "StackOverflow";
73 case Trap::CheckInterrupt:
74 return "CheckInterrupt";
75 case Trap::ThrowReported:
76 return "ThrowReported";
77 case Trap::Limit:
78 return "Limit";
79 default:
80 return "NameOfTrap:unknown";
84 const char* js::wasm::NameOfTrapMachineInsn(TrapMachineInsn tmi) {
85 switch (tmi) {
86 case TrapMachineInsn::OfficialUD:
87 return "OfficialUD";
88 case TrapMachineInsn::Load8:
89 return "Load8";
90 case TrapMachineInsn::Load16:
91 return "Load16";
92 case TrapMachineInsn::Load32:
93 return "Load32";
94 case TrapMachineInsn::Load64:
95 return "Load64";
96 case TrapMachineInsn::Load128:
97 return "Load128";
98 case TrapMachineInsn::Store8:
99 return "Store8";
100 case TrapMachineInsn::Store16:
101 return "Store16";
102 case TrapMachineInsn::Store32:
103 return "Store32";
104 case TrapMachineInsn::Store64:
105 return "Store64";
106 case TrapMachineInsn::Store128:
107 return "Store128";
108 case TrapMachineInsn::Atomic:
109 return "Atomic";
110 default:
111 return "NameOfTrapMachineInsn::unknown";
114 #endif // DEBUG
116 void TrapSiteVectorArray::clear() {
117 for (Trap trap : MakeEnumeratedRange(Trap::Limit)) {
118 (*this)[trap].clear();
122 void TrapSiteVectorArray::swap(TrapSiteVectorArray& rhs) {
123 for (Trap trap : MakeEnumeratedRange(Trap::Limit)) {
124 (*this)[trap].swap(rhs[trap]);
128 void TrapSiteVectorArray::shrinkStorageToFit() {
129 for (Trap trap : MakeEnumeratedRange(Trap::Limit)) {
130 (*this)[trap].shrinkStorageToFit();
134 size_t TrapSiteVectorArray::sumOfLengths() const {
135 size_t ret = 0;
136 for (Trap trap : MakeEnumeratedRange(Trap::Limit)) {
137 ret += (*this)[trap].length();
139 return ret;
142 size_t TrapSiteVectorArray::sizeOfExcludingThis(
143 MallocSizeOf mallocSizeOf) const {
144 size_t ret = 0;
145 for (Trap trap : MakeEnumeratedRange(Trap::Limit)) {
146 ret += (*this)[trap].sizeOfExcludingThis(mallocSizeOf);
148 return ret;
151 CodeRange::CodeRange(Kind kind, Offsets offsets)
152 : begin_(offsets.begin), ret_(0), end_(offsets.end), kind_(kind) {
153 MOZ_ASSERT(begin_ <= end_);
154 PodZero(&u);
155 #ifdef DEBUG
156 switch (kind_) {
157 case FarJumpIsland:
158 case TrapExit:
159 case Throw:
160 break;
161 default:
162 MOZ_CRASH("should use more specific constructor");
164 #endif
167 CodeRange::CodeRange(Kind kind, uint32_t funcIndex, Offsets offsets)
168 : begin_(offsets.begin), ret_(0), end_(offsets.end), kind_(kind) {
169 u.funcIndex_ = funcIndex;
170 u.func.lineOrBytecode_ = 0;
171 u.func.beginToUncheckedCallEntry_ = 0;
172 u.func.beginToTierEntry_ = 0;
173 u.func.hasUnwindInfo_ = false;
174 MOZ_ASSERT(isEntry());
175 MOZ_ASSERT(begin_ <= end_);
178 CodeRange::CodeRange(Kind kind, CallableOffsets offsets)
179 : begin_(offsets.begin), ret_(offsets.ret), end_(offsets.end), kind_(kind) {
180 MOZ_ASSERT(begin_ < ret_);
181 MOZ_ASSERT(ret_ < end_);
182 PodZero(&u);
183 #ifdef DEBUG
184 switch (kind_) {
185 case DebugTrap:
186 case BuiltinThunk:
187 break;
188 default:
189 MOZ_CRASH("should use more specific constructor");
191 #endif
194 CodeRange::CodeRange(Kind kind, uint32_t funcIndex, CallableOffsets offsets)
195 : begin_(offsets.begin), ret_(offsets.ret), end_(offsets.end), kind_(kind) {
196 MOZ_ASSERT(isImportExit() || isJitEntry());
197 MOZ_ASSERT(begin_ < ret_);
198 MOZ_ASSERT(ret_ < end_);
199 u.funcIndex_ = funcIndex;
200 u.func.lineOrBytecode_ = 0;
201 u.func.beginToUncheckedCallEntry_ = 0;
202 u.func.beginToTierEntry_ = 0;
203 u.func.hasUnwindInfo_ = false;
206 CodeRange::CodeRange(uint32_t funcIndex, uint32_t funcLineOrBytecode,
207 FuncOffsets offsets, bool hasUnwindInfo)
208 : begin_(offsets.begin),
209 ret_(offsets.ret),
210 end_(offsets.end),
211 kind_(Function) {
212 MOZ_ASSERT(begin_ < ret_);
213 MOZ_ASSERT(ret_ < end_);
214 MOZ_ASSERT(offsets.uncheckedCallEntry - begin_ <= UINT16_MAX);
215 MOZ_ASSERT(offsets.tierEntry - begin_ <= UINT16_MAX);
216 u.funcIndex_ = funcIndex;
217 u.func.lineOrBytecode_ = funcLineOrBytecode;
218 u.func.beginToUncheckedCallEntry_ = offsets.uncheckedCallEntry - begin_;
219 u.func.beginToTierEntry_ = offsets.tierEntry - begin_;
220 u.func.hasUnwindInfo_ = hasUnwindInfo;
223 const CodeRange* wasm::LookupInSorted(const CodeRangeVector& codeRanges,
224 CodeRange::OffsetInCode target) {
225 size_t lowerBound = 0;
226 size_t upperBound = codeRanges.length();
228 size_t match;
229 if (!BinarySearch(codeRanges, lowerBound, upperBound, target, &match)) {
230 return nullptr;
233 return &codeRanges[match];
236 CallIndirectId CallIndirectId::forAsmJSFunc() {
237 return CallIndirectId(CallIndirectIdKind::AsmJS);
240 CallIndirectId CallIndirectId::forFunc(const ModuleEnvironment& moduleEnv,
241 uint32_t funcIndex) {
242 // asm.js tables are homogenous and don't require a signature check
243 if (moduleEnv.isAsmJS()) {
244 return CallIndirectId::forAsmJSFunc();
247 FuncDesc func = moduleEnv.funcs[funcIndex];
248 if (!func.canRefFunc()) {
249 return CallIndirectId();
251 return CallIndirectId::forFuncType(moduleEnv,
252 moduleEnv.funcs[funcIndex].typeIndex);
255 CallIndirectId CallIndirectId::forFuncType(const ModuleEnvironment& moduleEnv,
256 uint32_t funcTypeIndex) {
257 // asm.js tables are homogenous and don't require a signature check
258 if (moduleEnv.isAsmJS()) {
259 return CallIndirectId::forAsmJSFunc();
262 const TypeDef& typeDef = moduleEnv.types->type(funcTypeIndex);
263 const FuncType& funcType = typeDef.funcType();
264 CallIndirectId callIndirectId;
265 if (funcType.hasImmediateTypeId()) {
266 callIndirectId.kind_ = CallIndirectIdKind::Immediate;
267 callIndirectId.immediate_ = funcType.immediateTypeId();
268 } else {
269 callIndirectId.kind_ = CallIndirectIdKind::Global;
270 callIndirectId.global_.instanceDataOffset_ =
271 moduleEnv.offsetOfTypeDef(funcTypeIndex);
272 callIndirectId.global_.hasSuperType_ = typeDef.superTypeDef() != nullptr;
274 return callIndirectId;
277 CalleeDesc CalleeDesc::function(uint32_t funcIndex) {
278 CalleeDesc c;
279 c.which_ = Func;
280 c.u.funcIndex_ = funcIndex;
281 return c;
283 CalleeDesc CalleeDesc::import(uint32_t instanceDataOffset) {
284 CalleeDesc c;
285 c.which_ = Import;
286 c.u.import.instanceDataOffset_ = instanceDataOffset;
287 return c;
289 CalleeDesc CalleeDesc::wasmTable(const ModuleEnvironment& moduleEnv,
290 const TableDesc& desc, uint32_t tableIndex,
291 CallIndirectId callIndirectId) {
292 CalleeDesc c;
293 c.which_ = WasmTable;
294 c.u.table.instanceDataOffset_ =
295 moduleEnv.offsetOfTableInstanceData(tableIndex);
296 c.u.table.minLength_ = desc.initialLength;
297 c.u.table.maxLength_ = desc.maximumLength;
298 c.u.table.callIndirectId_ = callIndirectId;
299 return c;
301 CalleeDesc CalleeDesc::asmJSTable(const ModuleEnvironment& moduleEnv,
302 uint32_t tableIndex) {
303 CalleeDesc c;
304 c.which_ = AsmJSTable;
305 c.u.table.instanceDataOffset_ =
306 moduleEnv.offsetOfTableInstanceData(tableIndex);
307 return c;
309 CalleeDesc CalleeDesc::builtin(SymbolicAddress callee) {
310 CalleeDesc c;
311 c.which_ = Builtin;
312 c.u.builtin_ = callee;
313 return c;
315 CalleeDesc CalleeDesc::builtinInstanceMethod(SymbolicAddress callee) {
316 CalleeDesc c;
317 c.which_ = BuiltinInstanceMethod;
318 c.u.builtin_ = callee;
319 return c;
321 CalleeDesc CalleeDesc::wasmFuncRef() {
322 CalleeDesc c;
323 c.which_ = FuncRef;
324 return c;