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 2021 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_pages_h 20 #define wasm_pages_h 21 22 #include "mozilla/CheckedInt.h" 23 24 #include <stdint.h> 25 26 namespace js { 27 namespace wasm { 28 29 // Pages is a typed unit representing a multiple of wasm::PageSize. We 30 // generally use pages as the unit of length when representing linear memory 31 // lengths so as to avoid overflow when the specified initial or maximum pages 32 // would overflow the native word size. 33 // 34 // Modules may specify pages up to 2^48 inclusive and so Pages is 64-bit on all 35 // platforms. 36 // 37 // We represent byte lengths using the native word size, as it is assumed that 38 // consumers of this API will only need byte lengths once it is time to 39 // allocate memory, at which point the pages will be checked against the 40 // implementation limits `MaxMemory32Pages()` and will then be guaranteed to 41 // fit in a native word. 42 struct Pages { 43 private: 44 // Pages are specified by limit fields, which in general may be up to 2^48, 45 // so we must use uint64_t here. 46 uint64_t value_; 47 48 public: PagesPages49 constexpr explicit Pages(uint64_t value) : value_(value) {} 50 51 // Get the wrapped page value. Only use this if you must, prefer to use or 52 // add new APIs to Page. valuePages53 uint64_t value() const { return value_; } 54 55 // Converts from a byte length to pages, assuming that the length is an 56 // exact multiple of the page size. fromByteLengthExactPages57 static Pages fromByteLengthExact(size_t byteLength) { 58 MOZ_ASSERT(byteLength % PageSize == 0); 59 return Pages(byteLength / PageSize); 60 } 61 62 // Return whether the page length may overflow when converted to a byte 63 // length in the native word size. hasByteLengthPages64 bool hasByteLength() const { 65 mozilla::CheckedInt<size_t> length(value_); 66 length *= PageSize; 67 return length.isValid(); 68 } 69 70 // Converts from pages to byte length in the native word size. Users must 71 // check for overflow, or be assured else-how that overflow cannot happen. byteLengthPages72 size_t byteLength() const { 73 mozilla::CheckedInt<size_t> length(value_); 74 length *= PageSize; 75 return length.value(); 76 } 77 78 // Increment this pages by delta and return whether the resulting value 79 // did not overflow. If there is no overflow, then this is set to the 80 // resulting value. checkedIncrementPages81 bool checkedIncrement(Pages delta) { 82 mozilla::CheckedInt<uint64_t> newValue = value_; 83 newValue += delta.value_; 84 if (!newValue.isValid()) { 85 return false; 86 } 87 value_ = newValue.value(); 88 return true; 89 } 90 91 // Implement pass-through comparison operators so that Pages can be compared. 92 93 bool operator==(Pages other) const { return value_ == other.value_; } 94 bool operator!=(Pages other) const { return value_ != other.value_; } 95 bool operator<=(Pages other) const { return value_ <= other.value_; } 96 bool operator<(Pages other) const { return value_ < other.value_; } 97 bool operator>=(Pages other) const { return value_ >= other.value_; } 98 bool operator>(Pages other) const { return value_ > other.value_; } 99 }; 100 101 } // namespace wasm 102 } // namespace js 103 104 #endif // wasm_pages_h 105