NativeThenHandler.cpp (5556B)
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 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "gtest/gtest.h" 8 #include "js/TypeDecls.h" 9 #include "js/Value.h" 10 #include "mozilla/dom/Promise-inl.h" 11 #include "mozilla/dom/Promise.h" 12 #include "xpcpublic.h" 13 14 using namespace mozilla; 15 using namespace mozilla::dom; 16 17 struct TraceCounts { 18 int32_t mValue = 0; 19 int32_t mId = 0; 20 int32_t mObject = 0; 21 int32_t mWrapperCache = 0; 22 int32_t mTenuredHeapObject = 0; 23 int32_t mString = 0; 24 int32_t mScript = 0; 25 int32_t mFunction = 0; 26 }; 27 28 struct DummyCallbacks final : public TraceCallbacks { 29 void Trace(JS::Heap<JS::Value>*, const char*, void* aClosure) const override { 30 static_cast<TraceCounts*>(aClosure)->mValue++; 31 } 32 33 void Trace(JS::Heap<jsid>*, const char*, void* aClosure) const override { 34 static_cast<TraceCounts*>(aClosure)->mId++; 35 } 36 37 void Trace(JS::Heap<JSObject*>*, const char*, void* aClosure) const override { 38 static_cast<TraceCounts*>(aClosure)->mObject++; 39 } 40 41 void Trace(nsWrapperCache*, const char* aName, 42 void* aClosure) const override { 43 static_cast<TraceCounts*>(aClosure)->mWrapperCache++; 44 } 45 46 void Trace(JS::TenuredHeap<JSObject*>*, const char*, 47 void* aClosure) const override { 48 static_cast<TraceCounts*>(aClosure)->mTenuredHeapObject++; 49 } 50 51 void Trace(JS::Heap<JSString*>*, const char*, void* aClosure) const override { 52 static_cast<TraceCounts*>(aClosure)->mString++; 53 } 54 55 void Trace(JS::Heap<JSScript*>*, const char*, void* aClosure) const override { 56 static_cast<TraceCounts*>(aClosure)->mScript++; 57 } 58 59 void Trace(JS::Heap<JSFunction*>*, const char*, 60 void* aClosure) const override { 61 static_cast<TraceCounts*>(aClosure)->mFunction++; 62 } 63 }; 64 65 TEST(NativeThenHandler, TraceValue) 66 { 67 auto onResolve = [](JSContext*, JS::Handle<JS::Value>, ErrorResult&, 68 JS::Handle<JS::Value>) -> already_AddRefed<Promise> { 69 return nullptr; 70 }; 71 auto onReject = [](JSContext*, JS::Handle<JS::Value>, ErrorResult&, 72 JS::Handle<JS::Value>) -> already_AddRefed<Promise> { 73 return nullptr; 74 }; 75 76 // Explicit type for backward compatibility with clang<7 / gcc<8 77 using HandlerType = 78 NativeThenHandler<decltype(onResolve), decltype(onReject), std::tuple<>, 79 std::tuple<JS::HandleValue>>; 80 RefPtr<HandlerType> handler = new HandlerType( 81 nullptr, Some(onResolve), Some(onReject), std::make_tuple(), 82 std::make_tuple(JS::UndefinedHandleValue)); 83 84 TraceCounts counts; 85 NS_CYCLE_COLLECTION_PARTICIPANT(HandlerType) 86 ->Trace(handler.get(), DummyCallbacks(), &counts); 87 88 EXPECT_EQ(counts.mValue, 1); 89 } 90 91 TEST(NativeThenHandler, TraceObject) 92 { 93 auto onResolve = [](JSContext*, JS::Handle<JS::Value>, ErrorResult&, 94 JS::Handle<JSObject*>) -> already_AddRefed<Promise> { 95 return nullptr; 96 }; 97 auto onReject = [](JSContext*, JS::Handle<JS::Value>, ErrorResult&, 98 JS::Handle<JSObject*>) -> already_AddRefed<Promise> { 99 return nullptr; 100 }; 101 102 AutoJSAPI jsapi; 103 MOZ_ALWAYS_TRUE(jsapi.Init(xpc::PrivilegedJunkScope())); 104 JSContext* cx = jsapi.cx(); 105 JS::Rooted<JSObject*> obj(cx, JS_NewPlainObject(cx)); 106 107 // Explicit type for backward compatibility with clang<7 / gcc<8 108 using HandlerType = 109 NativeThenHandler<decltype(onResolve), decltype(onReject), std::tuple<>, 110 std::tuple<JS::HandleObject>>; 111 RefPtr<HandlerType> handler = new HandlerType( 112 nullptr, Some(onResolve), Some(onReject), std::make_tuple(), 113 std::make_tuple(JS::HandleObject(obj))); 114 115 TraceCounts counts; 116 NS_CYCLE_COLLECTION_PARTICIPANT(HandlerType) 117 ->Trace(handler.get(), DummyCallbacks(), &counts); 118 119 EXPECT_EQ(counts.mObject, 1); 120 } 121 122 TEST(NativeThenHandler, TraceMixed) 123 { 124 auto onResolve = [](JSContext*, JS::Handle<JS::Value>, ErrorResult&, 125 nsIGlobalObject*, Promise*, JS::Handle<JS::Value>, 126 JS::Handle<JSObject*>) -> already_AddRefed<Promise> { 127 return nullptr; 128 }; 129 auto onReject = [](JSContext*, JS::Handle<JS::Value>, ErrorResult&, 130 nsIGlobalObject*, Promise*, JS::Handle<JS::Value>, 131 JS::Handle<JSObject*>) -> already_AddRefed<Promise> { 132 return nullptr; 133 }; 134 135 AutoJSAPI jsapi; 136 MOZ_ALWAYS_TRUE(jsapi.Init(xpc::PrivilegedJunkScope())); 137 JSContext* cx = jsapi.cx(); 138 nsCOMPtr<nsIGlobalObject> global = xpc::CurrentNativeGlobal(cx); 139 JS::Rooted<JSObject*> obj(cx, JS_NewPlainObject(cx)); 140 141 RefPtr<Promise> promise = Promise::Create(global, IgnoreErrors()); 142 143 // Explicit type for backward compatibility with clang<7 / gcc<8 144 using HandlerType = 145 NativeThenHandler<decltype(onResolve), decltype(onReject), 146 std::tuple<nsCOMPtr<nsIGlobalObject>, RefPtr<Promise>>, 147 std::tuple<JS::HandleValue, JS::HandleObject>>; 148 RefPtr<HandlerType> handler = new HandlerType( 149 nullptr, Some(onResolve), Some(onReject), 150 std::make_tuple(global, promise), 151 std::make_tuple(JS::UndefinedHandleValue, JS::HandleObject(obj))); 152 153 TraceCounts counts; 154 NS_CYCLE_COLLECTION_PARTICIPANT(HandlerType) 155 ->Trace(handler.get(), DummyCallbacks(), &counts); 156 157 EXPECT_EQ(counts.mValue, 1); 158 EXPECT_EQ(counts.mObject, 1); 159 }