/* -*- 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/. */ #include "mozilla/Maybe.h" #include "mozilla/UniquePtr.h" #include "mozilla/Unused.h" #include "gc/GCRuntime.h" #include "js/ArrayBuffer.h" // JS::NewArrayBuffer #include "js/RootingAPI.h" #include "jsapi-tests/tests.h" #include "vm/Runtime.h" #include "vm/JSContext-inl.h" using namespace js; // A heap-allocated structure containing one of our barriered pointer wrappers // to test. template struct TestStruct { W wrapper; void trace(JSTracer* trc) { TraceNullableEdge(trc, &wrapper, "TestStruct::wrapper"); } TestStruct() {} explicit TestStruct(T init) : wrapper(init) {} }; template static T* CreateNurseryGCThing(JSContext* cx) { MOZ_CRASH(); return nullptr; } template <> JSObject* CreateNurseryGCThing(JSContext* cx) { JS::RootedObject obj(cx, JS_NewPlainObject(cx)); if (!obj) { return nullptr; } JS_DefineProperty(cx, obj, "x", 42, 0); MOZ_ASSERT(IsInsideNursery(obj)); return obj; } template <> JSFunction* CreateNurseryGCThing(JSContext* cx) { /* * We don't actually use the function as a function, so here we cheat and * cast a JSObject. */ return static_cast(CreateNurseryGCThing(cx)); } template static T* CreateTenuredGCThing(JSContext* cx) { MOZ_CRASH(); return nullptr; } template <> JSObject* CreateTenuredGCThing(JSContext* cx) { // Use ArrayBuffers because they have finalizers, which allows using them in // TenuredHeap<> without awkward conversations about nursery allocatability. // Note that at some point ArrayBuffers might become nursery allocated at // which point this test will have to change. JSObject* obj = JS::NewArrayBuffer(cx, 20); MOZ_ASSERT(!IsInsideNursery(obj)); MOZ_ASSERT(obj->getClass()->hasFinalize() && !(obj->getClass()->flags & JSCLASS_SKIP_NURSERY_FINALIZE)); return obj; } static void MakeWhite(JSObject* obj) { gc::TenuredCell* cell = &obj->asTenured(); cell->unmark(); MOZ_ASSERT(!obj->isMarkedAny()); } static void MakeGray(JSObject* obj) { gc::TenuredCell* cell = &obj->asTenured(); cell->unmark(); cell->markIfUnmarked(gc::MarkColor::Gray); MOZ_ASSERT(obj->isMarkedGray()); } // Test post-barrier implementation on wrapper types. The following wrapper // types have post barriers: // - JS::Heap // - GCPtr // - HeapPtr // - WeakHeapPtr BEGIN_TEST(testGCHeapPostBarriers) { #ifdef JS_GC_ZEAL AutoLeaveZeal nozeal(cx); #endif /* JS_GC_ZEAL */ /* Sanity check - objects start in the nursery and then become tenured. */ JS_GC(cx); JS::RootedObject obj(cx, CreateNurseryGCThing(cx)); CHECK(js::gc::IsInsideNursery(obj.get())); JS_GC(cx); CHECK(!js::gc::IsInsideNursery(obj.get())); JS::RootedObject tenuredObject(cx, obj); /* JSObject and JSFunction objects are nursery allocated. */ CHECK(TestHeapPostBarriersForType()); CHECK(TestHeapPostBarriersForType()); // Bug 1599378: Add string tests. return true; } bool CanAccessObject(JSObject* obj) { JS::RootedObject rootedObj(cx, obj); JS::RootedValue value(cx); CHECK(JS_GetProperty(cx, rootedObj, "x", &value)); CHECK(value.isInt32()); CHECK(value.toInt32() == 42); return true; } template bool TestHeapPostBarriersForType() { CHECK((TestHeapPostBarriersForWrapper())); CHECK((TestHeapPostBarriersForMovableWrapper())); CHECK((TestHeapPostBarriersForMovableWrapper())); CHECK((TestHeapPostBarriersForMovableWrapper())); return true; } template