From 22cdf0c0fdbde05e2dc15c4c6445ff3bd683bd8a Mon Sep 17 00:00:00 2001 From: "verwaest@chromium.org" Date: Tue, 29 Apr 2014 17:48:07 +0000 Subject: [PATCH] Pass in the prototype to CreateApiFunction rather than setting it on the result. BUG= R=ishell@chromium.org Review URL: https://codereview.chromium.org/253603003 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@21066 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/apinatives.js | 34 ++++++++++++++-------------- src/bootstrapper.cc | 2 ++ src/factory.cc | 64 +++++++++++++++++++++++++++++++++++++++-------------- src/factory.h | 7 ++++++ src/runtime.cc | 8 ++++--- src/runtime.h | 2 +- 6 files changed, 78 insertions(+), 39 deletions(-) diff --git a/src/apinatives.js b/src/apinatives.js index 6068882..0579caf 100644 --- a/src/apinatives.js +++ b/src/apinatives.js @@ -48,31 +48,29 @@ function InstantiateFunction(data, name) { (serialNumber in cache) && (cache[serialNumber] != kUninitialized); if (!isFunctionCached) { try { - var fun = %CreateApiFunction(data); - if (name) %FunctionSetName(fun, name); var flags = %GetTemplateField(data, kApiFlagOffset); - var doNotCache = flags & (1 << kDoNotCacheBit); - if (!doNotCache) cache[serialNumber] = fun; - if (flags & (1 << kRemovePrototypeBit)) { - %FunctionRemovePrototype(fun); - } else { - var prototype = %GetTemplateField(data, kApiPrototypeTemplateOffset); - // Note: Do not directly use an object template as a condition, our - // internal ToBoolean doesn't handle that! - fun.prototype = typeof prototype === 'undefined' ? - {} : Instantiate(prototype); - if (flags & (1 << kReadOnlyPrototypeBit)) { - %FunctionSetReadOnlyPrototype(fun); - } - %SetProperty(fun.prototype, "constructor", fun, DONT_ENUM); + var has_proto = !(flags & (1 << kRemovePrototypeBit)); + var prototype; + if (has_proto) { + var template = %GetTemplateField(data, kApiPrototypeTemplateOffset); + prototype = typeof template === 'undefined' + ? {} : Instantiate(template); + var parent = %GetTemplateField(data, kApiParentTemplateOffset); // Note: Do not directly use a function template as a condition, our // internal ToBoolean doesn't handle that! - if (!(typeof parent === 'undefined')) { + if (typeof parent !== 'undefined') { var parent_fun = Instantiate(parent); - %SetPrototype(fun.prototype, parent_fun.prototype); + %SetPrototype(prototype, parent_fun.prototype); } } + var fun = %CreateApiFunction(data, prototype); + if (name) %FunctionSetName(fun, name); + var doNotCache = flags & (1 << kDoNotCacheBit); + if (!doNotCache) cache[serialNumber] = fun; + if (has_proto && flags & (1 << kReadOnlyPrototypeBit)) { + %FunctionSetReadOnlyPrototype(fun); + } ConfigureTemplateInstance(fun, data); if (doNotCache) return fun; } catch (e) { diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index 0bc0587..3419a6e 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -729,6 +729,7 @@ Handle Genesis::CreateNewGlobals( FunctionTemplateInfo::cast(js_global_template->constructor())); js_global_function = factory()->CreateApiFunction(js_global_constructor, + factory()->the_hole_value(), factory()->InnerGlobalObject); } @@ -756,6 +757,7 @@ Handle Genesis::CreateNewGlobals( FunctionTemplateInfo::cast(data->constructor())); global_proxy_function = factory()->CreateApiFunction(global_constructor, + factory()->the_hole_value(), factory()->OuterGlobalObject); } diff --git a/src/factory.cc b/src/factory.cc index e12d296..272383c 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -1255,19 +1255,30 @@ Handle Factory::NewError(const char* constructor, } -Handle Factory::NewFunction(Handle name, +Handle Factory::NewFunction(MaybeHandle maybe_prototype, + Handle name, InstanceType type, int instance_size, Handle code, bool force_initial_map) { // Allocate the function - Handle function = NewFunction(name, code, the_hole_value()); + Handle function = NewFunction(name, code, maybe_prototype); - if (force_initial_map || - type != JS_OBJECT_TYPE || - instance_size != JSObject::kHeaderSize) { + Handle prototype; + if (maybe_prototype.ToHandle(&prototype) && + (force_initial_map || + type != JS_OBJECT_TYPE || + instance_size != JSObject::kHeaderSize)) { Handle initial_map = NewMap(type, instance_size); - Handle prototype = NewFunctionPrototype(function); + if (prototype->IsJSObject()) { + JSObject::SetLocalPropertyIgnoreAttributes( + Handle::cast(prototype), + constructor_string(), + function, + DONT_ENUM).Assert(); + } else if (!function->shared()->is_generator()) { + prototype = NewFunctionPrototype(function); + } initial_map->set_prototype(*prototype); function->set_initial_map(*initial_map); initial_map->set_constructor(*function); @@ -1280,6 +1291,16 @@ Handle Factory::NewFunction(Handle name, } +Handle Factory::NewFunction(Handle name, + InstanceType type, + int instance_size, + Handle code, + bool force_initial_map) { + return NewFunction( + the_hole_value(), name, type, instance_size, code, force_initial_map); +} + + Handle Factory::NewFunctionWithPrototype(Handle name, InstanceType type, int instance_size, @@ -2057,7 +2078,9 @@ Handle Factory::NewArgumentsObject(Handle callee, Handle Factory::CreateApiFunction( - Handle obj, ApiInstanceType instance_type) { + Handle obj, + Handle prototype, + ApiInstanceType instance_type) { Handle code = isolate()->builtins()->HandleApiCall(); Handle construct_stub = isolate()->builtins()->JSConstructStubApi(); @@ -2093,20 +2116,31 @@ Handle Factory::CreateApiFunction( break; } + MaybeHandle maybe_prototype = prototype; + if (obj->remove_prototype()) maybe_prototype = MaybeHandle(); + Handle result = NewFunction( - Factory::empty_string(), type, instance_size, code, true); + maybe_prototype, Factory::empty_string(), type, + instance_size, code, true); - // Set length. result->shared()->set_length(obj->length()); - - // Set class name. - Handle class_name = Handle(obj->class_name(), isolate()); + Handle class_name(obj->class_name(), isolate()); if (class_name->IsString()) { result->shared()->set_instance_class_name(*class_name); result->shared()->set_name(*class_name); } + result->shared()->set_function_data(*obj); + result->shared()->set_construct_stub(*construct_stub); + result->shared()->DontAdaptArguments(); - Handle map = Handle(result->initial_map()); + if (obj->remove_prototype()) { + ASSERT(result->shared()->IsApiFunction()); + return result; + } + // Down from here is only valid for API functions that can be used as a + // constructor (don't set the "remove prototype" flag). + + Handle map(result->initial_map()); // Mark as undetectable if needed. if (obj->undetectable()) { @@ -2136,10 +2170,6 @@ Handle Factory::CreateApiFunction( map->set_has_instance_call_handler(); } - result->shared()->set_function_data(*obj); - result->shared()->set_construct_stub(*construct_stub); - result->shared()->DontAdaptArguments(); - // Recursively copy parent instance templates' accessors, // 'data' may be modified. int max_number_of_additional_properties = 0; diff --git a/src/factory.h b/src/factory.h index d79a9c9..a87c093 100644 --- a/src/factory.h +++ b/src/factory.h @@ -464,6 +464,12 @@ class Factory V8_FINAL { Handle context, PretenureFlag pretenure = TENURED); + Handle NewFunction(MaybeHandle maybe_prototype, + Handle name, + InstanceType type, + int instance_size, + Handle code, + bool force_initial_map); Handle NewFunction(Handle name, InstanceType type, int instance_size, @@ -551,6 +557,7 @@ class Factory V8_FINAL { Handle CreateApiFunction( Handle data, + Handle prototype, ApiInstanceType type = JavaScriptObject); Handle InstallMembers(Handle function); diff --git a/src/runtime.cc b/src/runtime.cc index f5dc2ac..e28783d 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -2112,9 +2112,10 @@ RUNTIME_FUNCTION(Runtime_RegExpCompile) { RUNTIME_FUNCTION(Runtime_CreateApiFunction) { HandleScope scope(isolate); - ASSERT(args.length() == 1); + ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0); - return *isolate->factory()->CreateApiFunction(data); + CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); + return *isolate->factory()->CreateApiFunction(data, prototype); } @@ -2786,7 +2787,8 @@ static Handle InstallBuiltin(Isolate* isolate, Handle key = isolate->factory()->InternalizeUtf8String(name); Handle code(isolate->builtins()->builtin(builtin_name)); Handle optimized = - isolate->factory()->NewFunction(key, + isolate->factory()->NewFunction(MaybeHandle(), + key, JS_OBJECT_TYPE, JSObject::kHeaderSize, code, diff --git a/src/runtime.h b/src/runtime.h index 092d323..eb28f83 100644 --- a/src/runtime.h +++ b/src/runtime.h @@ -202,7 +202,7 @@ namespace internal { F(SetCode, 2, 1) \ F(SetExpectedNumberOfProperties, 2, 1) \ \ - F(CreateApiFunction, 1, 1) \ + F(CreateApiFunction, 2, 1) \ F(IsTemplate, 1, 1) \ F(GetTemplateField, 2, 1) \ F(DisableAccessChecks, 1, 1) \ -- 2.7.4