WasmModuleTypes.cpp (7834B)
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 2015 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 #include "wasm/WasmModuleTypes.h" 20 21 #include "vm/JSAtomUtils.h" // AtomizeUTF8Chars 22 #include "vm/MallocProvider.h" 23 #include "wasm/WasmUtility.h" 24 25 #include "vm/JSAtomUtils-inl.h" // AtomToId 26 27 using namespace js; 28 using namespace js::wasm; 29 30 using mozilla::CheckedInt32; 31 using mozilla::MallocSizeOf; 32 33 //========================================================================= 34 // TagLayout 35 36 static CheckedInt32 RoundUpToAlignment(CheckedInt32 address, uint32_t align) { 37 MOZ_ASSERT(mozilla::IsPowerOfTwo(align)); 38 39 // Note: Be careful to order operators such that we first make the 40 // value smaller and then larger, so that we don't get false 41 // overflow errors due to (e.g.) adding `align` and then 42 // subtracting `1` afterwards when merely adding `align-1` would 43 // not have overflowed. Note that due to the nature of two's 44 // complement representation, if `address` is already aligned, 45 // then adding `align-1` cannot itself cause an overflow. 46 47 return ((address + (align - 1)) / align) * align; 48 } 49 50 class TagLayout { 51 mozilla::CheckedInt32 sizeSoFar = 0; 52 uint32_t tagAlignment = 1; 53 54 public: 55 // The field adders return the offset of the the field. 56 mozilla::CheckedInt32 addField(StorageType type) { 57 uint32_t fieldSize = type.size(); 58 uint32_t fieldAlignment = type.alignmentInStruct(); 59 60 MOZ_ASSERT(fieldSize >= 1 && fieldSize <= 16); 61 MOZ_ASSERT((fieldSize & (fieldSize - 1)) == 0); // is a power of 2 62 MOZ_ASSERT(fieldAlignment == fieldSize); // is naturally aligned 63 64 // Alignment of the tag is the max of the alignment of its fields. 65 tagAlignment = std::max(tagAlignment, fieldAlignment); 66 67 // Align the pointer. 68 CheckedInt32 offset = RoundUpToAlignment(sizeSoFar, fieldAlignment); 69 if (!offset.isValid()) { 70 return offset; 71 } 72 73 // Allocate space. 74 sizeSoFar = offset + fieldSize; 75 if (!sizeSoFar.isValid()) { 76 return sizeSoFar; 77 } 78 79 return offset; 80 } 81 82 // The close method rounds up the structure size to the appropriate 83 // alignment and returns that size. 84 mozilla::CheckedInt32 close() { 85 CheckedInt32 size = RoundUpToAlignment(sizeSoFar, tagAlignment); 86 // Make the overall size be an integral number of machine words. 87 if (tagAlignment < sizeof(uintptr_t)) { 88 size = RoundUpToAlignment(size, sizeof(uintptr_t)); 89 } 90 return size; 91 } 92 }; 93 94 //========================================================================= 95 96 /* static */ 97 CacheableName CacheableName::fromUTF8Chars(UniqueChars&& utf8Chars) { 98 size_t length = strlen(utf8Chars.get()); 99 UTF8Bytes bytes; 100 bytes.replaceRawBuffer(utf8Chars.release(), length, length + 1); 101 return CacheableName(std::move(bytes)); 102 } 103 104 /* static */ 105 bool CacheableName::fromUTF8Chars(const char* utf8Chars, CacheableName* name) { 106 size_t utf8CharsLen = strlen(utf8Chars); 107 UTF8Bytes bytes; 108 if (!bytes.resizeUninitialized(utf8CharsLen)) { 109 return false; 110 } 111 memcpy(bytes.begin(), utf8Chars, utf8CharsLen); 112 *name = CacheableName(std::move(bytes)); 113 return true; 114 } 115 116 MOZ_RUNINIT BranchHintVector BranchHintCollection::invalidVector_; 117 118 JSString* CacheableName::toJSString(JSContext* cx) const { 119 return NewStringCopyUTF8N(cx, JS::UTF8Chars(begin(), length())); 120 } 121 122 JSAtom* CacheableName::toAtom(JSContext* cx) const { 123 return AtomizeUTF8Chars(cx, begin(), length()); 124 } 125 126 bool CacheableName::toPropertyKey(JSContext* cx, 127 MutableHandleId propertyKey) const { 128 JSAtom* atom = toAtom(cx); 129 if (!atom) { 130 return false; 131 } 132 propertyKey.set(AtomToId(atom)); 133 return true; 134 } 135 136 UniqueChars CacheableName::toQuotedString(JSContext* cx) const { 137 RootedString atom(cx, toAtom(cx)); 138 if (!atom) { 139 return nullptr; 140 } 141 return QuoteString(cx, atom.get()); 142 } 143 144 size_t CacheableName::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const { 145 return bytes_.sizeOfExcludingThis(mallocSizeOf); 146 } 147 148 size_t Import::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const { 149 return module.sizeOfExcludingThis(mallocSizeOf) + 150 field.sizeOfExcludingThis(mallocSizeOf); 151 } 152 153 Export::Export(CacheableName&& fieldName, uint32_t index, DefinitionKind kind) 154 : fieldName_(std::move(fieldName)) { 155 pod.kind_ = kind; 156 pod.index_ = index; 157 } 158 159 uint32_t Export::funcIndex() const { 160 MOZ_ASSERT(pod.kind_ == DefinitionKind::Function); 161 return pod.index_; 162 } 163 164 uint32_t Export::memoryIndex() const { 165 MOZ_ASSERT(pod.kind_ == DefinitionKind::Memory); 166 return pod.index_; 167 } 168 169 uint32_t Export::globalIndex() const { 170 MOZ_ASSERT(pod.kind_ == DefinitionKind::Global); 171 return pod.index_; 172 } 173 174 uint32_t Export::tagIndex() const { 175 MOZ_ASSERT(pod.kind_ == DefinitionKind::Tag); 176 return pod.index_; 177 } 178 179 uint32_t Export::tableIndex() const { 180 MOZ_ASSERT(pod.kind_ == DefinitionKind::Table); 181 return pod.index_; 182 } 183 184 size_t Export::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const { 185 return fieldName_.sizeOfExcludingThis(mallocSizeOf); 186 } 187 188 size_t GlobalDesc::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const { 189 return initial_.sizeOfExcludingThis(mallocSizeOf); 190 } 191 192 bool TagType::initialize(const SharedTypeDef& funcType) { 193 MOZ_ASSERT(funcType->isFuncType()); 194 type_ = funcType; 195 196 const ValTypeVector& args = argTypes(); 197 // Compute the byte offsets for arguments when we layout an exception. 198 if (!argOffsets_.resize(args.length())) { 199 return false; 200 } 201 202 TagLayout layout; 203 for (size_t i = 0; i < args.length(); i++) { 204 CheckedInt32 offset = layout.addField(StorageType(args[i].packed())); 205 if (!offset.isValid()) { 206 return false; 207 } 208 argOffsets_[i] = offset.value(); 209 } 210 211 // Find the total size of all the arguments. 212 CheckedInt32 size = layout.close(); 213 if (!size.isValid()) { 214 return false; 215 } 216 this->size_ = size.value(); 217 218 return true; 219 } 220 221 size_t TagType::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const { 222 return argOffsets_.sizeOfExcludingThis(mallocSizeOf); 223 } 224 225 size_t TagDesc::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const { 226 return type->sizeOfExcludingThis(mallocSizeOf); 227 } 228 229 size_t ModuleElemSegment::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const { 230 return SizeOfMaybeExcludingThis(offsetIfActive, mallocSizeOf) + 231 elemIndices.sizeOfExcludingThis(mallocSizeOf); 232 } 233 234 size_t ModuleElemSegment::Expressions::sizeOfExcludingThis( 235 MallocSizeOf mallocSizeOf) const { 236 return exprBytes.sizeOfExcludingThis(mallocSizeOf); 237 } 238 239 size_t DataSegment::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const { 240 return SizeOfMaybeExcludingThis(offsetIfActive, mallocSizeOf) + 241 bytes.sizeOfExcludingThis(mallocSizeOf); 242 } 243 244 size_t CustomSection::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const { 245 return name.sizeOfExcludingThis(mallocSizeOf) + sizeof(*payload) + 246 payload->sizeOfExcludingThis(mallocSizeOf); 247 } 248 249 size_t NameSection::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const { 250 return funcNames.sizeOfExcludingThis(mallocSizeOf); 251 } 252 253 const char* wasm::ToString(LimitsKind kind) { 254 switch (kind) { 255 case LimitsKind::Memory: 256 return "Memory"; 257 case LimitsKind::Table: 258 return "Table"; 259 default: 260 MOZ_CRASH(); 261 } 262 }