Skip to content

Commit ff1b979

Browse files
authored
Remove weak callback from __postFrameCallback cache (#1755)
* feat: Remove NDK profiler BREAKING CHANGE: __startNDKProfiler() and __stopNDKProfiler() global bindings no longer available. The NDK profiler was not functional, since nothing in the build process defined the NDK_PROFILER_ENABLED preprocessor symbol. The start and stop functions were already no-ops. * chore: Remove outdated comment RunMicrotasks no longer exists, it's already been replaced in the code with PerformMicrotaskCheckpoint. * chore: Use unique_ptr for NewBackingStore in byte buffers V8 doc: https://docs.google.com/document/d/1sTc_jRL87Fu175Holm5SV0kajkseGl2r8ifGY76G35k/edit The V8 usage examples show unique_ptr here; it probably doesn't matter much, but we don't need the backing store after creating the ArrayBuffer, and I believe shared_ptr is slightly more overhead than unique_ptr. For convenience, replace the manual empty deleter for direct buffers with v8::BackingStore::EmptyDeleter. * chore: Remove weak finalizer callback from __postFrameCallback() Weak finalizer callbacks are going away in V8 11.x, so we have to remove this one. Luckily, a finalizer callback is not necessary - it's never needed to prevent the frame callback from being collected. However, a weak callback is not necessary in the first place. We can just clean up the cache entry after the callback is executed, since it is only executed once. Note that the call to erase() destructs the FrameCallbackCacheEntry instance, making `entry` a dangling pointer, so don't use it after the erase(). There's probably a safer way to do this, although the way that first occurred to me (pass the key to the callback instead of the entry, and then use std::unordered_map::extract()) is not available on robin_hood::unordered_map. * fix: Make sure frame callbacks are not ignored There was a bug where __postFrameCallback() would not always cause the callback to be called. Without initializing `removed`, sometimes it would have a nonzero value, so the callback would be ignored. * chore: Clear callback caches' persistent handles in destructor Clearing the persistent handles in the destructor makes it a bit easier to deal with the cache entry's lifetime: they are cleared whenever the entry is removed from the cache. We do this for both the main thread callback cache and the frame callback cache. Adding a destructor makes the cache entries non-movable. But the only place where they were moved was when inserting them into the cache anyway. We can use C++17's try_emplace() method to insert them without having to move them. * chore: Construct FrameCallbackCacheEntry with ID This avoids the situation of forgetting to add an ID to the cache entry. * chore: Improve usage of unordered_map APIs in CallbackHandlers This fixes a few places where we can avoid double lookups: - In RunOnMainThreadFdCallback, we already have a valid iterator, so no need to look up the same key again in RemoveKey (this is the only usage of RemoveKey, so we can remove it.) (Additionally, we probably want to remove the cache entry before throwing a NativeScript exception.) - In PostFrameCallback and RemoveFrameCallback, we should not do contains() immediately followed by find(). * chore: Fix runtime typo * chore: Ignore main thread and frame callback return values We don't do anything with the return value from these callbacks, so it's OK to ignore them and not convert them to a local handle.
1 parent d08c4a5 commit ff1b979

File tree

6 files changed

+49
-133
lines changed

6 files changed

+49
-133
lines changed

test-app/runtime/src/main/cpp/ArrayBufferHelper.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,13 @@ void ArrayBufferHelper::CreateFromCallbackImpl(const FunctionCallbackInfo<Value>
8989
auto data = env.GetDirectBufferAddress(obj);
9090
auto size = env.GetDirectBufferCapacity(obj);
9191

92-
std::shared_ptr<v8::BackingStore> store = ArrayBuffer::NewBackingStore(
92+
std::unique_ptr<v8::BackingStore> store = ArrayBuffer::NewBackingStore(
9393
data,
9494
size,
95-
[](void* data, size_t length, void* deleter_data) {},
96-
data);
95+
BackingStore::EmptyDeleter,
96+
nullptr);
9797

98-
arrayBuffer = ArrayBuffer::New(isolate, store);
98+
arrayBuffer = ArrayBuffer::New(isolate, std::move(store));
9999
} else {
100100
if (m_remainingMethodID == nullptr) {
101101
m_remainingMethodID = env.GetMethodID(m_ByteBufferClass, "remaining", "()I");
@@ -117,15 +117,15 @@ void ArrayBufferHelper::CreateFromCallbackImpl(const FunctionCallbackInfo<Value>
117117
jbyte* data = new jbyte[bufferRemainingSize];
118118
memcpy(data, byteArrayElements, bufferRemainingSize);
119119

120-
std::shared_ptr<v8::BackingStore> store = ArrayBuffer::NewBackingStore(
120+
std::unique_ptr<v8::BackingStore> store = ArrayBuffer::NewBackingStore(
121121
data,
122122
bufferRemainingSize,
123123
[](void *data, size_t length, void *deleter_data) {
124124
delete[] ((jbyte*)data);
125125
},
126126
nullptr);
127127

128-
arrayBuffer = ArrayBuffer::New(isolate, store);
128+
arrayBuffer = ArrayBuffer::New(isolate, std::move(store));
129129
env.ReleaseByteArrayElements(byteArray, byteArrayElements, 0);
130130
}
131131

test-app/runtime/src/main/cpp/CallbackHandlers.cpp

Lines changed: 22 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -671,8 +671,11 @@ void CallbackHandlers::RunOnMainThreadCallback(const FunctionCallbackInfo<v8::Va
671671

672672
uint64_t key = ++count_;
673673
Local<v8::Function> callback = args[0].As<v8::Function>();
674-
CacheEntry entry(isolate, callback, context);
675-
cache_.emplace(key, std::move(entry));
674+
675+
bool inserted;
676+
std::tie(std::ignore, inserted) = cache_.try_emplace(key, isolate, callback, context);
677+
assert(inserted && "Main thread callback ID should not be duplicated");
678+
676679
auto value = Callback(key);
677680
auto size = sizeof(Callback);
678681
auto wrote = write(Runtime::GetWriter(),&value , size);
@@ -697,32 +700,20 @@ int CallbackHandlers::RunOnMainThreadFdCallback(int fd, int events, void *data)
697700
auto context = it->second.context_.Get(isolate);
698701
Context::Scope context_scope(context);
699702
Local<v8::Function> cb = it->second.callback_.Get(isolate);
700-
Local<Value> result;
701703

702704
v8::TryCatch tc(isolate);
703705

704-
if (!cb->Call(context, context->Global(), 0, nullptr).ToLocal(&result)) {}
706+
cb->Call(context, context->Global(), 0, nullptr); // ignore JS return value
707+
708+
cache_.erase(it);
705709

706710
if(tc.HasCaught()){
707711
throw NativeScriptException(tc);
708712
}
709713

710-
RemoveKey(key);
711-
712714
return 1;
713715
}
714716

715-
void CallbackHandlers::RemoveKey(const uint64_t key) {
716-
auto it = cache_.find(key);
717-
if (it == cache_.end()) {
718-
return;
719-
}
720-
721-
it->second.callback_.Reset();
722-
it->second.context_.Reset();
723-
cache_.erase(it);
724-
}
725-
726717
void CallbackHandlers::LogMethodCallback(const v8::FunctionCallbackInfo<v8::Value> &args) {
727718
try {
728719
if ((args.Length() > 0) && args[0]->IsString()) {
@@ -834,10 +825,10 @@ void CallbackHandlers::EnableVerboseLoggingMethodCallback(
834825
const v8::FunctionCallbackInfo<v8::Value> &args) {
835826
try {
836827
auto isolate = args.GetIsolate();
837-
auto runtume = Runtime::GetRuntime(isolate);
828+
auto runtime = Runtime::GetRuntime(isolate);
838829
tns::LogEnabled = true;
839830
JEnv env;
840-
env.CallVoidMethod(runtume->GetJavaRuntime(), ENABLE_VERBOSE_LOGGING_METHOD_ID);
831+
env.CallVoidMethod(runtime->GetJavaRuntime(), ENABLE_VERBOSE_LOGGING_METHOD_ID);
841832
} catch (NativeScriptException &e) {
842833
e.ReThrowToV8();
843834
} catch (std::exception e) {
@@ -855,10 +846,10 @@ void CallbackHandlers::DisableVerboseLoggingMethodCallback(
855846
const v8::FunctionCallbackInfo<v8::Value> &args) {
856847
try {
857848
auto isolate = args.GetIsolate();
858-
auto runtume = Runtime::GetRuntime(isolate);
849+
auto runtime = Runtime::GetRuntime(isolate);
859850
tns::LogEnabled = false;
860851
JEnv env;
861-
env.CallVoidMethod(runtume->GetJavaRuntime(), DISABLE_VERBOSE_LOGGING_METHOD_ID);
852+
env.CallVoidMethod(runtime->GetJavaRuntime(), DISABLE_VERBOSE_LOGGING_METHOD_ID);
862853
} catch (NativeScriptException &e) {
863854
e.ReThrowToV8();
864855
} catch (std::exception e) {
@@ -1589,16 +1580,12 @@ void CallbackHandlers::TerminateWorkerThread(Isolate *isolate) {
15891580
void CallbackHandlers::RemoveIsolateEntries(v8::Isolate *isolate) {
15901581
for (auto &item: cache_) {
15911582
if (item.second.isolate_ == isolate) {
1592-
item.second.callback_.Reset();
1593-
item.second.context_.Reset();
15941583
cache_.erase(item.first);
15951584
}
15961585
}
15971586

15981587
for (auto &item: frameCallbackCache_) {
15991588
if (item.second.isolate_ == isolate) {
1600-
item.second.callback_.Reset();
1601-
item.second.context_.Reset();
16021589
frameCallbackCache_.erase(item.first);
16031590
}
16041591
}
@@ -1653,12 +1640,10 @@ void CallbackHandlers::PostFrameCallback(const FunctionCallbackInfo<v8::Value> &
16531640

16541641
if (success && pId->IsNumber()){
16551642
auto id = pId->IntegerValue(context).FromMaybe(0);
1656-
if(frameCallbackCache_.contains(id)){
1657-
auto cb = frameCallbackCache_.find(id);
1658-
if(cb != frameCallbackCache_.end()){
1659-
cb->second.removed = false;
1660-
PostCallback(args, &cb->second, context);
1661-
}
1643+
auto cb = frameCallbackCache_.find(id);
1644+
if (cb != frameCallbackCache_.end()) {
1645+
cb->second.removed = false;
1646+
PostCallback(args, &cb->second, context);
16621647
return;
16631648
}
16641649
}
@@ -1668,26 +1653,10 @@ void CallbackHandlers::PostFrameCallback(const FunctionCallbackInfo<v8::Value> &
16681653

16691654
V8SetPrivateValue(isolate, func, idKey, v8::Number::New(isolate, (double) key));
16701655

1671-
FrameCallbackCacheEntry entry (isolate, callback, context);
1672-
entry.id = key;
1673-
1674-
auto finalCallback = [](const v8::WeakCallbackInfo<FrameCallbackCacheEntry> &data) {
1675-
auto value = data.GetParameter();
1676-
for (auto &item: frameCallbackCache_) {
1677-
if (item.second.id == value->id) {
1678-
item.second.context_.Reset();
1679-
item.second.callback_.Reset();
1680-
frameCallbackCache_.erase(item.first);
1681-
break;
1682-
}
1683-
}
1684-
};
1685-
1686-
entry.callback_.SetWeak(&entry, finalCallback, v8::WeakCallbackType::kFinalizer);
1687-
1688-
frameCallbackCache_.emplace(key, std::move(entry));
1689-
1690-
auto val = frameCallbackCache_.find(key);
1656+
robin_hood::unordered_map<uint64_t, FrameCallbackCacheEntry>::iterator val;
1657+
bool inserted;
1658+
std::tie(val, inserted) = frameCallbackCache_.try_emplace(key, isolate, callback, context, key);
1659+
assert(inserted && "Frame callback ID should not be duplicated");
16911660

16921661
PostCallback(args, &val->second, context);
16931662
}
@@ -1715,8 +1684,8 @@ void CallbackHandlers::RemoveFrameCallback(const FunctionCallbackInfo<v8::Value>
17151684

17161685
if (success && pId->IsNumber()){
17171686
auto id = pId->IntegerValue(context).FromMaybe(0);
1718-
if(frameCallbackCache_.contains(id)){
1719-
auto cb = frameCallbackCache_.find(id);
1687+
auto cb = frameCallbackCache_.find(id);
1688+
if (cb != frameCallbackCache_.end()) {
17201689
cb->second.removed = true;
17211690
}
17221691
}

test-app/runtime/src/main/cpp/CallbackHandlers.h

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -284,8 +284,6 @@ namespace tns {
284284
jobject _runtime;
285285
};
286286

287-
static void RemoveKey(const uint64_t key);
288-
289287
static std::atomic_int64_t count_;
290288

291289

@@ -305,6 +303,11 @@ namespace tns {
305303
context_(isolate, context){
306304
}
307305

306+
~CacheEntry() {
307+
context_.Reset();
308+
callback_.Reset();
309+
}
310+
308311
v8::Isolate* isolate_;
309312
v8::Global<v8::Function> callback_;
310313
v8::Global<v8::Context> context_;
@@ -316,17 +319,23 @@ namespace tns {
316319
static std::atomic_uint64_t frameCallbackCount_;
317320

318321
struct FrameCallbackCacheEntry {
319-
FrameCallbackCacheEntry(v8::Isolate *isolate, v8::Local<v8::Function> callback, v8::Local<v8::Context> context)
320-
: isolate_(isolate),
321-
callback_(isolate,callback),
322-
context_(isolate, context)
323-
{
322+
FrameCallbackCacheEntry(v8::Isolate *isolate, v8::Local<v8::Function> callback,
323+
v8::Local<v8::Context> context, uint64_t aId)
324+
: isolate_(isolate),
325+
callback_(isolate, callback),
326+
context_(isolate, context),
327+
id(aId) {
328+
}
329+
330+
~FrameCallbackCacheEntry() {
331+
context_.Reset();
332+
callback_.Reset();
324333
}
325334

326335
v8::Isolate *isolate_;
327336
v8::Global<v8::Function> callback_;
328337
v8::Global<v8::Context> context_;
329-
bool removed;
338+
bool removed = false;
330339
uint64_t id;
331340

332341
AChoreographer_frameCallback frameCallback_ = [](long ts, void *data) {
@@ -341,6 +350,7 @@ namespace tns {
341350
if (data != nullptr) {
342351
auto entry = static_cast<FrameCallbackCacheEntry *>(data);
343352
if (entry->removed) {
353+
frameCallbackCache_.erase(entry->id); // invalidates *entry
344354
return;
345355
}
346356
v8::Isolate *isolate = entry->isolate_;
@@ -352,15 +362,13 @@ namespace tns {
352362
v8::Context::Scope context_scope(context);
353363

354364
v8::Local<v8::Function> cb = entry->callback_.Get(isolate);
355-
v8::Local<v8::Value> result;
356-
357365
v8::Local<v8::Value> args[1] = {v8::Number::New(isolate, ts)};
358366

359367
v8::TryCatch tc(isolate);
360368

361-
if (!cb->Call(context, context->Global(), 1, args).ToLocal(&result)) {
362-
// TODO
363-
}
369+
cb->Call(context, context->Global(), 1, args); // ignore JS return value
370+
371+
frameCallbackCache_.erase(entry->id); // invalidates *entry
364372

365373
if(tc.HasCaught()){
366374
throw NativeScriptException(tc);

test-app/runtime/src/main/cpp/MessageLoopTimer.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,6 @@ int MessageLoopTimer::PumpMessageLoopCallback(int fd, int events, void* data) {
129129
v8::HandleScope handleScope(isolate);
130130

131131
while (v8::platform::PumpMessageLoop(Runtime::platform, isolate)) {
132-
// isolate->RunMicrotasks();
133132
isolate->PerformMicrotaskCheckpoint();
134133
}
135134

test-app/runtime/src/main/cpp/Profiler.cpp

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ void Profiler::Init(Isolate* isolate, const Local<Object>& globalObj, const stri
1818
globalObj->Set(context, ArgConverter::ConvertToV8String(isolate, "__startCPUProfiler"), FunctionTemplate::New(isolate, Profiler::StartCPUProfilerCallback, extData)->GetFunction(context).ToLocalChecked());
1919
globalObj->Set(context, ArgConverter::ConvertToV8String(isolate, "__stopCPUProfiler"), FunctionTemplate::New(isolate, Profiler::StopCPUProfilerCallback, extData)->GetFunction(context).ToLocalChecked());
2020
globalObj->Set(context, ArgConverter::ConvertToV8String(isolate, "__heapSnapshot"), FunctionTemplate::New(isolate, Profiler::HeapSnapshotMethodCallback, extData)->GetFunction(context).ToLocalChecked());
21-
globalObj->Set(context, ArgConverter::ConvertToV8String(isolate, "__startNDKProfiler"), FunctionTemplate::New(isolate, Profiler::StartNDKProfilerCallback, extData)->GetFunction(context).ToLocalChecked());
22-
globalObj->Set(context, ArgConverter::ConvertToV8String(isolate, "__stopNDKProfiler"), FunctionTemplate::New(isolate, Profiler::StopNDKProfilerCallback, extData)->GetFunction(context).ToLocalChecked());
2321
}
2422

2523
void Profiler::StartCPUProfilerCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
@@ -195,56 +193,6 @@ bool Profiler::Write(CpuProfile* cpuProfile) {
195193
return true;
196194
}
197195

198-
void Profiler::StartNDKProfilerCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
199-
try {
200-
auto isolate = args.GetIsolate();
201-
auto extData = args.Data().As<External>();
202-
auto thiz = static_cast<Profiler*>(extData->Value());
203-
thiz->StartNDKProfiler();
204-
} catch (NativeScriptException& e) {
205-
e.ReThrowToV8();
206-
} catch (std::exception e) {
207-
stringstream ss;
208-
ss << "Error: c++ exception: " << e.what() << endl;
209-
NativeScriptException nsEx(ss.str());
210-
nsEx.ReThrowToV8();
211-
} catch (...) {
212-
NativeScriptException nsEx(std::string("Error: c++ exception!"));
213-
nsEx.ReThrowToV8();
214-
}
215-
}
216-
217-
void Profiler::StopNDKProfilerCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
218-
try {
219-
auto isolate = args.GetIsolate();
220-
auto extData = args.Data().As<External>();
221-
auto thiz = static_cast<Profiler*>(extData->Value());
222-
thiz->StopNDKProfiler();
223-
} catch (NativeScriptException& e) {
224-
e.ReThrowToV8();
225-
} catch (std::exception e) {
226-
stringstream ss;
227-
ss << "Error: c++ exception: " << e.what() << endl;
228-
NativeScriptException nsEx(ss.str());
229-
nsEx.ReThrowToV8();
230-
} catch (...) {
231-
NativeScriptException nsEx(std::string("Error: c++ exception!"));
232-
nsEx.ReThrowToV8();
233-
}
234-
}
235-
236-
void Profiler::StartNDKProfiler() {
237-
#ifdef NDK_PROFILER_ENABLED
238-
monstartup("libNativeScript.so");
239-
#endif
240-
}
241-
242-
void Profiler::StopNDKProfiler() {
243-
#ifdef NDK_PROFILER_ENABLED
244-
moncleanup();
245-
#endif
246-
}
247-
248196
class FileOutputStream: public OutputStream {
249197
public:
250198
FileOutputStream(FILE* stream) :

test-app/runtime/src/main/cpp/Profiler.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,6 @@ class Profiler {
1717

1818
static void StopCPUProfilerCallback(const v8::FunctionCallbackInfo<v8::Value>& args);
1919

20-
static void StartNDKProfilerCallback(const v8::FunctionCallbackInfo<v8::Value>& args);
21-
22-
static void StopNDKProfilerCallback(const v8::FunctionCallbackInfo<v8::Value>& args);
23-
2420
static void HeapSnapshotMethodCallback(const v8::FunctionCallbackInfo<v8::Value>& args);
2521

2622
void StartCPUProfilerCallbackImpl(const v8::FunctionCallbackInfo<v8::Value>& args);
@@ -33,10 +29,6 @@ class Profiler {
3329

3430
bool StopCPUProfiler(v8::Isolate* isolate, const v8::Local<v8::String>& name);
3531

36-
void StartNDKProfiler();
37-
38-
void StopNDKProfiler();
39-
4032
bool Write(v8::CpuProfile* cpuProfile);
4133

4234
std::string m_appName;

0 commit comments

Comments
 (0)