tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }