diff --git a/.travis.yml b/.travis.yml index f74e5bc2d..62d0b9752 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,10 @@ env: global: - - NDK_VERSION=r11c + - NDK_VERSION=r12b - DATE=$(date +%Y-%m-%d) - PACKAGE_VERSION=next-$DATE-$TRAVIS_BUILD_NUMBER - PACKAGE_NAME=tns-android -sudo: false +sudo: true language: android jdk: - oraclejdk8 @@ -39,7 +39,8 @@ script: - echo no | android create avd --force -n Arm21 -t android-21 -b armeabi-v7a -c 12M - emulator -avd Arm21 -no-skin -no-audio -no-window & - android-wait-for-emulator - - "cd test-app && ./gradlew runtest -PembedBindingGenerator=true --stacktrace" + - "cd test-app && ./gradlew assembleDebug runtests -PembedBindingGenerator=true --stacktrace" + - adb -e logcat -d 300 - cd .. before_deploy: - FULL_PACKAGE_VERSION=`sed -n 's/\s*"version":\s*"\([a-zA-Z0-9\.]*\)"\s*,*/\1/p' dist/package.json` diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index d7ef37351..aa821ac5a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip diff --git a/runtime/build.gradle b/runtime/build.gradle index 19963b69c..5cdf4a834 100644 --- a/runtime/build.gradle +++ b/runtime/build.gradle @@ -7,7 +7,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle-experimental:0.7.0-beta3' + classpath 'com.android.tools.build:gradle-experimental:0.8.0-beta2' } } @@ -59,9 +59,16 @@ model { ldLibs.addAll(["android", "dl", "log", "atomic", "z"]) - stl = "stlport_static" + stl = "c++_static" - abiFilters.addAll(["armeabi-v7a", "x86", "arm64-v8a"]) + if (ndkDebuggable) + { + abiFilters.addAll(["armeabi-v7a"]) + } + else + { + abiFilters.addAll(["armeabi-v7a", "x86", "arm64-v8a"]) + } } android.sources { diff --git a/runtime/gradle/wrapper/gradle-wrapper.properties b/runtime/gradle/wrapper/gradle-wrapper.properties index c52ebaf8d..f336f77b4 100644 --- a/runtime/gradle/wrapper/gradle-wrapper.properties +++ b/runtime/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip diff --git a/runtime/src/main/java/com/tns/Runtime.java b/runtime/src/main/java/com/tns/Runtime.java index a9d2a8907..eb3c62d0f 100644 --- a/runtime/src/main/java/com/tns/Runtime.java +++ b/runtime/src/main/java/com/tns/Runtime.java @@ -41,7 +41,10 @@ public class Runtime private native void passUncaughtExceptionToJsNative(int runtimeId, Throwable ex, String stackTrace); - private native void ClearStartupData(int runtimeId); + private native void clearStartupData(int runtimeId); + + // Used to determine the bitness of the current process (32 vs 64) + public static native int getPointerSize(); void passUncaughtExceptionToJs(Throwable ex, String stackTrace) { @@ -231,7 +234,7 @@ private void init(Logger logger, Debugger debugger, String appName, File runtime jsDebugger.start(); } - ClearStartupData(getRuntimeId()); // It's safe to delete the data after the V8 debugger is initialized + clearStartupData(getRuntimeId()); // It's safe to delete the data after the V8 debugger is initialized if (logger.isEnabled()) { diff --git a/runtime/src/main/jni/ArgConverter.cpp b/runtime/src/main/jni/ArgConverter.cpp index fdde739a2..1756ae464 100644 --- a/runtime/src/main/jni/ArgConverter.cpp +++ b/runtime/src/main/jni/ArgConverter.cpp @@ -5,6 +5,7 @@ #include "NativeScriptException.h" #include "NumericCasts.h" #include "Runtime.h" +#include "V8GlobalHelpers.h" #include using namespace v8; @@ -78,8 +79,8 @@ void ArgConverter::NativeScriptLongFunctionCallback(const v8::FunctionCallbackIn auto isolate = args.GetIsolate(); auto thiz = args.This(); auto cache = GetTypeLongCache(isolate); - thiz->SetHiddenValue(V8StringConstants::GetJavaLong(isolate), Boolean::New(isolate, true)); - NumericCasts::MarkAsLong(thiz, args[0]); + V8SetPrivateValue(isolate, thiz, V8StringConstants::GetJavaLong(isolate), Boolean::New(isolate, true)); + NumericCasts::MarkAsLong(isolate, thiz, args[0]); thiz->SetPrototype(Local::New(isolate, *cache->NanNumberObject)); } catch (NativeScriptException& e) @@ -329,8 +330,7 @@ Local ArgConverter::ConvertToV8String(Isolate *isolate, const jchar* dat Local ArgConverter::ConvertToV8String(Isolate *isolate, const string& s) { - Local str; - String::NewFromUtf8(isolate, s.c_str(), NewStringType::kNormal, s.length()).ToLocal(&str); + Local str = String::NewFromUtf8(isolate, s.c_str(), NewStringType::kNormal, s.length()).ToLocalChecked(); return str; } diff --git a/runtime/src/main/jni/CallbackHandlers.cpp b/runtime/src/main/jni/CallbackHandlers.cpp index 914723027..29dbc42a6 100644 --- a/runtime/src/main/jni/CallbackHandlers.cpp +++ b/runtime/src/main/jni/CallbackHandlers.cpp @@ -814,11 +814,13 @@ Local CallbackHandlers::CallJSMethod(Isolate *isolate, JNIEnv *_env, auto jsArgs = ArgConverter::ConvertJavaArgsToJsArgs(isolate, args); int argc = jsArgs->Length(); - Local arguments[argc]; - for (int i = 0; i < argc; i++) { + Local* arguments = new Local[argc]; + for (int i = 0; i < argc; i++) + { arguments[i] = jsArgs->Get(i); } + DEBUG_WRITE("implementationObject->GetIdentityHash()=%d", jsObject->GetIdentityHash()); TryCatch tc; @@ -828,9 +830,12 @@ Local CallbackHandlers::CallJSMethod(Isolate *isolate, JNIEnv *_env, jsResult = jsMethod->Call(jsObject, argc, argc == 0 ? nullptr : arguments); } + delete [] arguments; + //TODO: if javaResult is a pure js object create a java object that represents this object in java land - if (tc.HasCaught()) { + if (tc.HasCaught()) + { stringstream ss; ss << "Calling js method " << methodName << " failed"; string exceptionMessage = ss.str(); diff --git a/runtime/src/main/jni/JsArgConverter.cpp b/runtime/src/main/jni/JsArgConverter.cpp index 174011bd2..9ea6abf5b 100644 --- a/runtime/src/main/jni/JsArgConverter.cpp +++ b/runtime/src/main/jni/JsArgConverter.cpp @@ -7,6 +7,8 @@ #include "NumericCasts.h" #include "NativeScriptException.h" #include "Runtime.h" +#include "V8GlobalHelpers.h" +#include using namespace v8; using namespace std; @@ -126,7 +128,7 @@ bool JsArgConverter::ConvertArg(const Local& arg, int index) { auto jsObject = arg->ToObject(); - auto castType = NumericCasts::GetCastType(jsObject); + auto castType = NumericCasts::GetCastType(m_isolate, jsObject); Local castValue; JniLocalRef obj; @@ -218,7 +220,8 @@ bool JsArgConverter::ConvertArg(const Local& arg, int index) case CastType::None: obj = objectManager->GetJavaObjectByJsObject(jsObject); - castValue = jsObject->GetHiddenValue(ArgConverter::ConvertToV8String(m_isolate, V8StringConstants::NULL_NODE_NAME)); + V8GetPrivateValue(m_isolate, jsObject, ArgConverter::ConvertToV8String(m_isolate, V8StringConstants::NULL_NODE_NAME), castValue); + if(!castValue.IsEmpty()) { SetConvertedObject(index, nullptr); success = true; diff --git a/runtime/src/main/jni/JsArgToArrayConverter.cpp b/runtime/src/main/jni/JsArgToArrayConverter.cpp index 7d3d2b205..bb3fe6775 100644 --- a/runtime/src/main/jni/JsArgToArrayConverter.cpp +++ b/runtime/src/main/jni/JsArgToArrayConverter.cpp @@ -7,6 +7,7 @@ #include "NativeScriptException.h" #include "Runtime.h" #include "MetadataNode.h" +#include "V8GlobalHelpers.h" using namespace v8; using namespace std; @@ -155,7 +156,8 @@ bool JsArgToArrayConverter::ConvertArg(const Local& arg, int index) { auto jsObj = arg->ToObject(); - auto castType = NumericCasts::GetCastType(jsObj); + auto castType = NumericCasts::GetCastType(m_isolate, jsObj); + Local castValue; jchar charValue; jbyte byteValue; @@ -268,7 +270,7 @@ bool JsArgToArrayConverter::ConvertArg(const Local& arg, int index) case CastType::None: obj = objectManager->GetJavaObjectByJsObject(jsObj); - castValue = jsObj->GetHiddenValue(V8StringConstants::GetNullNodeName(m_isolate)); + V8GetPrivateValue(m_isolate, jsObj, V8StringConstants::GetNullNodeName(m_isolate), castValue); if(!castValue.IsEmpty()) { auto node = reinterpret_cast(castValue.As()->Value()); diff --git a/runtime/src/main/jni/LRUCache.h b/runtime/src/main/jni/LRUCache.h index fc57239d4..bca1b5383 100644 --- a/runtime/src/main/jni/LRUCache.h +++ b/runtime/src/main/jni/LRUCache.h @@ -43,7 +43,7 @@ namespace tns typedef std::list key_tracker_type; // Key to value and key history iterator - typedef std::tr1::unordered_map< key_type, std::pair > key_to_value_type; + typedef std::unordered_map< key_type, std::pair > key_to_value_type; // Constuctor specifies the cached function and // the maximum number of records to be stored diff --git a/runtime/src/main/jni/MetadataNode.cpp b/runtime/src/main/jni/MetadataNode.cpp index 565356824..272e90ee0 100644 --- a/runtime/src/main/jni/MetadataNode.cpp +++ b/runtime/src/main/jni/MetadataNode.cpp @@ -12,6 +12,8 @@ #include #include +#include "v8.h" + using namespace v8; using namespace std; using namespace tns; @@ -58,6 +60,7 @@ Local MetadataNode::CreateExtendedJSWrapper(Isolate *isolate, ObjectMana extInstance->SetInternalField(static_cast(ObjectManager::MetadataNodeKeys::CallSuper), True(isolate)); auto extdCtorFunc = Local::New(isolate, *cacheData.extendedCtorFunction); extInstance->SetPrototype(extdCtorFunc->Get(V8StringConstants::GetPrototype(isolate))); + extInstance->Set(ConvertToV8String("constructor"), extdCtorFunc); SetInstanceMetadata(isolate, extInstance, cacheData.node); } @@ -219,14 +222,14 @@ void MetadataNode::ArrayLengthGetterCallack(Local property, const Proper Local MetadataNode::CreateArrayWrapper(Isolate *isolate) { auto node = GetOrCreate("java/lang/Object"); - auto objPrototype = node->GetConstructorFunction(isolate); + auto ctorFunc = node->GetConstructorFunction(isolate); auto arrayObjectTemplate = ObjectTemplate::New(isolate); arrayObjectTemplate->SetInternalFieldCount(static_cast(ObjectManager::MetadataNodeKeys::END)); arrayObjectTemplate->SetIndexedPropertyHandler(ArrayIndexedPropertyGetterCallback, ArrayIndexedPropertySetterCallback); auto arr = arrayObjectTemplate->NewInstance(); - arr->SetPrototype(objPrototype->Get(V8StringConstants::GetPrototype(isolate))); + arr->SetPrototype(ctorFunc->Get(V8StringConstants::GetPrototype(isolate))); arr->SetAccessor(ArgConverter::ConvertToV8String(isolate, "length"), ArrayLengthGetterCallack, nullptr, Local(), AccessControl::ALL_CAN_READ, PropertyAttribute::DontDelete); SetInstanceMetadata(isolate, arr, this); @@ -291,14 +294,16 @@ void MetadataNode::NullObjectAccessorGetterCallback(Local property,const { try { - DEBUG_WRITE("NullObjectAccessorGetterCallback"); + DEBUG_WRITE("NullObjectAccessorGetterCallback called"); auto isolate = info.GetIsolate(); auto thiz = info.This(); - if((thiz->GetHiddenValue(V8StringConstants::GetNullNodeName(isolate))).IsEmpty()) + Local hiddenVal; + V8GetPrivateValue(isolate, thiz, V8StringConstants::GetNullNodeName(isolate), hiddenVal); + if(hiddenVal.IsEmpty()) { auto node = reinterpret_cast(info.Data().As()->Value()); - thiz->SetHiddenValue(V8StringConstants::GetNullNodeName(isolate), External::New(isolate, node)); + V8SetPrivateValue(isolate, thiz, V8StringConstants::GetNullNodeName(isolate), External::New(isolate, node)); auto funcTemplate = FunctionTemplate::New(isolate, MetadataNode::NullValueOfCallback); thiz->Delete(V8StringConstants::GetValueOf(isolate)); thiz->Set(V8StringConstants::GetValueOf(isolate), funcTemplate->GetFunction()); @@ -427,7 +432,10 @@ void MetadataNode::SuperAccessorGetterCallback(Local property, const Pro auto thiz = info.This(); auto isolate = info.GetIsolate(); auto key = ArgConverter::ConvertToV8String(isolate, "supervalue"); - auto superValue = thiz->GetHiddenValue(key).As(); + Local hidenVal; + V8GetPrivateValue(isolate, thiz, key, hidenVal); + auto superValue = hidenVal.As(); + if (superValue.IsEmpty()) { auto runtime = Runtime::GetRuntime(isolate); @@ -439,7 +447,7 @@ void MetadataNode::SuperAccessorGetterCallback(Local property, const Pro superValue->SetInternalField(static_cast(ObjectManager::MetadataNodeKeys::CallSuper), True(isolate)); superValue->SetPrototype(thiz->GetPrototype().As()->GetPrototype().As()->GetPrototype()); - thiz->SetHiddenValue(key, superValue); + V8SetPrivateValue(isolate, thiz, key, superValue); objectManager->CloneLink(thiz, superValue); DEBUG_WRITE("superValue.GetPrototype=%d", superValue->GetPrototype().As()->GetIdentityHash()); @@ -476,14 +484,17 @@ void MetadataNode::SetInstanceMembers(Isolate *isolate, Local& } else { - SetInstanceMembersFromStaticMetadata(isolate, ctorFuncTemplate, prototypeTemplate, instanceMethodsCallbackData, baseInstanceMethodsCallbackData, treeNode); + SetInstanceFieldsFromStaticMetadata(isolate, ctorFuncTemplate, prototypeTemplate, instanceMethodsCallbackData, baseInstanceMethodsCallbackData, treeNode); + SetInstanceMethodsFromStaticMetadata(isolate, ctorFuncTemplate, prototypeTemplate, instanceMethodsCallbackData, baseInstanceMethodsCallbackData, treeNode); } } -void MetadataNode::SetInstanceMembersFromStaticMetadata(Isolate *isolate, Local& ctorFuncTemplate, Local& prototypeTemplate, vector& instanceMethodsCallbackData, const vector& baseInstanceMethodsCallbackData, MetadataTreeNode *treeNode) +void MetadataNode::SetInstanceMethodsFromStaticMetadata(Isolate *isolate, Local& ctorFuncTemplate, Local& prototypeTemplate, vector& instanceMethodsCallbackData, const vector& baseInstanceMethodsCallbackData, MetadataTreeNode *treeNode) { SET_PROFILER_FRAME(); + Local ctorFunction; + uint8_t *curPtr = s_metadataReader.GetValueData() + treeNode->offsetValue + 1; auto nodeType = s_metadataReader.GetNodeType(treeNode); @@ -503,8 +514,7 @@ void MetadataNode::SetInstanceMembersFromStaticMetadata(Isolate *isolate, Local< string lastMethodName; MethodCallbackData *callbackData = nullptr; - auto origin = Constants::APP_ROOT_FOLDER_PATH + GetOrCreateInternal(treeNode)->m_name; - + auto origin = Constants::APP_ROOT_FOLDER_PATH + GetOrCreateInternal(treeNode)->m_name; for (auto i = 0; i < instanceMethodCout; i++) { auto entry = s_metadataReader.ReadInstanceMethodEntry(&curPtr); @@ -518,7 +528,7 @@ void MetadataNode::SetInstanceMembersFromStaticMetadata(Isolate *isolate, Local< auto itBegin = baseInstanceMethodsCallbackData.begin(); auto itEnd = baseInstanceMethodsCallbackData.end(); auto itFound = find_if(itBegin, itEnd, [&entry] (MethodCallbackData *x) - { return x->candidates.front().name == entry.name;}); + { return x->candidates.front().name == entry.name;}); if (itFound != itEnd) { callbackData->parent = *itFound; @@ -526,14 +536,60 @@ void MetadataNode::SetInstanceMembersFromStaticMetadata(Isolate *isolate, Local< auto funcData = External::New(isolate, callbackData); auto funcTemplate = FunctionTemplate::New(isolate, MethodCallback, funcData); - auto func = funcTemplate->GetFunction(); - auto funcName = ArgConverter::ConvertToV8String(isolate, entry.name); - prototypeTemplate->Set(funcName, Wrap(isolate, func, entry.name, origin, false /* isCtorFunc */)); + + auto funcName = ConvertToV8String(entry.name); + + if (s_profilerEnabled) + { + auto func = funcTemplate->GetFunction(); + Local wrapperFunc = Wrap(isolate, func, entry.name, origin, false /* isCtorFunc */); + Local ctorFunc = ctorFuncTemplate->GetFunction(); + Local protoObject = ctorFunc->Get(ConvertToV8String("prototype")).As(); + if (!protoObject.IsEmpty() && !protoObject->IsUndefined() && !protoObject->IsNull()) + { + protoObject->Set(funcName, wrapperFunc); + } + } + else + { + prototypeTemplate->Set(funcName, funcTemplate); + } + lastMethodName = entry.name; } callbackData->candidates.push_back(entry); } +} + +void MetadataNode::SetInstanceFieldsFromStaticMetadata(Isolate *isolate, Local& ctorFuncTemplate, Local& prototypeTemplate, vector& instanceMethodsCallbackData, const vector& baseInstanceMethodsCallbackData, MetadataTreeNode *treeNode) +{ + SET_PROFILER_FRAME(); + + Local ctorFunction; + + uint8_t *curPtr = s_metadataReader.GetValueData() + treeNode->offsetValue + 1; + + auto nodeType = s_metadataReader.GetNodeType(treeNode); + + auto curType = s_metadataReader.ReadTypeName(treeNode); + + curPtr += sizeof(uint16_t /* baseClassId */); + + if (s_metadataReader.IsNodeTypeInterface(nodeType)) + { + curPtr += sizeof(uint8_t) + sizeof(uint32_t); + } + + //get candidates from instance methods metadata + auto instanceMethodCout = *reinterpret_cast(curPtr); + curPtr += sizeof(uint16_t); + + //skip metadata methods -- advance the pointer only + for (auto i = 0; i < instanceMethodCout; i++) + { + auto entry = s_metadataReader.ReadInstanceMethodEntry(&curPtr); + } //get candidates from instance fields metadata auto instanceFieldCout = *reinterpret_cast(curPtr); @@ -542,7 +598,7 @@ void MetadataNode::SetInstanceMembersFromStaticMetadata(Isolate *isolate, Local< { auto entry = s_metadataReader.ReadInstanceFieldEntry(&curPtr); - auto fieldName = ArgConverter::ConvertToV8String(isolate, entry.name); + auto fieldName = ConvertToV8String(entry.name); auto fieldInfo = new FieldCallbackData(entry); fieldInfo->declaringType = curType; auto fieldData = External::New(isolate, fieldInfo); @@ -606,9 +662,8 @@ void MetadataNode::SetInstanceMembersFromRuntimeMetadata(Isolate *isolate, Local auto funcData = External::New(isolate, callbackData); auto funcTemplate = FunctionTemplate::New(isolate, MethodCallback, funcData); - auto func = funcTemplate->GetFunction(); auto funcName = ArgConverter::ConvertToV8String(isolate, entry.name); - prototypeTemplate->Set(funcName, func); + prototypeTemplate->Set(funcName, funcTemplate); lastMethodName = entry.name; } callbackData->candidates.push_back(entry); @@ -706,8 +761,8 @@ void MetadataNode::SetInnerTypes(Isolate *isolate, Local& ctorFunction { const auto& children = *treeNode->children; - // prototype of outer class - auto prototypeTemplate2 = ctorFunction->Get(V8StringConstants::GetPrototype(isolate)).As(); +// // prototype of outer class +// auto prototypeTemplate2 = ctorFunction->Get(V8StringConstants::GetPrototype(isolate)).As(); for (auto curChild : children) { @@ -726,7 +781,7 @@ void MetadataNode::SetInnerTypes(Isolate *isolate, Local& ctorFunction Local MetadataNode::GetConstructorFunctionTemplate(Isolate *isolate, MetadataTreeNode *treeNode) { - vector instanceMethodsCallbackData; + std::vector instanceMethodsCallbackData; auto ft = GetConstructorFunctionTemplate(isolate, treeNode, instanceMethodsCallbackData); @@ -805,18 +860,22 @@ Local MetadataNode::GetConstructorFunction(Isolate *isolate) { auto ctorFuncTemplate = GetConstructorFunctionTemplate(isolate, m_treeNode); auto ctorFunc = Local::New(isolate, *m_poCtorFunc); + return ctorFunc; } MetadataNode::TypeMetadata* MetadataNode::GetTypeMetadata(Isolate *isolate, const Local& value) { - auto data = reinterpret_cast(V8GetHiddenValue(value, "typemetadata").As()->Value()); + Local hiddenVal; + V8GetPrivateValue(isolate, value, String::NewFromUtf8(isolate, "typemetadata"), hiddenVal); + + auto data = reinterpret_cast(hiddenVal.As()->Value()); return data; } void MetadataNode::SetTypeMetadata(Isolate *isolate, Local value, TypeMetadata *data) { - V8SetHiddenValue(value, "typemetadata", External::New(isolate, data)); + V8SetPrivateValue(isolate, value, String::NewFromUtf8(isolate, "typemetadata"), External::New(isolate, data)); } MetadataNode* MetadataNode::GetInstanceMetadata(Isolate *isolate, const Local& value) @@ -824,7 +883,9 @@ MetadataNode* MetadataNode::GetInstanceMetadata(Isolate *isolate, const Local::New(isolate, *cache->MetadataKey); - auto ext = value->GetHiddenValue(key); + Local hiddenVal; + V8GetPrivateValue(isolate, value, key, hiddenVal); + auto ext = hiddenVal; if (!ext.IsEmpty()) { node = reinterpret_cast(ext.As()->Value()); @@ -832,11 +893,11 @@ MetadataNode* MetadataNode::GetInstanceMetadata(Isolate *isolate, const Local value, MetadataNode *node) +void MetadataNode::SetInstanceMetadata(Isolate *isolate, Local object, MetadataNode *node) { auto cache = GetMetadataNodeCache(isolate); auto key = Local::New(isolate, *cache->MetadataKey); - value->SetHiddenValue(key, External::New(isolate, node)); + V8SetPrivateValue(isolate, object, key, External::New(isolate, node)); } void MetadataNode::ExtendedClassConstructorCallback(const v8::FunctionCallbackInfo& info) @@ -857,7 +918,7 @@ void MetadataNode::ExtendedClassConstructorCallback(const v8::FunctionCallbackIn SetInstanceMetadata(isolate, thiz, extData->node); thiz->SetInternalField(static_cast(ObjectManager::MetadataNodeKeys::CallSuper), True(isolate)); - thiz->SetHiddenValue(V8StringConstants::GetImplementationObject(isolate), implementationObject); + V8SetPrivateValue(isolate, thiz, V8StringConstants::GetImplementationObject(isolate), implementationObject); ArgsWrapper argWrapper(info, ArgType::Class); @@ -929,7 +990,7 @@ void MetadataNode::InterfaceConstructorCallback(const v8::FunctionCallbackInfoSetPrototype(thiz->GetPrototype()); thiz->SetPrototype(implementationObject); - thiz->SetHiddenValue(V8StringConstants::GetImplementationObject(isolate), implementationObject); + V8SetPrivateValue(isolate, thiz, V8StringConstants::GetImplementationObject(isolate), implementationObject); ArgsWrapper argWrapper(info, ArgType::Interface); @@ -958,6 +1019,7 @@ void MetadataNode::ClassConstructorCallback(const v8::FunctionCallbackInfo(info.Data().As()->Value()); @@ -1124,17 +1186,19 @@ void MetadataNode::ArrayIndexedPropertySetterCallback(uint32_t index, Local MetadataNode::GetImplementationObject(const Local& object) +Local MetadataNode::GetImplementationObject(Isolate* isolate, const Local& object) { DEBUG_WRITE("GetImplementationObject called on object:%d", object->GetIdentityHash()); auto target = object; - auto isolate = object->GetIsolate(); Local currentPrototype = target; Local implementationObject; - implementationObject = object->GetHiddenValue(V8StringConstants::GetImplementationObject(isolate)).As(); + Local hiddenVal; + V8GetPrivateValue(isolate, object, V8StringConstants::GetImplementationObject(isolate), hiddenVal); + implementationObject = hiddenVal.As(); + if (!implementationObject.IsEmpty()) { return implementationObject; @@ -1152,7 +1216,9 @@ Local MetadataNode::GetImplementationObject(const Local& object) return object->Get(v8Prototype).As(); } - auto obj = V8GetHiddenValue(object, "t::ActivityImplementationObject").As(); + Local hiddenValue; + V8GetPrivateValue(isolate, object, String::NewFromUtf8(isolate, "t::ActivityImplementationObject"), hiddenValue); + auto obj = hiddenValue.As(); if (!obj.IsEmpty()) { DEBUG_WRITE("GetImplementationObject returning ActivityImplementationObject property on object: %d", object->GetIdentityHash()); @@ -1186,7 +1252,9 @@ Local MetadataNode::GetImplementationObject(const Local& object) } else { - auto value = currentPrototype.As()->GetHiddenValue(V8StringConstants::GetClassImplementationObject(isolate)); + Local hiddenVal; + V8GetPrivateValue(isolate, currentPrototype.As(), V8StringConstants::GetClassImplementationObject(isolate), hiddenVal); + auto value = hiddenVal; if (!value.IsEmpty()) { @@ -1219,7 +1287,9 @@ void MetadataNode::PackageGetterCallback(Local property, const PropertyCal auto thiz = info.This(); - auto cachedItem = thiz->GetHiddenValue(strProperty); + Local hiddenVal; + V8GetPrivateValue(isolate, thiz, strProperty, hiddenVal); + auto cachedItem = hiddenVal; if (cachedItem.IsEmpty()) { @@ -1236,7 +1306,7 @@ void MetadataNode::PackageGetterCallback(Local property, const PropertyCal { auto childNode = MetadataNode::GetOrCreateInternal(child.treeNode); cachedItem = childNode->CreateWrapper(isolate); - thiz->SetHiddenValue(strProperty, cachedItem); + V8SetPrivateValue(isolate, thiz, strProperty, cachedItem); } } @@ -1360,7 +1430,7 @@ void MetadataNode::ExtendMethodCallback(const v8::FunctionCallbackInfoGetHiddenValue(implementationObjectPropertyName).As(); + Local hiddenVal; + V8GetPrivateValue(isolate, implementationObject, implementationObjectPropertyName, hiddenVal); + auto implementationObjectProperty = hiddenVal.As(); if (implementationObjectProperty.IsEmpty()) { //mark the implementationObject as such and set a pointer to it's class node inside it for reuse validation later - implementationObject->SetHiddenValue(implementationObjectPropertyName, String::NewFromUtf8(isolate, fullExtendedName.c_str())); + V8SetPrivateValue(isolate, implementationObject, implementationObjectPropertyName, String::NewFromUtf8(isolate, fullExtendedName.c_str())); } else { @@ -1724,11 +1796,11 @@ void MetadataNode::EnableProfiler(bool enableProfiler) s_profilerEnabled = enableProfiler; } -Local MetadataNode::Wrap(Isolate* isolate, const Local& f, const string& name, const string& origin, bool isCtorFunc) +Local MetadataNode::Wrap(Isolate* isolate, const Local& function, const string& name, const string& origin, bool isCtorFunc) { - if (!s_profilerEnabled) + if (!s_profilerEnabled || name == "") { - return f; + return function; } static set keywords; @@ -1743,11 +1815,6 @@ Local MetadataNode::Wrap(Isolate* isolate, const Local& f, c keywords = set(kw, kw + sizeof(kw)/sizeof(kw[0])); } - if (name == "") - { - return f; - } - string actualName = name; while (keywords.find(actualName) != keywords.end()) { @@ -1795,10 +1862,11 @@ Local MetadataNode::Wrap(Isolate* isolate, const Local& f, c if (!result.IsEmpty()) { ret = result.As(); - ret->Set(ArgConverter::ConvertToV8String(isolate, "__func"), f); + ret->Set(ArgConverter::ConvertToV8String(isolate, "__func"), function); + ret->SetName(ConvertToV8String(actualName)); auto prototypePropName = V8StringConstants::GetPrototype(isolate); - ret->Set(prototypePropName, f->Get(prototypePropName)); + ret->Set(prototypePropName, function->Get(prototypePropName)); } else { diff --git a/runtime/src/main/jni/MetadataNode.h b/runtime/src/main/jni/MetadataNode.h index 96e568ffb..81bb414ea 100644 --- a/runtime/src/main/jni/MetadataNode.h +++ b/runtime/src/main/jni/MetadataNode.h @@ -51,7 +51,7 @@ namespace tns static v8::Local CreateExtendedJSWrapper(v8::Isolate *isolate, ObjectManager *objectManager, const std::string& proxyClassName); - static v8::Local GetImplementationObject(const v8::Local& object); + static v8::Local GetImplementationObject(v8::Isolate *isolate, const v8::Local& object); static void CreateTopLevelNamespaces(v8::Isolate *isolate, const v8::Local& global); @@ -79,7 +79,8 @@ namespace tns v8::Local GetConstructorFunctionTemplate(v8::Isolate *isolate, MetadataTreeNode *treeNode, std::vector& instanceMethodsCallbackData); void SetInstanceMembers(v8::Isolate *isolate, v8::Local& ctorFuncTemplate, v8::Local& prototypeTemplate, std::vector& instanceMethodsCallbackData, const std::vector& baseInstanceMethodsCallbackData, MetadataTreeNode *treeNode); - void SetInstanceMembersFromStaticMetadata(v8::Isolate *isolate, v8::Local& ctorFuncTemplate, v8::Local& prototypeTemplate, std::vector& instanceMethodsCallbackData, const std::vector& baseInstanceMethodsCallbackData, MetadataTreeNode *treeNode); + void SetInstanceMethodsFromStaticMetadata(v8::Isolate *isolate, v8::Local& ctorFuncTemplate, v8::Local& prototypeTemplate, std::vector& instanceMethodsCallbackData, const std::vector& baseInstanceMethodsCallbackData, MetadataTreeNode *treeNode); + void SetInstanceFieldsFromStaticMetadata(v8::Isolate *isolate, v8::Local& ctorFuncTemplate, v8::Local& prototypeTemplate, std::vector& instanceMethodsCallbackData, const std::vector& baseInstanceMethodsCallbackData, MetadataTreeNode *treeNode); void SetInstanceMembersFromRuntimeMetadata(v8::Isolate *isolate, v8::Local& ctorFuncTemplate, v8::Local& prototypeTemplate, std::vector& instanceMethodsCallbackData, const std::vector& baseInstanceMethodsCallbackData, MetadataTreeNode *treeNode); void SetStaticMembers(v8::Isolate *isolate, v8::Local& ctorFunction, MetadataTreeNode *treeNode); void SetInnerTypes(v8::Isolate *isolate, v8::Local& ctorFunction, MetadataTreeNode *treeNode); @@ -129,7 +130,7 @@ namespace tns static bool GetExtendLocation(std::string& extendLocation); static ExtendedClassCacheData GetCachedExtendedClassData(v8::Isolate *isolate, const std::string& proxyClassName); - v8::Local Wrap(v8::Isolate* isolate, const v8::Local& f, const std::string& name, const std::string& origin, bool isCtorFunc); + v8::Local Wrap(v8::Isolate* isolate, const v8::Local&function, const std::string& name, const std::string& origin, bool isCtorFunc); MetadataTreeNode *m_treeNode; v8::Persistent *m_poCtorFunc; diff --git a/runtime/src/main/jni/MethodCache.cpp b/runtime/src/main/jni/MethodCache.cpp index 868147626..a74c89cbc 100644 --- a/runtime/src/main/jni/MethodCache.cpp +++ b/runtime/src/main/jni/MethodCache.cpp @@ -124,22 +124,21 @@ string MethodCache::EncodeSignature(const string& className, const string& metho for (int i = 0; i < len; i++) { sig.append("."); - sig.append(GetType(args[i])); + sig.append(GetType(args.GetIsolate(), args[i])); } return sig; } -string MethodCache::GetType(const v8::Local& value) +string MethodCache::GetType(Isolate *isolate, const v8::Local& value) { string type; if(value->IsObject()) { auto objVal = value->ToObject(); - - auto isolate = objVal->GetIsolate(); - Local nullNode = objVal->GetHiddenValue(V8StringConstants::GetNullNodeName(isolate)); + Local nullNode; //out + V8GetPrivateValue(isolate, objVal, V8StringConstants::GetNullNodeName(isolate), nullNode); if(!nullNode.IsEmpty()) { auto treeNode = reinterpret_cast(nullNode.As()->Value()); @@ -197,7 +196,7 @@ string MethodCache::GetType(const v8::Local& value) else if (value->IsObject()) { auto object = value->ToObject(); - auto castType = NumericCasts::GetCastType(object); + auto castType = NumericCasts::GetCastType(isolate, object); MetadataNode *node; switch (castType) diff --git a/runtime/src/main/jni/MethodCache.h b/runtime/src/main/jni/MethodCache.h index da81afdc1..c9c92b6df 100644 --- a/runtime/src/main/jni/MethodCache.h +++ b/runtime/src/main/jni/MethodCache.h @@ -47,7 +47,7 @@ namespace tns static std::string EncodeSignature(const std::string& className, const std::string& methodName, const v8::FunctionCallbackInfo& args, bool isStatic); - static std::string GetType(const v8::Local& value); + static std::string GetType(v8::Isolate *isolate, const v8::Local& value); static std::string ResolveJavaMethod(const v8::FunctionCallbackInfo& args, const std::string& className, const std::string& methodName); diff --git a/runtime/src/main/jni/NumericCasts.cpp b/runtime/src/main/jni/NumericCasts.cpp index d23110bde..09bdd5c30 100644 --- a/runtime/src/main/jni/NumericCasts.cpp +++ b/runtime/src/main/jni/NumericCasts.cpp @@ -23,12 +23,12 @@ void NumericCasts::CreateGlobalCastFunctions(Isolate *isolate, const LocalSet(ArgConverter::ConvertToV8String(isolate, "char"), FunctionTemplate::New(isolate, NumericCasts::MarkAsCharCallbackStatic, ext)); } -CastType NumericCasts::GetCastType(const Local& object) +CastType NumericCasts::GetCastType(Isolate *isolate, const Local& object) { auto ret = CastType::None; - auto isolate = object->GetIsolate(); auto key = ArgConverter::ConvertToV8String(isolate, s_castMarker); - auto hidden = object->GetHiddenValue(key); + Local hidden; + V8GetPrivateValue(isolate, object, key, hidden); if (!hidden.IsEmpty()) { ret = static_cast(hidden->Int32Value()); @@ -44,9 +44,9 @@ Local NumericCasts::GetCastValue(const Local& object) return value; } -void NumericCasts::MarkAsLong(const v8::Local& object, const v8::Local& value) +void NumericCasts::MarkAsLong(Isolate *isolate, const v8::Local& object, const v8::Local& value) { - MarkJsObject(object, CastType::Long, value); + MarkJsObject(isolate, object, CastType::Long, value); } NumericCasts* NumericCasts::GetThis(const v8::FunctionCallbackInfo& args) @@ -228,7 +228,7 @@ void NumericCasts::MarkAsLongCallback(const v8::FunctionCallbackInfo& arg } auto cast = Object::New(isolate); - MarkJsObject(cast, CastType::Long, value); + MarkJsObject(isolate, cast, CastType::Long, value); args.GetReturnValue().Set(cast); } catch (NativeScriptException& e) @@ -273,7 +273,7 @@ void NumericCasts::MarkAsByteCallback(const v8::FunctionCallbackInfo& arg } auto cast = Object::New(isolate); - MarkJsObject(cast, CastType::Byte, value); + MarkJsObject(isolate, cast, CastType::Byte, value); args.GetReturnValue().Set(cast); } catch (NativeScriptException& e) @@ -319,7 +319,7 @@ void NumericCasts::MarkAsShortCallback(const v8::FunctionCallbackInfo& ar } auto cast = Object::New(isolate); - MarkJsObject(cast, CastType::Short, value); + MarkJsObject(isolate, cast, CastType::Short, value); args.GetReturnValue().Set(cast); } catch (NativeScriptException& e) @@ -360,7 +360,7 @@ void NumericCasts::MarkAsCharCallback(const v8::FunctionCallbackInfo& arg } auto cast = Object::New(isolate); - MarkJsObject(cast, CastType::Char, value); + MarkJsObject(isolate, cast, CastType::Char, value); args.GetReturnValue().Set(cast); } catch (NativeScriptException& e) @@ -396,7 +396,7 @@ void NumericCasts::MarkAsFloatCallback(const v8::FunctionCallbackInfo& ar auto value = args[0]->ToNumber(); auto cast = Object::New(isolate); - MarkJsObject(cast, CastType::Float, value); + MarkJsObject(isolate, cast, CastType::Float, value); args.GetReturnValue().Set(cast); } catch (NativeScriptException& e) @@ -432,7 +432,7 @@ void NumericCasts::MarkAsDoubleCallback(const v8::FunctionCallbackInfo& a auto value = args[0]->ToNumber(); auto cast = Object::New(isolate); - MarkJsObject(cast, CastType::Double, value); + MarkJsObject(isolate, cast, CastType::Double, value); args.GetReturnValue().Set(cast); } catch (NativeScriptException& e) @@ -451,14 +451,13 @@ void NumericCasts::MarkAsDoubleCallback(const v8::FunctionCallbackInfo& a } } -void NumericCasts::MarkJsObject(const Local& object, CastType castType, const Local& value) +void NumericCasts::MarkJsObject(Isolate *isolate, const Local& object, CastType castType, const Local& value) { - auto isolate = object->GetIsolate(); auto key = ArgConverter::ConvertToV8String(isolate, s_castMarker); auto type = Integer::New(isolate, static_cast(castType)); - - object->SetHiddenValue(key, type); + V8SetPrivateValue(isolate, object, key, type); object->Set(V8StringConstants::GetValue(isolate), value); + DEBUG_WRITE("MarkJsObject: Marking js object: %d with cast type: %d", object->GetIdentityHash(), castType); } diff --git a/runtime/src/main/jni/NumericCasts.h b/runtime/src/main/jni/NumericCasts.h index 86039fa84..037334898 100644 --- a/runtime/src/main/jni/NumericCasts.h +++ b/runtime/src/main/jni/NumericCasts.h @@ -22,11 +22,11 @@ namespace tns public: void CreateGlobalCastFunctions(v8::Isolate *isolate, const v8::Local& globalTemplate); - static CastType GetCastType(const v8::Local& object); + static CastType GetCastType(v8::Isolate *isolate, const v8::Local& object); static v8::Local GetCastValue(const v8::Local& object); - static void MarkAsLong(const v8::Local& object, const v8::Local& value); + static void MarkAsLong(v8::Isolate *isolate, const v8::Local& object, const v8::Local& value); private: void MarkAsLongCallback(const v8::FunctionCallbackInfo& args); @@ -41,7 +41,7 @@ namespace tns void MarkAsDoubleCallback(const v8::FunctionCallbackInfo& args); - static void MarkJsObject(const v8::Local& object, CastType castType, const v8::Local& value); + static void MarkJsObject(v8::Isolate *isolate, const v8::Local& object, CastType castType, const v8::Local& value); static void MarkAsLongCallbackStatic(const v8::FunctionCallbackInfo& args); diff --git a/runtime/src/main/jni/ObjectManager.cpp b/runtime/src/main/jni/ObjectManager.cpp index a99491bf6..84e5d8107 100644 --- a/runtime/src/main/jni/ObjectManager.cpp +++ b/runtime/src/main/jni/ObjectManager.cpp @@ -18,7 +18,7 @@ using namespace tns; ObjectManager::ObjectManager(jobject javaRuntimeObject) - : m_javaRuntimeObject(javaRuntimeObject), m_env(JEnv()), m_numberOfGC(0), m_currentObjectId(0), m_cache(NewWeakGlobalRefCallback, DeleteWeakGlobalRefCallback, 1000, this) + :m_isolate(nullptr), m_javaRuntimeObject(javaRuntimeObject), m_env(JEnv()), m_numberOfGC(0), m_currentObjectId(0), m_cache(NewWeakGlobalRefCallback, DeleteWeakGlobalRefCallback, 1000, this) { auto runtimeClass = m_env.FindClass("com/tns/Runtime"); assert(runtimeClass != nullptr); @@ -241,7 +241,7 @@ void ObjectManager::Link(const Local& object, uint32_t javaObjectID, jcl auto state = new ObjectWeakCallbackState(this, jsInstanceInfo, objectHandle); // subscribe for JS GC event - objectHandle->SetWeak(state, JSObjectWeakCallbackStatic); + objectHandle->SetWeak(state, JSObjectWeakCallbackStatic, WeakCallbackType::kFinalizer); auto jsInfoIdx = static_cast(MetadataNodeKeys::JsInfo); @@ -287,7 +287,7 @@ string ObjectManager::GetClassName(jclass clazz) return className; } -void ObjectManager::JSObjectWeakCallbackStatic(const WeakCallbackData& data) +void ObjectManager::JSObjectWeakCallbackStatic(const WeakCallbackInfo& data) { ObjectWeakCallbackState *callbackState = data.GetParameter(); @@ -348,7 +348,7 @@ void ObjectManager::JSObjectWeakCallback(Isolate *isolate, ObjectWeakCallbackSta } } - po->SetWeak(callbackState, JSObjectWeakCallbackStatic); + po->SetWeak(callbackState, JSObjectWeakCallbackStatic, WeakCallbackType::kFinalizer); } int ObjectManager::GenerateNewObjectID() @@ -390,11 +390,9 @@ void ObjectManager::ReleaseJSInstance(Persistent *po, JSInstanceInfo *js * */ void ObjectManager::ReleaseRegularObjects() { - auto isolate = m_isolate; - - HandleScope handleScope(isolate); + HandleScope handleScope(m_isolate); - auto propName = String::NewFromUtf8(isolate, "t::gcNum"); + auto propName = String::NewFromUtf8(m_isolate, "t::gcNum", NewStringType::kNormal).ToLocalChecked(); auto& topGCInfo = m_markedForGC.top(); auto& marked = topGCInfo.markedForGC; @@ -405,11 +403,12 @@ void ObjectManager::ReleaseRegularObjects() if (m_released.contains(po)) continue; - auto obj = Local::New(isolate, *po); + auto obj = Local::New(m_isolate, *po); assert(!obj.IsEmpty()); - auto gcNum = obj->GetHiddenValue(propName); + Local gcNum; + V8GetPrivateValue(m_isolate, obj, propName, gcNum); bool isReachableFromImplementationObject = false; @@ -439,7 +438,7 @@ void ObjectManager::ReleaseRegularObjects() bool ObjectManager::HasImplObject(Isolate *isolate, const Local& obj) { - auto implObject = MetadataNode::GetImplementationObject(obj); + auto implObject = MetadataNode::GetImplementationObject(isolate, obj); bool hasImplObj = !implObject.IsEmpty(); @@ -489,7 +488,8 @@ void ObjectManager::MarkReachableObjects(Isolate *isolate, const Local& // here we are leaving "callback2" object to remain strong in java m_implObjStrong[jsInfo->JavaObjectID] = nullptr; } - o->SetHiddenValue(propName, curGCNumValue); + + V8SetPrivateValue(isolate, o, propName, curGCNumValue); } uint8_t *addr = NativeScriptExtension::GetAddress(o); diff --git a/runtime/src/main/jni/ObjectManager.h b/runtime/src/main/jni/ObjectManager.h index eea36c649..6798def87 100644 --- a/runtime/src/main/jni/ObjectManager.h +++ b/runtime/src/main/jni/ObjectManager.h @@ -152,7 +152,7 @@ namespace tns v8::Local CreateJSWrapperHelper(jint javaObjectID, const std::string& typeName, jclass clazz); - static void JSObjectWeakCallbackStatic(const v8::WeakCallbackData& data); + static void JSObjectWeakCallbackStatic(const v8::WeakCallbackInfo& data); void JSObjectWeakCallback(v8::Isolate *isolate, ObjectWeakCallbackState *callbackState); diff --git a/runtime/src/main/jni/ReadWriteLock.cpp b/runtime/src/main/jni/ReadWriteLock.cpp new file mode 100644 index 000000000..6af3abee0 --- /dev/null +++ b/runtime/src/main/jni/ReadWriteLock.cpp @@ -0,0 +1,57 @@ +// +// Created by plamen5kov on 9/10/16. +// + +#include "ReadWriteLock.h" + +using namespace std; +using namespace tns; + +ReadWriteLock::ReadWriteLock() + : shared(), reader_gate(), writer_gate(), active_readers(0), waiting_writers(0), active_writers(0) +{ +} + +void ReadWriteLock::AquireReadLock() { + //wait till there are no waiting writers and increment active readers + std::unique_lock lk(shared); + while( waiting_writers != 0 ) //starving readers and giving writer priority + { + reader_gate.wait(lk); + } + active_readers++; + lk.unlock(); +} + +void ReadWriteLock::ReleaseReadUnlock() { + //get lock decrement active readers and notify one waiting writer + std::unique_lock lk(shared); + active_readers--; + lk.unlock(); + writer_gate.notify_one(); +} + +void ReadWriteLock::AquireWriteLock() { + //declare waiting and wait till there are no more active readers or writers and get lock + std::unique_lock lk(shared); + waiting_writers++; + while( active_readers != 0 || active_writers != 0 ) //if any is active wait for them to finish + { + writer_gate.wait(lk); + } + active_writers++; + lk.unlock(); +} + +void ReadWriteLock::ReleaseWriteUnlock() { + //decrement waiting and active writers + std::unique_lock lk(shared); + waiting_writers--; + active_writers--; + if(waiting_writers > 0) + writer_gate.notify_one(); //(priority to writers) + else + reader_gate.notify_all(); //notify readers + lk.unlock(); +} + diff --git a/runtime/src/main/jni/ReadWriteLock.h b/runtime/src/main/jni/ReadWriteLock.h new file mode 100644 index 000000000..a9796ed29 --- /dev/null +++ b/runtime/src/main/jni/ReadWriteLock.h @@ -0,0 +1,34 @@ +// +// Created by plamen5kov on 9/10/16. +// + +#ifndef READWRITELOCK_H +#define READWRITELOCK_H + +#include +#include +#include + +namespace tns { + + class ReadWriteLock + { + public: + ReadWriteLock(); + + void AquireReadLock(); + void ReleaseReadUnlock(); + void AquireWriteLock(); + void ReleaseWriteUnlock(); + + private: + std::mutex shared; + std::condition_variable reader_gate; + std::condition_variable writer_gate; + int active_readers; + int active_writers; + int waiting_writers; + }; +} + +#endif //READWRITELOCK_H diff --git a/runtime/src/main/jni/Runtime.cpp b/runtime/src/main/jni/Runtime.cpp index 3da8b0a43..08f6b3f76 100644 --- a/runtime/src/main/jni/Runtime.cpp +++ b/runtime/src/main/jni/Runtime.cpp @@ -258,7 +258,7 @@ void Runtime::CreateJSInstanceNative(JNIEnv *_env, jobject obj, jobject javaObje throw NativeScriptException(string("Failed to create JavaScript extend wrapper for class '" + proxyClassName + "'")); } - implementationObject = MetadataNode::GetImplementationObject(jsInstance); + implementationObject = MetadataNode::GetImplementationObject(isolate, jsInstance); if (implementationObject.IsEmpty()) { string msg("createJSInstanceNative: implementationObject is empty"); @@ -381,7 +381,7 @@ Isolate* Runtime::PrepareV8Runtime(const string& filesPath, jstring packageName, else { // This should be executed before V8::Initialize, which calls it with false. - NativeScriptExtension::Probe(true); + NativeScriptExtension::CpuFeaturesProbe(true); InitializeV8(); didInitializeV8 = true; diff --git a/runtime/src/main/jni/V8GlobalHelpers.cpp b/runtime/src/main/jni/V8GlobalHelpers.cpp index 260df9ab6..b06501dfb 100644 --- a/runtime/src/main/jni/V8GlobalHelpers.cpp +++ b/runtime/src/main/jni/V8GlobalHelpers.cpp @@ -1,22 +1,117 @@ #include "V8GlobalHelpers.h" #include "ArgConverter.h" #include "include/v8.h" +#include "JEnv.h" +#include "NativeScriptException.h" +#include using namespace v8; using namespace std; -Local tns::V8GetHiddenValue(const Local& obj, const string& propName) -{ - // TODO: Pete: Temporary - this function is changed in the new v8 api refactoring branch - auto isolate = Isolate::GetCurrent(); - auto s = ArgConverter::ConvertToV8String(isolate, propName); - return obj->GetHiddenValue(s); +string tns::ConvertToString(const v8::Local &s) { + if (s.IsEmpty()) + { + return string(); + } + else + { + String::Utf8Value str(s); + return string(*str); + } } -bool tns::V8SetHiddenValue(const Local& obj, const string& propName, const Local& value) -{ -// TODO: Pete: Temporary - this function is changed in the new v8 api refactoring branch - auto isolate = Isolate::GetCurrent(); - auto s = ArgConverter::ConvertToV8String(isolate, propName); - return obj->SetHiddenValue(s, value); +jstring tns::ConvertToJavaString(const Local &value) { + JEnv env; + String::Value stringValue(value); + return env.NewString((const jchar *) *stringValue, stringValue.length()); } + +Local tns::ConvertToV8String(const jchar *data, int length) { + auto isolate = Isolate::GetCurrent(); + return String::NewFromTwoByte(isolate, (const uint16_t *) data, String::kNormalString, length); +} + +Local tns::ConvertToV8String(const string &s) { + auto isolate = Isolate::GetCurrent(); + Local str = String::NewFromUtf8(isolate, s.c_str(), NewStringType::kNormal, s.length()).ToLocalChecked(); + return str; +} + +Local tns::ConvertToV8String(const char *data, int length) { + auto isolate = Isolate::GetCurrent(); + return String::NewFromUtf8(isolate, (const char *) data, String::kNormalString, length); +} + +bool tns::V8HasPrivateValue(Isolate *isolate, const Local &obj, const Local &propName) { + + if (obj.IsEmpty()) + { + return false; + } + + auto privateKey = Private::ForApi(isolate, propName); + + auto hasPrivate = obj->HasPrivate(isolate->GetCurrentContext(), privateKey); + + if (hasPrivate.IsNothing()) + { + return false; + } + + if (!hasPrivate.FromMaybe(false)) + { + return false; + } + + auto res = obj->GetPrivate(isolate->GetCurrentContext(), privateKey); + if (res.IsEmpty()) + { + return false; + } + + return true; +} + +bool tns::V8GetPrivateValue(Isolate *isolate, const Local &obj, const Local &propName, Local &out) { + auto privateKey = Private::ForApi(isolate, propName); + + auto hasPrivate = obj->HasPrivate(isolate->GetCurrentContext(), privateKey); + + if (hasPrivate.IsNothing()) + { + stringstream ss; + ss << "Failed to Get Private Value for prop: " << tns::ConvertToString(propName).c_str() << endl; + throw tns::NativeScriptException(ss.str()); + } + + if (!hasPrivate.FromMaybe(false)) + { + return false; + } + + auto res = obj->GetPrivate(isolate->GetCurrentContext(), privateKey); + + if (res.IsEmpty()) + { + stringstream ss; + ss << "Failed to Get Private Value for prop: " << tns::ConvertToString(propName).c_str() << endl; + throw tns::NativeScriptException(ss.str()); + } + + return res.ToLocal(&out); +} + +bool tns::V8SetPrivateValue(Isolate *isolate, const Local &obj, const Local &propName, const Local &value) { + auto privateKey = Private::ForApi(isolate, propName); + auto res = obj->SetPrivate(isolate->GetCurrentContext(), privateKey, value); + + if (res.IsNothing()) + { + stringstream ss; + ss << "Failed to Set Private Value for prop: " << tns::ConvertToString(propName).c_str() << endl; + throw tns::NativeScriptException(ss.str()); + } + + return res.FromMaybe(false); +} + diff --git a/runtime/src/main/jni/V8GlobalHelpers.h b/runtime/src/main/jni/V8GlobalHelpers.h index d94609e7d..16af6651c 100644 --- a/runtime/src/main/jni/V8GlobalHelpers.h +++ b/runtime/src/main/jni/V8GlobalHelpers.h @@ -7,9 +7,21 @@ namespace tns { - v8::Local V8GetHiddenValue(const v8::Local& obj, const std::string& propName); + std::string ConvertToString(const v8::Local& s); - bool V8SetHiddenValue(const v8::Local& obj, const std::string& propName, const v8::Local& value); + jstring ConvertToJavaString(const v8::Local& jsValue); + + v8::Local ConvertToV8String(const jchar* data, int length); + + v8::Local ConvertToV8String(const std::string& s); + + v8::Local ConvertToV8String(const char *data, int length); + + bool V8HasPrivateValue(v8::Isolate *isolate, const v8::Local &obj, const v8::Local &propName); + + bool V8GetPrivateValue(v8::Isolate *isolate, const v8::Local& obj, const v8::Local& propName, v8::Local& out); + + bool V8SetPrivateValue(v8::Isolate *isolate, const v8::Local& obj, const v8::Local& propName, const v8::Local& value); } #endif /* V8GLOBALHELPERS_H_ */ diff --git a/runtime/src/main/jni/WeakRef.cpp b/runtime/src/main/jni/WeakRef.cpp index 61bc9f572..017e10a61 100644 --- a/runtime/src/main/jni/WeakRef.cpp +++ b/runtime/src/main/jni/WeakRef.cpp @@ -2,6 +2,7 @@ #include "ArgConverter.h" #include "V8StringConstants.h" #include "NativeScriptException.h" +#include "V8GlobalHelpers.h" #include using namespace v8; @@ -64,12 +65,12 @@ void WeakRef::ConstructorCallbackImpl(const FunctionCallbackInfo& args) auto poHolder = new Persistent(isolate, weakRef); auto callbackState = new CallbackState(poTarget, poHolder); - poTarget->SetWeak(callbackState, WeakTargetCallback); - poHolder->SetWeak(callbackState, WeakHolderCallback); + poTarget->SetWeak(callbackState, WeakTargetCallback, WeakCallbackType::kFinalizer); + poHolder->SetWeak(callbackState, WeakHolderCallback, WeakCallbackType::kFinalizer); weakRef->Set(ArgConverter::ConvertToV8String(isolate, "get"), GetGetterFunction(isolate)); weakRef->Set(ArgConverter::ConvertToV8String(isolate, "clear"), GetClearFunction(isolate)); - weakRef->SetHiddenValue(V8StringConstants::GetTarget(isolate), External::New(isolate, poTarget)); + V8SetPrivateValue(isolate, weakRef, V8StringConstants::GetTarget(isolate), External::New(isolate, poTarget)); args.GetReturnValue().Set(weakRef); } @@ -89,7 +90,7 @@ void WeakRef::ConstructorCallbackImpl(const FunctionCallbackInfo& args) } } -void WeakRef::WeakTargetCallback(const WeakCallbackData& data) +void WeakRef::WeakTargetCallback(const WeakCallbackInfo& data) { auto callbackState = data.GetParameter(); auto poTarget = callbackState->target; @@ -102,7 +103,7 @@ void WeakRef::WeakTargetCallback(const WeakCallbackData& if (poHolder != nullptr) { auto holder = Local::New(isolate, *poHolder); - holder->SetHiddenValue(V8StringConstants::GetTarget(isolate), External::New(isolate, nullptr)); + V8SetPrivateValue(isolate, holder, V8StringConstants::GetTarget(isolate), External::New(isolate, nullptr)); } if (callbackState->holder == nullptr) @@ -111,7 +112,7 @@ void WeakRef::WeakTargetCallback(const WeakCallbackData& } } -void WeakRef::WeakHolderCallback(const WeakCallbackData& data) +void WeakRef::WeakHolderCallback(const WeakCallbackInfo& data) { try { @@ -120,11 +121,13 @@ void WeakRef::WeakHolderCallback(const WeakCallbackData& auto isolate = data.GetIsolate(); auto holder = Local::New(isolate, *poHolder); - auto poTarget = reinterpret_cast*>(holder->GetHiddenValue(V8StringConstants::GetTarget(isolate)).As()->Value()); + Local hiddenVal; + V8GetPrivateValue(isolate, holder, V8StringConstants::GetTarget(isolate), hiddenVal); + auto poTarget = reinterpret_cast*>(hiddenVal.As()->Value()); if (poTarget != nullptr) { - poHolder->SetWeak(callbackState, WeakHolderCallback); + poHolder->SetWeak(callbackState, WeakHolderCallback, WeakCallbackType::kFinalizer); } else { @@ -160,7 +163,7 @@ void WeakRef::ClearCallback(const FunctionCallbackInfo& args) auto holder = args.This(); auto isolate = args.GetIsolate(); - holder->SetHiddenValue(V8StringConstants::GetTarget(isolate), External::New(isolate, nullptr)); + V8SetPrivateValue(isolate, holder, V8StringConstants::GetTarget(isolate), External::New(isolate, nullptr)); } catch (NativeScriptException& e) { @@ -183,8 +186,10 @@ void WeakRef::GettertCallback(const FunctionCallbackInfo& args) try { auto holder = args.This(); + Local hiddenVal; auto isolate = args.GetIsolate(); - auto poTarget = reinterpret_cast*>(holder->GetHiddenValue(V8StringConstants::GetTarget(isolate)).As()->Value()); + V8GetPrivateValue(isolate, holder, V8StringConstants::GetTarget(isolate), hiddenVal); + auto poTarget = reinterpret_cast*>(hiddenVal.As()->Value()); if (poTarget != nullptr) { diff --git a/runtime/src/main/jni/WeakRef.h b/runtime/src/main/jni/WeakRef.h index 89ac1e1e8..efff9b3d7 100644 --- a/runtime/src/main/jni/WeakRef.h +++ b/runtime/src/main/jni/WeakRef.h @@ -38,9 +38,9 @@ namespace tns v8::Local GetGetterFunction(v8::Isolate *isolate); - static void WeakTargetCallback(const v8::WeakCallbackData& data); + static void WeakTargetCallback(const v8::WeakCallbackInfo& data); - static void WeakHolderCallback(const v8::WeakCallbackData& data); + static void WeakHolderCallback(const v8::WeakCallbackInfo& data); ObjectManager *m_objectManager; diff --git a/runtime/src/main/jni/com_tns_Runtime.cpp b/runtime/src/main/jni/com_tns_Runtime.cpp index 8417ad70f..d55e65712 100644 --- a/runtime/src/main/jni/com_tns_Runtime.cpp +++ b/runtime/src/main/jni/com_tns_Runtime.cpp @@ -301,7 +301,7 @@ extern "C" void Java_com_tns_Runtime_passUncaughtExceptionToJsNative(JNIEnv *env } } -extern "C" void Java_com_tns_Runtime_ClearStartupData(JNIEnv *env, jobject obj, jint runtimeId) +extern "C" void Java_com_tns_Runtime_clearStartupData(JNIEnv *env, jobject obj, jint runtimeId) { auto runtime = TryGetRuntime(runtimeId); if (runtime == nullptr) @@ -311,3 +311,8 @@ extern "C" void Java_com_tns_Runtime_ClearStartupData(JNIEnv *env, jobject obj, runtime->ClearStartupData(env, obj); } + +extern "C" jint Java_com_tns_Runtime_getPointerSize(JNIEnv *env, jobject obj) +{ + return sizeof(void*); +} diff --git a/runtime/src/main/jni/include/OWNERS b/runtime/src/main/jni/include/OWNERS new file mode 100644 index 000000000..efa3b936d --- /dev/null +++ b/runtime/src/main/jni/include/OWNERS @@ -0,0 +1,2 @@ +danno@chromium.org +jochen@chromium.org diff --git a/runtime/src/main/jni/include/V8NativeScriptExtension.h b/runtime/src/main/jni/include/V8NativeScriptExtension.h index ac0296203..53b721d3e 100644 --- a/runtime/src/main/jni/include/V8NativeScriptExtension.h +++ b/runtime/src/main/jni/include/V8NativeScriptExtension.h @@ -16,9 +16,10 @@ namespace v8 { static int GetInternalFieldCount(const v8::Local& object); - static void Probe(bool cross_compile); + static void CpuFeaturesProbe(bool cross_compile); private: NativeScriptExtension(); + + // static v8::internal::Handle GetEnumPropertyKeys(const v8::internal::Handle& object, bool cache_result); }; } - diff --git a/runtime/src/main/jni/include/libplatform/libplatform.h b/runtime/src/main/jni/include/libplatform/libplatform.h index 3dd06e0c2..f180b4fe8 100644 --- a/runtime/src/main/jni/include/libplatform/libplatform.h +++ b/runtime/src/main/jni/include/libplatform/libplatform.h @@ -5,10 +5,7 @@ #ifndef V8_LIBPLATFORM_LIBPLATFORM_H_ #define V8_LIBPLATFORM_LIBPLATFORM_H_ -#include "include/v8-platform.h" - -#include -unsigned int __page_size = sysconf(_SC_PAGESIZE); +#include "v8-platform.h" // NOLINT(build/include) namespace v8 { namespace platform { diff --git a/runtime/src/main/jni/include/v8-debug.h b/runtime/src/main/jni/include/v8-debug.h index 0b64fb388..e41df29ad 100644 --- a/runtime/src/main/jni/include/v8-debug.h +++ b/runtime/src/main/jni/include/v8-debug.h @@ -18,13 +18,11 @@ enum DebugEvent { Exception = 2, NewFunction = 3, BeforeCompile = 4, - AfterCompile = 5, + AfterCompile = 5, CompileError = 6, - PromiseEvent = 7, - AsyncTaskEvent = 8, + AsyncTaskEvent = 7, }; - class V8_EXPORT Debug { public: /** @@ -155,8 +153,11 @@ class V8_EXPORT Debug { */ typedef void (*DebugMessageDispatchHandler)(); - static bool SetDebugEventListener(EventCallback that, + static bool SetDebugEventListener(Isolate* isolate, EventCallback that, Local data = Local()); + V8_DEPRECATED("Use version with an Isolate", + static bool SetDebugEventListener( + EventCallback that, Local data = Local())); // Schedule a debugger break to happen when JavaScript code is run // in the given isolate. @@ -170,7 +171,9 @@ class V8_EXPORT Debug { static bool CheckDebugBreak(Isolate* isolate); // Message based interface. The message protocol is JSON. - static void SetMessageHandler(MessageHandler handler); + static void SetMessageHandler(Isolate* isolate, MessageHandler handler); + V8_DEPRECATED("Use version with an Isolate", + static void SetMessageHandler(MessageHandler handler)); static void SendCommand(Isolate* isolate, const uint16_t* command, int length, @@ -194,10 +197,9 @@ class V8_EXPORT Debug { * } * \endcode */ - static V8_DEPRECATE_SOON( - "Use maybe version", - Local Call(v8::Local fun, - Local data = Local())); + static V8_DEPRECATED("Use maybe version", + Local Call(v8::Local fun, + Local data = Local())); // TODO(dcarney): data arg should be a MaybeLocal static MaybeLocal Call(Local context, v8::Local fun, @@ -206,8 +208,8 @@ class V8_EXPORT Debug { /** * Returns a mirror object for the given object. */ - static V8_DEPRECATE_SOON("Use maybe version", - Local GetMirror(v8::Local obj)); + static V8_DEPRECATED("Use maybe version", + Local GetMirror(v8::Local obj)); static MaybeLocal GetMirror(Local context, v8::Local obj); @@ -242,7 +244,9 @@ class V8_EXPORT Debug { * "Evaluate" debug command behavior currently is not specified in scope * of this method. */ - static void ProcessDebugMessages(); + static void ProcessDebugMessages(Isolate* isolate); + V8_DEPRECATED("Use version with an Isolate", + static void ProcessDebugMessages()); /** * Debugger is running in its own context which is entered while debugger @@ -251,7 +255,9 @@ class V8_EXPORT Debug { * to change. The Context exists only when the debugger is active, i.e. at * least one DebugEventListener or MessageHandler is set. */ - static Local GetDebugContext(); + static Local GetDebugContext(Isolate* isolate); + V8_DEPRECATED("Use version with an Isolate", + static Local GetDebugContext()); /** @@ -268,6 +274,14 @@ class V8_EXPORT Debug { */ static MaybeLocal GetInternalProperties(Isolate* isolate, Local value); + + /** + * Defines if the ES2015 tail call elimination feature is enabled or not. + * The change of this flag triggers deoptimization of all functions that + * contain calls at tail position. + */ + static bool IsTailCallEliminationEnabled(Isolate* isolate); + static void SetTailCallEliminationEnabled(Isolate* isolate, bool enabled); }; diff --git a/runtime/src/main/jni/include/v8-experimental.h b/runtime/src/main/jni/include/v8-experimental.h new file mode 100644 index 000000000..294ba647f --- /dev/null +++ b/runtime/src/main/jni/include/v8-experimental.h @@ -0,0 +1,54 @@ +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * This header contains a set of experimental V8 APIs. We hope these will + * become a part of standard V8, but they may also be removed if we deem the + * experiment to not be successul. + */ +#ifndef V8_INCLUDE_V8_EXPERIMENTAL_H_ +#define V8_INCLUDE_V8_EXPERIMENTAL_H_ + +#include "v8.h" // NOLINT(build/include) + +namespace v8 { +namespace experimental { + +// Allow the embedder to construct accessors that V8 can compile and use +// directly, without jumping into the runtime. +class V8_EXPORT FastAccessorBuilder { + public: + struct ValueId { + size_t value_id; + }; + struct LabelId { + size_t label_id; + }; + + static FastAccessorBuilder* New(Isolate* isolate); + + ValueId IntegerConstant(int int_constant); + ValueId GetReceiver(); + ValueId LoadInternalField(ValueId value_id, int field_no); + ValueId LoadValue(ValueId value_id, int offset); + ValueId LoadObject(ValueId value_id, int offset); + void ReturnValue(ValueId value_id); + void CheckFlagSetOrReturnNull(ValueId value_id, int mask); + void CheckNotZeroOrReturnNull(ValueId value_id); + LabelId MakeLabel(); + void SetLabel(LabelId label_id); + void CheckNotZeroOrJump(ValueId value_id, LabelId label_id); + ValueId Call(v8::FunctionCallback callback, ValueId value_id); + + private: + FastAccessorBuilder() = delete; + FastAccessorBuilder(const FastAccessorBuilder&) = delete; + ~FastAccessorBuilder() = delete; + void operator=(const FastAccessorBuilder&) = delete; +}; + +} // namespace experimental +} // namespace v8 + +#endif // V8_INCLUDE_V8_EXPERIMENTAL_H_ diff --git a/runtime/src/main/jni/include/v8-platform.h b/runtime/src/main/jni/include/v8-platform.h index c6cba0f98..4023a5b23 100644 --- a/runtime/src/main/jni/include/v8-platform.h +++ b/runtime/src/main/jni/include/v8-platform.h @@ -5,6 +5,9 @@ #ifndef V8_V8_PLATFORM_H_ #define V8_V8_PLATFORM_H_ +#include +#include + namespace v8 { class Isolate; @@ -53,6 +56,15 @@ class Platform { virtual ~Platform() {} + /** + * Gets the number of threads that are used to execute background tasks. Is + * used to estimate the number of tasks a work package should be split into. + * A return value of 0 means that there are no background threads available. + * Note that a value of 0 won't prohibit V8 from posting tasks using + * |CallOnBackgroundThread|. + */ + virtual size_t NumberOfAvailableBackgroundThreads() { return 0; } + /** * Schedules a task to be invoked on a background thread. |expected_runtime| * indicates that the task will run a long time. The Platform implementation @@ -107,6 +119,51 @@ class Platform { * the epoch. **/ virtual double MonotonicallyIncreasingTime() = 0; + + /** + * Called by TRACE_EVENT* macros, don't call this directly. + * The name parameter is a category group for example: + * TRACE_EVENT0("v8,parse", "V8.Parse") + * The pointer returned points to a value with zero or more of the bits + * defined in CategoryGroupEnabledFlags. + **/ + virtual const uint8_t* GetCategoryGroupEnabled(const char* name) { + static uint8_t no = 0; + return &no; + } + + /** + * Gets the category group name of the given category_enabled_flag pointer. + * Usually used while serliazing TRACE_EVENTs. + **/ + virtual const char* GetCategoryGroupName( + const uint8_t* category_enabled_flag) { + static const char dummy[] = "dummy"; + return dummy; + } + + /** + * Adds a trace event to the platform tracing system. This function call is + * usually the result of a TRACE_* macro from trace_event_common.h when + * tracing and the category of the particular trace are enabled. It is not + * advisable to call this function on its own; it is really only meant to be + * used by the trace macros. The returned handle can be used by + * UpdateTraceEventDuration to update the duration of COMPLETE events. + */ + virtual uint64_t AddTraceEvent( + char phase, const uint8_t* category_enabled_flag, const char* name, + const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args, + const char** arg_names, const uint8_t* arg_types, + const uint64_t* arg_values, unsigned int flags) { + return 0; + } + + /** + * Sets the duration field of a COMPLETE trace event. It must be called with + * the handle returned from AddTraceEvent(). + **/ + virtual void UpdateTraceEventDuration(const uint8_t* category_enabled_flag, + const char* name, uint64_t handle) {} }; } // namespace v8 diff --git a/runtime/src/main/jni/include/v8-profiler.h b/runtime/src/main/jni/include/v8-profiler.h index e43260029..535e8212d 100644 --- a/runtime/src/main/jni/include/v8-profiler.h +++ b/runtime/src/main/jni/include/v8-profiler.h @@ -206,6 +206,13 @@ class V8_EXPORT CpuProfiler { */ CpuProfile* StopProfiling(Local title); + /** + * Force collection of a sample. Must be called on the VM thread. + * Recording the forced sample does not contribute to the aggregated + * profile statistics. + */ + void CollectSample(); + /** * Tells the profiler whether the embedder is idle. */ @@ -418,12 +425,101 @@ class V8_EXPORT ActivityControl { // NOLINT }; +/** + * AllocationProfile is a sampled profile of allocations done by the program. + * This is structured as a call-graph. + */ +class V8_EXPORT AllocationProfile { + public: + struct Allocation { + /** + * Size of the sampled allocation object. + */ + size_t size; + + /** + * The number of objects of such size that were sampled. + */ + unsigned int count; + }; + + /** + * Represents a node in the call-graph. + */ + struct Node { + /** + * Name of the function. May be empty for anonymous functions or if the + * script corresponding to this function has been unloaded. + */ + Local name; + + /** + * Name of the script containing the function. May be empty if the script + * name is not available, or if the script has been unloaded. + */ + Local script_name; + + /** + * id of the script where the function is located. May be equal to + * v8::UnboundScript::kNoScriptId in cases where the script doesn't exist. + */ + int script_id; + + /** + * Start position of the function in the script. + */ + int start_position; + + /** + * 1-indexed line number where the function starts. May be + * kNoLineNumberInfo if no line number information is available. + */ + int line_number; + + /** + * 1-indexed column number where the function starts. May be + * kNoColumnNumberInfo if no line number information is available. + */ + int column_number; + + /** + * List of callees called from this node for which we have sampled + * allocations. The lifetime of the children is scoped to the containing + * AllocationProfile. + */ + std::vector children; + + /** + * List of self allocations done by this node in the call-graph. + */ + std::vector allocations; + }; + + /** + * Returns the root node of the call-graph. The root node corresponds to an + * empty JS call-stack. The lifetime of the returned Node* is scoped to the + * containing AllocationProfile. + */ + virtual Node* GetRootNode() = 0; + + virtual ~AllocationProfile() {} + + static const int kNoLineNumberInfo = Message::kNoLineNumberInfo; + static const int kNoColumnNumberInfo = Message::kNoColumnInfo; +}; + + /** * Interface for controlling heap profiling. Instance of the * profiler can be retrieved using v8::Isolate::GetHeapProfiler. */ class V8_EXPORT HeapProfiler { public: + enum SamplingFlags { + kSamplingNoFlags = 0, + kSamplingForceGC = 1 << 0, + }; + /** * Callback function invoked for obtaining RetainedObjectInfo for * the given JavaScript wrapper object. It is prohibited to enter V8 @@ -521,6 +617,50 @@ class V8_EXPORT HeapProfiler { */ void StopTrackingHeapObjects(); + /** + * Starts gathering a sampling heap profile. A sampling heap profile is + * similar to tcmalloc's heap profiler and Go's mprof. It samples object + * allocations and builds an online 'sampling' heap profile. At any point in + * time, this profile is expected to be a representative sample of objects + * currently live in the system. Each sampled allocation includes the stack + * trace at the time of allocation, which makes this really useful for memory + * leak detection. + * + * This mechanism is intended to be cheap enough that it can be used in + * production with minimal performance overhead. + * + * Allocations are sampled using a randomized Poisson process. On average, one + * allocation will be sampled every |sample_interval| bytes allocated. The + * |stack_depth| parameter controls the maximum number of stack frames to be + * captured on each allocation. + * + * NOTE: This is a proof-of-concept at this point. Right now we only sample + * newspace allocations. Support for paged space allocation (e.g. pre-tenured + * objects, large objects, code objects, etc.) and native allocations + * doesn't exist yet, but is anticipated in the future. + * + * Objects allocated before the sampling is started will not be included in + * the profile. + * + * Returns false if a sampling heap profiler is already running. + */ + bool StartSamplingHeapProfiler(uint64_t sample_interval = 512 * 1024, + int stack_depth = 16, + SamplingFlags flags = kSamplingNoFlags); + + /** + * Stops the sampling heap profile and discards the current profile. + */ + void StopSamplingHeapProfiler(); + + /** + * Returns the sampled profile of allocations allocated (and still live) since + * StartSamplingHeapProfiler was called. The ownership of the pointer is + * transfered to the caller. Returns nullptr if sampling heap profiler is not + * active. + */ + AllocationProfile* GetAllocationProfile(); + /** * Deletes all snapshots taken. All previously returned pointers to * snapshots and their contents become invalid after this call. diff --git a/runtime/src/main/jni/include/v8-testing.h b/runtime/src/main/jni/include/v8-testing.h index d18fc7258..f67bf2530 100644 --- a/runtime/src/main/jni/include/v8-testing.h +++ b/runtime/src/main/jni/include/v8-testing.h @@ -39,7 +39,7 @@ class V8_EXPORT Testing { /** * Force deoptimization of all functions. */ - static void DeoptimizeAll(); + static void DeoptimizeAll(Isolate* isolate); }; diff --git a/runtime/src/main/jni/include/v8-util.h b/runtime/src/main/jni/include/v8-util.h index 73ec658f7..8133fdd49 100644 --- a/runtime/src/main/jni/include/v8-util.h +++ b/runtime/src/main/jni/include/v8-util.h @@ -95,12 +95,12 @@ class DefaultPersistentValueMapTraits : public StdMapTraits { MapType* map, const K& key, Local value) { return NULL; } - static MapType* MapFromWeakCallbackData( - const WeakCallbackData& data) { + static MapType* MapFromWeakCallbackInfo( + const WeakCallbackInfo& data) { return NULL; } - static K KeyFromWeakCallbackData( - const WeakCallbackData& data) { + static K KeyFromWeakCallbackInfo( + const WeakCallbackInfo& data) { return K(); } static void DisposeCallbackData(WeakCallbackDataType* data) { } @@ -205,6 +205,17 @@ class PersistentValueMapBase { reinterpret_cast(FromVal(Traits::Get(&impl_, key)))); } + /** + * Call V8::RegisterExternallyReferencedObject with the map value for given + * key. + */ + void RegisterExternallyReferencedObject(K& key) { + DCHECK(Contains(key)); + V8::RegisterExternallyReferencedObject( + reinterpret_cast(FromVal(Traits::Get(&impl_, key))), + reinterpret_cast(GetIsolate())); + } + /** * Return value for key and remove it from the map. */ @@ -402,11 +413,11 @@ class PersistentValueMap : public PersistentValueMapBase { private: static void WeakCallback( - const WeakCallbackData& data) { + const WeakCallbackInfo& data) { if (Traits::kCallbackType != kNotWeak) { PersistentValueMap* persistentValueMap = - Traits::MapFromWeakCallbackData(data); - K key = Traits::KeyFromWeakCallbackData(data); + Traits::MapFromWeakCallbackInfo(data); + K key = Traits::KeyFromWeakCallbackInfo(data); Traits::Dispose(data.GetIsolate(), persistentValueMap->Remove(key).Pass(), key); Traits::DisposeCallbackData(data.GetParameter()); diff --git a/runtime/src/main/jni/include/v8-version.h b/runtime/src/main/jni/include/v8-version.h index 1cc779b33..fe3e61d2e 100644 --- a/runtime/src/main/jni/include/v8-version.h +++ b/runtime/src/main/jni/include/v8-version.h @@ -8,9 +8,9 @@ // These macros define the version number for the current version. // NOTE these macros are used by some of the tool scripts and the build // system so their names cannot be changed without changing the scripts. -#define V8_MAJOR_VERSION 4 -#define V8_MINOR_VERSION 7 -#define V8_BUILD_NUMBER 80 +#define V8_MAJOR_VERSION 5 +#define V8_MINOR_VERSION 2 +#define V8_BUILD_NUMBER 361 #define V8_PATCH_LEVEL 0 // Use 1 for candidates and 0 otherwise. diff --git a/runtime/src/main/jni/include/v8.h b/runtime/src/main/jni/include/v8.h index 395354341..3079958d5 100644 --- a/runtime/src/main/jni/include/v8.h +++ b/runtime/src/main/jni/include/v8.h @@ -12,12 +12,14 @@ * For other documentation see http://code.google.com/apis/v8/ */ -#ifndef V8_H_ -#define V8_H_ +#ifndef INCLUDE_V8_H_ +#define INCLUDE_V8_H_ #include #include #include +#include +#include #include "v8-version.h" // NOLINT(build/include) #include "v8config.h" // NOLINT(build/include) @@ -92,6 +94,7 @@ class ObjectTemplate; class Platform; class Primitive; class Promise; +class Proxy; class RawOperationDescriptor; class Script; class SharedArrayBuffer; @@ -103,6 +106,7 @@ class String; class StringObject; class Symbol; class SymbolObject; +class Private; class Uint32; class Utils; class Value; @@ -135,6 +139,10 @@ class CallHandlerHelper; class EscapableHandleScope; template class ReturnValue; +namespace experimental { +class FastAccessorBuilder; +} // namespace experimental + namespace internal { class Arguments; class Heap; @@ -146,7 +154,7 @@ template class CustomArguments; class PropertyCallbackArguments; class FunctionCallbackArguments; class GlobalHandles; -} +} // namespace internal /** @@ -311,6 +319,7 @@ class Local { friend class String; friend class Object; friend class Context; + friend class Private; template friend class internal::CustomArguments; friend Local Undefined(Isolate* isolate); friend Local Null(Isolate* isolate); @@ -321,10 +330,10 @@ class Local { template friend class PersistentValueMapBase; template friend class PersistentValueVector; + template + friend class ReturnValue; - template - V8_INLINE Local(S* that) - : val_(that) {} + explicit V8_INLINE Local(T* that) : val_(that) {} V8_INLINE static Local New(Isolate* isolate, T* that); T* val_; }; @@ -418,16 +427,19 @@ class WeakCallbackInfo { V8_INLINE T* GetParameter() const { return parameter_; } V8_INLINE void* GetInternalField(int index) const; - V8_INLINE V8_DEPRECATE_SOON("use indexed version", - void* GetInternalField1() const) { + V8_INLINE V8_DEPRECATED("use indexed version", + void* GetInternalField1() const) { return internal_fields_[0]; } - V8_INLINE V8_DEPRECATE_SOON("use indexed version", - void* GetInternalField2() const) { + V8_INLINE V8_DEPRECATED("use indexed version", + void* GetInternalField2() const) { return internal_fields_[1]; } - bool IsFirstPass() const { return callback_ != nullptr; } + V8_DEPRECATED("Not realiable once SetSecondPassCallback() was used.", + bool IsFirstPass() const) { + return callback_ != nullptr; + } // When first called, the embedder MUST Reset() the Global which triggered the // callback. The Global itself is unusable for anything else. No v8 other api @@ -445,32 +457,12 @@ class WeakCallbackInfo { }; -template -class WeakCallbackData { - public: - typedef void (*Callback)(const WeakCallbackData& data); - - WeakCallbackData(Isolate* isolate, P* parameter, Local handle) - : isolate_(isolate), parameter_(parameter), handle_(handle) {} - - V8_INLINE Isolate* GetIsolate() const { return isolate_; } - V8_INLINE P* GetParameter() const { return parameter_; } - V8_INLINE Local GetValue() const { return handle_; } - - private: - Isolate* isolate_; - P* parameter_; - Local handle_; -}; - - -// TODO(dcarney): delete this with WeakCallbackData -template -using PhantomCallbackData = WeakCallbackInfo; - - -enum class WeakCallbackType { kParameter, kInternalFields }; - +// kParameter will pass a void* parameter back to the callback, kInternalFields +// will pass the first two internal fields back to the callback, kFinalizer +// will pass a void* parameter back, but is invoked before the object is +// actually collected, so it can be resurrected. In the last case, it is not +// possible to request a second pass callback. +enum class WeakCallbackType { kParameter, kInternalFields, kFinalizer }; /** * An object reference that is independent of any handle scope. Where @@ -549,42 +541,32 @@ template class PersistentBase { * critical form of resource management! */ template - V8_INLINE V8_DEPRECATE_SOON( - "use WeakCallbackInfo version", - void SetWeak(P* parameter, - typename WeakCallbackData::Callback callback)); - - template - V8_INLINE V8_DEPRECATE_SOON( - "use WeakCallbackInfo version", - void SetWeak(P* parameter, - typename WeakCallbackData::Callback callback)); - - // Phantom persistents work like weak persistents, except that the pointer to - // the object being collected is not available in the finalization callback. - // This enables the garbage collector to collect the object and any objects - // it references transitively in one GC cycle. At the moment you can either - // specify a parameter for the callback or the location of two internal - // fields in the dying object. - template - V8_INLINE V8_DEPRECATE_SOON( - "use SetWeak", - void SetPhantom(P* parameter, - typename WeakCallbackInfo

::Callback callback, - int internal_field_index1 = -1, - int internal_field_index2 = -1)); - - template V8_INLINE void SetWeak(P* parameter, typename WeakCallbackInfo

::Callback callback, WeakCallbackType type); + /** + * Turns this handle into a weak phantom handle without finalization callback. + * The handle will be reset automatically when the garbage collector detects + * that the object is no longer reachable. + * A related function Isolate::NumberOfPhantomHandleResetsSinceLastCall + * returns how many phantom handles were reset by the garbage collector. + */ + V8_INLINE void SetWeak(); + template V8_INLINE P* ClearWeak(); // TODO(dcarney): remove this. V8_INLINE void ClearWeak() { ClearWeak(); } + /** + * Allows the embedder to tell the v8 garbage collector that a certain object + * is alive. Only allowed when the embedder is asked to trace its heap by + * EmbedderHeapTracer. + */ + V8_INLINE void RegisterExternalReference(Isolate* isolate) const; + /** * Marks the reference to this object independent. Garbage collector is free * to ignore any object groups containing this object. Weak callback for an @@ -601,7 +583,16 @@ template class PersistentBase { * external dependencies. This mark is automatically cleared after each * garbage collection. */ - V8_INLINE void MarkPartiallyDependent(); + V8_INLINE V8_DEPRECATED( + "deprecated optimization, do not use partially dependent groups", + void MarkPartiallyDependent()); + + /** + * Marks the reference to this object as active. The scavenge garbage + * collection should not reclaim the objects marked as active. + * This bit is cleared after the each garbage collection pass. + */ + V8_INLINE void MarkActive(); V8_INLINE bool IsIndependent() const; @@ -773,7 +764,7 @@ template class Persistent : public PersistentBase { template friend class Persistent; template friend class ReturnValue; - template V8_INLINE Persistent(S* that) : PersistentBase(that) { } + explicit V8_INLINE Persistent(T* that) : PersistentBase(that) {} V8_INLINE T* operator*() const { return this->val_; } template V8_INLINE void Copy(const Persistent& that); @@ -872,7 +863,7 @@ using UniquePersistent = Global; */ class V8_EXPORT HandleScope { public: - HandleScope(Isolate* isolate); + explicit HandleScope(Isolate* isolate); ~HandleScope(); @@ -925,7 +916,7 @@ class V8_EXPORT HandleScope { */ class V8_EXPORT EscapableHandleScope : public HandleScope { public: - EscapableHandleScope(Isolate* isolate); + explicit EscapableHandleScope(Isolate* isolate); V8_INLINE ~EscapableHandleScope() {} /** @@ -966,8 +957,8 @@ class V8_EXPORT SealHandleScope { void operator delete(void*, size_t); internal::Isolate* isolate_; - int prev_level_; internal::Object** prev_limit_; + int prev_sealed_level_; }; @@ -1304,10 +1295,10 @@ class V8_EXPORT ScriptCompiler { * \return Compiled script object (context independent; for running it must be * bound to a context). */ - static V8_DEPRECATE_SOON("Use maybe version", - Local CompileUnbound( - Isolate* isolate, Source* source, - CompileOptions options = kNoCompileOptions)); + static V8_DEPRECATED("Use maybe version", + Local CompileUnbound( + Isolate* isolate, Source* source, + CompileOptions options = kNoCompileOptions)); static V8_WARN_UNUSED_RESULT MaybeLocal CompileUnboundScript( Isolate* isolate, Source* source, CompileOptions options = kNoCompileOptions); @@ -1323,7 +1314,7 @@ class V8_EXPORT ScriptCompiler { * when this function was called. When run it will always use this * context. */ - static V8_DEPRECATE_SOON( + static V8_DEPRECATED( "Use maybe version", Local