--- node/common.gypi +++ node/common.gypi @@ -164,17 +164,28 @@ 'v8_enable_handle_zapping': 0, 'pgo_generate': ' -fprofile-generate ', 'pgo_use': ' -fprofile-use -fprofile-correction ', - 'lto': ' -flto=4 -fuse-linker-plugin -ffat-lto-objects ', 'conditions': [ ['node_shared != "true"', { 'MSVC_runtimeType': 0 # MultiThreaded (/MT) }, { 'MSVC_runtimeType': 2 # MultiThreadedDLL (/MD) }], + ['llvm_version=="0.0"', { + 'lto': ' -flto=4 -ffat-lto-objects ', # GCC + }, { + 'lto': ' -flto ', # Clang + }], ], }, 'cflags': [ '-O3' ], 'conditions': [ + ['enable_lto=="true"', { + 'cflags': ['<(lto)'], + 'ldflags': ['<(lto)'], + 'xcode_settings': { + 'LLVM_LTO': 'YES', + }, + }], ['OS=="linux"', { 'conditions': [ ['node_section_ordering_info!=""', { @@ -206,10 +217,6 @@ 'cflags': ['<(pgo_use)'], 'ldflags': ['<(pgo_use)'], },], - ['enable_lto=="true"', { - 'cflags': ['<(lto)'], - 'ldflags': ['<(lto)'], - },], ], },], ['OS == "android"', { --- node/configure.py +++ node/configure.py @@ -160,7 +160,7 @@ parser.add_option("--enable-lto", action="store_true", dest="enable_lto", help="Enable compiling with lto of a binary. This feature is only available " - "on linux with gcc and g++ 5.4.1 or newer.") + "with gcc 5.4.1+ or clang 3.9.1+.") parser.add_option("--link-module", action="append", @@ -861,6 +861,7 @@ def get_gas_version(cc): # quite prepared to go that far yet. def check_compiler(o): if sys.platform == 'win32': + o['variables']['llvm_version'] = '0.0' if not options.openssl_no_asm and options.dest_cpu in ('x86', 'x64'): nasm_version = get_nasm_version('nasm') o['variables']['nasm_version'] = nasm_version @@ -1040,12 +1041,19 @@ def configure_mips(o, target_arch): host_byteorder = 'little' if target_arch in ('mipsel', 'mips64el') else 'big' o['variables']['v8_host_byteorder'] = host_byteorder +def clang_version_ge(version_checked): + for compiler in [(CC, 'c'), (CXX, 'c++')]: + ok, is_clang, clang_version, gcc_version = \ + try_check_compiler(compiler[0], compiler[1]) + if is_clang and clang_version >= version_checked: + return True + return False def gcc_version_ge(version_checked): for compiler in [(CC, 'c'), (CXX, 'c++')]: - ok, is_clang, clang_version, compiler_version = \ + ok, is_clang, clang_version, gcc_version = \ try_check_compiler(compiler[0], compiler[1]) - if is_clang or compiler_version < version_checked: + if is_clang or gcc_version < version_checked: return False return True @@ -1126,18 +1134,19 @@ def configure_node(o): o['variables']['enable_pgo_generate'] = b(options.enable_pgo_generate) o['variables']['enable_pgo_use'] = b(options.enable_pgo_use) - if flavor != 'linux' and (options.enable_lto): + if flavor == 'win' and (options.enable_lto): raise Exception( - 'The lto option is supported only on linux.') - - if flavor == 'linux': - if options.enable_lto: - version_checked = (5, 4, 1) - if not gcc_version_ge(version_checked): - version_checked_str = ".".join(map(str, version_checked)) - raise Exception( - 'The option --enable-lto is supported for gcc and gxx %s' - ' or newer only.' % (version_checked_str)) + 'Use Link Time Code Generation instead.') + + if options.enable_lto: + gcc_version_checked = (5, 4, 1) + clang_version_checked = (3, 9, 1) + if not gcc_version_ge(gcc_version_checked) and not clang_version_ge(clang_version_checked): + gcc_version_checked_str = ".".join(map(str, gcc_version_checked)) + clang_version_checked_str = ".".join(map(str, clang_version_checked)) + raise Exception( + 'The option --enable-lto is supported for gcc %s+' + 'or clang %s+ only.' % (gcc_version_checked_str, clang_version_checked_str)) o['variables']['enable_lto'] = b(options.enable_lto) --- node/deps/v8/include/v8.h +++ node/deps/v8/include/v8.h @@ -9633,6 +9633,10 @@ class V8_EXPORT V8 { char** argv, bool remove_flags); + static void EnableCompilationForSourcelessUse(); + static void DisableCompilationForSourcelessUse(); + static void FixSourcelessScript(Isolate* v8_isolate, Local script); + /** Get the version string. */ static const char* GetVersion(); --- node/deps/v8/src/api/api.cc +++ node/deps/v8/src/api/api.cc @@ -840,6 +840,34 @@ void V8::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags) { i::FlagList::SetFlagsFromCommandLine(argc, argv, remove_flags); } + +bool save_lazy; +bool save_predictable; + + +void V8::EnableCompilationForSourcelessUse() { + save_lazy = i::FLAG_lazy; + i::FLAG_lazy = false; + save_predictable = i::FLAG_predictable; + i::FLAG_predictable = true; +} + + +void V8::DisableCompilationForSourcelessUse() { + i::FLAG_lazy = save_lazy; + i::FLAG_predictable = save_predictable; +} + + +void V8::FixSourcelessScript(Isolate* v8_isolate, Local unbound_script) { + auto isolate = reinterpret_cast(v8_isolate); + auto function_info = + i::Handle::cast(Utils::OpenHandle(*unbound_script)); + i::Handle script(i::Script::cast(function_info->script()), isolate); + script->set_source(i::ReadOnlyRoots(isolate).undefined_value()); +} + + RegisteredExtension* RegisteredExtension::first_extension_ = nullptr; RegisteredExtension::RegisteredExtension(std::unique_ptr extension) --- node/deps/v8/src/codegen/compiler.cc +++ node/deps/v8/src/codegen/compiler.cc @@ -2365,7 +2365,7 @@ MaybeHandle Compiler::GetSharedFunctionInfoForScript( source, script_details.name_obj, script_details.line_offset, script_details.column_offset, origin_options, isolate->native_context(), language_mode); - if (!maybe_result.is_null()) { + if (!maybe_result.is_null() && source_length) { compile_timer.set_hit_isolate_cache(); } else if (can_consume_code_cache) { compile_timer.set_consuming_code_cache(); --- node/deps/v8/src/objects/js-objects.cc +++ node/deps/v8/src/objects/js-objects.cc @@ -5514,6 +5514,9 @@ Handle JSFunction::ToString(Handle function) { Handle maybe_class_positions = JSReceiver::GetDataProperty( function, isolate->factory()->class_positions_symbol()); if (maybe_class_positions->IsClassPositions()) { + if (String::cast(Script::cast(shared_info->script()).source()).IsUndefined(isolate)) { + return isolate->factory()->NewStringFromAsciiChecked("class {}"); + } ClassPositions class_positions = ClassPositions::cast(*maybe_class_positions); int start_position = class_positions.start(); --- node/deps/v8/src/objects/shared-function-info-inl.h +++ node/deps/v8/src/objects/shared-function-info-inl.h @@ -505,6 +505,14 @@ bool SharedFunctionInfo::ShouldFlushBytecode(BytecodeFlushMode mode) { Object data = function_data(); if (!data.IsBytecodeArray()) return false; + Object script_obj = script(); + if (!script_obj.IsUndefined()) { + Script script = Script::cast(script_obj); + if (script.source().IsUndefined()) { + return false; + } + } + if (mode == BytecodeFlushMode::kStressFlushBytecode) return true; BytecodeArray bytecode = BytecodeArray::cast(data); --- node/deps/v8/src/parsing/parsing.cc +++ node/deps/v8/src/parsing/parsing.cc @@ -42,6 +42,7 @@ bool ParseProgram(ParseInfo* info, Handle