Skip to content

Commit a88bfa4

Browse files
author
Mihail Slavchev
authored
Merge pull request #470 from NativeScript/slavchev/profiler-show-func-names
Workaround for V8 profiler in order to show correct function names in…
2 parents 5d1f26e + 08c8e7e commit a88bfa4

4 files changed

Lines changed: 217 additions & 76 deletions

File tree

src/jni/MetadataNode.cpp

Lines changed: 201 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ void MetadataNode::Init(Isolate *isolate)
2525
}
2626

2727
MetadataNode::MetadataNode(MetadataTreeNode *treeNode) :
28-
m_treeNode(treeNode)
28+
m_treeNode(treeNode), m_poCtorFunc(nullptr)
2929
{
3030
uint8_t nodeType = s_metadataReader.GetNodeType(treeNode);
3131

@@ -453,17 +453,21 @@ void MetadataNode::SuperAccessorGetterCallback(Local<String> property, const Pro
453453
}
454454
}
455455

456-
Local<Function> MetadataNode::SetMembers(Isolate *isolate, Local<FunctionTemplate>& ctorFuncTemplate, Local<ObjectTemplate>& prototypeTemplate, vector<MethodCallbackData*>& instanceMethodsCallbackData, const vector<MethodCallbackData*>& baseInstanceMethodsCallbackData, MetadataTreeNode *treeNode)
456+
void MetadataNode::SetInstanceMembers(Isolate *isolate, Local<FunctionTemplate>& ctorFuncTemplate, Local<ObjectTemplate>& prototypeTemplate, vector<MethodCallbackData*>& instanceMethodsCallbackData, const vector<MethodCallbackData*>& baseInstanceMethodsCallbackData, MetadataTreeNode *treeNode)
457457
{
458458
auto hasCustomMetadata = treeNode->metadata != nullptr;
459459

460-
return hasCustomMetadata
461-
? SetMembersFromRuntimeMetadata(isolate, ctorFuncTemplate, prototypeTemplate, instanceMethodsCallbackData, baseInstanceMethodsCallbackData, treeNode)
462-
:
463-
SetMembersFromStaticMetadata(isolate, ctorFuncTemplate, prototypeTemplate, instanceMethodsCallbackData, baseInstanceMethodsCallbackData, treeNode);
460+
if (hasCustomMetadata)
461+
{
462+
SetInstanceMembersFromRuntimeMetadata(isolate, ctorFuncTemplate, prototypeTemplate, instanceMethodsCallbackData, baseInstanceMethodsCallbackData, treeNode);
463+
}
464+
else
465+
{
466+
SetInstanceMembersFromStaticMetadata(isolate, ctorFuncTemplate, prototypeTemplate, instanceMethodsCallbackData, baseInstanceMethodsCallbackData, treeNode);
467+
}
464468
}
465469

466-
Local<Function> MetadataNode::SetMembersFromStaticMetadata(Isolate *isolate, Local<FunctionTemplate>& ctorFuncTemplate, Local<ObjectTemplate>& prototypeTemplate, vector<MethodCallbackData*>& instanceMethodsCallbackData, const vector<MethodCallbackData*>& baseInstanceMethodsCallbackData, MetadataTreeNode *treeNode)
470+
void MetadataNode::SetInstanceMembersFromStaticMetadata(Isolate *isolate, Local<FunctionTemplate>& ctorFuncTemplate, Local<ObjectTemplate>& prototypeTemplate, vector<MethodCallbackData*>& instanceMethodsCallbackData, const vector<MethodCallbackData*>& baseInstanceMethodsCallbackData, MetadataTreeNode *treeNode)
467471
{
468472
SET_PROFILER_FRAME();
469473

@@ -511,8 +515,7 @@ Local<Function> MetadataNode::SetMembersFromStaticMetadata(Isolate *isolate, Loc
511515
auto funcTemplate = FunctionTemplate::New(isolate, MethodCallback, funcData);
512516
auto func = funcTemplate->GetFunction();
513517
auto funcName = ConvertToV8String(entry.name);
514-
func->SetName(funcName);
515-
prototypeTemplate->Set(funcName, func);
518+
prototypeTemplate->Set(funcName, Wrap(isolate, func, entry.name, false /* isCtorFunc */));
516519
lastMethodName = entry.name;
517520
}
518521

@@ -532,59 +535,9 @@ Local<Function> MetadataNode::SetMembersFromStaticMetadata(Isolate *isolate, Loc
532535
auto fieldData = External::New(isolate, fieldInfo);
533536
prototypeTemplate->SetAccessor(fieldName, FieldAccessorGetterCallback, FieldAccessorSetterCallback, fieldData, AccessControl::DEFAULT, PropertyAttribute::DontDelete);
534537
}
535-
536-
ctorFunction = ctorFuncTemplate->GetFunction();
537-
538-
//get candidates from static methods metadata
539-
callbackData = nullptr;
540-
lastMethodName.clear();
541-
auto staticMethodCout = *reinterpret_cast<uint16_t*>(curPtr);
542-
curPtr += sizeof(uint16_t);
543-
for (auto i = 0; i < staticMethodCout; i++)
544-
{
545-
auto entry = s_metadataReader.ReadStaticMethodEntry(&curPtr);
546-
if (entry.name != lastMethodName)
547-
{
548-
callbackData = new MethodCallbackData(this);
549-
auto funcData = External::New(isolate, callbackData);
550-
auto funcTemplate = FunctionTemplate::New(isolate, MethodCallback, funcData);
551-
auto func = funcTemplate->GetFunction();
552-
auto funcName = ConvertToV8String(entry.name);
553-
func->SetName(funcName);
554-
ctorFunction->Set(funcName, func);
555-
lastMethodName = entry.name;
556-
}
557-
callbackData->candidates.push_back(entry);
558-
}
559-
560-
//attach .extend function
561-
auto extendFuncName = V8StringConstants::GetExtend();
562-
auto extendFuncTemplate = FunctionTemplate::New(isolate, ExtendCallMethodCallback, External::New(isolate, this));
563-
ctorFunction->Set(extendFuncName, extendFuncTemplate->GetFunction());
564-
565-
//get candidates from static fields metadata
566-
auto staticFieldCout = *reinterpret_cast<uint16_t*>(curPtr);
567-
curPtr += sizeof(uint16_t);
568-
for (auto i = 0; i < staticFieldCout; i++)
569-
{
570-
auto entry = s_metadataReader.ReadStaticFieldEntry(&curPtr);
571-
572-
auto fieldName = ConvertToV8String(entry.name);
573-
auto fieldData = External::New(isolate, new FieldCallbackData(entry));
574-
ctorFunction->SetAccessor(fieldName, FieldAccessorGetterCallback, FieldAccessorSetterCallback, fieldData, AccessControl::DEFAULT, PropertyAttribute::DontDelete);
575-
}
576-
577-
auto nullObjectName = V8StringConstants::GetNullObject();
578-
579-
Local<Value> nullObjectData = External::New(isolate, this);
580-
ctorFunction->SetAccessor(nullObjectName, NullObjectAccessorGetterCallback, nullptr, nullObjectData);
581-
582-
SetClassAccessor(ctorFunction);
583-
584-
return ctorFunction;
585538
}
586539

587-
Local<Function> MetadataNode::SetMembersFromRuntimeMetadata(Isolate *isolate, Local<FunctionTemplate>& ctorFuncTemplate, Local<ObjectTemplate>& prototypeTemplate, vector<MethodCallbackData*>& instanceMethodsCallbackData, const vector<MethodCallbackData*>& baseInstanceMethodsCallbackData, MetadataTreeNode *treeNode)
540+
void MetadataNode::SetInstanceMembersFromRuntimeMetadata(Isolate *isolate, Local<FunctionTemplate>& ctorFuncTemplate, Local<ObjectTemplate>& prototypeTemplate, vector<MethodCallbackData*>& instanceMethodsCallbackData, const vector<MethodCallbackData*>& baseInstanceMethodsCallbackData, MetadataTreeNode *treeNode)
588541
{
589542
SET_PROFILER_FRAME();
590543

@@ -642,7 +595,6 @@ Local<Function> MetadataNode::SetMembersFromRuntimeMetadata(Isolate *isolate, Lo
642595
auto funcTemplate = FunctionTemplate::New(isolate, MethodCallback, funcData);
643596
auto func = funcTemplate->GetFunction();
644597
auto funcName = ConvertToV8String(entry.name);
645-
func->SetName(funcName);
646598
prototypeTemplate->Set(funcName, func);
647599
lastMethodName = entry.name;
648600
}
@@ -656,12 +608,85 @@ Local<Function> MetadataNode::SetMembersFromRuntimeMetadata(Isolate *isolate, Lo
656608
prototypeTemplate->SetAccessor(fieldName, FieldAccessorGetterCallback, FieldAccessorSetterCallback, fieldData, access, PropertyAttribute::DontDelete);
657609
}
658610
}
611+
}
612+
613+
void MetadataNode::SetStaticMembers(Isolate *isolate, Local<Function>& ctorFunction, MetadataTreeNode *treeNode)
614+
{
615+
auto hasCustomMetadata = treeNode->metadata != nullptr;
616+
617+
if (!hasCustomMetadata)
618+
{
619+
uint8_t *curPtr = s_metadataReader.GetValueData() + treeNode->offsetValue + 1;
620+
auto nodeType = s_metadataReader.GetNodeType(treeNode);
621+
auto curType = s_metadataReader.ReadTypeName(treeNode);
622+
curPtr += sizeof(uint16_t /* baseClassId */);
623+
if (s_metadataReader.IsNodeTypeInterface(nodeType))
624+
{
625+
curPtr += sizeof(uint8_t) + sizeof(uint32_t);
626+
}
627+
auto instanceMethodCout = *reinterpret_cast<uint16_t*>(curPtr);
628+
curPtr += sizeof(uint16_t);
629+
for (auto i = 0; i < instanceMethodCout; i++)
630+
{
631+
auto entry = s_metadataReader.ReadInstanceMethodEntry(&curPtr);
632+
}
633+
auto instanceFieldCout = *reinterpret_cast<uint16_t*>(curPtr);
634+
curPtr += sizeof(uint16_t);
635+
for (auto i = 0; i < instanceFieldCout; i++)
636+
{
637+
auto entry = s_metadataReader.ReadInstanceFieldEntry(&curPtr);
638+
}
639+
640+
string lastMethodName;
641+
MethodCallbackData *callbackData = nullptr;
642+
643+
//get candidates from static methods metadata
644+
auto staticMethodCout = *reinterpret_cast<uint16_t*>(curPtr);
645+
curPtr += sizeof(uint16_t);
646+
for (auto i = 0; i < staticMethodCout; i++)
647+
{
648+
auto entry = s_metadataReader.ReadStaticMethodEntry(&curPtr);
649+
if (entry.name != lastMethodName)
650+
{
651+
callbackData = new MethodCallbackData(this);
652+
auto funcData = External::New(isolate, callbackData);
653+
auto funcTemplate = FunctionTemplate::New(isolate, MethodCallback, funcData);
654+
auto func = funcTemplate->GetFunction();
655+
auto funcName = ConvertToV8String(entry.name);
656+
ctorFunction->Set(funcName, Wrap(isolate, func, entry.name, false /* isCtorFunc */));
657+
lastMethodName = entry.name;
658+
}
659+
callbackData->candidates.push_back(entry);
660+
}
661+
662+
//attach .extend function
663+
auto extendFuncName = V8StringConstants::GetExtend();
664+
auto extendFuncTemplate = FunctionTemplate::New(isolate, ExtendCallMethodCallback, External::New(isolate, this));
665+
ctorFunction->Set(extendFuncName, extendFuncTemplate->GetFunction());
666+
667+
//get candidates from static fields metadata
668+
auto staticFieldCout = *reinterpret_cast<uint16_t*>(curPtr);
669+
curPtr += sizeof(uint16_t);
670+
for (auto i = 0; i < staticFieldCout; i++)
671+
{
672+
auto entry = s_metadataReader.ReadStaticFieldEntry(&curPtr);
659673

660-
auto ctorFunction = ctorFuncTemplate->GetFunction();
674+
auto fieldName = ConvertToV8String(entry.name);
675+
auto fieldData = External::New(isolate, new FieldCallbackData(entry));
676+
ctorFunction->SetAccessor(fieldName, FieldAccessorGetterCallback, FieldAccessorSetterCallback, fieldData, AccessControl::DEFAULT, PropertyAttribute::DontDelete);
677+
}
678+
679+
auto nullObjectName = V8StringConstants::GetNullObject();
661680

662-
return ctorFunction;
681+
Local<Value> nullObjectData = External::New(isolate, this);
682+
ctorFunction->SetAccessor(nullObjectName, NullObjectAccessorGetterCallback, nullptr, nullObjectData);
683+
684+
SetClassAccessor(ctorFunction);
685+
}
663686
}
664687

688+
689+
665690
void MetadataNode::InnerClassConstructorCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
666691
{
667692
try
@@ -760,7 +785,7 @@ void MetadataNode::SetInnnerTypes(Isolate *isolate, Local<Function>& ctorFunctio
760785
if (isStatic)
761786
{
762787
auto innerTypeCtorFuncTemplate = childNode->GetConstructorFunctionTemplate(isolate, curChild);
763-
auto innerTypeCtorFunc = innerTypeCtorFuncTemplate->GetFunction();
788+
auto innerTypeCtorFunc = Local<Function>::New(isolate, *GetOrCreateInternal(curChild)->m_poCtorFunc);
764789
auto innerTypeName = ConvertToV8String(curChild->name);
765790
ctorFunction->Set(innerTypeName, innerTypeCtorFunc);
766791
}
@@ -804,42 +829,50 @@ Local<FunctionTemplate> MetadataNode::GetConstructorFunctionTemplate(Isolate *is
804829
ctorFuncTemplate = FunctionTemplate::New(isolate, funcCallback, ctorCallbackData);
805830
ctorFuncTemplate->InstanceTemplate()->SetInternalFieldCount(static_cast<int>(ObjectManager::MetadataNodeKeys::END));
806831

807-
auto baseClass = s_metadataReader.GetBaseClassNode(treeNode);
832+
auto baseTreeNode = s_metadataReader.GetBaseClassNode(treeNode);
808833
Local<Function> baseCtorFunc;
809834
vector<MethodCallbackData*> baseInstanceMethodsCallbackData;
810-
if ((baseClass != treeNode) && (baseClass != nullptr) && (baseClass->offsetValue > 0))
835+
if ((baseTreeNode != treeNode) && (baseTreeNode != nullptr) && (baseTreeNode->offsetValue > 0))
811836
{
812-
auto baseFuncTemplate = GetConstructorFunctionTemplate(isolate, baseClass, baseInstanceMethodsCallbackData);
837+
auto baseFuncTemplate = GetConstructorFunctionTemplate(isolate, baseTreeNode, baseInstanceMethodsCallbackData);
813838
if (!baseFuncTemplate.IsEmpty())
814839
{
815840
ctorFuncTemplate->Inherit(baseFuncTemplate);
816-
baseCtorFunc = baseFuncTemplate->GetFunction();
841+
baseCtorFunc = Local<Function>::New(isolate, *GetOrCreateInternal(baseTreeNode)->m_poCtorFunc);
817842
}
818843
}
819844

820845
auto prototypeTemplate = ctorFuncTemplate->PrototypeTemplate();
821846

822-
auto ctorFunc = node->SetMembers(isolate, ctorFuncTemplate, prototypeTemplate, instanceMethodsCallbackData, baseInstanceMethodsCallbackData, treeNode);
847+
node->SetInstanceMembers(isolate, ctorFuncTemplate, prototypeTemplate, instanceMethodsCallbackData, baseInstanceMethodsCallbackData, treeNode);
848+
849+
auto ctorFunc = ctorFuncTemplate->GetFunction();
850+
851+
auto wrappedCtorFunc = Wrap(isolate, ctorFunc, node->m_treeNode->name, true /* isCtorFunc */);
852+
853+
node->SetStaticMembers(isolate, wrappedCtorFunc, treeNode);
854+
855+
node->m_poCtorFunc = new Persistent<Function>(isolate, wrappedCtorFunc);
823856
if (!baseCtorFunc.IsEmpty())
824857
{
825-
ctorFunc->SetPrototype(baseCtorFunc);
858+
wrappedCtorFunc->SetPrototype(baseCtorFunc);
826859
}
827860

828861
auto pft = new Persistent<FunctionTemplate>(isolate, ctorFuncTemplate);
829862
CtorCacheItem ctorCacheItem(pft, instanceMethodsCallbackData);
830863
cache->CtorFuncCache.insert(make_pair(treeNode, ctorCacheItem));
831864

832-
SetInnnerTypes(isolate, ctorFunc, treeNode);
865+
SetInnnerTypes(isolate, wrappedCtorFunc, treeNode);
833866

834-
SetTypeMetadata(isolate, ctorFunc, new TypeMetadata(s_metadataReader.ReadTypeName(treeNode)));
867+
SetTypeMetadata(isolate, wrappedCtorFunc, new TypeMetadata(s_metadataReader.ReadTypeName(treeNode)));
835868

836869
return ctorFuncTemplate;
837870
}
838871

839872
Local<Function> MetadataNode::GetConstructorFunction(Isolate *isolate)
840873
{
841874
auto ctorFuncTemplate = GetConstructorFunctionTemplate(isolate, m_treeNode);
842-
auto ctorFunc = ctorFuncTemplate->GetFunction();
875+
auto ctorFunc = Local<Function>::New(isolate, *m_poCtorFunc);
843876
return ctorFunc;
844877
}
845878

@@ -1775,9 +1808,104 @@ MetadataNode::MetadataNodeCache* MetadataNode::GetCache(Isolate *isolate)
17751808
return cache;
17761809
}
17771810

1811+
void MetadataNode::EnableProfiler(bool enableProfiler)
1812+
{
1813+
s_profilerEnabled = enableProfiler;
1814+
}
1815+
1816+
Local<Function> MetadataNode::Wrap(Isolate* isolate, const Local<Function>& f, const string& name, bool isCtorFunc)
1817+
{
1818+
if (!s_profilerEnabled)
1819+
{
1820+
return f;
1821+
}
1822+
1823+
static set<string> keywords;
1824+
1825+
if (keywords.empty())
1826+
{
1827+
string kw[] { "abstract", "arguments", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue", "debugger", "default", "delete", "do",
1828+
"double", "else", "enum", "eval", "export", "extends", "false", "final", "finally", "float", "for", "function", "goto", "if", "implements",
1829+
"import", "in", "instanceof", "int", "interface", "let", "long", "native", "new", "null", "package", "private", "protected", "public", "return",
1830+
"short", "static", "super", "switch", "synchronized", "this", "throw", "throws", "transient", "true", "try", "typeof", "var", "void", "volatile", "while", "with", "yield" };
1831+
1832+
keywords = set<string>(kw, kw + sizeof(kw)/sizeof(kw[0]));
1833+
}
1834+
1835+
if (name == "<init>")
1836+
{
1837+
return f;
1838+
}
1839+
1840+
string actualName = name;
1841+
while (keywords.find(actualName) != keywords.end())
1842+
{
1843+
actualName.append("_");
1844+
}
1845+
1846+
Local<Function> ret;
1847+
1848+
stringstream ss;
1849+
ss << "(function() { ";
1850+
ss << "function " << actualName << "() { ";
1851+
if (isCtorFunc)
1852+
{
1853+
ss << "var args = [null]; for (var i=0; i<arguments.length; i++) { args.push(arguments[i]); }; ";
1854+
ss << "return new (Function.prototype.bind.apply(" << actualName << ".__func, args)); ";
1855+
}
1856+
else
1857+
{
1858+
ss << "return " << actualName << ".__func.apply(this, arguments); ";
1859+
}
1860+
ss << "} ";
1861+
ss << "return " << actualName << "; ";
1862+
ss << "})()";
1863+
1864+
auto str = ss.str();
1865+
auto source = ConvertToV8String(str);
1866+
auto context = isolate->GetCurrentContext();
1867+
1868+
TryCatch tc;
1869+
1870+
Local<Script> script;
1871+
ScriptOrigin origin(ConvertToV8String(Constants::APP_ROOT_FOLDER_PATH + m_name));
1872+
auto maybeScript = Script::Compile(context, source, &origin).ToLocal(&script);
1873+
1874+
if (tc.HasCaught())
1875+
{
1876+
throw NativeScriptException(tc, "Cannot compile wrapper");
1877+
}
1878+
1879+
if (!script.IsEmpty())
1880+
{
1881+
Local<Value> result;
1882+
auto maybeResult = script->Run(context).ToLocal(&result);
1883+
1884+
if (!result.IsEmpty())
1885+
{
1886+
ret = result.As<Function>();
1887+
ret->Set(ConvertToV8String("__func"), f);
1888+
1889+
auto prototypePropName = ConvertToV8String("prototype");
1890+
ret->Set(prototypePropName, f->Get(prototypePropName));
1891+
}
1892+
else
1893+
{
1894+
throw NativeScriptException("Cannot create wrapper function");
1895+
}
1896+
}
1897+
else
1898+
{
1899+
throw NativeScriptException(str);
1900+
}
1901+
1902+
return ret;
1903+
}
1904+
17781905
string MetadataNode::TNS_PREFIX = "com/tns/gen/";
17791906
MetadataReader MetadataNode::s_metadataReader;
17801907
std::map<std::string, MetadataNode*> MetadataNode::s_name2NodeCache;
17811908
std::map<std::string, MetadataTreeNode*> MetadataNode::s_name2TreeNodeCache;
17821909
std::map<MetadataTreeNode*, MetadataNode*> MetadataNode::s_treeNode2NodeCache;
17831910
map<Isolate*, MetadataNode::MetadataNodeCache*> MetadataNode::s_cache;
1911+
bool MetadataNode::s_profilerEnabled = false;

0 commit comments

Comments
 (0)