Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
9096fd1
Update V8Runtime.cpp for UncaughtException handler
Informate Feb 8, 2025
2b4f484
Update V8Runtime.cpp
Informate Feb 8, 2025
9819946
Update V8Runtime.cpp
Informate Feb 8, 2025
0e09f3b
Update V8Runtime.cpp
Informate Feb 8, 2025
e6c0004
Update V8Runtime.cpp
Informate Feb 9, 2025
228f3ce
Update V8Util.cpp
Informate Feb 9, 2025
07a381e
Update V8Runtime.cpp
Informate Feb 9, 2025
e61cbd8
Update V8Runtime.cpp
Informate Feb 9, 2025
3ce8d0a
Update V8Runtime.cpp
Informate Feb 9, 2025
5db21dd
Update V8Runtime.cpp
Informate Feb 9, 2025
90ef049
Update V8Runtime.cpp
Informate Feb 9, 2025
f4f7069
Update V8Runtime.cpp
Informate Feb 10, 2025
5495fc9
Update V8Runtime.cpp
Informate Feb 10, 2025
25606c3
Update V8Runtime.cpp
Informate Feb 10, 2025
c9f7ebd
Update V8Runtime.cpp
Informate Feb 10, 2025
8992417
Update V8Util.cpp
Informate Feb 10, 2025
26c8be8
Update V8Util.h
Informate Feb 10, 2025
ed77266
Update V8Util.cpp
Informate Feb 10, 2025
8ce6228
Update V8Util.cpp
Informate Feb 11, 2025
7647436
Update V8Util.cpp
Informate Feb 13, 2025
96898a4
Merge branch 'master' into master
m1ga Aug 7, 2025
a4dcf19
Merge branch 'tidev:main' into master
Informate Jan 6, 2026
2dc4982
Optimize V8Util.cpp
Informate Jan 9, 2026
0134031
Merge branch 'tidev:main' into master
Informate Jan 28, 2026
d3d8b1c
Merge branch 'main' into master
m1ga Jan 29, 2026
9c6fcf1
Update V8Util.cpp
Informate Feb 8, 2026
fcc2900
Update V8Util.cpp
Informate Feb 9, 2026
5e2730a
Update V8Util.cpp
Informate Feb 9, 2026
4f1f2d1
Merge branch 'tidev:main' into master
Informate Feb 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions android/runtime/v8/src/native/V8Runtime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ JNIEXPORT void JNICALL Java_org_appcelerator_kroll_runtime_v8_V8Runtime_nativeIn
// isolate->SetAbortOnUncaughtExceptionCallback(ShouldAbortOnUncaughtException);
// isolate->SetAutorunMicrotasks(false);
// isolate->SetFatalErrorHandler(OnFatalError);
isolate->SetPromiseRejectCallback(V8Util::reportRejection);
isolate->SetCaptureStackTraceForUncaughtExceptions(true, 10, v8::StackTrace::kOverview);
} else {
isolate = V8Runtime::v8_isolate;
Expand Down
110 changes: 110 additions & 0 deletions android/runtime/v8/src/native/V8Util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/
#include <cstring>
#include <sstream>
#include <unordered_set>

#include "V8Util.h"
#include "JNIUtil.h"
Expand Down Expand Up @@ -157,6 +158,115 @@ void V8Util::reportException(Isolate* isolate, TryCatch &tryCatch, bool showLine
LOGE(EXC_TAG, *error);
}

static thread_local std::unordered_set<v8::Global<v8::Value>*> seenErrors;
static void errorWeakCallback(const v8::WeakCallbackInfo<v8::Global<v8::Value>>& info) {
v8::Global<v8::Value>* g = info.GetParameter();
seenErrors.erase(g);
g->Reset();
delete g;
}
void V8Util::reportRejection(v8::PromiseRejectMessage data)
{
// Extract main Objects
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::Local<v8::Value> value=data.GetValue();

// Deduplication Process and Rejection consistency check
v8::PromiseRejectEvent event = data.GetEvent();
if (event == v8::kPromiseRejectWithNoHandler) {

// Deduplicate on same value (Error)
for (v8::Global<v8::Value>* g : seenErrors) {
if (g->Get(isolate)->StrictEquals(value)) {
LOGD(EXC_TAG, "PromiseRejectEvent duplicated discarded");
return;
}
}
} else if (event == v8::kPromiseHandlerAddedAfterReject) {
LOGD(EXC_TAG, "PromiseRejectEvent handler added after reject discarded");
return;
} else {
LOGE(EXC_TAG, "PromiseRejectEvent with unexpected event (%d) Lost", event);
return;
}

// Value consistency check
if (value.IsEmpty()) {
LOGE(EXC_TAG, "PromiseRejectEvent with Empty Value Lost");
return;
}

// Track the Error with Global + weak
v8::Global<v8::Value>* g = new v8::Global<v8::Value>(isolate, value);
g->SetWeak(g, errorWeakCallback, v8::WeakCallbackType::kParameter);
seenErrors.insert(g);

// Extract Error message
v8::Local<v8::Message> message = v8::Exception::CreateMessage(isolate, value);
v8::String::Utf8Value utf8Message(isolate, message->Get());
v8::String::Utf8Value utf8ScriptName(isolate, message->GetScriptResourceName());
v8::Local<v8::String> logSourceLine = message->GetSourceLine(context).ToLocalChecked();
v8::String::Utf8Value utf8SourceLine(isolate, logSourceLine);

// Log Error message to Console
LOGE(TAG, "%s", *utf8Message);
LOGE(TAG, "%s @ %d >>> %s",
*utf8ScriptName,
message->GetLineNumber(context).FromMaybe(-1),
*utf8SourceLine);

// Obtain javascript and java stack traces
Local<Value> jsStack=Undefined(isolate);
Local<Value> javaStack=Undefined(isolate);
if (value->IsObject()) {
Local<Object> error = value.As<Object>();
jsStack = error->Get(context, STRING_NEW(isolate, "stack")).FromMaybe(Undefined(isolate).As<Value>());
javaStack = error->Get(context, STRING_NEW(isolate, "nativeStack")).FromMaybe(Undefined(isolate).As<Value>());
}

// javascript stack trace not provided? obtain current javascript stack trace
if (jsStack.IsEmpty() || jsStack->IsNullOrUndefined()) {
Local<StackTrace> frames = message->GetStackTrace();
if (frames.IsEmpty() || !frames->GetFrameCount()) {
frames = StackTrace::CurrentStackTrace(isolate, MAX_STACK);
}
if (!frames.IsEmpty()) {
std::string stackString = V8Util::stackTraceString(isolate, frames);
if (!stackString.empty()) {
jsStack = String::NewFromUtf8(isolate, stackString.c_str(), v8::NewStringType::kNormal).ToLocalChecked().As<Value>();
}
}
}

// Report Exception to JS via krollRuntimeDispatchExceptionMethod
JNIEnv* env = titanium::JNIUtil::getJNIEnv();
jstring title = env->NewStringUTF("Rejected Promise");
jstring errorMessage = titanium::TypeConverter::jsValueToJavaString(isolate, env, message->Get());
jstring resourceName = titanium::TypeConverter::jsValueToJavaString(isolate, env, message->GetScriptResourceName());
jstring sourceLine = titanium::TypeConverter::jsValueToJavaString(isolate, env, message->GetSourceLine(context).FromMaybe(Null(isolate).As<Value>()));
jstring jsStackString = titanium::TypeConverter::jsValueToJavaString(isolate, env, jsStack);
jstring javaStackString = titanium::TypeConverter::jsValueToJavaString(isolate, env, javaStack);
env->CallStaticVoidMethod(
titanium::JNIUtil::krollRuntimeClass,
titanium::JNIUtil::krollRuntimeDispatchExceptionMethod,
title,
errorMessage,
resourceName,
message->GetLineNumber(context).FromMaybe(-1),
sourceLine,
message->GetEndColumn(context).FromMaybe(-1),
jsStackString,
javaStackString);
env->DeleteLocalRef(title);
env->DeleteLocalRef(errorMessage);
env->DeleteLocalRef(resourceName);
env->DeleteLocalRef(sourceLine);
env->DeleteLocalRef(jsStackString);
env->DeleteLocalRef(javaStackString);
}

void V8Util::openJSErrorDialog(Isolate* isolate, TryCatch &tryCatch)
{
JNIEnv *env = JNIUtil::getJNIEnv();
Expand Down
1 change: 1 addition & 0 deletions android/runtime/v8/src/native/V8Util.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ class V8Util {
static void objectExtend(v8::Local<v8::Object> dest, v8::Local<v8::Object> src); // TODO: Remove when we do a breaking change!
static void objectExtend(v8::Isolate* isolate, v8::Local<v8::Object> dest, v8::Local<v8::Object> src);
static void reportException(v8::Isolate* isolate, v8::TryCatch &tryCatch, bool showLine = true);
static void reportRejection(v8::PromiseRejectMessage data);
static void openJSErrorDialog(v8::Isolate* isolate, v8::TryCatch &tryCatch);
static void fatalException(v8::Isolate* isolate, v8::TryCatch &tryCatch);
static v8::Local<v8::String> jsonStringify(v8::Isolate* isolate, v8::Local<v8::Value> value);
Expand Down