Index: src/builtins.cc |
diff --git a/src/builtins.cc b/src/builtins.cc |
index 90e11e3d6cccbc10323287f2250452ea74889cf0..9cd2a5e94b4b65af0d1c5cfc6328b9e0ccc7df4c 100644 |
--- a/src/builtins.cc |
+++ b/src/builtins.cc |
@@ -4066,42 +4066,64 @@ BUILTIN(FunctionPrototypeBind) { |
isolate, function, |
isolate->factory()->NewJSBoundFunction(target, this_arg, argv)); |
- // TODO(bmeurer): Optimize the rest for the common cases where {target} is |
- // a function with some initial map or even a bound function. |
+ LookupIterator length_lookup(target, isolate->factory()->length_string(), |
+ target, LookupIterator::HIDDEN); |
// Setup the "length" property based on the "length" of the {target}. |
- Handle<Object> length(Smi::FromInt(0), isolate); |
- Maybe<bool> target_has_length = |
- JSReceiver::HasOwnProperty(target, isolate->factory()->length_string()); |
- if (!target_has_length.IsJust()) { |
- return isolate->heap()->exception(); |
- } else if (target_has_length.FromJust()) { |
- Handle<Object> target_length; |
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
- isolate, target_length, |
- JSReceiver::GetProperty(target, isolate->factory()->length_string())); |
- if (target_length->IsNumber()) { |
- length = isolate->factory()->NewNumber(std::max( |
- 0.0, DoubleToInteger(target_length->Number()) - argv.length())); |
+ // If the targets length is the default JSFunction accessor, we can keep the |
+ // accessor that's installed by default on the JSBoundFunction. It lazily |
+ // computes the value from the underlying internal length. |
+ if (!target->IsJSFunction() || |
+ length_lookup.state() != LookupIterator::ACCESSOR || |
+ !length_lookup.GetAccessors()->IsAccessorInfo()) { |
+ Handle<Object> length(Smi::FromInt(0), isolate); |
+ Maybe<PropertyAttributes> attributes = |
+ JSReceiver::GetPropertyAttributes(&length_lookup); |
+ if (!attributes.IsJust()) return isolate->heap()->exception(); |
+ if (attributes.FromJust() != ABSENT) { |
+ Handle<Object> target_length; |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, target_length, |
+ Object::GetProperty(&length_lookup)); |
+ if (target_length->IsNumber()) { |
+ length = isolate->factory()->NewNumber(std::max( |
+ 0.0, DoubleToInteger(target_length->Number()) - argv.length())); |
+ } |
} |
+ LookupIterator it(function, isolate->factory()->length_string(), function); |
+ DCHECK_EQ(LookupIterator::ACCESSOR, it.state()); |
+ RETURN_FAILURE_ON_EXCEPTION(isolate, |
+ JSObject::DefineOwnPropertyIgnoreAttributes( |
+ &it, length, it.property_attributes())); |
} |
- function->set_length(*length); |
// Setup the "name" property based on the "name" of the {target}. |
- Handle<Object> target_name; |
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
- isolate, target_name, |
- JSReceiver::GetProperty(target, isolate->factory()->name_string())); |
- Handle<String> name; |
- if (!target_name->IsString()) { |
- name = isolate->factory()->bound__string(); |
- } else { |
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
- isolate, name, Name::ToFunctionName(Handle<String>::cast(target_name))); |
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
- isolate, name, isolate->factory()->NewConsString( |
- isolate->factory()->bound__string(), name)); |
+ // If the targets name is the default JSFunction accessor, we can keep the |
+ // accessor that's installed by default on the JSBoundFunction. It lazily |
+ // computes the value from the underlying internal name. |
+ LookupIterator name_lookup(target, isolate->factory()->name_string(), target, |
+ LookupIterator::HIDDEN); |
+ if (!target->IsJSFunction() || |
+ name_lookup.state() != LookupIterator::ACCESSOR || |
+ !name_lookup.GetAccessors()->IsAccessorInfo()) { |
+ Handle<Object> target_name; |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, target_name, |
+ Object::GetProperty(&name_lookup)); |
+ Handle<String> name; |
+ if (target_name->IsString()) { |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
+ isolate, name, |
+ Name::ToFunctionName(Handle<String>::cast(target_name))); |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
+ isolate, name, isolate->factory()->NewConsString( |
+ isolate->factory()->bound__string(), name)); |
+ } else { |
+ name = isolate->factory()->bound__string(); |
+ } |
+ LookupIterator it(function, isolate->factory()->name_string()); |
+ DCHECK_EQ(LookupIterator::ACCESSOR, it.state()); |
+ RETURN_FAILURE_ON_EXCEPTION(isolate, |
+ JSObject::DefineOwnPropertyIgnoreAttributes( |
+ &it, name, it.property_attributes())); |
} |
- function->set_name(*name); |
return *function; |
} |