js/src/jit/TypeDescrSet.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "jit/TypeDescrSet.h"
michael@0 8
michael@0 9 #include "mozilla/HashFunctions.h"
michael@0 10
michael@0 11 #include "builtin/TypedObject.h"
michael@0 12 #include "jit/IonBuilder.h"
michael@0 13
michael@0 14 using namespace js;
michael@0 15 using namespace jit;
michael@0 16
michael@0 17 ///////////////////////////////////////////////////////////////////////////
michael@0 18 // TypeDescrSet hasher
michael@0 19
michael@0 20 HashNumber
michael@0 21 TypeDescrSetHasher::hash(TypeDescrSet key)
michael@0 22 {
michael@0 23 HashNumber hn = mozilla::HashGeneric(key.length());
michael@0 24 for (size_t i = 0; i < key.length(); i++)
michael@0 25 hn = mozilla::AddToHash(hn, uintptr_t(key.get(i)));
michael@0 26 return hn;
michael@0 27 }
michael@0 28
michael@0 29 bool
michael@0 30 TypeDescrSetHasher::match(TypeDescrSet key1, TypeDescrSet key2)
michael@0 31 {
michael@0 32 if (key1.length() != key2.length())
michael@0 33 return false;
michael@0 34
michael@0 35 // Note: entries are always sorted
michael@0 36 for (size_t i = 0; i < key1.length(); i++) {
michael@0 37 if (key1.get(i) != key2.get(i))
michael@0 38 return false;
michael@0 39 }
michael@0 40
michael@0 41 return true;
michael@0 42 }
michael@0 43
michael@0 44 ///////////////////////////////////////////////////////////////////////////
michael@0 45 // TypeDescrSetBuilder
michael@0 46
michael@0 47 TypeDescrSetBuilder::TypeDescrSetBuilder()
michael@0 48 : invalid_(false)
michael@0 49 {}
michael@0 50
michael@0 51 bool
michael@0 52 TypeDescrSetBuilder::insert(TypeDescr *descr)
michael@0 53 {
michael@0 54 // All type descriptors should be tenured, so it is safe to assume
michael@0 55 // that the pointers do not change during compilation, since no
michael@0 56 // major GC can overlap with compilation.
michael@0 57 JS_ASSERT(!GetIonContext()->runtime->isInsideNursery(descr));
michael@0 58
michael@0 59 if (invalid_)
michael@0 60 return true;
michael@0 61
michael@0 62 if (entries_.empty())
michael@0 63 return entries_.append(descr);
michael@0 64
michael@0 65 // Check that this new type repr is of the same basic kind as the
michael@0 66 // ones we have seen thus far. If not, for example if we have an
michael@0 67 // `int` and a `struct`, then convert this set to the invalid set.
michael@0 68 TypeDescr *entry0 = entries_[0];
michael@0 69 if (descr->kind() != entry0->kind()) {
michael@0 70 invalid_ = true;
michael@0 71 entries_.clear();
michael@0 72 return true;
michael@0 73 }
michael@0 74
michael@0 75 // Otherwise, use binary search to find the right place to insert
michael@0 76 // the TypeDescr. We keep the list sorted by the *address* of
michael@0 77 // the TypeDescrs within.
michael@0 78 uintptr_t descrAddr = (uintptr_t) descr;
michael@0 79 size_t min = 0;
michael@0 80 size_t max = entries_.length();
michael@0 81 while (min != max) {
michael@0 82 size_t i = min + ((max - min) >> 1); // average w/o fear of overflow
michael@0 83
michael@0 84 uintptr_t entryiaddr = (uintptr_t) entries_[i];
michael@0 85 if (entryiaddr == descrAddr)
michael@0 86 return true; // descr already present in the set
michael@0 87
michael@0 88 if (entryiaddr < descrAddr) {
michael@0 89 // descr lies to the right of entry i
michael@0 90 min = i + 1;
michael@0 91 } else {
michael@0 92 // descr lies to the left of entry i
michael@0 93 max = i;
michael@0 94 }
michael@0 95 }
michael@0 96
michael@0 97 // As a sanity check, give up if the TypeDescrSet grows too large.
michael@0 98 if (entries_.length() >= 512) {
michael@0 99 invalid_ = true;
michael@0 100 entries_.clear();
michael@0 101 return true;
michael@0 102 }
michael@0 103
michael@0 104 // Not present. Insert at position `min`.
michael@0 105 if (min == entries_.length())
michael@0 106 return entries_.append(descr);
michael@0 107 TypeDescr **insertLoc = &entries_[min];
michael@0 108 return entries_.insert(insertLoc, descr) != nullptr;
michael@0 109 }
michael@0 110
michael@0 111 bool
michael@0 112 TypeDescrSetBuilder::build(IonBuilder &builder, TypeDescrSet *out)
michael@0 113 {
michael@0 114 if (invalid_) {
michael@0 115 *out = TypeDescrSet();
michael@0 116 return true;
michael@0 117 }
michael@0 118
michael@0 119 TypeDescrSetHash *table = builder.getOrCreateDescrSetHash();
michael@0 120 if (!table)
michael@0 121 return false;
michael@0 122
michael@0 123 // Check if there is already a copy in the hashtable.
michael@0 124 size_t length = entries_.length();
michael@0 125 TypeDescrSet tempSet(length, entries_.begin());
michael@0 126 TypeDescrSetHash::AddPtr p = table->lookupForAdd(tempSet);
michael@0 127 if (p) {
michael@0 128 *out = *p;
michael@0 129 return true;
michael@0 130 }
michael@0 131
michael@0 132 // If not, allocate a permanent copy in Ion temp memory and add it.
michael@0 133 size_t space = sizeof(TypeDescr*) * length;
michael@0 134 TypeDescr **array = (TypeDescr**)
michael@0 135 GetIonContext()->temp->allocate(space);
michael@0 136 if (!array)
michael@0 137 return false;
michael@0 138 memcpy(array, entries_.begin(), space);
michael@0 139 TypeDescrSet permSet(length, array);
michael@0 140 if (!table->add(p, permSet))
michael@0 141 return false;
michael@0 142
michael@0 143 *out = permSet;
michael@0 144 return true;
michael@0 145 }
michael@0 146
michael@0 147 ///////////////////////////////////////////////////////////////////////////
michael@0 148 // TypeDescrSet
michael@0 149
michael@0 150 TypeDescrSet::TypeDescrSet(const TypeDescrSet &c)
michael@0 151 : length_(c.length_),
michael@0 152 entries_(c.entries_)
michael@0 153 {}
michael@0 154
michael@0 155 TypeDescrSet::TypeDescrSet(size_t length,
michael@0 156 TypeDescr **entries)
michael@0 157 : length_(length),
michael@0 158 entries_(entries)
michael@0 159 {}
michael@0 160
michael@0 161 TypeDescrSet::TypeDescrSet()
michael@0 162 : length_(0),
michael@0 163 entries_(nullptr)
michael@0 164 {}
michael@0 165
michael@0 166 bool
michael@0 167 TypeDescrSet::empty() const
michael@0 168 {
michael@0 169 return length_ == 0;
michael@0 170 }
michael@0 171
michael@0 172 bool
michael@0 173 TypeDescrSet::allOfArrayKind()
michael@0 174 {
michael@0 175 if (empty())
michael@0 176 return false;
michael@0 177
michael@0 178 switch (kind()) {
michael@0 179 case TypeDescr::SizedArray:
michael@0 180 case TypeDescr::UnsizedArray:
michael@0 181 return true;
michael@0 182
michael@0 183 case TypeDescr::X4:
michael@0 184 case TypeDescr::Reference:
michael@0 185 case TypeDescr::Scalar:
michael@0 186 case TypeDescr::Struct:
michael@0 187 return false;
michael@0 188 }
michael@0 189
michael@0 190 MOZ_ASSUME_UNREACHABLE("Invalid kind() in TypeDescrSet");
michael@0 191 }
michael@0 192
michael@0 193 bool
michael@0 194 TypeDescrSet::allOfKind(TypeDescr::Kind aKind)
michael@0 195 {
michael@0 196 if (empty())
michael@0 197 return false;
michael@0 198
michael@0 199 return kind() == aKind;
michael@0 200 }
michael@0 201
michael@0 202 bool
michael@0 203 TypeDescrSet::allHaveSameSize(int32_t *out)
michael@0 204 {
michael@0 205 if (empty())
michael@0 206 return false;
michael@0 207
michael@0 208 JS_ASSERT(TypeDescr::isSized(kind()));
michael@0 209
michael@0 210 int32_t size = get(0)->as<SizedTypeDescr>().size();
michael@0 211 for (size_t i = 1; i < length(); i++) {
michael@0 212 if (get(i)->as<SizedTypeDescr>().size() != size)
michael@0 213 return false;
michael@0 214 }
michael@0 215
michael@0 216 *out = size;
michael@0 217 return true;
michael@0 218 }
michael@0 219
michael@0 220 JSObject *
michael@0 221 TypeDescrSet::knownPrototype() const
michael@0 222 {
michael@0 223 JS_ASSERT(!empty());
michael@0 224 if (length() > 1 || !get(0)->is<ComplexTypeDescr>())
michael@0 225 return nullptr;
michael@0 226 return &get(0)->as<ComplexTypeDescr>().instancePrototype();
michael@0 227 }
michael@0 228
michael@0 229 TypeDescr::Kind
michael@0 230 TypeDescrSet::kind()
michael@0 231 {
michael@0 232 JS_ASSERT(!empty());
michael@0 233 return get(0)->kind();
michael@0 234 }
michael@0 235
michael@0 236 template<typename T>
michael@0 237 bool
michael@0 238 TypeDescrSet::genericType(typename T::Type *out)
michael@0 239 {
michael@0 240 JS_ASSERT(allOfKind(TypeDescr::Scalar));
michael@0 241
michael@0 242 typename T::Type type = get(0)->as<T>().type();
michael@0 243 for (size_t i = 1; i < length(); i++) {
michael@0 244 if (get(i)->as<T>().type() != type)
michael@0 245 return false;
michael@0 246 }
michael@0 247
michael@0 248 *out = type;
michael@0 249 return true;
michael@0 250 }
michael@0 251
michael@0 252 bool
michael@0 253 TypeDescrSet::scalarType(ScalarTypeDescr::Type *out)
michael@0 254 {
michael@0 255 return genericType<ScalarTypeDescr>(out);
michael@0 256 }
michael@0 257
michael@0 258 bool
michael@0 259 TypeDescrSet::referenceType(ReferenceTypeDescr::Type *out)
michael@0 260 {
michael@0 261 return genericType<ReferenceTypeDescr>(out);
michael@0 262 }
michael@0 263
michael@0 264 bool
michael@0 265 TypeDescrSet::x4Type(X4TypeDescr::Type *out)
michael@0 266 {
michael@0 267 return genericType<X4TypeDescr>(out);
michael@0 268 }
michael@0 269
michael@0 270 bool
michael@0 271 TypeDescrSet::hasKnownArrayLength(int32_t *l)
michael@0 272 {
michael@0 273 switch (kind()) {
michael@0 274 case TypeDescr::UnsizedArray:
michael@0 275 return false;
michael@0 276
michael@0 277 case TypeDescr::SizedArray:
michael@0 278 {
michael@0 279 const size_t result = get(0)->as<SizedArrayTypeDescr>().length();
michael@0 280 for (size_t i = 1; i < length(); i++) {
michael@0 281 size_t l = get(i)->as<SizedArrayTypeDescr>().length();
michael@0 282 if (l != result)
michael@0 283 return false;
michael@0 284 }
michael@0 285 *l = result;
michael@0 286 return true;
michael@0 287 }
michael@0 288
michael@0 289 default:
michael@0 290 MOZ_ASSUME_UNREACHABLE("Invalid array size for call to arrayLength()");
michael@0 291 }
michael@0 292 }
michael@0 293
michael@0 294 bool
michael@0 295 TypeDescrSet::arrayElementType(IonBuilder &builder, TypeDescrSet *out)
michael@0 296 {
michael@0 297 TypeDescrSetBuilder elementTypes;
michael@0 298 for (size_t i = 0; i < length(); i++) {
michael@0 299 switch (kind()) {
michael@0 300 case TypeDescr::UnsizedArray:
michael@0 301 if (!elementTypes.insert(&get(i)->as<UnsizedArrayTypeDescr>().elementType()))
michael@0 302 return false;
michael@0 303 break;
michael@0 304
michael@0 305 case TypeDescr::SizedArray:
michael@0 306 if (!elementTypes.insert(&get(i)->as<SizedArrayTypeDescr>().elementType()))
michael@0 307 return false;
michael@0 308 break;
michael@0 309
michael@0 310 default:
michael@0 311 MOZ_ASSUME_UNREACHABLE("Invalid kind for arrayElementType()");
michael@0 312 }
michael@0 313 }
michael@0 314 return elementTypes.build(builder, out);
michael@0 315 }
michael@0 316
michael@0 317 bool
michael@0 318 TypeDescrSet::fieldNamed(IonBuilder &builder,
michael@0 319 jsid id,
michael@0 320 int32_t *offset,
michael@0 321 TypeDescrSet *out,
michael@0 322 size_t *index)
michael@0 323 {
michael@0 324 JS_ASSERT(kind() == TypeDescr::Struct);
michael@0 325
michael@0 326 // Initialize `*offset` and `*out` for the case where incompatible
michael@0 327 // or absent fields are found.
michael@0 328 *offset = -1;
michael@0 329 *index = SIZE_MAX;
michael@0 330 *out = TypeDescrSet();
michael@0 331
michael@0 332 // Remember offset of the first field.
michael@0 333 int32_t offset0;
michael@0 334 size_t index0;
michael@0 335 TypeDescrSetBuilder fieldTypes;
michael@0 336 {
michael@0 337 StructTypeDescr &descr0 = get(0)->as<StructTypeDescr>();
michael@0 338 if (!descr0.fieldIndex(id, &index0))
michael@0 339 return true;
michael@0 340
michael@0 341 offset0 = descr0.fieldOffset(index0);
michael@0 342 if (!fieldTypes.insert(&descr0.fieldDescr(index0)))
michael@0 343 return false;
michael@0 344 }
michael@0 345
michael@0 346 // Check that all subsequent fields are at the same offset
michael@0 347 // and compute the union of their types.
michael@0 348 for (size_t i = 1; i < length(); i++) {
michael@0 349 StructTypeDescr &descri = get(i)->as<StructTypeDescr>();
michael@0 350
michael@0 351 size_t indexi;
michael@0 352 if (!descri.fieldIndex(id, &indexi))
michael@0 353 return true;
michael@0 354
michael@0 355 // Track whether all indices agree, but do not require it to be true
michael@0 356 if (indexi != index0)
michael@0 357 index0 = SIZE_MAX;
michael@0 358
michael@0 359 // Require that all offsets agree
michael@0 360 if (descri.fieldOffset(indexi) != offset0)
michael@0 361 return true;
michael@0 362
michael@0 363 if (!fieldTypes.insert(&descri.fieldDescr(indexi)))
michael@0 364 return false;
michael@0 365 }
michael@0 366
michael@0 367 // All struct types had a field named `id` at the same offset
michael@0 368 // (though it's still possible that the types are incompatible and
michael@0 369 // that the indices disagree).
michael@0 370 *offset = offset0;
michael@0 371 *index = index0;
michael@0 372 return fieldTypes.build(builder, out);
michael@0 373 }

mercurial