Added: trunk/JSTests/stress/builtin-function-length.js (0 => 220324)
--- trunk/JSTests/stress/builtin-function-length.js (rev 0)
+++ trunk/JSTests/stress/builtin-function-length.js 2017-08-06 17:57:26 UTC (rev 220324)
@@ -0,0 +1,47 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+function shouldThrow(func, errorMessage) {
+ var errorThrown = false;
+ var error = null;
+ try {
+ func();
+ } catch (e) {
+ errorThrown = true;
+ error = e;
+ }
+ if (!errorThrown)
+ throw new Error('not thrown');
+ if (String(error) !== errorMessage)
+ throw new Error(`bad error: ${String(error)}`);
+}
+
+{
+ shouldBe(JSON.stringify(Object.getOwnPropertyNames(Array.prototype.filter).sort()), `["length","name"]`);
+ shouldBe(Array.prototype.filter.length, 1);
+ shouldBe(JSON.stringify(Object.getOwnPropertyDescriptor(Array.prototype.filter, 'length')), `{"value":1,"writable":false,"enumerable":false,"configurable":true}`);
+ shouldBe(delete Array.prototype.filter.length, true);
+ shouldBe(JSON.stringify(Object.getOwnPropertyNames(Array.prototype.filter).sort()), `["name"]`);
+}
+
+{
+ shouldThrow(function () {
+ "use strict";
+ Array.prototype.forEach.length = 42;
+ }, `TypeError: Attempted to assign to readonly property.`);
+}
+
+{
+ var resolve = null;
+ var reject = null;
+ new Promise(function (arg0, arg1) {
+ resolve = arg0;
+ reject = arg1;
+ });
+ shouldBe(resolve.length, 1);
+ shouldBe(JSON.stringify(Object.getOwnPropertyDescriptor(resolve, 'length')), `{"value":1,"writable":false,"enumerable":false,"configurable":true}`);
+ shouldBe(reject.length, 1);
+ shouldBe(JSON.stringify(Object.getOwnPropertyDescriptor(reject, 'length')), `{"value":1,"writable":false,"enumerable":false,"configurable":true}`);
+}
Modified: trunk/Source/_javascript_Core/runtime/JSFunction.cpp (220323 => 220324)
--- trunk/Source/_javascript_Core/runtime/JSFunction.cpp 2017-08-06 13:04:32 UTC (rev 220323)
+++ trunk/Source/_javascript_Core/runtime/JSFunction.cpp 2017-08-06 17:57:26 UTC (rev 220324)
@@ -105,7 +105,6 @@
{
JSFunction* function = create(vm, executable, globalObject);
function->putDirect(vm, vm.propertyNames->name, jsString(&vm, executable->name().string()), ReadOnly | DontEnum);
- function->putDirect(vm, vm.propertyNames->length, jsNumber(executable->parameterCount()), ReadOnly | DontEnum);
return function;
}
@@ -113,7 +112,6 @@
{
JSFunction* function = create(vm, executable, globalObject);
function->putDirect(vm, vm.propertyNames->name, jsString(&vm, name), ReadOnly | DontEnum);
- function->putDirect(vm, vm.propertyNames->length, jsNumber(executable->parameterCount()), ReadOnly | DontEnum);
return function;
}
@@ -350,7 +348,7 @@
VM& vm = exec->vm();
JSFunction* thisObject = jsCast<JSFunction*>(object);
if (thisObject->isHostOrBuiltinFunction()) {
- thisObject->reifyBoundNameIfNeeded(vm, exec, propertyName);
+ thisObject->reifyLazyPropertyForHostOrBuiltinIfNeeded(vm, exec, propertyName);
return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
}
@@ -402,21 +400,27 @@
{
JSFunction* thisObject = jsCast<JSFunction*>(object);
VM& vm = exec->vm();
- if (!thisObject->isHostOrBuiltinFunction() && mode.includeDontEnumProperties()) {
- // Make sure prototype has been reified.
- PropertySlot slot(thisObject, PropertySlot::InternalMethodType::VMInquiry);
- thisObject->methodTable(vm)->getOwnPropertySlot(thisObject, exec, vm.propertyNames->prototype, slot);
+ if (mode.includeDontEnumProperties()) {
+ if (!thisObject->isHostOrBuiltinFunction()) {
+ // Make sure prototype has been reified.
+ PropertySlot slot(thisObject, PropertySlot::InternalMethodType::VMInquiry);
+ thisObject->methodTable(vm)->getOwnPropertySlot(thisObject, exec, vm.propertyNames->prototype, slot);
- if (thisObject->jsExecutable()->hasCallerAndArgumentsProperties()) {
- propertyNames.add(vm.propertyNames->arguments);
- propertyNames.add(vm.propertyNames->caller);
+ if (thisObject->jsExecutable()->hasCallerAndArgumentsProperties()) {
+ propertyNames.add(vm.propertyNames->arguments);
+ propertyNames.add(vm.propertyNames->caller);
+ }
+ if (!thisObject->hasReifiedLength())
+ propertyNames.add(vm.propertyNames->length);
+ if (!thisObject->hasReifiedName())
+ propertyNames.add(vm.propertyNames->name);
+ } else {
+ if (thisObject->isBuiltinFunction() && !thisObject->hasReifiedLength())
+ propertyNames.add(vm.propertyNames->length);
+ if (thisObject->inherits(vm, JSBoundFunction::info()) && !thisObject->hasReifiedName())
+ propertyNames.add(vm.propertyNames->name);
}
- if (!thisObject->hasReifiedLength())
- propertyNames.add(vm.propertyNames->length);
- if (!thisObject->hasReifiedName())
- propertyNames.add(vm.propertyNames->name);
- } else if (thisObject->isHostOrBuiltinFunction() && mode.includeDontEnumProperties() && thisObject->inherits(vm, JSBoundFunction::info()) && !thisObject->hasReifiedName())
- propertyNames.add(exec->vm().propertyNames->name);
+ }
Base::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode);
}
@@ -433,7 +437,7 @@
}
if (thisObject->isHostOrBuiltinFunction()) {
- LazyPropertyType propType = thisObject->reifyBoundNameIfNeeded(vm, exec, propertyName);
+ LazyPropertyType propType = thisObject->reifyLazyPropertyForHostOrBuiltinIfNeeded(vm, exec, propertyName);
if (propType == LazyPropertyType::IsLazyProperty)
slot.disableCaching();
scope.release();
@@ -475,12 +479,12 @@
bool JSFunction::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
{
+ VM& vm = exec->vm();
JSFunction* thisObject = jsCast<JSFunction*>(cell);
if (thisObject->isHostOrBuiltinFunction())
- thisObject->reifyBoundNameIfNeeded(exec->vm(), exec, propertyName);
- else if (exec->vm().deletePropertyMode() != VM::DeletePropertyMode::IgnoreConfigurable) {
+ thisObject->reifyLazyPropertyForHostOrBuiltinIfNeeded(vm, exec, propertyName);
+ else if (vm.deletePropertyMode() != VM::DeletePropertyMode::IgnoreConfigurable) {
// For non-host functions, don't let these properties by deleted - except by DefineOwnProperty.
- VM& vm = exec->vm();
FunctionExecutable* executable = thisObject->jsExecutable();
if (propertyName == exec->propertyNames().caller || propertyName == exec->propertyNames().arguments)
@@ -502,7 +506,7 @@
JSFunction* thisObject = jsCast<JSFunction*>(object);
if (thisObject->isHostOrBuiltinFunction()) {
- thisObject->reifyBoundNameIfNeeded(vm, exec, propertyName);
+ thisObject->reifyLazyPropertyForHostOrBuiltinIfNeeded(vm, exec, propertyName);
scope.release();
return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
}
@@ -680,11 +684,9 @@
JSFunction::LazyPropertyType JSFunction::reifyLazyPropertyIfNeeded(VM& vm, ExecState* exec, PropertyName propertyName)
{
- if (propertyName == vm.propertyNames->length) {
- if (!hasReifiedLength())
- reifyLength(vm);
+ if (reifyLazyLengthIfNeeded(vm, exec, propertyName) == LazyPropertyType::IsLazyProperty)
return LazyPropertyType::IsLazyProperty;
- } else if (propertyName == vm.propertyNames->name) {
+ if (propertyName == vm.propertyNames->name) {
if (!hasReifiedName())
reifyName(vm, exec);
return LazyPropertyType::IsLazyProperty;
@@ -692,8 +694,28 @@
return LazyPropertyType::NotLazyProperty;
}
-JSFunction::LazyPropertyType JSFunction::reifyBoundNameIfNeeded(VM& vm, ExecState* exec, PropertyName propertyName)
+JSFunction::LazyPropertyType JSFunction::reifyLazyPropertyForHostOrBuiltinIfNeeded(VM& vm, ExecState* exec, PropertyName propertyName)
{
+ ASSERT(isHostOrBuiltinFunction());
+ if (isBuiltinFunction()) {
+ if (reifyLazyLengthIfNeeded(vm, exec, propertyName) == LazyPropertyType::IsLazyProperty)
+ return LazyPropertyType::IsLazyProperty;
+ }
+ return reifyLazyBoundNameIfNeeded(vm, exec, propertyName);
+}
+
+JSFunction::LazyPropertyType JSFunction::reifyLazyLengthIfNeeded(VM& vm, ExecState*, PropertyName propertyName)
+{
+ if (propertyName == vm.propertyNames->length) {
+ if (!hasReifiedLength())
+ reifyLength(vm);
+ return LazyPropertyType::IsLazyProperty;
+ }
+ return LazyPropertyType::NotLazyProperty;
+}
+
+JSFunction::LazyPropertyType JSFunction::reifyLazyBoundNameIfNeeded(VM& vm, ExecState* exec, PropertyName propertyName)
+{
const Identifier& nameIdent = vm.propertyNames->name;
if (propertyName != nameIdent)
return LazyPropertyType::NotLazyProperty;
Modified: trunk/Source/_javascript_Core/runtime/JSFunction.h (220323 => 220324)
--- trunk/Source/_javascript_Core/runtime/JSFunction.h 2017-08-06 13:04:32 UTC (rev 220323)
+++ trunk/Source/_javascript_Core/runtime/JSFunction.h 2017-08-06 17:57:26 UTC (rev 220324)
@@ -190,7 +190,9 @@
enum class LazyPropertyType { NotLazyProperty, IsLazyProperty };
LazyPropertyType reifyLazyPropertyIfNeeded(VM&, ExecState*, PropertyName);
- LazyPropertyType reifyBoundNameIfNeeded(VM&, ExecState*, PropertyName);
+ LazyPropertyType reifyLazyPropertyForHostOrBuiltinIfNeeded(VM&, ExecState*, PropertyName);
+ LazyPropertyType reifyLazyLengthIfNeeded(VM&, ExecState*, PropertyName);
+ LazyPropertyType reifyLazyBoundNameIfNeeded(VM&, ExecState*, PropertyName);
friend class LLIntOffsetsExtractor;