Skip to content

Commit

Permalink
perf: optimizations around generating JS classes from Metadata (#1824)
Browse files Browse the repository at this point in the history
  • Loading branch information
ammarahm-ed authored Jan 19, 2025
1 parent 3423e6f commit f290ed2
Show file tree
Hide file tree
Showing 13 changed files with 694 additions and 529 deletions.
1 change: 1 addition & 0 deletions test-app/runtime/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ add_library(
src/main/cpp/MetadataNode.cpp
src/main/cpp/MetadataReader.cpp
src/main/cpp/MetadataTreeNode.cpp
src/main/cpp/MetadataEntry.cpp
src/main/cpp/MethodCache.cpp
src/main/cpp/ModuleBinding.cpp
src/main/cpp/ModuleInternal.cpp
Expand Down
21 changes: 11 additions & 10 deletions test-app/runtime/src/main/cpp/CallbackHandlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,8 @@ void CallbackHandlers::CallJavaMethod(const Local<Object> &caller, const string

auto isolate = args.GetIsolate();

if ((entry != nullptr) && entry->isResolved) {
if ((entry != nullptr) && entry->getIsResolved()) {
auto &entrySignature = entry->getSig();
isStatic = entry->isStatic;

if (entry->memberId == nullptr) {
Expand All @@ -236,14 +237,14 @@ void CallbackHandlers::CallJavaMethod(const Local<Object> &caller, const string
if (isFromInterface) {
auto methodAndClassPair = env.GetInterfaceStaticMethodIDAndJClass(className,
methodName,
entry->sig);
entrySignature);
entry->memberId = methodAndClassPair.first;
clazz = methodAndClassPair.second;
} else {
entry->memberId = env.GetStaticMethodID(clazz, methodName, entry->sig);
entry->memberId = env.GetStaticMethodID(clazz, methodName, entrySignature);
}
} else {
entry->memberId = env.GetMethodID(clazz, methodName, entry->sig);
entry->memberId = env.GetMethodID(clazz, methodName, entrySignature);
}

if (entry->memberId == nullptr) {
Expand All @@ -257,14 +258,14 @@ void CallbackHandlers::CallJavaMethod(const Local<Object> &caller, const string
if (isFromInterface) {
auto methodAndClassPair = env.GetInterfaceStaticMethodIDAndJClass(className,
methodName,
entry->sig);
entrySignature);
entry->memberId = methodAndClassPair.first;
clazz = methodAndClassPair.second;
} else {
entry->memberId = env.GetStaticMethodID(clazz, methodName, entry->sig);
entry->memberId = env.GetStaticMethodID(clazz, methodName, entrySignature);
}
} else {
entry->memberId = env.GetMethodID(clazz, methodName, entry->sig);
entry->memberId = env.GetMethodID(clazz, methodName, entrySignature);
}

if (entry->memberId == nullptr) {
Expand All @@ -279,9 +280,9 @@ void CallbackHandlers::CallJavaMethod(const Local<Object> &caller, const string

mid = reinterpret_cast<jmethodID>(entry->memberId);
clazz = entry->clazz;
sig = &entry->sig;
returnType = &entry->returnType;
retType = entry->retType;
sig = &entrySignature;
returnType = &entry->getReturnType();
retType = entry->getRetType();
} else {
DEBUG_WRITE("Resolving method: %s on className %s", methodName.c_str(), className.c_str());

Expand Down
33 changes: 19 additions & 14 deletions test-app/runtime/src/main/cpp/FieldAccessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ Local<Value> FieldAccessor::GetJavaField(Isolate* isolate, const Local<Object>&

JniLocalRef targetJavaObject;

const auto& fieldTypeName = fieldData->signature;
auto isStatic = fieldData->isStatic;
auto &fieldMetadata = fieldData->metadata;

const auto& fieldTypeName = fieldMetadata.getSig();
auto isStatic = fieldMetadata.isStatic;

auto isPrimitiveType = fieldTypeName.size() == 1;
auto isFieldArray = fieldTypeName[0] == '[';
Expand All @@ -35,11 +37,11 @@ Local<Value> FieldAccessor::GetJavaField(Isolate* isolate, const Local<Object>&
("L" + fieldTypeName + ";"));

if (isStatic) {
fieldData->clazz = env.FindClass(fieldData->declaringType);
fieldData->fid = env.GetStaticFieldID(fieldData->clazz, fieldData->name, fieldJniSig);
fieldData->clazz = env.FindClass(fieldMetadata.getDeclaringType());
fieldData->fid = env.GetStaticFieldID(fieldData->clazz, fieldMetadata.name, fieldJniSig);
} else {
fieldData->clazz = env.FindClass(fieldData->declaringType);
fieldData->fid = env.GetFieldID(fieldData->clazz, fieldData->name, fieldJniSig);
fieldData->clazz = env.FindClass(fieldMetadata.getDeclaringType());
fieldData->fid = env.GetFieldID(fieldData->clazz, fieldMetadata.name, fieldJniSig);
}
}

Expand All @@ -48,7 +50,7 @@ Local<Value> FieldAccessor::GetJavaField(Isolate* isolate, const Local<Object>&

if (targetJavaObject.IsNull()) {
stringstream ss;
ss << "Cannot access property '" << fieldData->name.c_str() << "' because there is no corresponding Java object";
ss << "Cannot access property '" << fieldMetadata.name.c_str() << "' because there is no corresponding Java object";
throw NativeScriptException(ss.str());
}
}
Expand Down Expand Up @@ -186,14 +188,17 @@ Local<Value> FieldAccessor::GetJavaField(Isolate* isolate, const Local<Object>&
void FieldAccessor::SetJavaField(Isolate* isolate, const Local<Object>& target, const Local<Value>& value, FieldCallbackData* fieldData) {
JEnv env;

auto &fieldMetadata = fieldData->metadata;

HandleScope handleScope(isolate);
auto runtime = Runtime::GetRuntime(isolate);
auto objectManager = runtime->GetObjectManager();

JniLocalRef targetJavaObject;

const auto& fieldTypeName = fieldData->signature;
auto isStatic = fieldData->isStatic;
const auto& fieldTypeName = fieldMetadata.getSig();
auto isStatic = fieldMetadata.isStatic;


auto isPrimitiveType = fieldTypeName.size() == 1;
auto isFieldArray = fieldTypeName[0] == '[';
Expand All @@ -208,14 +213,14 @@ void FieldAccessor::SetJavaField(Isolate* isolate, const Local<Object>& target,
("L" + fieldTypeName + ";"));

if (isStatic) {
fieldData->clazz = env.FindClass(fieldData->declaringType);
fieldData->clazz = env.FindClass(fieldMetadata.getDeclaringType());
assert(fieldData->clazz != nullptr);
fieldData->fid = env.GetStaticFieldID(fieldData->clazz, fieldData->name, fieldJniSig);
fieldData->fid = env.GetStaticFieldID(fieldData->clazz, fieldMetadata.name, fieldJniSig);
assert(fieldData->fid != nullptr);
} else {
fieldData->clazz = env.FindClass(fieldData->declaringType);
fieldData->clazz = env.FindClass(fieldMetadata.getDeclaringType());
assert(fieldData->clazz != nullptr);
fieldData->fid = env.GetFieldID(fieldData->clazz, fieldData->name, fieldJniSig);
fieldData->fid = env.GetFieldID(fieldData->clazz, fieldMetadata.name, fieldJniSig);
assert(fieldData->fid != nullptr);
}
}
Expand All @@ -225,7 +230,7 @@ void FieldAccessor::SetJavaField(Isolate* isolate, const Local<Object>& target,

if (targetJavaObject.IsNull()) {
stringstream ss;
ss << "Cannot access property '" << fieldData->name.c_str() << "' because there is no corresponding Java object";
ss << "Cannot access property '" << fieldMetadata.name.c_str() << "' because there is no corresponding Java object";
throw NativeScriptException(ss.str());
}
}
Expand Down
27 changes: 9 additions & 18 deletions test-app/runtime/src/main/cpp/FieldCallbackData.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,16 @@
#include "MetadataEntry.h"

namespace tns {
struct FieldCallbackData {
FieldCallbackData(const MetadataEntry& metadata)
:
fid(nullptr), clazz(nullptr) {
name = metadata.name;
signature = metadata.sig;
declaringType = metadata.declaringType;
isStatic = metadata.isStatic;
isFinal = metadata.isFinal;
}
struct FieldCallbackData {
FieldCallbackData(MetadataEntry metadata)
:
metadata(metadata), fid(nullptr), clazz(nullptr) {
}

std::string name;
std::string signature;
std::string declaringType;
bool isStatic;
bool isFinal;
jfieldID fid;
jclass clazz;
};
MetadataEntry metadata;
jfieldID fid;
jclass clazz;
};

}

Expand Down
4 changes: 2 additions & 2 deletions test-app/runtime/src/main/cpp/JsArgConverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ JsArgConverter::JsArgConverter(const Local<Object> &caller,
m_argsLen = 1 + v8ProvidedArgumentsLength;

if (m_argsLen > 0) {
if ((entry != nullptr) && (entry->isResolved)) {
if ((entry != nullptr) && (entry->getIsResolved())) {
if (entry->parsedSig.empty()) {
JniSignatureParser parser(m_methodSignature);
entry->parsedSig = parser.Parse();
Expand Down Expand Up @@ -58,7 +58,7 @@ JsArgConverter::JsArgConverter(const v8::FunctionCallbackInfo<Value> &args,
m_argsLen = !hasImplementationObject ? args.Length() : args.Length() - 1;

if (m_argsLen > 0) {
if ((entry != nullptr) && (entry->isResolved)) {
if ((entry != nullptr) && (entry->getIsResolved())) {
if (entry->parsedSig.empty()) {
JniSignatureParser parser(m_methodSignature);
entry->parsedSig = parser.Parse();
Expand Down
135 changes: 135 additions & 0 deletions test-app/runtime/src/main/cpp/MetadataEntry.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
#include "MetadataNode.h"
#include "MetadataEntry.h"
#include "MetadataMethodInfo.h"
#include "MetadataReader.h"

using namespace tns;

MetadataEntry::MetadataEntry(MetadataTreeNode *m_treeNode, NodeType nodeType) :
treeNode(m_treeNode), type(nodeType), isExtensionFunction(false), isStatic(false),
isTypeMember(false), memberId(nullptr), clazz(nullptr), mi(nullptr),fi(nullptr), sfi(nullptr),
retType(MethodReturnType::Unknown),
paramCount(-1), isFinal(false), isResolved(false), retTypeParsed(false),
isFinalSet(false), isResolvedSet(false) {}

std::string &MetadataEntry::getName() {
if (!name.empty()) return name;

auto reader = MetadataNode::getMetadataReader();

if (type == NodeType::Field) {
name = reader->ReadName(fi->nameOffset);
} else if (type == NodeType::StaticField) {
name = reader->ReadName(sfi->nameOffset);
} else if (type == NodeType::Method) {
name = mi.GetName();
}

return name;
}

std::string &MetadataEntry::getSig() {
if (!sig.empty()) return sig;

auto reader = MetadataNode::getMetadataReader();

if (type == NodeType::Field) {
sig = reader->ReadTypeName(fi->nodeId);
} else if (type == NodeType::StaticField) {
sig = reader->ReadTypeName(sfi->nodeId);
} else if (type == NodeType::Method) {
uint8_t sigLength = mi.GetSignatureLength();
if (sigLength > 0)
sig = mi.GetSignature();

}

return sig;
}

std::string &MetadataEntry::getReturnType() {
if (!returnType.empty()) return returnType;

auto reader = MetadataNode::getMetadataReader();

if (type == NodeType::Method) {
if (mi.GetSignatureLength() > 0) {
returnType = MetadataReader::ParseReturnType(this->getSig());
}
} else {
return returnType;
}

return returnType;
}

MethodReturnType MetadataEntry::getRetType() {
if (retTypeParsed) return retType;
auto reader = MetadataNode::getMetadataReader();

if (type == NodeType::Method && !this->getReturnType().empty()) {
retType = MetadataReader::GetReturnType(this->returnType);
}

retTypeParsed = true;

return retType;
}

std::string &MetadataEntry::getDeclaringType() {
if (!declaringType.empty()) return declaringType;

auto reader = MetadataNode::getMetadataReader();

if (type == NodeType::StaticField) {
declaringType = reader->ReadTypeName(sfi->declaringType);
} else if (type == NodeType::Method && isStatic) {
declaringType = mi.GetDeclaringType();
}

return declaringType;
}

int MetadataEntry::getParamCount() {
if (paramCount != -1) return paramCount;

auto reader = MetadataNode::getMetadataReader();

if (type == NodeType::Method) {
auto sigLength = mi.GetSignatureLength();
if (sigLength > 0) {
paramCount = sigLength - 1;
} else {
paramCount = 0;
}
}

return paramCount;
}

bool MetadataEntry::getIsFinal() {
if (isFinalSet) return isFinal;

if (type == NodeType::Field) {
isFinal = fi->finalModifier == MetadataTreeNode::FINAL;
} else if (type == NodeType::StaticField) {
isFinal = sfi->finalModifier == MetadataTreeNode::FINAL;
}

isFinalSet = true;

return isFinal;
}

bool MetadataEntry::getIsResolved() {
if (isResolvedSet) return isResolved;

auto reader = MetadataNode::getMetadataReader();
if (type == NodeType::Method) {
isResolved = mi.CheckIsResolved() == 1;
}

isResolvedSet = true;

return isResolved;
}
Loading

0 comments on commit f290ed2

Please sign in to comment.