[builtins] Fix binding function with native data property accessors
When the function is created with FunctionTemplate and set name with native data property accessors, binding the function should throw immediately if the native accessor throws. Bug: v8:11989 Change-Id: Ief282202aa5b8515f581fd5478886ed5f001fd4f Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3492966 Reviewed-by: Shu-yu Guo <syg@chromium.org> Commit-Queue: Chengzhong Wu <legendecas@gmail.com> Cr-Commit-Position: refs/heads/main@{#79356}
This commit is contained in:
parent
a0b25ebd75
commit
8e18ea3913
@ -207,16 +207,18 @@ Object DoFunctionBind(Isolate* isolate, BuiltinArguments args) {
|
||||
isolate, function,
|
||||
isolate->factory()->NewJSBoundFunction(target, this_arg, argv));
|
||||
|
||||
LookupIterator length_lookup(isolate, target,
|
||||
isolate->factory()->length_string(), target,
|
||||
LookupIterator::OWN);
|
||||
// Setup the "length" property based on the "length" of the {target}.
|
||||
// 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.
|
||||
Handle<AccessorInfo> function_length_accessor =
|
||||
isolate->factory()->function_length_accessor();
|
||||
LookupIterator length_lookup(isolate, target,
|
||||
isolate->factory()->length_string(), target,
|
||||
LookupIterator::OWN);
|
||||
if (!target->IsJSFunction() ||
|
||||
length_lookup.state() != LookupIterator::ACCESSOR ||
|
||||
!length_lookup.GetAccessors()->IsAccessorInfo()) {
|
||||
!length_lookup.GetAccessors().is_identical_to(function_length_accessor)) {
|
||||
Handle<Object> length(Smi::zero(), isolate);
|
||||
Maybe<PropertyAttributes> attributes =
|
||||
JSReceiver::GetPropertyAttributes(&length_lookup);
|
||||
@ -242,11 +244,13 @@ Object DoFunctionBind(Isolate* isolate, BuiltinArguments args) {
|
||||
// If the target's 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.
|
||||
Handle<AccessorInfo> function_name_accessor =
|
||||
isolate->factory()->function_name_accessor();
|
||||
LookupIterator name_lookup(isolate, target, isolate->factory()->name_string(),
|
||||
target);
|
||||
if (!target->IsJSFunction() ||
|
||||
name_lookup.state() != LookupIterator::ACCESSOR ||
|
||||
!name_lookup.GetAccessors()->IsAccessorInfo() ||
|
||||
!name_lookup.GetAccessors().is_identical_to(function_name_accessor) ||
|
||||
(name_lookup.IsFound() && !name_lookup.HolderIsReceiver())) {
|
||||
Handle<Object> target_name;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, target_name,
|
||||
@ -257,8 +261,9 @@ Object DoFunctionBind(Isolate* isolate, BuiltinArguments args) {
|
||||
isolate, name,
|
||||
Name::ToFunctionName(isolate, Handle<String>::cast(target_name)));
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, name, isolate->factory()->NewConsString(
|
||||
isolate->factory()->bound__string(), name));
|
||||
isolate, name,
|
||||
isolate->factory()->NewConsString(isolate->factory()->bound__string(),
|
||||
name));
|
||||
} else {
|
||||
name = isolate->factory()->bound__string();
|
||||
}
|
||||
|
@ -778,3 +778,42 @@ TEST(ObjectTemplateSetLazyPropertyHasNoSideEffect) {
|
||||
->Int32Value(env.local())
|
||||
.FromJust());
|
||||
}
|
||||
|
||||
namespace {
|
||||
void FunctionNativeGetter(v8::Local<v8::String> property,
|
||||
const v8::PropertyCallbackInfo<v8::Value>& info) {
|
||||
info.GetIsolate()->ThrowError(v8_str("side effect in getter"));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST(BindFunctionTemplateSetNativeDataProperty) {
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
// Check that getter is called on Function.prototype.bind.
|
||||
{
|
||||
v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
|
||||
templ->SetNativeDataProperty(v8_str("name"), FunctionNativeGetter);
|
||||
v8::Local<v8::Function> func =
|
||||
templ->GetFunction(env.local()).ToLocalChecked();
|
||||
CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
|
||||
|
||||
v8::TryCatch try_catch(isolate);
|
||||
CHECK(CompileRun("func.bind()").IsEmpty());
|
||||
CHECK(try_catch.HasCaught());
|
||||
}
|
||||
|
||||
// Check that getter is called on Function.prototype.bind.
|
||||
{
|
||||
v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
|
||||
templ->SetNativeDataProperty(v8_str("length"), FunctionNativeGetter);
|
||||
v8::Local<v8::Function> func =
|
||||
templ->GetFunction(env.local()).ToLocalChecked();
|
||||
CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
|
||||
|
||||
v8::TryCatch try_catch(isolate);
|
||||
CHECK(CompileRun("func.bind()").IsEmpty());
|
||||
CHECK(try_catch.HasCaught());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user