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