/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef builtin_WeakMapObject_inl_h #define builtin_WeakMapObject_inl_h #include "builtin/WeakMapObject.h" #include "gc/ZoneAllocator.h" #include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_* #include "js/Prefs.h" #include "js/Wrapper.h" #include "gc/WeakMap-inl.h" #include "vm/JSObject-inl.h" namespace js { static bool TryPreserveReflector(JSContext* cx, HandleObject obj) { if (!MaybePreserveDOMWrapper(cx, obj)) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_WEAKMAP_KEY); return false; } return true; } static MOZ_ALWAYS_INLINE bool EnsureObjectHasWeakMap( JSContext* cx, WeakCollectionObject* obj) { if (obj->getMap()) { return true; } MOZ_ASSERT(obj->isTenured()); auto map = gc::NewBuffer(obj, cx, obj); if (!map) { ReportOutOfMemory(cx); return false; } InitBufferSlot(obj, WeakCollectionObject::DataSlot, map); return true; } static MOZ_ALWAYS_INLINE bool PreserveReflectorAndAssertValidEntry( JSContext* cx, Handle obj, HandleValue key, HandleValue value) { if (key.isObject()) { RootedObject keyObj(cx, &key.toObject()); // Preserve wrapped native keys to prevent wrapper optimization. if (!TryPreserveReflector(cx, keyObj)) { return false; } RootedObject delegate(cx, UncheckedUnwrapWithoutExpose(keyObj)); if (delegate && !TryPreserveReflector(cx, delegate)) { return false; } } MOZ_ASSERT_IF(key.isObject(), key.toObject().compartment() == obj->compartment()); MOZ_ASSERT_IF(value.isGCThing(), gc::ToMarkable(value)->zoneFromAnyThread() == obj->zone() || gc::ToMarkable(value)->zoneFromAnyThread()->isAtomsZone()); MOZ_ASSERT_IF(value.isObject(), value.toObject().compartment() == obj->compartment()); return true; } static MOZ_ALWAYS_INLINE bool WeakCollectionPutEntryInternal( JSContext* cx, Handle obj, HandleValue key, HandleValue value) { if (!EnsureObjectHasWeakMap(cx, obj)) { return false; } if (!PreserveReflectorAndAssertValidEntry(cx, obj, key, value)) { return false; } if (!obj->getMap()->put(key, value)) { JS_ReportOutOfMemory(cx); return false; } return true; } static unsigned GetErrorNumber(bool isWeakMap) { bool symbolsAsWeakMapKeysEnabled = JS::Prefs::experimental_symbols_as_weakmap_keys(); if (symbolsAsWeakMapKeysEnabled) { return isWeakMap ? JSMSG_WEAKMAP_KEY_CANT_BE_HELD_WEAKLY : JSMSG_WEAKSET_VAL_CANT_BE_HELD_WEAKLY; } return isWeakMap ? JSMSG_WEAKMAP_KEY_MUST_BE_AN_OBJECT : JSMSG_WEAKSET_VAL_MUST_BE_AN_OBJECT; } } // namespace js #endif /* builtin_WeakMapObject_inl_h */