}
+MUST_USE_RESULT static MaybeHandle<Object> SetFunctionName(
+ Isolate* isolate, Handle<JSFunction> function, Handle<Object> value) {
+ Handle<Object> old_value;
+ bool is_observed = function->map()->is_observed();
+ if (is_observed) {
+ old_value = handle(function->shared()->name(), isolate);
+ }
+
+ Handle<Name> name = isolate->factory()->name_string();
+ LookupIterator it(function, name);
+ CHECK_EQ(LookupIterator::ACCESSOR, it.state());
+ DCHECK(it.HolderIsReceiverOrHiddenPrototype());
+ it.ReconfigureDataProperty(value, it.property_details().attributes());
+ value = it.WriteDataValue(value);
+
+ if (is_observed && !old_value->SameValue(*value)) {
+ return JSObject::EnqueueChangeRecord(function, "update", name, old_value);
+ }
+
+ return value;
+}
+
+
void Accessors::FunctionNameSetter(
v8::Local<v8::Name> name,
v8::Local<v8::Value> val,
const v8::PropertyCallbackInfo<void>& info) {
- // Function name is non writable, non configurable.
- UNREACHABLE();
+ i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
+ HandleScope scope(isolate);
+ Handle<Object> value = Utils::OpenHandle(*val);
+
+ if (SetPropertyOnInstanceIfInherited(isolate, info, name, value)) return;
+
+ Handle<JSFunction> object =
+ Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
+ if (SetFunctionName(isolate, object, value).is_null()) {
+ isolate->OptionalRescheduleException(false);
+ }
}
int size = IsFunctionModeWithPrototype(function_mode) ? 5 : 4;
Map::EnsureDescriptorSlack(map, size);
- PropertyAttributes attribs = static_cast<PropertyAttributes>(
- DONT_ENUM | DONT_DELETE | READ_ONLY);
+ PropertyAttributes ro_attribs =
+ static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
+ PropertyAttributes roc_attribs =
+ static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
Handle<AccessorInfo> length =
- Accessors::FunctionLengthInfo(isolate(), attribs);
+ Accessors::FunctionLengthInfo(isolate(), ro_attribs);
{ // Add length.
AccessorConstantDescriptor d(Handle<Name>(Name::cast(length->name())),
- length, attribs);
+ length, ro_attribs);
map->AppendDescriptor(&d);
}
Handle<AccessorInfo> name =
- Accessors::FunctionNameInfo(isolate(), attribs);
+ Accessors::FunctionNameInfo(isolate(), ro_attribs);
{ // Add name.
AccessorConstantDescriptor d(Handle<Name>(Name::cast(name->name())), name,
- attribs);
+ roc_attribs);
map->AppendDescriptor(&d);
}
Handle<AccessorInfo> args =
- Accessors::FunctionArgumentsInfo(isolate(), attribs);
+ Accessors::FunctionArgumentsInfo(isolate(), ro_attribs);
{ // Add arguments.
AccessorConstantDescriptor d(Handle<Name>(Name::cast(args->name())), args,
- attribs);
+ ro_attribs);
map->AppendDescriptor(&d);
}
Handle<AccessorInfo> caller =
- Accessors::FunctionCallerInfo(isolate(), attribs);
+ Accessors::FunctionCallerInfo(isolate(), ro_attribs);
{ // Add caller.
AccessorConstantDescriptor d(Handle<Name>(Name::cast(caller->name())),
- caller, attribs);
+ caller, ro_attribs);
map->AppendDescriptor(&d);
}
if (IsFunctionModeWithPrototype(function_mode)) {
if (function_mode == FUNCTION_WITH_WRITEABLE_PROTOTYPE) {
- attribs = static_cast<PropertyAttributes>(attribs & ~READ_ONLY);
+ ro_attribs = static_cast<PropertyAttributes>(ro_attribs & ~READ_ONLY);
}
Handle<AccessorInfo> prototype =
- Accessors::FunctionPrototypeInfo(isolate(), attribs);
+ Accessors::FunctionPrototypeInfo(isolate(), ro_attribs);
AccessorConstantDescriptor d(Handle<Name>(Name::cast(prototype->name())),
- prototype, attribs);
+ prototype, ro_attribs);
map->AppendDescriptor(&d);
}
}
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
PropertyAttributes ro_attribs =
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
+ PropertyAttributes roc_attribs =
+ static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
// Add length.
if (function_mode == BOUND_FUNCTION) {
map->AppendDescriptor(&d);
}
Handle<AccessorInfo> name =
- Accessors::FunctionNameInfo(isolate(), ro_attribs);
+ Accessors::FunctionNameInfo(isolate(), roc_attribs);
{ // Add name.
AccessorConstantDescriptor d(Handle<Name>(Name::cast(name->name())), name,
- ro_attribs);
+ roc_attribs);
map->AppendDescriptor(&d);
}
{ // Add arguments.
--- /dev/null
+// Copyright 2015 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.
+
+function getStrictF() {
+ 'use strict';
+ return function f() {};
+}
+
+
+function getSloppyF() {
+ return function f() {};
+}
+
+
+function test(testFunction) {
+ testFunction(getStrictF());
+ testFunction(getSloppyF());
+}
+
+
+function testDescriptor(f) {
+ var descr = Object.getOwnPropertyDescriptor(f, 'name');
+ assertTrue(descr.configurable);
+ assertFalse(descr.enumerable);
+ assertEquals('f', descr.value);
+ assertFalse(descr.writable);
+}
+test(testDescriptor);
+
+
+function testSet(f) {
+ f.name = 'g';
+ assertEquals('f', f.name);
+}
+test(testSet);
+
+
+function testSetStrict(f) {
+ 'use strict';
+ assertThrows(function() {
+ f.name = 'g';
+ }, TypeError);
+}
+test(testSetStrict);
+
+
+function testReconfigureAsDataProperty(f) {
+ Object.defineProperty(f, 'name', {
+ value: 'g',
+ });
+ assertEquals('g', f.name);
+ Object.defineProperty(f, 'name', {
+ writable: true
+ });
+ f.name = 'h';
+ assertEquals('h', f.name);
+
+ f.name = 42;
+ assertEquals(42, f.name);
+}
+test(testReconfigureAsDataProperty);
+
+
+function testReconfigureAsAccessorProperty(f) {
+ var name = 'g';
+ Object.defineProperty(f, 'name', {
+ get: function() { return name; },
+ set: function(v) { name = v; }
+ });
+ assertEquals('g', f.name);
+ f.name = 'h';
+ assertEquals('h', f.name);
+}
+test(testReconfigureAsAccessorProperty);
+
+
+function testFunctionToString(f) {
+ Object.defineProperty(f, 'name', {
+ value: {toString: function() { assertUnreachable(); }},
+ });
+ assertEquals('function f() {}', f.toString());
+}
+test(testFunctionToString);
+
+
+(function testSetOnInstance() {
+ // This needs to come before testDelete below
+ assertTrue(Function.prototype.hasOwnProperty('name'));
+
+ function f() {}
+ delete f.name;
+ assertEquals('Empty', f.name);
+
+ f.name = 42;
+ assertEquals('Empty', f.name); // non writable prototype property.
+ assertFalse(f.hasOwnProperty('name'));
+
+ Object.defineProperty(Function.prototype, 'name', {writable: true});
+
+ f.name = 123;
+ assertTrue(f.hasOwnProperty('name'));
+ assertEquals(123, f.name);
+})();
+
+
+(function testDelete() {
+ function f() {}
+ assertTrue(delete f.name);
+ assertFalse(f.hasOwnProperty('name'));
+ assertEquals('Empty', f.name);
+
+ assertTrue(delete Function.prototype.name);
+ assertEquals(undefined, f.name);
+})();
function blacklisted(obj, prop) {
return (obj instanceof Int32Array && prop == 1) ||
(obj instanceof Int32Array && prop === "length") ||
- (obj instanceof ArrayBuffer && prop == 1)
+ (obj instanceof ArrayBuffer && prop == 1) ||
+ (obj instanceof Function && prop === "name"); // Has its own test.
}
for (var i in objects) for (var j in properties) {
for (var n = 0; n < 3; ++n)
for (var i in mutationByIncr)
TestFastElementsLength(mutationByIncr[i], b1 != 0, b2 != 0, 7*n, 7*n+1);
+
+
+(function TestFunctionName() {
+ reset();
+
+ function fun() {}
+ Object.observe(fun, observer.callback);
+ fun.name = 'x'; // No change. Not writable.
+ Object.defineProperty(fun, 'name', {value: 'a'});
+ Object.defineProperty(fun, 'name', {writable: true});
+ fun.name = 'b';
+ delete fun.name;
+ fun.name = 'x'; // No change. Function.prototype.name is non writable
+ Object.defineProperty(Function.prototype, 'name', {writable: true});
+ fun.name = 'c';
+ fun.name = 'c'; // Same, no update.
+ Object.deliverChangeRecords(observer.callback);
+ observer.assertCallbackRecords([
+ { object: fun, type: 'update', name: 'name', oldValue: 'fun' },
+ { object: fun, type: 'reconfigure', name: 'name'},
+ { object: fun, type: 'update', name: 'name', oldValue: 'a' },
+ { object: fun, type: 'delete', name: 'name', oldValue: 'b' },
+ { object: fun, type: 'add', name: 'name' },
+ ]);
+})();
assertThrows("'use strict'; f.prototype = {}");
assertThrows("Object.defineProperty(f, 'prototype', { value: {} })");
-// Verify that non-writability of other properties is respected.
-assertThrows("Object.defineProperty(f, 'name', { value: {} })");
+// Verify that non-configurability of other properties is respected, but
+// non-writability is ignored by Object.defineProperty().
+Object.defineProperty(f, 'name', { value: {} });
assertThrows("Object.defineProperty(f, 'length', { value: {} })");
assertThrows("Object.defineProperty(f, 'caller', { value: {} })");
assertThrows("Object.defineProperty(f, 'arguments', { value: {} })");
function checkNameDescriptor(f) {
var descriptor = Object.getOwnPropertyDescriptor(f, "name");
- assertFalse(descriptor.configurable);
+ assertTrue(descriptor.configurable);
assertFalse(descriptor.enumerable);
assertFalse(descriptor.writable);
}