From 94eeaae7a33d2954184b222c7f527a1e384be097 Mon Sep 17 00:00:00 2001 From: luomy Date: Tue, 4 Apr 2023 15:26:49 +0800 Subject: [PATCH] feat(ios): support v8 for ios --- .gitignore | 1 + framework/examples/ios-demo/podfile | 1 + .../enginewrapper/v8/HippyV8ContextWrapper.mm | 34 ++++---- framework/ios/utils/v8/NSObject+V8Value.h | 9 +- framework/ios/utils/v8/NSObject+V8Value.mm | 25 +++--- hippy.podspec | 84 +++++++++++++++++-- xcodeinitscript.sh | 31 +++++++ 7 files changed, 147 insertions(+), 38 deletions(-) diff --git a/.gitignore b/.gitignore index af953bbe8e1..abc87ef24bf 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ coverage dist node_modules xcuserdata +v8forios *.log *.iml diff --git a/framework/examples/ios-demo/podfile b/framework/examples/ios-demo/podfile index 8d6b81dda9e..9fcf344c618 100644 --- a/framework/examples/ios-demo/podfile +++ b/framework/examples/ios-demo/podfile @@ -1,4 +1,5 @@ ENV["layout_engine"]="Taitank" +# ENV["js_engine"] = "v8" install! 'cocoapods', :deterministic_uuids => false, :generate_multiple_pod_projects => true diff --git a/framework/ios/base/enginewrapper/v8/HippyV8ContextWrapper.mm b/framework/ios/base/enginewrapper/v8/HippyV8ContextWrapper.mm index c46a1010c94..871cbad03ec 100644 --- a/framework/ios/base/enginewrapper/v8/HippyV8ContextWrapper.mm +++ b/framework/ios/base/enginewrapper/v8/HippyV8ContextWrapper.mm @@ -20,15 +20,17 @@ * limitations under the License. */ -#import "HippyAssert.h" +#import "HPAsserts.h" +#import "HPLog.h" +#import "HPDriverStackFrame.h" #import "HippyV8ContextWrapper.h" -#import "HippyJSStackFrame.h" -#import "NativeRenderLog.h" #import "NSObject+CtxValue.h" #import "NSObject+V8Value.h" #include -#include "driver/napi/v8/js_native_api_v8.h" + +#include "driver/napi/v8/v8_ctx_value.h" +#include "driver/napi/v8/v8_ctx.h" static id StringJSONToObject(NSString *string) { @autoreleasepool { @@ -38,19 +40,19 @@ static id StringJSONToObject(NSString *string) { } } -static v8::Local V8ValueFromCtxValue(const std::shared_ptr &value) { +static v8::Local V8ValueFromCtxValue(const std::shared_ptr &value, v8::Local context) { auto ctxValue = std::static_pointer_cast(value); - v8::Local v8Value = ctxValue->global_value_.Get(ctxValue->isolate_); + v8::Local v8Value = ctxValue->global_value_.Get(context->GetIsolate()); return v8Value; } static v8::Local V8ObjectFromCtxValue(const std::shared_ptr &value, v8::Local context) { auto ctxValue = std::static_pointer_cast(value); - v8::Local v8Value = ctxValue->global_value_.Get(ctxValue->isolate_); - HippyAssert(v8Value->IsObject(), @"value is not a object"); + v8::Local v8Value = ctxValue->global_value_.Get(context->GetIsolate()); + HPAssert(v8Value->IsObject(), @"value is not a object"); v8::MaybeLocal maybeObject = v8Value->ToObject(context); - HippyAssert(!maybeObject.IsEmpty(), @"maybe object is not a object"); + HPAssert(!maybeObject.IsEmpty(), @"maybe object is not a object"); return maybeObject.ToLocalChecked(); } @@ -104,7 +106,7 @@ static void HandleUncaughtJsError(v8::Local message, v8::LocalGetIsolate(); NSString *errorMessage = v8StringToNSString(isolate, message->Get()); int frameCount = stack->GetFrameCount(); - NSMutableArray *stacks = [NSMutableArray arrayWithCapacity:frameCount]; + NSMutableArray *stacks = [NSMutableArray arrayWithCapacity:frameCount]; for (int i = 0; i < frameCount; i++) { v8::Local frame = stack->GetFrame(isolate, i); v8::Local functionName = frame->GetFunctionName(); @@ -114,7 +116,10 @@ static void HandleUncaughtJsError(v8::Local message, v8::Local scrName = frame->GetScriptNameOrSourceURL(); NSString *scriptName = v8StringToNSString(isolate, scrName); - HippyJSStackFrame *stackFrame = [[HippyJSStackFrame alloc] initWithMethodName:funcName file:scriptName lineNumber:frame->GetLineNumber() column:frame->GetColumn()]; + HPDriverStackFrame *stackFrame = [[HPDriverStackFrame alloc] initWithMethodName:funcName + file:scriptName + lineNumber:frame->GetLineNumber() + column:frame->GetColumn()]; [stacks addObject:stackFrame]; } excpetionHandler(wrapper, errorMessage, [stacks copy]); @@ -325,7 +330,8 @@ - (BOOL)setProperties:(NSDictionary *)properties toGlobalObject:(NSString *)obje v8::Local keyString = [key toV8StringInIsolate:isolate]; v8::Local localValue = [object toV8ValueInIsolate:isolate context:localContext]; if (!targetObject->Set(localContext, keyString, localValue).FromMaybe(false)) { - NativeRenderLogWarn(@"createGlobalObject withDictionary failed, key:%@, value:%@", key, object); +// NativeRenderLogWarn(@"createGlobalObject withDictionary failed, key:%@, value:%@", key, object); + } if (tryCache.HasCaught()) { _exception = TryToFetchStringFromV8Value(tryCache.Exception(), isolate); @@ -352,7 +358,7 @@ - (BOOL)setProperty:(NSString *)propertyName v8::Context::Scope contextScope(localContext); v8::Local v8Name = [propertyName toV8StringInIsolate:isolate]; v8::Local targetObject = V8ObjectFromCtxValue(object, localContext); - v8::Local targetValue = V8ValueFromCtxValue(value); + v8::Local targetValue = V8ValueFromCtxValue(value, localContext); v8::TryCatch tryCache(isolate); BOOL ret = targetObject->Set(localContext, v8Name, targetValue).FromMaybe(false); if (tryCache.HasCaught()) { @@ -379,7 +385,7 @@ - (BOOL)setProperty:(NSString *)propertyName v8::Local v8Name = [propertyName toV8StringInIsolate:isolate]; v8::MaybeLocal maybeValue = targetObject->Get(localContext, v8Name); if (maybeValue.IsEmpty()) { - NativeRenderLogWarn(@"get property %@ for object failed", propertyName); + HPLog(@"get property %@ for object failed", propertyName); return nullptr; } v8::Local value = maybeValue.ToLocalChecked(); diff --git a/framework/ios/utils/v8/NSObject+V8Value.h b/framework/ios/utils/v8/NSObject+V8Value.h index fff37b1aa92..0a03330d308 100644 --- a/framework/ios/utils/v8/NSObject+V8Value.h +++ b/framework/ios/utils/v8/NSObject+V8Value.h @@ -21,8 +21,9 @@ */ #import -#include "driver/napi/v8/js_native_api_v8.h" -#import "HippyDefines.h" +#import "MacroDefines.h" + +#include "v8/v8.h" NS_ASSUME_NONNULL_BEGIN @@ -69,8 +70,8 @@ NS_ASSUME_NONNULL_BEGIN @end -HIPPY_EXTERN id ObjectFromV8Value(v8::Local value, v8::Isolate *isolate, v8::Local context); +HP_EXTERN id ObjectFromV8Value(v8::Local value, v8::Isolate *isolate, v8::Local context); -HIPPY_EXTERN NSString *TryToFetchStringFromV8Value(v8::Local value, v8::Isolate *isolate); +HP_EXTERN NSString *TryToFetchStringFromV8Value(v8::Local value, v8::Isolate *isolate); NS_ASSUME_NONNULL_END diff --git a/framework/ios/utils/v8/NSObject+V8Value.mm b/framework/ios/utils/v8/NSObject+V8Value.mm index 38a0e517caf..fe37133afd2 100644 --- a/framework/ios/utils/v8/NSObject+V8Value.mm +++ b/framework/ios/utils/v8/NSObject+V8Value.mm @@ -21,19 +21,19 @@ */ #import "NSObject+V8Value.h" -#import "HippyAssert.h" +#import "HPAsserts.h" @implementation NSObject (V8Value) - (v8::Local)toV8ValueInIsolate:(v8::Isolate *)isolate context:(v8::Local)context { - HippyAssert(isolate, @"ios must not be null for object convert"); + HPAssert(isolate, @"ios must not be null for object convert"); #ifdef DEBUG BOOL isRightType = [self isKindOfClass:[NSArray class]] || [self isKindOfClass:[NSDictionary class]] || [self isKindOfClass:[NSData class]] || [self isKindOfClass:[NSString class]] || [self isKindOfClass:[NSNumber class]]; - HippyAssert(isRightType, @"toV8ValueInIsolate is not supported by %@ class", NSStringFromClass([self class])); + HPAssert(isRightType, @"toV8ValueInIsolate is not supported by %@ class", NSStringFromClass([self class])); #endif v8::Local object = v8::Object::New(isolate); return object; @@ -44,7 +44,7 @@ @implementation NSObject (V8Value) @implementation NSArray (V8Value) - (v8::Local)toV8ValueInIsolate:(v8::Isolate *)isolate context:(v8::Local)context { - HippyAssert(isolate, @"ios must not be null for array convert"); + HPAssert(isolate, @"ios must not be null for array convert"); size_t count = [self count]; v8::Local elements[count]; for (size_t i = 0; i < count; i++) { @@ -59,7 +59,7 @@ @implementation NSArray (V8Value) @implementation NSDictionary (V8Value) - (v8::Local)toV8ValueInIsolate:(v8::Isolate *)isolate context:(v8::Local)context { - HippyAssert(isolate, @"ios must not be null for dictionary convert"); + HPAssert(isolate, @"ios must not be null for dictionary convert"); v8::Local object = v8::Object::New(isolate); for (id key in self) { id value = [self objectForKey:key]; @@ -81,7 +81,7 @@ static void ArrayBufferDataDeleter(void* data, size_t length, void* deleter_data #endif //V8_MAJOR_VERSION >= 9 - (v8::Local)toV8ValueInIsolate:(v8::Isolate *)isolate context:(v8::Local)context { - HippyAssert(isolate, @"ios must not be null for data convert"); + HPAssert(isolate, @"ios must not be null for data convert"); size_t length = [self length]; void *buffer = malloc(length); if (!buffer) { @@ -106,7 +106,7 @@ @implementation NSString (V8Value) } - (v8::Local)toV8StringInIsolate:(v8::Isolate *)isolate { - HippyAssert(isolate, @"ios must not be null for string convert"); + HPAssert(isolate, @"ios must not be null for string convert"); const char *p = [self UTF8String]?:""; v8::MaybeLocal string = v8::String::NewFromUtf8(isolate, p); return string.ToLocalChecked(); @@ -117,7 +117,7 @@ @implementation NSString (V8Value) @implementation NSNumber (V8Value) - (v8::Local)toV8ValueInIsolate:(v8::Isolate *)isolate context:(v8::Local)context { - HippyAssert(isolate, @"ios must not be null for number convert"); + HPAssert(isolate, @"ios must not be null for number convert"); v8::Local number = v8::Number::New(isolate, [self doubleValue]); return number; } @@ -132,6 +132,7 @@ @implementation NSNull (V8Value) @end +id ObjectFromV8Value(v8::Local value, v8::Isolate *isolate, v8::Local context); static id ObjectFromV8MaybeValue(v8::MaybeLocal maybeValue, v8::Isolate *isolate, v8::Local context) { if (maybeValue.IsEmpty()) { return nil; @@ -147,7 +148,7 @@ id ObjectFromV8Value(v8::Local value, v8::Isolate *isolate, v8::Local return nil; } else if (value->IsString()) { - HippyAssert(isolate, @"isolate must not be null for string value"); + HPAssert(isolate, @"isolate must not be null for string value"); v8::Local string = value.As(); int len = string->Length(); if (string->IsOneByte()) { @@ -164,7 +165,7 @@ id ObjectFromV8Value(v8::Local value, v8::Isolate *isolate, v8::Local } } else if (value->IsStringObject()) { - HippyAssert(isolate, @"isolate must not be null for string value"); + HPAssert(isolate, @"isolate must not be null for string value"); v8::Local stringObj = value.As(); return ObjectFromV8Value(stringObj->ValueOf(), isolate, context); } @@ -237,7 +238,7 @@ id ObjectFromV8Value(v8::Local value, v8::Isolate *isolate, v8::Local NSMutableDictionary *keysValues = [NSMutableDictionary dictionaryWithCapacity:length]; for (uint32_t i = 0; i < length; i++) { v8::Local key = props->Get(context, i).ToLocalChecked(); - HippyAssert(key->IsString(), @"ObjectFromV8Value only supports keys as string"); + HPAssert(key->IsString(), @"ObjectFromV8Value only supports keys as string"); if (!key->IsString()) { continue; } @@ -252,7 +253,7 @@ id ObjectFromV8Value(v8::Local value, v8::Isolate *isolate, v8::Local else { #ifdef DEBUG - HippyAssert(NO, @"no implementation ObjectFromV8Value for type %@", ObjectFromV8Value(value->TypeOf(isolate), isolate, context)); + HPAssert(NO, @"no implementation ObjectFromV8Value for type %@", ObjectFromV8Value(value->TypeOf(isolate), isolate, context)); #endif return nil; } diff --git a/hippy.podspec b/hippy.podspec index b9ed25af009..e84385191e8 100644 --- a/hippy.podspec +++ b/hippy.podspec @@ -7,7 +7,9 @@ # layout_engine = "Taitank" +js_engine = "jsc" use_frameworks = false; + Pod::Spec.new do |s| if ENV["layout_engine"] layout_engine = ENV["layout_engine"] @@ -15,6 +17,10 @@ Pod::Spec.new do |s| if ENV["use_frameworks"] use_frameworks = true end + if ENV["js_engine"] + js_engine = ENV["js_engine"] + end + puts "layout engine is #{layout_engine}, js engine is #{js_engine}" puts "use_frameworks trigger is #{use_frameworks}" if use_frameworks framework_header_path = '${PODS_CONFIGURATION_BUILD_DIR}/hippy/hippy.framework/Headers' @@ -43,14 +49,20 @@ Pod::Spec.new do |s| #prepare_command not working for subspecs,so we remove devtools script from devtools subspec to root s.prepare_command = <<-CMD - ./xcodeinitscript.sh "#{layout_engine}" + ./xcodeinitscript.sh "#{layout_engine}" "#{js_engine}" CMD s.subspec 'Framework' do |framework| puts 'hippy subspec \'framework\' read begin' framework.source_files = 'framework/ios/**/*.{h,m,c,mm,s,cpp,cc}' framework.public_header_files = 'framework/ios/**/*.h' - framework.exclude_files = ['framework/ios/base/enginewrapper/v8', 'framework/ios/utils/v8'] + if js_engine == "jsc" + framework.exclude_files = ['framework/ios/base/enginewrapper/v8', 'framework/ios/utils/v8'] + elsif js_engine == "v8" + framework.exclude_files = ['framework/ios/base/enginewrapper/jsc', 'framework/ios/utils/jsc'] + else + framework.exclude_files = ['framework/ios/base/enginewrapper/jsc', 'framework/ios/utils/jsc', 'framework/ios/base/enginewrapper/v8', 'framework/ios/utils/v8'] + end framework.libraries = 'c++' framework.pod_target_xcconfig = { 'CLANG_CXX_LANGUAGE_STANDARD' => 'c++17', @@ -162,16 +174,50 @@ Pod::Spec.new do |s| driver.frameworks = 'JavaScriptCore' driver.source_files = ['driver/js/include/**/*.h', 'driver/js/src/**/*.cc'] driver.public_header_files = 'driver/js/include/**/*.h' - driver.exclude_files = ['driver/js/include/driver/napi/v8','driver/js/src/napi/v8','driver/js/include/driver/runtime','driver/js/src/runtime', 'driver/js/include/vm/v8', 'driver/js/src/vm/v8'] + if js_engine == "jsc" + driver.exclude_files = [ + 'driver/js/include/driver/napi/v8', + 'driver/js/src/napi/v8', + 'driver/js/include/driver/runtime', + 'driver/js/src/runtime', + 'driver/js/include/driver/vm/v8', + 'driver/js/src/vm/v8'] + elsif js_engine == "v8" + driver.exclude_files = [ + 'driver/js/include/driver/napi/jsc', + 'driver/js/src/napi/jsc', + 'driver/js/include/driver/vm/jsc', + 'driver/js/src/vm/jsc'] + else + driver.exclude_files = [ + 'driver/js/include/driver/napi/v8', + 'driver/js/src/napi/v8', + 'driver/js/include/driver/runtime', + 'driver/js/src/runtime', + 'driver/js/include/vm/v8', + 'driver/js/src/vm/v8', + 'driver/js/include/driver/napi/jsc', + 'driver/js/src/napi/jsc', + 'driver/js/include/vm/jsc', + 'driver/js/src/vm/jsc'] + end + if use_frameworks header_search_paths = framework_header_path driver.header_mappings_dir = 'driver/js/include' else header_search_paths = '${PODS_ROOT}/hippy/driver/js/include/' end + definition_engine = '' + if js_engine == "jsc" + definition_engine = 'JS_JSC=1' + elsif js_engine == "v8" + definition_engine = 'JS_V8=1' + else + end driver.pod_target_xcconfig = { 'HEADER_SEARCH_PATHS' => header_search_paths, - 'GCC_PREPROCESSOR_DEFINITIONS' => 'JS_JSC=1', + 'GCC_PREPROCESSOR_DEFINITIONS' => definition_engine, 'CLANG_CXX_LANGUAGE_STANDARD' => 'c++17', 'GCC_ENABLE_CPP_EXCEPTIONS' => false, 'GCC_ENABLE_CPP_RTTI' => false, @@ -294,10 +340,14 @@ Pod::Spec.new do |s| s.subspec 'DevTools' do |devtools| puts 'hippy subspec \'devtools\' read begin' devtools.libraries = 'c++' + devtools_exclude_files = Array.new; + if js_engine == "jsc" + devtools_exclude_files += ['devtools/devtools-integration/native/include/devtools/v8', 'devtools/devtools-integration/native/src/v8'] + elsif js_engine == "v8" + else + devtools_exclude_files += ['devtools/devtools-integration/native/include/devtools/v8', 'devtools/devtools-integration/native/src/v8'] + end devtools.exclude_files = [ - #v8 files - 'devtools/devtools-integration/native/include/devtools/v8', - 'devtools/devtools-integration/native/src/v8', #test files 'devtools/devtools-integration/ios/DevtoolsBackend/_deps/**/*test*/**/*', 'devtools/devtools-integration/ios/DevtoolsBackend/_deps/**/*test*', @@ -314,7 +364,7 @@ Pod::Spec.new do |s| 'devtools/devtools-integration/ios/DevtoolsBackend/_deps/base64-src/lib/tables/table_generator.c', 'devtools/devtools-integration/ios/DevtoolsBackend/_deps/base64-src/lib/arch/**/{dec,enc}_*.c', 'devtools/devtools-integration/ios/DevtoolsBackend/_deps/base64-src/bin/base64.c', - ] + ] + devtools_exclude_files devtools.public_header_files = [ 'devtools/devtools-integration/native/include/devtools/devtools_data_source.h', #devtools_integration/native @@ -370,5 +420,23 @@ Pod::Spec.new do |s| puts 'hippy subspec \'devtools\' read end' end + if js_engine == "v8" + s.subspec 'v8' do |v8| + puts 'hippy subspec \'v8\' read begin' + v8.source_files = ['v8forios/v8/include'] + v8.public_header_files = ['v8forios/v8/include'] + v8.pod_target_xcconfig = { + 'CLANG_CXX_LANGUAGE_STANDARD' => 'c++17', + 'HEADER_SEARCH_PATHS' => '${PODS_ROOT}/hippy/v8forios/v8/include ${PODS_ROOT}/hippy/v8forios/v8/include/v8', + 'GCC_ENABLE_CPP_EXCEPTIONS' => false, + 'GCC_ENABLE_CPP_RTTI' => false, + } + v8.libraries = 'c++' + v8.vendored_library = 'v8forios/v8/libv8.a' + v8.preserve_path = 'v8forios/v8' + puts 'hippy subspec \'v8\' read end' + end + end + puts 'hippy.podspec read ends' end diff --git a/xcodeinitscript.sh b/xcodeinitscript.sh index 34510ac8a24..570f772b6a3 100755 --- a/xcodeinitscript.sh +++ b/xcodeinitscript.sh @@ -41,3 +41,34 @@ if [[ ${1} ]]; then fi cmake ./CMakeLists.txt -B ./dom_project -G Xcode -DMODULE_TOOLS=YES -DCMAKE_TOOLCHAIN_FILE=${ios_tool_chain_path} -DPLATFORM=OS64COMBINED -DDEPLOYMENT_TARGET=11.0 -DLAYOUT_ENGINE=${layout_engine} echo -e "\033[33m dom cmake build end\033[0m" + +if [[ "v8" == ${2} ]]; then + echo "use v8 js engine" + cd ${root_dir} + rm -rf v8forios + mkdir v8forios + mkdir v8forios/arm64 + mkdir v8forios/x64 + + #download and unzip arm64 bundle + curl https://infra-packages.openhippy.com/hippy/global_packages/v8/9.8-lkgr/ios-arm64.tgz --output v8forios/arm64/arm64.tgz + tar zxvf v8forios/arm64/arm64.tgz -C ./v8forios/arm64 + rm -f v8forios/arm64/arm64.tgz + + #download and unzip x64 bundle + curl https://infra-packages.openhippy.com/hippy/global_packages/v8/9.8-lkgr/ios-x64.tgz --output v8forios/x64/x64.tgz + tar zxvf v8forios/x64/x64.tgz -C ./v8forios/x64 + rm -f v8forios/x64/x64.tgz + + #move header to v8forios folder + mkdir v8forios/v8 + mv v8forios/arm64/include v8forios/v8/include + + #merge libraries + lipo -create v8forios/arm64/lib/libv8_monolith.a v8forios/x64/lib/libv8_monolith.a -output v8forios/v8/libv8.a + +elif [[ "custom" == ${2} ]]; then + echo "use custom js engine" +else + echo "use default jsc js engine" +fi \ No newline at end of file