Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DCHECK fixes #1764

Merged
merged 6 commits into from
Jun 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion test-app/app/src/main/assets/app/shared
Submodule shared updated 1 files
+2 −2 Require/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,27 @@ describe("Tests Kotlin extension functions support", function () {
expect(hasException).toBe(false);
});

describe("Kotlin extension functions that shadow Java functions", function () {
let handler;
beforeEach(function () {
handler = new android.os.Handler(android.os.Looper.getMainLooper());
});

it("should call the Java function", function (done) {
const run = jasmine.createSpy("java.lang.Runnable.run").and.callFake(function () {
done();
});
const javaRunnable = new java.lang.Runnable({run});
handler.postAtTime(javaRunnable, 1);
})

it("should call the Kotlin function", function (done) {
const invoke = jasmine.createSpy("kotlin.jvm.functions.Function0.invoke").and.callFake(function () {
done();
});
const cancelToken = new java.lang.Object();
const kotlinFunc = new kotlin.jvm.functions.Function0({invoke});
handler.postAtTime(1, cancelToken, kotlinFunc);
})
});
});
47 changes: 18 additions & 29 deletions test-app/runtime/src/main/cpp/CallbackHandlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -570,40 +570,25 @@ CallbackHandlers::GetImplementedInterfaces(JEnv &env, const Local<Object> &imple
vector<jstring> interfacesToImplement;
auto isolate = implementationObject->GetIsolate();
auto context = implementationObject->CreationContext();
auto propNames = implementationObject->GetOwnPropertyNames(context).ToLocalChecked();
for (int i = 0; i < propNames->Length(); i++) {
auto name = propNames->Get(context, i).ToLocalChecked().As<String>();
auto prop = implementationObject->Get(context, name).ToLocalChecked();

bool arrFound = !prop.IsEmpty() && prop->IsArray();
Local<String> interfacesName = String::NewFromUtf8Literal(isolate, "interfaces");
Local<Value> prop;
if (implementationObject->Get(context, interfacesName).ToLocal(&prop) && !prop.IsEmpty() && prop->IsArray()) {
auto interfacesArr = prop->ToObject(context).ToLocalChecked();

if (arrFound) {
v8::String::Utf8Value propName(isolate, name);
std::string arrNameC = std::string(*propName);
if (arrNameC == "interfaces") {
auto interfacesArr = prop->ToObject(context).ToLocalChecked();
Local<String> lengthName = String::NewFromUtf8Literal(isolate, "length");
unsigned length = interfacesArr->Get(context,lengthName).ToLocalChecked()
->Uint32Value(context).ToChecked();

int length = interfacesArr->Get(
context,
v8::String::NewFromUtf8(isolate,
"length").ToLocalChecked()).ToLocalChecked()->ToObject(
context).ToLocalChecked()->Uint32Value(
context).ToChecked();
for (int j = 0; j < length; j++) {
auto element = interfacesArr->Get(context, j).ToLocalChecked();

if (length > 0) {
for (int j = 0; j < length; j++) {
auto element = interfacesArr->Get(context, j).ToLocalChecked();
if (element->IsFunction()) {
auto node = MetadataNode::GetTypeMetadataName(isolate, element);

if (element->IsFunction()) {
auto node = MetadataNode::GetTypeMetadataName(isolate, element);
node = Util::ReplaceAll(node, std::string("/"), std::string("."));

node = Util::ReplaceAll(node, std::string("/"), std::string("."));

jstring value = env.NewStringUTF(node.c_str());
interfacesToImplement.push_back(value);
}
}
}
jstring value = env.NewStringUTF(node.c_str());
interfacesToImplement.push_back(value);
}
}
}
Expand Down Expand Up @@ -634,6 +619,10 @@ CallbackHandlers::GetMethodOverrides(JEnv &env, const Local<Object> &implementat
auto propNames = implementationObject->GetOwnPropertyNames(context).ToLocalChecked();
for (int i = 0; i < propNames->Length(); i++) {
auto name = propNames->Get(context, i).ToLocalChecked().As<String>();
if (name->StringEquals(V8StringConstants::GetSuper(isolate))) {
continue;
}

auto method = implementationObject->Get(context, name).ToLocalChecked();

bool methodFound = !method.IsEmpty() && method->IsFunction();
Expand Down
148 changes: 102 additions & 46 deletions test-app/runtime/src/main/cpp/MetadataNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -483,23 +483,86 @@ void MetadataNode::SuperAccessorGetterCallback(Local<Name> property, const Prope
}
}

std::vector<MetadataNode::MethodCallbackData*> MetadataNode::SetInstanceMembers(Isolate* isolate, Local<FunctionTemplate>& ctorFuncTemplate, Local<ObjectTemplate>& prototypeTemplate, vector<MethodCallbackData*>& instanceMethodsCallbackData, const vector<MethodCallbackData*>& baseInstanceMethodsCallbackData, MetadataTreeNode* treeNode) {
class MetadataNode::PrototypeTemplateFiller {
public:
explicit PrototypeTemplateFiller(Local<ObjectTemplate> protoTemplate)
: m_protoTemplate(protoTemplate) {}

void FillPrototypeMethod(Isolate *isolate, const std::string& name,
MethodCallbackData* methodInfo) {
if (m_addedNames.count(name) != 0) {
DEBUG_WRITE("Not defining method prototype.%s which has already been added", name.c_str());
return;
}

Local<External> funcData = External::New(isolate, methodInfo);
Local<FunctionTemplate> funcTemplate = FunctionTemplate::New(isolate, MetadataNode::MethodCallback, funcData);
Local<String> nameString = ArgConverter::ConvertToV8String(isolate, name);
m_protoTemplate->Set(nameString, funcTemplate);
m_addedNames.insert(name);
}

void FillPrototypeField(Isolate* isolate, const std::string& name, FieldCallbackData* fieldInfo,
AccessControl access = AccessControl::DEFAULT) {
if (m_addedNames.count(name) != 0) {
DEBUG_WRITE("Not defining field prototype.%s which already exists", name.c_str());
return;
}

Local<External> fieldData = External::New(isolate, fieldInfo);
Local<Name> nameString = ArgConverter::ConvertToV8String(isolate, name);
m_protoTemplate->SetAccessor(nameString, MetadataNode::FieldAccessorGetterCallback,
MetadataNode::FieldAccessorSetterCallback, fieldData, access,
PropertyAttribute::DontDelete);
m_addedNames.insert(name);
}

void FillPrototypeProperty(Isolate* isolate, const std::string& name,
PropertyCallbackData* propertyInfo) {
if (m_addedNames.count(name) != 0) {
DEBUG_WRITE("Not defining property prototype.%s which already exists", name.c_str());
return;
}

Local<External> propertyData = External::New(isolate, propertyInfo);
Local<Name> nameString = ArgConverter::ConvertToV8String(isolate, name);
m_protoTemplate->SetAccessor(nameString, MetadataNode::PropertyAccessorGetterCallback,
MetadataNode::PropertyAccessorSetterCallback, propertyData,
AccessControl::DEFAULT, PropertyAttribute::DontDelete);
m_addedNames.insert(name);
}

private:
Local<ObjectTemplate> m_protoTemplate;
std::unordered_set<std::string> m_addedNames;
};

std::vector<MetadataNode::MethodCallbackData*> MetadataNode::SetInstanceMembers(
Isolate* isolate, Local<FunctionTemplate>& ctorFuncTemplate,
PrototypeTemplateFiller& protoFiller,
vector<MethodCallbackData*>& instanceMethodsCallbackData,
const vector<MethodCallbackData*>& baseInstanceMethodsCallbackData,
MetadataTreeNode* treeNode) {
auto hasCustomMetadata = treeNode->metadata != nullptr;

if (hasCustomMetadata) {
return SetInstanceMembersFromRuntimeMetadata(isolate, ctorFuncTemplate, prototypeTemplate, instanceMethodsCallbackData, baseInstanceMethodsCallbackData, treeNode);
} else {
SetInstanceFieldsFromStaticMetadata(isolate, ctorFuncTemplate, prototypeTemplate, instanceMethodsCallbackData, baseInstanceMethodsCallbackData, treeNode);
return SetInstanceMethodsFromStaticMetadata(isolate, ctorFuncTemplate, prototypeTemplate, instanceMethodsCallbackData, baseInstanceMethodsCallbackData, treeNode);
return SetInstanceMembersFromRuntimeMetadata(
isolate, protoFiller, instanceMethodsCallbackData,
baseInstanceMethodsCallbackData, treeNode);
}

SetInstanceFieldsFromStaticMetadata(isolate, protoFiller, treeNode);
return SetInstanceMethodsFromStaticMetadata(
isolate, ctorFuncTemplate, protoFiller, instanceMethodsCallbackData,
baseInstanceMethodsCallbackData, treeNode);
}

vector<MetadataNode::MethodCallbackData *> MetadataNode::SetInstanceMethodsFromStaticMetadata(Isolate *isolate,
Local<FunctionTemplate> &ctorFuncTemplate,
Local<ObjectTemplate> &prototypeTemplate,
vector<MethodCallbackData *> &instanceMethodsCallbackData,
const vector<MethodCallbackData *> &baseInstanceMethodsCallbackData,
MetadataTreeNode *treeNode) {
vector<MetadataNode::MethodCallbackData *> MetadataNode::SetInstanceMethodsFromStaticMetadata(
Isolate *isolate, Local<FunctionTemplate> &ctorFuncTemplate,
PrototypeTemplateFiller& protoFiller,
vector<MethodCallbackData *> &instanceMethodsCallbackData,
const vector<MethodCallbackData *> &baseInstanceMethodsCallbackData,
MetadataTreeNode *treeNode) {
SET_PROFILER_FRAME();

std::vector<MethodCallbackData *> instanceMethodData;
Expand All @@ -520,7 +583,6 @@ vector<MetadataNode::MethodCallbackData *> MetadataNode::SetInstanceMethodsFromS
MethodCallbackData *callbackData = nullptr;

auto context = isolate->GetCurrentContext();
auto origin = Constants::APP_ROOT_FOLDER_PATH + GetOrCreateInternal(treeNode)->m_name;

std::unordered_map<std::string, MethodCallbackData *> collectedExtensionMethodDatas;

Expand All @@ -535,10 +597,7 @@ vector<MetadataNode::MethodCallbackData *> MetadataNode::SetInstanceMethodsFromS
entry.name);
if (callbackData == nullptr) {
callbackData = new MethodCallbackData(this);
auto funcData = External::New(isolate, callbackData);
auto funcTemplate = FunctionTemplate::New(isolate, MethodCallback, funcData);
auto funcName = ArgConverter::ConvertToV8String(isolate, entry.name);
prototypeTemplate->Set(funcName, funcTemplate);
protoFiller.FillPrototypeMethod(isolate, entry.name, callbackData);

lastMethodName = entry.name;
std::pair<std::string, MethodCallbackData *> p(entry.name, callbackData);
Expand Down Expand Up @@ -581,25 +640,24 @@ vector<MetadataNode::MethodCallbackData *> MetadataNode::SetInstanceMethodsFromS
callbackData->parent = *itFound;
}

auto funcData = External::New(isolate, callbackData);
auto funcTemplate = FunctionTemplate::New(isolate, MethodCallback, funcData);

auto funcName = ArgConverter::ConvertToV8String(isolate, entry.name);

if (s_profilerEnabled) {
Local<External> funcData = External::New(isolate, callbackData);
Local<FunctionTemplate> funcTemplate = FunctionTemplate::New(isolate, MethodCallback, funcData);
auto func = funcTemplate->GetFunction(context).ToLocalChecked();
std::string origin = Constants::APP_ROOT_FOLDER_PATH + GetOrCreateInternal(treeNode)->m_name;
Local<Function> wrapperFunc = Wrap(isolate, func, entry.name, origin,
false /* isCtorFunc */);
Local<Function> ctorFunc = ctorFuncTemplate->GetFunction(context).ToLocalChecked();
Local<Value> protoVal;
ctorFunc->Get(context,
ArgConverter::ConvertToV8String(isolate, "prototype")).ToLocal(
&protoVal);
Local<String> funcName = ArgConverter::ConvertToV8String(isolate, entry.name);
if (!protoVal.IsEmpty() && !protoVal->IsUndefined() && !protoVal->IsNull()) {
protoVal.As<Object>()->Set(context, funcName, wrapperFunc);
}
} else {
prototypeTemplate->Set(funcName, funcTemplate);
protoFiller.FillPrototypeMethod(isolate, entry.name, callbackData);
}

lastMethodName = entry.name;
Expand Down Expand Up @@ -628,7 +686,8 @@ MetadataNode::MethodCallbackData *MetadataNode::tryGetExtensionMethodCallbackDat
return nullptr;
}

void MetadataNode::SetInstanceFieldsFromStaticMetadata(Isolate* isolate, Local<FunctionTemplate>& ctorFuncTemplate, Local<ObjectTemplate>& prototypeTemplate, vector<MethodCallbackData*>& instanceMethodsCallbackData, const vector<MethodCallbackData*>& baseInstanceMethodsCallbackData, MetadataTreeNode* treeNode) {
void MetadataNode::SetInstanceFieldsFromStaticMetadata(
Isolate* isolate, PrototypeTemplateFiller& prototypeTemplate, MetadataTreeNode* treeNode) {
SET_PROFILER_FRAME();

Local<Function> ctorFunction;
Expand Down Expand Up @@ -665,12 +724,9 @@ void MetadataNode::SetInstanceFieldsFromStaticMetadata(Isolate* isolate, Local<F
curPtr += sizeof(uint16_t);
for (auto i = 0; i < instanceFieldCout; i++) {
auto entry = s_metadataReader.ReadInstanceFieldEntry(&curPtr);

auto fieldName = ArgConverter::ConvertToV8String(isolate, entry.name);
auto fieldInfo = new FieldCallbackData(entry);
fieldInfo->declaringType = curType;
auto fieldData = External::New(isolate, fieldInfo);
prototypeTemplate->SetAccessor(fieldName, FieldAccessorGetterCallback, FieldAccessorSetterCallback, fieldData, AccessControl::DEFAULT, PropertyAttribute::DontDelete);
prototypeTemplate.FillPrototypeField(isolate, entry.name, fieldInfo);
}

auto kotlinPropertiesCount = *reinterpret_cast<uint16_t*>(curPtr);
Expand Down Expand Up @@ -699,12 +755,15 @@ void MetadataNode::SetInstanceFieldsFromStaticMetadata(Isolate* isolate, Local<F
}

auto propertyInfo = new PropertyCallbackData(propertyName, getterMethodName, setterMethodName);
auto propertyData = External::New(isolate, propertyInfo);
prototypeTemplate->SetAccessor(ArgConverter::ConvertToV8String(isolate, propertyName), PropertyAccessorGetterCallback, PropertyAccessorSetterCallback, propertyData, AccessControl::DEFAULT, PropertyAttribute::DontDelete);
prototypeTemplate.FillPrototypeProperty(isolate, propertyName, propertyInfo);
}
}

vector<MetadataNode::MethodCallbackData*> MetadataNode::SetInstanceMembersFromRuntimeMetadata(Isolate* isolate, Local<FunctionTemplate>& ctorFuncTemplate, Local<ObjectTemplate>& prototypeTemplate, vector<MethodCallbackData*>& instanceMethodsCallbackData, const vector<MethodCallbackData*>& baseInstanceMethodsCallbackData, MetadataTreeNode* treeNode) {
vector<MetadataNode::MethodCallbackData*> MetadataNode::SetInstanceMembersFromRuntimeMetadata(
Isolate* isolate, PrototypeTemplateFiller& protoFiller,
vector<MethodCallbackData*>& instanceMethodsCallbackData,
const vector<MethodCallbackData*>& baseInstanceMethodsCallbackData,
MetadataTreeNode* treeNode) {
SET_PROFILER_FRAME();

assert(treeNode->metadata != nullptr);
Expand Down Expand Up @@ -757,18 +816,14 @@ vector<MetadataNode::MethodCallbackData*> MetadataNode::SetInstanceMembersFromRu
callbackData->parent = *itFound;
}

auto funcData = External::New(isolate, callbackData);
auto funcTemplate = FunctionTemplate::New(isolate, MethodCallback, funcData);
auto funcName = ArgConverter::ConvertToV8String(isolate, entry.name);
prototypeTemplate->Set(funcName, funcTemplate);
protoFiller.FillPrototypeMethod(isolate, entry.name, callbackData);
lastMethodName = entry.name;
}
callbackData->candidates.push_back(entry);
} else if (chKind == 'F') {
auto fieldName = ArgConverter::ConvertToV8String(isolate, entry.name);
auto fieldData = External::New(isolate, new FieldCallbackData(entry));
auto* fieldInfo = new FieldCallbackData(entry);
auto access = entry.isFinal ? AccessControl::ALL_CAN_READ : AccessControl::DEFAULT;
prototypeTemplate->SetAccessor(fieldName, FieldAccessorGetterCallback, FieldAccessorSetterCallback, fieldData, access, PropertyAttribute::DontDelete);
protoFiller.FillPrototypeField(isolate, entry.name, fieldInfo, access);
}
}
return instanceMethodData;
Expand Down Expand Up @@ -974,11 +1029,13 @@ Local<FunctionTemplate> MetadataNode::GetConstructorFunctionTemplate(Isolate* is
break;
}

auto prototypeTemplate = ctorFuncTemplate->PrototypeTemplate();
PrototypeTemplateFiller protoFiller{ctorFuncTemplate->PrototypeTemplate()};

auto instanceMethodData = node->SetInstanceMembers(isolate, ctorFuncTemplate, prototypeTemplate, instanceMethodsCallbackData, baseInstanceMethodsCallbackData, treeNode);
auto instanceMethodData = node->SetInstanceMembers(
isolate, ctorFuncTemplate, protoFiller, instanceMethodsCallbackData,
baseInstanceMethodsCallbackData, treeNode);
if (!skippedBaseTypes.empty()) {
node->SetMissingBaseMethods(isolate, skippedBaseTypes, instanceMethodData, prototypeTemplate);
node->SetMissingBaseMethods(isolate, skippedBaseTypes, instanceMethodData, protoFiller);
}

auto context = isolate->GetCurrentContext();
Expand Down Expand Up @@ -2075,7 +2132,10 @@ bool MetadataNode::CheckClassHierarchy(JEnv& env, jclass currentClass, MetadataT
* This method handles scenrios like Bundle/BaseBundle class hierarchy change in API level 21.
* See https://github.com/NativeScript/android-runtime/issues/628
*/
void MetadataNode::SetMissingBaseMethods(Isolate* isolate, const vector<MetadataTreeNode*>& skippedBaseTypes, const vector<MethodCallbackData*>& instanceMethodData, Local<ObjectTemplate>& prototypeTemplate) {
void MetadataNode::SetMissingBaseMethods(
Isolate* isolate, const vector<MetadataTreeNode*>& skippedBaseTypes,
const vector<MethodCallbackData*>& instanceMethodData,
PrototypeTemplateFiller& protoFiller) {
for (auto treeNode: skippedBaseTypes) {
uint8_t* curPtr = s_metadataReader.GetValueData() + treeNode->offsetValue + 1;

Expand Down Expand Up @@ -2111,11 +2171,7 @@ void MetadataNode::SetMissingBaseMethods(Isolate* isolate, const vector<Metadata

if (callbackData == nullptr) {
callbackData = new MethodCallbackData(this);

auto funcData = External::New(isolate, callbackData);
auto funcTemplate = FunctionTemplate::New(isolate, MethodCallback, funcData);
auto funcName = ArgConverter::ConvertToV8String(isolate, entry.name);
prototypeTemplate->Set(funcName, funcTemplate);
protoFiller.FillPrototypeMethod(isolate, entry.name, callbackData);
}

bool foundSameSig = false;
Expand Down
Loading