// Copyright 2014 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. #include "src/init/bootstrapper.h" #include "src/api/api-inl.h" #include "src/api/api-natives.h" #include "src/base/hashmap.h" #include "src/base/ieee754.h" #include "src/builtins/accessors.h" #include "src/codegen/compiler.h" #include "src/common/globals.h" #include "src/debug/debug.h" #include "src/execution/isolate-inl.h" #include "src/execution/microtask-queue.h" #include "src/execution/protectors.h" #include "src/extensions/cputracemark-extension.h" #include "src/extensions/externalize-string-extension.h" #include "src/extensions/gc-extension.h" #include "src/extensions/ignition-statistics-extension.h" #include "src/extensions/statistics-extension.h" #include "src/extensions/trigger-failure-extension.h" #include "src/logging/runtime-call-stats-scope.h" #include "src/objects/instance-type.h" #include "src/objects/objects.h" #ifdef ENABLE_VTUNE_TRACEMARK #include "src/extensions/vtunedomain-support-extension.h" #endif // ENABLE_VTUNE_TRACEMARK #include "src/heap/heap-inl.h" #include "src/logging/counters.h" #include "src/logging/log.h" #include "src/numbers/math-random.h" #include "src/objects/api-callbacks.h" #include "src/objects/arguments.h" #include "src/objects/function-kind.h" #include "src/objects/hash-table-inl.h" #ifdef V8_INTL_SUPPORT #include "src/objects/intl-objects.h" #endif // V8_INTL_SUPPORT #include "src/objects/js-array-buffer-inl.h" #include "src/objects/js-array-inl.h" #ifdef V8_INTL_SUPPORT #include "src/objects/js-break-iterator.h" #include "src/objects/js-collator.h" #include "src/objects/js-date-time-format.h" #include "src/objects/js-display-names.h" #include "src/objects/js-list-format.h" #include "src/objects/js-locale.h" #include "src/objects/js-number-format.h" #include "src/objects/js-plural-rules.h" #endif // V8_INTL_SUPPORT #include "src/objects/js-regexp-string-iterator.h" #include "src/objects/js-regexp.h" #include "src/objects/js-shadow-realms.h" #ifdef V8_INTL_SUPPORT #include "src/objects/js-relative-time-format.h" #include "src/objects/js-segment-iterator.h" #include "src/objects/js-segmenter.h" #include "src/objects/js-segments.h" #endif // V8_INTL_SUPPORT #include "src/codegen/script-details.h" #include "src/objects/js-struct.h" #include "src/objects/js-temporal-objects-inl.h" #include "src/objects/js-weak-refs.h" #include "src/objects/ordered-hash-table.h" #include "src/objects/property-cell.h" #include "src/objects/slots-inl.h" #include "src/objects/swiss-name-dictionary-inl.h" #include "src/objects/templates.h" #include "src/snapshot/snapshot.h" #include "src/zone/zone-hashmap.h" #if V8_ENABLE_WEBASSEMBLY #include "src/wasm/wasm-js.h" #endif // V8_ENABLE_WEBASSEMBLY namespace v8 { namespace internal { void SourceCodeCache::Initialize(Isolate* isolate, bool create_heap_objects) { cache_ = create_heap_objects ? ReadOnlyRoots(isolate).empty_fixed_array() : FixedArray(); } void SourceCodeCache::Iterate(RootVisitor* v) { v->VisitRootPointer(Root::kExtensions, nullptr, FullObjectSlot(&cache_)); } bool SourceCodeCache::Lookup(Isolate* isolate, base::Vector name, Handle* handle) { for (int i = 0; i < cache_.length(); i += 2) { SeqOneByteString str = SeqOneByteString::cast(cache_.get(i)); if (str.IsOneByteEqualTo(name)) { *handle = Handle( SharedFunctionInfo::cast(cache_.get(i + 1)), isolate); return true; } } return false; } void SourceCodeCache::Add(Isolate* isolate, base::Vector name, Handle shared) { Factory* factory = isolate->factory(); HandleScope scope(isolate); int length = cache_.length(); Handle new_array = factory->NewFixedArray(length + 2, AllocationType::kOld); cache_.CopyTo(0, *new_array, 0, cache_.length()); cache_ = *new_array; Handle str = factory ->NewStringFromOneByte(base::Vector::cast(name), AllocationType::kOld) .ToHandleChecked(); DCHECK(!str.is_null()); cache_.set(length, *str); cache_.set(length + 1, *shared); Script::cast(shared->script()).set_type(type_); } Bootstrapper::Bootstrapper(Isolate* isolate) : isolate_(isolate), nesting_(0), extensions_cache_(Script::TYPE_EXTENSION) {} void Bootstrapper::Initialize(bool create_heap_objects) { extensions_cache_.Initialize(isolate_, create_heap_objects); } static const char* GCFunctionName() { bool flag_given = FLAG_expose_gc_as != nullptr && strlen(FLAG_expose_gc_as) != 0; return flag_given ? FLAG_expose_gc_as : "gc"; } static bool isValidCpuTraceMarkFunctionName() { return FLAG_expose_cputracemark_as != nullptr && strlen(FLAG_expose_cputracemark_as) != 0; } void Bootstrapper::InitializeOncePerProcess() { v8::RegisterExtension(std::make_unique(GCFunctionName())); v8::RegisterExtension(std::make_unique()); v8::RegisterExtension(std::make_unique()); v8::RegisterExtension(std::make_unique()); v8::RegisterExtension(std::make_unique()); if (isValidCpuTraceMarkFunctionName()) { v8::RegisterExtension( std::make_unique(FLAG_expose_cputracemark_as)); } #ifdef ENABLE_VTUNE_TRACEMARK v8::RegisterExtension( std::make_unique("vtunedomainmark")); #endif // ENABLE_VTUNE_TRACEMARK } void Bootstrapper::TearDown() { extensions_cache_.Initialize(isolate_, false); // Yes, symmetrical } class Genesis { public: Genesis(Isolate* isolate, MaybeHandle maybe_global_proxy, v8::Local global_proxy_template, size_t context_snapshot_index, v8::DeserializeEmbedderFieldsCallback embedder_fields_deserializer, v8::MicrotaskQueue* microtask_queue); Genesis(Isolate* isolate, MaybeHandle maybe_global_proxy, v8::Local global_proxy_template); ~Genesis() = default; Isolate* isolate() const { return isolate_; } Factory* factory() const { return isolate_->factory(); } Builtins* builtins() const { return isolate_->builtins(); } Heap* heap() const { return isolate_->heap(); } Handle result() { return result_; } Handle global_proxy() { return global_proxy_; } private: Handle native_context() { return native_context_; } // Creates some basic objects. Used for creating a context from scratch. void CreateRoots(); // Creates the empty function. Used for creating a context from scratch. Handle CreateEmptyFunction(); // Returns the %ThrowTypeError% intrinsic function. // See ES#sec-%throwtypeerror% for details. Handle GetThrowTypeErrorIntrinsic(); void CreateSloppyModeFunctionMaps(Handle empty); void CreateStrictModeFunctionMaps(Handle empty); void CreateObjectFunction(Handle empty); void CreateIteratorMaps(Handle empty); void CreateAsyncIteratorMaps(Handle empty); void CreateAsyncFunctionMaps(Handle empty); void CreateJSProxyMaps(); // Make the "arguments" and "caller" properties throw a TypeError on access. void AddRestrictedFunctionProperties(Handle empty); // Creates the global objects using the global proxy and the template passed // in through the API. We call this regardless of whether we are building a // context from scratch or using a deserialized one from the context snapshot // but in the latter case we don't use the objects it produces directly, as // we have to use the deserialized ones that are linked together with the // rest of the context snapshot. At the end we link the global proxy and the // context to each other. Handle CreateNewGlobals( v8::Local global_proxy_template, Handle global_proxy); // Similarly, we want to use the global that has been created by the templates // passed through the API. The global from the snapshot is detached from the // other objects in the snapshot. void HookUpGlobalObject(Handle global_object); // Hooks the given global proxy into the context in the case we do not // replace the global object from the deserialized native context. void HookUpGlobalProxy(Handle global_proxy); // The native context has a ScriptContextTable that store declarative bindings // made in script scopes. Add a "this" binding to that table pointing to the // global proxy. void InstallGlobalThisBinding(); // New context initialization. Used for creating a context from scratch. void InitializeGlobal(Handle global_object, Handle empty_function); void InitializeExperimentalGlobal(); void InitializeIteratorFunctions(); void InitializeCallSiteBuiltins(); void InitializeConsole(Handle extras_binding); #define DECLARE_FEATURE_INITIALIZATION(id, descr) void InitializeGlobal_##id(); HARMONY_INPROGRESS(DECLARE_FEATURE_INITIALIZATION) HARMONY_STAGED(DECLARE_FEATURE_INITIALIZATION) HARMONY_SHIPPING(DECLARE_FEATURE_INITIALIZATION) #undef DECLARE_FEATURE_INITIALIZATION void InitializeGlobal_regexp_linear_flag(); enum ArrayBufferKind { ARRAY_BUFFER, SHARED_ARRAY_BUFFER }; Handle CreateArrayBuffer(Handle name, ArrayBufferKind array_buffer_kind); bool InstallABunchOfRandomThings(); bool InstallExtrasBindings(); Handle InstallTypedArray(const char* name, ElementsKind elements_kind, InstanceType constructor_type, int rab_gsab_initial_map_index); void InitializeMapCaches(); enum ExtensionTraversalState { UNVISITED, VISITED, INSTALLED }; class ExtensionStates { public: ExtensionStates(); ExtensionStates(const ExtensionStates&) = delete; ExtensionStates& operator=(const ExtensionStates&) = delete; ExtensionTraversalState get_state(RegisteredExtension* extension); void set_state(RegisteredExtension* extension, ExtensionTraversalState state); private: base::HashMap map_; }; // Used both for deserialized and from-scratch contexts to add the extensions // provided. static bool InstallExtensions(Isolate* isolate, Handle native_context, v8::ExtensionConfiguration* extensions); static bool InstallAutoExtensions(Isolate* isolate, ExtensionStates* extension_states); static bool InstallRequestedExtensions(Isolate* isolate, v8::ExtensionConfiguration* extensions, ExtensionStates* extension_states); static bool InstallExtension(Isolate* isolate, const char* name, ExtensionStates* extension_states); static bool InstallExtension(Isolate* isolate, v8::RegisteredExtension* current, ExtensionStates* extension_states); static bool InstallSpecialObjects(Isolate* isolate, Handle native_context); bool ConfigureApiObject(Handle object, Handle object_template); bool ConfigureGlobalObject( v8::Local global_proxy_template); // Migrates all properties from the 'from' object to the 'to' // object and overrides the prototype in 'to' with the one from // 'from'. void TransferObject(Handle from, Handle to); void TransferNamedProperties(Handle from, Handle to); void TransferIndexedProperties(Handle from, Handle to); Handle CreateInitialMapForArraySubclass(int size, int inobject_properties); static bool CompileExtension(Isolate* isolate, v8::Extension* extension); Isolate* isolate_; Handle result_; Handle native_context_; Handle global_proxy_; // %ThrowTypeError%. See ES#sec-%throwtypeerror% for details. Handle restricted_properties_thrower_; BootstrapperActive active_; friend class Bootstrapper; }; void Bootstrapper::Iterate(RootVisitor* v) { extensions_cache_.Iterate(v); v->Synchronize(VisitorSynchronization::kExtensions); } Handle Bootstrapper::CreateEnvironment( MaybeHandle maybe_global_proxy, v8::Local global_proxy_template, v8::ExtensionConfiguration* extensions, size_t context_snapshot_index, v8::DeserializeEmbedderFieldsCallback embedder_fields_deserializer, v8::MicrotaskQueue* microtask_queue) { HandleScope scope(isolate_); Handle env; { Genesis genesis(isolate_, maybe_global_proxy, global_proxy_template, context_snapshot_index, embedder_fields_deserializer, microtask_queue); env = genesis.result(); if (env.is_null() || !InstallExtensions(env, extensions)) { return Handle(); } } LogAllMaps(); isolate_->heap()->NotifyBootstrapComplete(); return scope.CloseAndEscape(env); } Handle Bootstrapper::NewRemoteContext( MaybeHandle maybe_global_proxy, v8::Local global_proxy_template) { HandleScope scope(isolate_); Handle global_proxy; { Genesis genesis(isolate_, maybe_global_proxy, global_proxy_template); global_proxy = genesis.global_proxy(); if (global_proxy.is_null()) return Handle(); } LogAllMaps(); return scope.CloseAndEscape(global_proxy); } void Bootstrapper::LogAllMaps() { if (!FLAG_log_maps || isolate_->initialized_from_snapshot()) return; // Log all created Map objects that are on the heap. For snapshots the Map // logging happens during deserialization in order to avoid printing Maps // multiple times during partial deserialization. LOG(isolate_, LogAllMaps()); } namespace { #ifdef DEBUG bool IsFunctionMapOrSpecialBuiltin(Handle map, Builtin builtin, Handle context) { // During bootstrapping some of these maps could be not created yet. return ((*map == context->get(Context::STRICT_FUNCTION_MAP_INDEX)) || (*map == context->get( Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX)) || (*map == context->get( Context::STRICT_FUNCTION_WITH_READONLY_PROTOTYPE_MAP_INDEX)) || // Check if it's a creation of an empty or Proxy function during // bootstrapping. (builtin == Builtin::kEmptyFunction || builtin == Builtin::kProxyConstructor)); } #endif // DEBUG V8_NOINLINE Handle CreateFunctionForBuiltin(Isolate* isolate, Handle name, Handle map, Builtin builtin) { Factory* factory = isolate->factory(); Handle context(isolate->native_context()); DCHECK(IsFunctionMapOrSpecialBuiltin(map, builtin, context)); Handle info = factory->NewSharedFunctionInfoForBuiltin(name, builtin); info->set_language_mode(LanguageMode::kStrict); return Factory::JSFunctionBuilder{isolate, info, context} .set_map(map) .Build(); } V8_NOINLINE Handle CreateFunctionForBuiltinWithPrototype( Isolate* isolate, Handle name, Builtin builtin, Handle prototype, InstanceType type, int instance_size, int inobject_properties, MutableMode prototype_mutability) { Factory* factory = isolate->factory(); Handle context(isolate->native_context()); Handle map = prototype_mutability == MUTABLE ? isolate->strict_function_map() : isolate->strict_function_with_readonly_prototype_map(); DCHECK(IsFunctionMapOrSpecialBuiltin(map, builtin, context)); Handle info = factory->NewSharedFunctionInfoForBuiltin(name, builtin); info->set_language_mode(LanguageMode::kStrict); info->set_expected_nof_properties(inobject_properties); Handle result = Factory::JSFunctionBuilder{isolate, info, context}.set_map(map).Build(); ElementsKind elements_kind; switch (type) { case JS_ARRAY_TYPE: elements_kind = PACKED_SMI_ELEMENTS; break; case JS_ARGUMENTS_OBJECT_TYPE: elements_kind = PACKED_ELEMENTS; break; default: elements_kind = TERMINAL_FAST_ELEMENTS_KIND; break; } Handle initial_map = factory->NewMap(type, instance_size, elements_kind, inobject_properties); if (type == JS_FUNCTION_TYPE) { DCHECK_EQ(instance_size, JSFunction::kSizeWithPrototype); // Since we are creating an initial map for JSFunction objects with // prototype slot, set the respective bit. initial_map->set_has_prototype_slot(true); } // TODO(littledan): Why do we have this is_generator test when // NewFunctionPrototype already handles finding an appropriately // shared prototype? if (!IsResumableFunction(info->kind()) && prototype->IsTheHole(isolate)) { prototype = factory->NewFunctionPrototype(result); } JSFunction::SetInitialMap(isolate, result, initial_map, prototype); return result; } V8_NOINLINE Handle CreateFunctionForBuiltinWithoutPrototype( Isolate* isolate, Handle name, Builtin builtin) { Factory* factory = isolate->factory(); Handle context(isolate->native_context()); Handle map = isolate->strict_function_without_prototype_map(); DCHECK(IsFunctionMapOrSpecialBuiltin(map, builtin, context)); Handle info = factory->NewSharedFunctionInfoForBuiltin(name, builtin); info->set_language_mode(LanguageMode::kStrict); return Factory::JSFunctionBuilder{isolate, info, context} .set_map(map) .Build(); } V8_NOINLINE Handle CreateFunction( Isolate* isolate, Handle name, InstanceType type, int instance_size, int inobject_properties, Handle prototype, Builtin builtin) { DCHECK(Builtins::HasJSLinkage(builtin)); Handle result = CreateFunctionForBuiltinWithPrototype( isolate, name, builtin, prototype, type, instance_size, inobject_properties, IMMUTABLE); // Make the JSFunction's prototype object fast. JSObject::MakePrototypesFast(handle(result->prototype(), isolate), kStartAtReceiver, isolate); // Make the resulting JSFunction object fast. JSObject::MakePrototypesFast(result, kStartAtReceiver, isolate); result->shared().set_native(true); return result; } V8_NOINLINE Handle CreateFunction( Isolate* isolate, const char* name, InstanceType type, int instance_size, int inobject_properties, Handle prototype, Builtin builtin) { return CreateFunction(isolate, isolate->factory()->InternalizeUtf8String(name), type, instance_size, inobject_properties, prototype, builtin); } V8_NOINLINE Handle InstallFunction( Isolate* isolate, Handle target, Handle name, InstanceType type, int instance_size, int inobject_properties, Handle prototype, Builtin call) { DCHECK(Builtins::HasJSLinkage(call)); Handle function = CreateFunction( isolate, name, type, instance_size, inobject_properties, prototype, call); JSObject::AddProperty(isolate, target, name, function, DONT_ENUM); return function; } V8_NOINLINE Handle InstallFunction( Isolate* isolate, Handle target, const char* name, InstanceType type, int instance_size, int inobject_properties, Handle prototype, Builtin call) { return InstallFunction(isolate, target, isolate->factory()->InternalizeUtf8String(name), type, instance_size, inobject_properties, prototype, call); } // This sets a constructor instance type on the constructor map which will be // used in IsXxxConstructor() predicates. Having such predicates helps figuring // out if a protector cell should be invalidated. If there are no protector // cell checks required for constructor, this function must not be used. // Note, this function doesn't create a copy of the constructor's map. So it's // better to set constructor instance type after all the properties are added // to the constructor and thus the map is already guaranteed to be unique. V8_NOINLINE void SetConstructorInstanceType(Isolate* isolate, Handle constructor, InstanceType constructor_type) { DCHECK(InstanceTypeChecker::IsJSFunction(constructor_type)); DCHECK_NE(constructor_type, JS_FUNCTION_TYPE); Map map = constructor->map(); // Check we don't accidentally change one of the existing maps. DCHECK_NE(map, *isolate->strict_function_map()); DCHECK_NE(map, *isolate->strict_function_with_readonly_prototype_map()); // Constructor function map is always a root map, and thus we don't have to // deal with updating the whole transition tree. DCHECK(map.GetBackPointer().IsUndefined(isolate)); DCHECK_EQ(JS_FUNCTION_TYPE, map.instance_type()); map.set_instance_type(constructor_type); } V8_NOINLINE Handle SimpleCreateFunction(Isolate* isolate, Handle name, Builtin call, int len, bool adapt) { DCHECK(Builtins::HasJSLinkage(call)); name = String::Flatten(isolate, name, AllocationType::kOld); Handle fun = CreateFunctionForBuiltinWithoutPrototype(isolate, name, call); // Make the resulting JSFunction object fast. JSObject::MakePrototypesFast(fun, kStartAtReceiver, isolate); fun->shared().set_native(true); if (adapt) { fun->shared().set_internal_formal_parameter_count(JSParameterCount(len)); } else { fun->shared().DontAdaptArguments(); } fun->shared().set_length(len); return fun; } V8_NOINLINE Handle InstallFunctionWithBuiltinId( Isolate* isolate, Handle base, const char* name, Builtin call, int len, bool adapt) { Handle internalized_name = isolate->factory()->InternalizeUtf8String(name); Handle fun = SimpleCreateFunction(isolate, internalized_name, call, len, adapt); JSObject::AddProperty(isolate, base, internalized_name, fun, DONT_ENUM); return fun; } V8_NOINLINE Handle SimpleInstallFunction( Isolate* isolate, Handle base, const char* name, Builtin call, int len, bool adapt, PropertyAttributes attrs = DONT_ENUM) { // Although function name does not have to be internalized the property name // will be internalized during property addition anyway, so do it here now. Handle internalized_name = isolate->factory()->InternalizeUtf8String(name); Handle fun = SimpleCreateFunction(isolate, internalized_name, call, len, adapt); JSObject::AddProperty(isolate, base, internalized_name, fun, attrs); return fun; } V8_NOINLINE Handle InstallFunctionAtSymbol( Isolate* isolate, Handle base, Handle symbol, const char* symbol_string, Builtin call, int len, bool adapt, PropertyAttributes attrs = DONT_ENUM) { Handle internalized_symbol = isolate->factory()->InternalizeUtf8String(symbol_string); Handle fun = SimpleCreateFunction(isolate, internalized_symbol, call, len, adapt); JSObject::AddProperty(isolate, base, symbol, fun, attrs); return fun; } V8_NOINLINE void SimpleInstallGetterSetter(Isolate* isolate, Handle base, Handle name, Builtin call_getter, Builtin call_setter) { Handle getter_name = Name::ToFunctionName(isolate, name, isolate->factory()->get_string()) .ToHandleChecked(); Handle getter = SimpleCreateFunction(isolate, getter_name, call_getter, 0, true); Handle setter_name = Name::ToFunctionName(isolate, name, isolate->factory()->set_string()) .ToHandleChecked(); Handle setter = SimpleCreateFunction(isolate, setter_name, call_setter, 1, true); JSObject::DefineAccessor(base, name, getter, setter, DONT_ENUM).Check(); } void SimpleInstallGetterSetter(Isolate* isolate, Handle base, const char* name, Builtin call_getter, Builtin call_setter) { SimpleInstallGetterSetter(isolate, base, isolate->factory()->InternalizeUtf8String(name), call_getter, call_setter); } V8_NOINLINE Handle SimpleInstallGetter(Isolate* isolate, Handle base, Handle name, Handle property_name, Builtin call, bool adapt) { Handle getter_name = Name::ToFunctionName(isolate, name, isolate->factory()->get_string()) .ToHandleChecked(); Handle getter = SimpleCreateFunction(isolate, getter_name, call, 0, adapt); Handle setter = isolate->factory()->undefined_value(); JSObject::DefineAccessor(base, property_name, getter, setter, DONT_ENUM) .Check(); return getter; } V8_NOINLINE Handle SimpleInstallGetter(Isolate* isolate, Handle base, Handle name, Builtin call, bool adapt) { return SimpleInstallGetter(isolate, base, name, name, call, adapt); } V8_NOINLINE void InstallConstant(Isolate* isolate, Handle holder, const char* name, Handle value) { JSObject::AddProperty( isolate, holder, isolate->factory()->InternalizeUtf8String(name), value, static_cast(DONT_DELETE | DONT_ENUM | READ_ONLY)); } V8_NOINLINE void InstallTrueValuedProperty(Isolate* isolate, Handle holder, const char* name) { JSObject::AddProperty(isolate, holder, isolate->factory()->InternalizeUtf8String(name), isolate->factory()->true_value(), NONE); } V8_NOINLINE void InstallSpeciesGetter(Isolate* isolate, Handle constructor) { Factory* factory = isolate->factory(); // TODO(adamk): We should be able to share a SharedFunctionInfo // between all these JSFunctins. SimpleInstallGetter(isolate, constructor, factory->symbol_species_string(), factory->species_symbol(), Builtin::kReturnReceiver, true); } V8_NOINLINE void InstallToStringTag(Isolate* isolate, Handle holder, Handle value) { JSObject::AddProperty(isolate, holder, isolate->factory()->to_string_tag_symbol(), value, static_cast(DONT_ENUM | READ_ONLY)); } void InstallToStringTag(Isolate* isolate, Handle holder, const char* value) { InstallToStringTag(isolate, holder, isolate->factory()->InternalizeUtf8String(value)); } } // namespace Handle Genesis::CreateEmptyFunction() { // Allocate the function map first and then patch the prototype later. Handle empty_function_map = factory()->CreateSloppyFunctionMap( FUNCTION_WITHOUT_PROTOTYPE, MaybeHandle()); empty_function_map->set_is_prototype_map(true); DCHECK(!empty_function_map->is_dictionary_map()); // Allocate the empty function as the prototype for function according to // ES#sec-properties-of-the-function-prototype-object Handle empty_function = CreateFunctionForBuiltin(isolate(), factory()->empty_string(), empty_function_map, Builtin::kEmptyFunction); native_context()->set_empty_function(*empty_function); // --- E m p t y --- Handle source = factory()->NewStringFromStaticChars("() {}"); Handle