put_by_val_direct need to check the property is index or not for using putDirect...
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 20 Jan 2015 21:14:48 +0000 (21:14 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 20 Jan 2015 21:14:48 +0000 (21:14 +0000)
https://bugs.webkit.org/show_bug.cgi?id=140426

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

In the put_by_val_direct operation, we use JSObject::putDirect.
However, it only accepts non-index property. For index property, we need to use JSObject::putDirectIndex.
This patch changes Identifier::asIndex() to return Optional<uint32_t>.
It forces callers to check the value is index or not explicitly.
Additionally, it checks toString-ed Identifier is index or not to choose putDirect / putDirectIndex.

* bytecode/GetByIdStatus.cpp:
(JSC::GetByIdStatus::computeFor):
* bytecode/PutByIdStatus.cpp:
(JSC::PutByIdStatus::computeFor):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitDirectPutById):
* dfg/DFGOperations.cpp:
(JSC::DFG::operationPutByValInternal):
* jit/JITOperations.cpp:
* jit/Repatch.cpp:
(JSC::emitPutTransitionStubAndGetOldStructure):
* jsc.cpp:
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* runtime/Arguments.cpp:
(JSC::Arguments::getOwnPropertySlot):
(JSC::Arguments::put):
(JSC::Arguments::deleteProperty):
(JSC::Arguments::defineOwnProperty):
* runtime/ArrayPrototype.cpp:
(JSC::arrayProtoFuncSort):
* runtime/JSArray.cpp:
(JSC::JSArray::defineOwnProperty):
* runtime/JSCJSValue.cpp:
(JSC::JSValue::putToPrimitive):
* runtime/JSGenericTypedArrayViewInlines.h:
(JSC::JSGenericTypedArrayView<Adaptor>::getOwnPropertySlot):
(JSC::JSGenericTypedArrayView<Adaptor>::put):
(JSC::JSGenericTypedArrayView<Adaptor>::defineOwnProperty):
(JSC::JSGenericTypedArrayView<Adaptor>::deleteProperty):
* runtime/JSObject.cpp:
(JSC::JSObject::put):
(JSC::JSObject::putDirectAccessor):
(JSC::JSObject::putDirectCustomAccessor):
(JSC::JSObject::deleteProperty):
(JSC::JSObject::putDirectMayBeIndex):
(JSC::JSObject::defineOwnProperty):
* runtime/JSObject.h:
(JSC::JSObject::getOwnPropertySlot):
(JSC::JSObject::getPropertySlot):
(JSC::JSObject::putDirectInternal):
* runtime/JSString.cpp:
(JSC::JSString::getStringPropertyDescriptor):
* runtime/JSString.h:
(JSC::JSString::getStringPropertySlot):
* runtime/LiteralParser.cpp:
(JSC::LiteralParser<CharType>::parse):
* runtime/PropertyName.h:
(JSC::toUInt32FromCharacters):
(JSC::toUInt32FromStringImpl):
(JSC::PropertyName::asIndex):
* runtime/PropertyNameArray.cpp:
(JSC::PropertyNameArray::add):
* runtime/StringObject.cpp:
(JSC::StringObject::deleteProperty):
* runtime/Structure.cpp:
(JSC::Structure::prototypeChainMayInterceptStoreTo):

Source/WebCore:

Test: js/dfg-put-by-val-direct-with-edge-numbers.html

* bindings/js/JSDOMWindowCustom.cpp:
(WebCore::JSDOMWindow::getOwnPropertySlot):
* bindings/js/JSHTMLAllCollectionCustom.cpp:
(WebCore::callHTMLAllCollection):
(WebCore::JSHTMLAllCollection::item):
* bindings/scripts/CodeGeneratorJS.pm:
(GenerateGetOwnPropertySlotBody):
(GenerateImplementation):
* bindings/scripts/test/JS/JSFloat64Array.cpp:
(WebCore::JSFloat64Array::getOwnPropertySlot):
(WebCore::JSFloat64Array::getOwnPropertyDescriptor):
(WebCore::JSFloat64Array::put):
* bindings/scripts/test/JS/JSTestEventTarget.cpp:
(WebCore::JSTestEventTarget::getOwnPropertySlot):
* bridge/runtime_array.cpp:
(JSC::RuntimeArray::getOwnPropertySlot):
(JSC::RuntimeArray::put):

LayoutTests:

* js/dfg-put-by-val-direct-with-edge-numbers-expected.txt: Added.
* js/dfg-put-by-val-direct-with-edge-numbers.html: Added.
* js/script-tests/dfg-put-by-val-direct-with-edge-numbers.js: Added.
(lookupWithKey):
(lookupWithKey2):
(toStringThrowsError.toString):
* resources/js-test-pre.js:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@178751 268f45cc-cd09-0410-ab3c-d52691b4dbfc

35 files changed:
LayoutTests/ChangeLog
LayoutTests/js/dfg-put-by-val-direct-with-edge-numbers-expected.txt [new file with mode: 0644]
LayoutTests/js/dfg-put-by-val-direct-with-edge-numbers.html [new file with mode: 0644]
LayoutTests/js/script-tests/dfg-put-by-val-direct-with-edge-numbers.js [new file with mode: 0644]
LayoutTests/resources/js-test-pre.js
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecode/GetByIdStatus.cpp
Source/JavaScriptCore/bytecode/PutByIdStatus.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/jit/JITOperations.cpp
Source/JavaScriptCore/jit/Repatch.cpp
Source/JavaScriptCore/jsc.cpp
Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
Source/JavaScriptCore/runtime/Arguments.cpp
Source/JavaScriptCore/runtime/ArrayPrototype.cpp
Source/JavaScriptCore/runtime/JSArray.cpp
Source/JavaScriptCore/runtime/JSCJSValue.cpp
Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h
Source/JavaScriptCore/runtime/JSObject.cpp
Source/JavaScriptCore/runtime/JSObject.h
Source/JavaScriptCore/runtime/JSString.cpp
Source/JavaScriptCore/runtime/JSString.h
Source/JavaScriptCore/runtime/LiteralParser.cpp
Source/JavaScriptCore/runtime/PropertyName.h
Source/JavaScriptCore/runtime/PropertyNameArray.cpp
Source/JavaScriptCore/runtime/StringObject.cpp
Source/JavaScriptCore/runtime/Structure.cpp
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/JSDOMWindowCustom.cpp
Source/WebCore/bindings/js/JSHTMLAllCollectionCustom.cpp
Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
Source/WebCore/bindings/scripts/test/JS/JSFloat64Array.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestEventTarget.cpp
Source/WebCore/bridge/runtime_array.cpp

index 33fbd8f..4ef460e 100644 (file)
@@ -1,3 +1,18 @@
+2015-01-20  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        put_by_val_direct need to check the property is index or not for using putDirect / putDirectIndex
+        https://bugs.webkit.org/show_bug.cgi?id=140426
+
+        Reviewed by Geoffrey Garen.
+
+        * js/dfg-put-by-val-direct-with-edge-numbers-expected.txt: Added.
+        * js/dfg-put-by-val-direct-with-edge-numbers.html: Added.
+        * js/script-tests/dfg-put-by-val-direct-with-edge-numbers.js: Added.
+        (lookupWithKey):
+        (lookupWithKey2):
+        (toStringThrowsError.toString):
+        * resources/js-test-pre.js:
+
 2015-01-20  Jeremy Jones  <jeremyj@apple.com>
 
         [mac] Fix test expectations after r178188
diff --git a/LayoutTests/js/dfg-put-by-val-direct-with-edge-numbers-expected.txt b/LayoutTests/js/dfg-put-by-val-direct-with-edge-numbers-expected.txt
new file mode 100644 (file)
index 0000000..316596d
--- /dev/null
@@ -0,0 +1,60 @@
+Test that a object accepts DFG PutByValueDirect operation with edge numbers.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS lookupWithKey(-0x80000001) is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey(-0x80000000) is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey(-1) is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey(0) is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey(1) is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey(0x7fffffff) is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey(0x80000000) is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey(0xfffffffd) is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey(0xfffffffe) is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey(0xffffffff) is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey(0x100000000) is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey("-2147483649") is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey("-2147483648") is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey("-1") is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey("0") is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey("1") is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey("2147483647") is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey("2147483648") is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey("4294967293") is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey("4294967294") is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey("4294967295") is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey("4294967296") is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey(Number.MIN_VALUE) is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey(Number.MAX_VALUE) is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey(Number.MIN_SAFE_INTEGER) is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey(Number.MAX_SAFE_INTEGER) is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey(Number.POSITIVE_INFINITY) is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey(Number.NEGATIVE_INFINITY) is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey(Number.NaN) is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey(Number.EPSILON) is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey(+0.0) is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey(-0.0) is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey(0.1) is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey(-0.1) is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey(4.2) is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey(-4.2) is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey("5e-324") is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey("1.7976931348623157e+308") is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey("-9007199254740991") is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey("9007199254740991") is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey("Infinity") is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey("-Infinity") is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey("NaN") is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey("2.220446049250313e-16") is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey("+0.0") is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey("-0.0") is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey("0.1") is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey("-0.1") is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey("4.2") is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey("-4.2") is 42 on all iterations including after DFG tier-up.
+PASS lookupWithKey2(toStringThrowsError) threw exception 'Error: ng' on all iterations including after DFG tier-up.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/dfg-put-by-val-direct-with-edge-numbers.html b/LayoutTests/js/dfg-put-by-val-direct-with-edge-numbers.html
new file mode 100644 (file)
index 0000000..07b4f54
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="script-tests/dfg-put-by-val-direct-with-edge-numbers.js"></script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/script-tests/dfg-put-by-val-direct-with-edge-numbers.js b/LayoutTests/js/script-tests/dfg-put-by-val-direct-with-edge-numbers.js
new file mode 100644 (file)
index 0000000..1a9c446
--- /dev/null
@@ -0,0 +1,86 @@
+description(
+"Test that a object accepts DFG PutByValueDirect operation with edge numbers."
+);
+
+function lookupWithKey(key) {
+    var object = {
+        [key]: 42
+    };
+    return object[key];
+}
+
+[
+    // integers
+    '-0x80000001',  // out of int32_t
+    '-0x80000000',  // int32_t min
+    '-1',           // negative
+    '0',            // zero
+    '1',            // positive
+    '0x7fffffff',   // int32_t max
+    '0x80000000',   // out of int32_t
+    '0xfffffffd',   // less than array max in JSObject
+    '0xfffffffe',   // array max in JSObject
+    '0xffffffff',   // uint32_t max, PropertyName::NotAnIndex
+    '0x100000000',  // out of uint32_t
+
+    // stringified integers
+    '"' + (-0x80000001).toString() + '"',  // out of int32_t
+    '"' + (-0x80000000).toString() + '"',  // int32_t min
+    '"' + (-1).toString() + '"',           // negative
+    '"' + (0).toString() + '"',            // zero
+    '"' + (1).toString() + '"',            // positive
+    '"' + (0x7fffffff).toString() + '"',   // int32_t max
+    '"' + (0x80000000).toString() + '"',   // out of int32_t
+    '"' + (0xfffffffd).toString() + '"',   // less than array max in JSObject
+    '"' + (0xfffffffe).toString() + '"',   // array max in JSObject
+    '"' + (0xffffffff).toString() + '"',   // uint32_t max).toString() PropertyName::NotAnIndex
+    '"' + (0x100000000).toString() + '"',  // out of uint32_t
+
+    // doubles
+    'Number.MIN_VALUE',
+    'Number.MAX_VALUE',
+    'Number.MIN_SAFE_INTEGER',
+    'Number.MAX_SAFE_INTEGER',
+    'Number.POSITIVE_INFINITY',
+    'Number.NEGATIVE_INFINITY',
+    'Number.NaN',
+    'Number.EPSILON',
+    '+0.0',
+    '-0.0',
+    '0.1',
+    '-0.1',
+    '4.2',
+    '-4.2',
+
+    // stringified doules
+    '"' + (Number.MIN_VALUE).toString() + '"',
+    '"' + (Number.MAX_VALUE).toString() + '"',
+    '"' + (Number.MIN_SAFE_INTEGER).toString() + '"',
+    '"' + (Number.MAX_SAFE_INTEGER).toString() + '"',
+    '"' + (Number.POSITIVE_INFINITY).toString() + '"',
+    '"' + (Number.NEGATIVE_INFINITY).toString() + '"',
+    '"NaN"',
+    '"' + (Number.EPSILON).toString() + '"',
+    '"+0.0"',
+    '"-0.0"',
+    '"0.1"',
+    '"-0.1"',
+    '"4.2"',
+    '"-4.2"',
+].forEach(function (key) {
+    dfgShouldBe(lookupWithKey, "lookupWithKey("+ key + ")", "42");
+});
+
+function lookupWithKey2(key) {
+    var object = {
+        [key]: 42
+    };
+    return object[key];
+}
+
+var toStringThrowsError = {
+    toString: function () {
+        throw new Error('ng');
+    }
+};
+dfgShouldThrow(lookupWithKey2, "lookupWithKey2(toStringThrowsError)", "'Error: ng'");
index f11b4b5..ff4559f 100644 (file)
@@ -617,6 +617,54 @@ function shouldThrow(_a, _e)
     testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was " + _av + ".");
 }
 
+function dfgShouldThrow(theFunction, _a, _e)
+{
+  if (typeof theFunction != "function" || typeof _a != "string" || typeof _e != "string")
+    debug("WARN: dfgShouldBe() expects a function and two strings");
+  noInline(theFunction);
+  var values = [], _av = undefined, notThrow = false;
+
+  // Defend against tests that muck with numeric properties on array.prototype.
+  values.__proto__ = null;
+  values.push = Array.prototype.push;
+
+  while (!dfgCompiled({f:theFunction})) {
+    try {
+        _av = eval(_a);
+        notThrow = true;
+    } catch (exception) {
+        values.push(exception);
+    }
+  }
+  try {
+    _av = eval(_a);
+    notThrow = true;
+  } catch (exception) {
+    values.push(exception);
+  }
+
+  var _ev = eval(_e);
+  if (notThrow) {
+    if (typeof _av == "undefined")
+      testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was undefined.");
+    else
+      testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was " + _av + ".");
+  } else {
+    var allPassed = true;
+    for (var i = 0; i < values.length; ++i) {
+      var _av = values[i];
+      if (typeof _e == "undefined" || _av == _ev)
+        continue;
+      testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Threw exception " + _av + ".");
+      allPassed = false;
+    }
+    if (allPassed)
+      testPassed(_a + " threw exception " + _e + " on all iterations including after DFG tier-up.");
+  }
+
+  return values.length;
+}
+
 function shouldHaveHadError(message)
 {
     if (errorMessage) {
index 62c3df1..a2a982f 100644 (file)
@@ -1,3 +1,74 @@
+2015-01-20  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        put_by_val_direct need to check the property is index or not for using putDirect / putDirectIndex
+        https://bugs.webkit.org/show_bug.cgi?id=140426
+
+        Reviewed by Geoffrey Garen.
+
+        In the put_by_val_direct operation, we use JSObject::putDirect.
+        However, it only accepts non-index property. For index property, we need to use JSObject::putDirectIndex.
+        This patch changes Identifier::asIndex() to return Optional<uint32_t>.
+        It forces callers to check the value is index or not explicitly.
+        Additionally, it checks toString-ed Identifier is index or not to choose putDirect / putDirectIndex.
+
+        * bytecode/GetByIdStatus.cpp:
+        (JSC::GetByIdStatus::computeFor):
+        * bytecode/PutByIdStatus.cpp:
+        (JSC::PutByIdStatus::computeFor):
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitDirectPutById):
+        * dfg/DFGOperations.cpp:
+        (JSC::DFG::operationPutByValInternal):
+        * jit/JITOperations.cpp:
+        * jit/Repatch.cpp:
+        (JSC::emitPutTransitionStubAndGetOldStructure):
+        * jsc.cpp:
+        * llint/LLIntSlowPaths.cpp:
+        (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+        * runtime/Arguments.cpp:
+        (JSC::Arguments::getOwnPropertySlot):
+        (JSC::Arguments::put):
+        (JSC::Arguments::deleteProperty):
+        (JSC::Arguments::defineOwnProperty):
+        * runtime/ArrayPrototype.cpp:
+        (JSC::arrayProtoFuncSort):
+        * runtime/JSArray.cpp:
+        (JSC::JSArray::defineOwnProperty):
+        * runtime/JSCJSValue.cpp:
+        (JSC::JSValue::putToPrimitive):
+        * runtime/JSGenericTypedArrayViewInlines.h:
+        (JSC::JSGenericTypedArrayView<Adaptor>::getOwnPropertySlot):
+        (JSC::JSGenericTypedArrayView<Adaptor>::put):
+        (JSC::JSGenericTypedArrayView<Adaptor>::defineOwnProperty):
+        (JSC::JSGenericTypedArrayView<Adaptor>::deleteProperty):
+        * runtime/JSObject.cpp:
+        (JSC::JSObject::put):
+        (JSC::JSObject::putDirectAccessor):
+        (JSC::JSObject::putDirectCustomAccessor):
+        (JSC::JSObject::deleteProperty):
+        (JSC::JSObject::putDirectMayBeIndex):
+        (JSC::JSObject::defineOwnProperty):
+        * runtime/JSObject.h:
+        (JSC::JSObject::getOwnPropertySlot):
+        (JSC::JSObject::getPropertySlot):
+        (JSC::JSObject::putDirectInternal):
+        * runtime/JSString.cpp:
+        (JSC::JSString::getStringPropertyDescriptor):
+        * runtime/JSString.h:
+        (JSC::JSString::getStringPropertySlot):
+        * runtime/LiteralParser.cpp:
+        (JSC::LiteralParser<CharType>::parse):
+        * runtime/PropertyName.h:
+        (JSC::toUInt32FromCharacters):
+        (JSC::toUInt32FromStringImpl):
+        (JSC::PropertyName::asIndex):
+        * runtime/PropertyNameArray.cpp:
+        (JSC::PropertyNameArray::add):
+        * runtime/StringObject.cpp:
+        (JSC::StringObject::deleteProperty):
+        * runtime/Structure.cpp:
+        (JSC::Structure::prototypeChainMayInterceptStoreTo):
+
 2015-01-20  Michael Saboff  <msaboff@apple.com>
 
         REGRESSION(178696): Sporadic crashes while garbage collecting
index a9a47e0..5b0fed2 100644 (file)
@@ -270,7 +270,7 @@ GetByIdStatus GetByIdStatus::computeFor(const StructureSet& set, AtomicStringImp
     if (set.isEmpty())
         return GetByIdStatus();
 
-    if (toUInt32FromStringImpl(uid) != PropertyName::NotAnIndex)
+    if (toUInt32FromStringImpl(uid))
         return GetByIdStatus(TakesSlowPath);
     
     GetByIdStatus result;
index 4a82ba7..9e98fcc 100644 (file)
@@ -310,7 +310,7 @@ PutByIdStatus PutByIdStatus::computeFor(CodeBlock* baselineBlock, CodeBlock* dfg
 
 PutByIdStatus PutByIdStatus::computeFor(JSGlobalObject* globalObject, const StructureSet& set, AtomicStringImpl* uid, bool isDirect)
 {
-    if (toUInt32FromStringImpl(uid) != PropertyName::NotAnIndex)
+    if (toUInt32FromStringImpl(uid))
         return PutByIdStatus(TakesSlowPath);
 
     if (set.isEmpty())
index c4923e9..fa22dc8 100644 (file)
@@ -1491,9 +1491,7 @@ RegisterID* BytecodeGenerator::emitDirectPutById(RegisterID* base, const Identif
     instructions().append(0);
     instructions().append(0);
     instructions().append(0);
-    instructions().append(
-        property != m_vm->propertyNames->underscoreProto
-        && PropertyName(property).asIndex() == PropertyName::NotAnIndex);
+    instructions().append(property != m_vm->propertyNames->underscoreProto && !PropertyName(property).asIndex());
     return value;
 }
 
index 795e605..c503838 100644 (file)
@@ -97,14 +97,16 @@ ALWAYS_INLINE static void JIT_OPERATION operationPutByValInternal(ExecState* exe
     JSValue value = JSValue::decode(encodedValue);
 
     if (LIKELY(property.isUInt32())) {
-        putByVal<strict, direct>(exec, baseValue, property.asUInt32(), value);
+        uint32_t index = property.asUInt32();
+        ASSERT_WITH_MESSAGE(index != PropertyName::NotAnIndex, "Since JSValue::isUInt32 returns true only when the boxed value is int32_t and positive, it doesn't return true for uint32_t max value that is PropertyName::NotAnIndex.");
+        putByVal<strict, direct>(exec, baseValue, index, value);
         return;
     }
 
     if (property.isDouble()) {
         double propertyAsDouble = property.asDouble();
         uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble);
-        if (propertyAsDouble == propertyAsUInt32) {
+        if (propertyAsDouble == propertyAsUInt32 && propertyAsUInt32 != PropertyName::NotAnIndex) {
             putByVal<strict, direct>(exec, baseValue, propertyAsUInt32, value);
             return;
         }
@@ -122,14 +124,19 @@ ALWAYS_INLINE static void JIT_OPERATION operationPutByValInternal(ExecState* exe
 
     // Don't put to an object if toString throws an exception.
     Identifier ident = property.toString(exec)->toIdentifier(exec);
-    if (!vm->exception()) {
-        PutPropertySlot slot(baseValue, strict);
-        if (direct) {
-            RELEASE_ASSERT(baseValue.isObject());
-            asObject(baseValue)->putDirect(*vm, ident, value, slot);
-        } else
-            baseValue.put(exec, ident, value, slot);
-    }
+    if (vm->exception())
+        return;
+
+    PutPropertySlot slot(baseValue, strict);
+    if (direct) {
+        PropertyName propertyName(ident);
+        RELEASE_ASSERT(baseValue.isObject());
+        if (Optional<uint32_t> index = propertyName.asIndex())
+            asObject(baseValue)->putDirectIndex(exec, index.value(), value, 0, strict ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
+        else
+            asObject(baseValue)->putDirect(*vm, propertyName, value, slot);
+    } else
+        baseValue.put(exec, ident, value, slot);
 }
 
 template<typename ViewClass>
index 37aa45d..fe2cbe4 100644 (file)
@@ -51,6 +51,7 @@
 #include "JSWithScope.h"
 #include "LegacyProfiler.h"
 #include "ObjectConstructor.h"
+#include "PropertyName.h"
 #include "Repatch.h"
 #include "RepatchBuffer.h"
 #include "TestRunnerUtils.h"
@@ -480,19 +481,41 @@ static void putByVal(CallFrame* callFrame, JSValue baseValue, JSValue subscript,
 
 static void directPutByVal(CallFrame* callFrame, JSObject* baseObject, JSValue subscript, JSValue value)
 {
+    bool isStrictMode = callFrame->codeBlock()->isStrictMode();
     if (LIKELY(subscript.isUInt32())) {
-        uint32_t i = subscript.asUInt32();
-        baseObject->putDirectIndex(callFrame, i, value);
-    } else if (isName(subscript)) {
-        PutPropertySlot slot(baseObject, callFrame->codeBlock()->isStrictMode());
-        baseObject->putDirect(callFrame->vm(), jsCast<NameInstance*>(subscript.asCell())->privateName(), value, slot);
-    } else {
-        Identifier property = subscript.toString(callFrame)->toIdentifier(callFrame);
-        if (!callFrame->vm().exception()) { // Don't put to an object if toString threw an exception.
-            PutPropertySlot slot(baseObject, callFrame->codeBlock()->isStrictMode());
-            baseObject->putDirect(callFrame->vm(), property, value, slot);
+        uint32_t index = subscript.asUInt32();
+        ASSERT_WITH_MESSAGE(index != PropertyName::NotAnIndex, "Since JSValue::isUInt32 returns true only when the boxed value is int32_t and positive, it doesn't return true for uint32_t max value that is PropertyName::NotAnIndex.");
+        baseObject->putDirectIndex(callFrame, index, value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
+        return;
+    }
+
+    if (subscript.isDouble()) {
+        double subscriptAsDouble = subscript.asDouble();
+        uint32_t subscriptAsUInt32 = static_cast<uint32_t>(subscriptAsDouble);
+        if (subscriptAsDouble == subscriptAsUInt32 && subscriptAsUInt32 != PropertyName::NotAnIndex) {
+            baseObject->putDirectIndex(callFrame, subscriptAsUInt32, value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
+            return;
         }
     }
+
+    if (isName(subscript)) {
+        PutPropertySlot slot(baseObject, isStrictMode);
+        baseObject->putDirect(callFrame->vm(), jsCast<NameInstance*>(subscript.asCell())->privateName(), value, slot);
+        return;
+    }
+
+    // Don't put to an object if toString throws an exception.
+    Identifier property = subscript.toString(callFrame)->toIdentifier(callFrame);
+    if (callFrame->vm().exception())
+        return;
+
+    PropertyName propertyName(property);
+    if (Optional<uint32_t> index = propertyName.asIndex())
+        baseObject->putDirectIndex(callFrame, index.value(), value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
+    else {
+        PutPropertySlot slot(baseObject, isStrictMode);
+        baseObject->putDirect(callFrame->vm(), propertyName, value, slot);
+    }
 }
 void JIT_OPERATION operationPutByVal(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue)
 {
index e849edc..ade62d0 100644 (file)
@@ -989,7 +989,7 @@ static Structure* emitPutTransitionStubAndGetOldStructure(ExecState* exec, VM* v
 {
     PropertyName pname(ident);
     Structure* oldStructure = structure;
-    if (!oldStructure->isObject() || oldStructure->isDictionary() || pname.asIndex() != PropertyName::NotAnIndex)
+    if (!oldStructure->isObject() || oldStructure->isDictionary() || pname.asIndex())
         return nullptr;
 
     PropertyOffset propertyOffset;
index 506bd0c..24db245 100644 (file)
@@ -334,10 +334,9 @@ public:
             return true;
         }
 
-        unsigned index = propertyName.asIndex();
-        if (index < thisObject->getLength()) {
-            ASSERT(index != PropertyName::NotAnIndex);
-            slot.setValue(thisObject, DontDelete | DontEnum, jsNumber(thisObject->m_vector[index]));
+        Optional<uint32_t> index = propertyName.asIndex();
+        if (index && index.value() < thisObject->getLength()) {
+            slot.setValue(thisObject, DontDelete | DontEnum, jsNumber(thisObject->m_vector[index.value()]));
             return true;
         }
 
index 85bac26..dee9e2f 100644 (file)
@@ -819,19 +819,42 @@ LLINT_SLOW_PATH_DECL(slow_path_put_by_val_direct)
     JSValue value = LLINT_OP_C(3).jsValue();
     RELEASE_ASSERT(baseValue.isObject());
     JSObject* baseObject = asObject(baseValue);
+    bool isStrictMode = exec->codeBlock()->isStrictMode();
     if (LIKELY(subscript.isUInt32())) {
-        uint32_t i = subscript.asUInt32();
-        baseObject->putDirectIndex(exec, i, value);
-    } else if (isName(subscript)) {
-        PutPropertySlot slot(baseObject, exec->codeBlock()->isStrictMode());
-        baseObject->putDirect(exec->vm(), jsCast<NameInstance*>(subscript.asCell())->privateName(), value, slot);
-    } else {
-        Identifier property = subscript.toString(exec)->toIdentifier(exec);
-        if (!exec->vm().exception()) { // Don't put to an object if toString threw an exception.
-            PutPropertySlot slot(baseObject, exec->codeBlock()->isStrictMode());
-            baseObject->putDirect(exec->vm(), property, value, slot);
+        uint32_t index = subscript.asUInt32();
+        ASSERT_WITH_MESSAGE(index != PropertyName::NotAnIndex, "Since JSValue::isUInt32 returns true only when the boxed value is int32_t and positive, it doesn't return true for uint32_t max value that is PropertyName::NotAnIndex.");
+        baseObject->putDirectIndex(exec, index, value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
+        LLINT_END();
+    }
+
+
+    if (subscript.isDouble()) {
+        double subscriptAsDouble = subscript.asDouble();
+        uint32_t subscriptAsUInt32 = static_cast<uint32_t>(subscriptAsDouble);
+        if (subscriptAsDouble == subscriptAsUInt32 && subscriptAsUInt32 != PropertyName::NotAnIndex) {
+            baseObject->putDirectIndex(exec, subscriptAsUInt32, value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
+            LLINT_END();
         }
     }
+
+    if (isName(subscript)) {
+        PutPropertySlot slot(baseObject, isStrictMode);
+        baseObject->putDirect(exec->vm(), jsCast<NameInstance*>(subscript.asCell())->privateName(), value, slot);
+        LLINT_END();
+    }
+
+    // Don't put to an object if toString throws an exception.
+    Identifier property = subscript.toString(exec)->toIdentifier(exec);
+    if (exec->vm().exception())
+        LLINT_END();
+
+    PropertyName propertyName(property);
+    if (Optional<uint32_t> index = propertyName.asIndex())
+        baseObject->putDirectIndex(exec, index.value(), value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
+    else {
+        PutPropertySlot slot(baseObject, isStrictMode);
+        baseObject->putDirect(exec->vm(), propertyName, value, slot);
+    }
     LLINT_END();
 }
 
index 6b6beac..2ca83fe 100644 (file)
@@ -161,11 +161,11 @@ void Arguments::createStrictModeCalleeIfNecessary(ExecState* exec)
 bool Arguments::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
 {
     Arguments* thisObject = jsCast<Arguments*>(object);
-    unsigned i = propertyName.asIndex();
-    if (JSValue value = thisObject->tryGetArgument(i)) {
-        RELEASE_ASSERT(i < PropertyName::NotAnIndex);
-        slot.setValue(thisObject, None, value);
-        return true;
+    if (Optional<uint32_t> index = propertyName.asIndex()) {
+        if (JSValue value = thisObject->tryGetArgument(index.value())) {
+            slot.setValue(thisObject, None, value);
+            return true;
+        }
     }
 
     if (propertyName == exec->propertyNames().length && LIKELY(!thisObject->m_overrodeLength)) {
@@ -224,8 +224,8 @@ void Arguments::putByIndex(JSCell* cell, ExecState* exec, unsigned i, JSValue va
 void Arguments::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
 {
     Arguments* thisObject = jsCast<Arguments*>(cell);
-    unsigned i = propertyName.asIndex();
-    if (thisObject->trySetArgument(exec->vm(), i, value))
+    Optional<uint32_t> index = propertyName.asIndex();
+    if (index && thisObject->trySetArgument(exec->vm(), index.value(), value))
         return;
 
     if (propertyName == exec->propertyNames().length && !thisObject->m_overrodeLength) {
@@ -267,12 +267,11 @@ bool Arguments::deleteProperty(JSCell* cell, ExecState* exec, PropertyName prope
         return Base::deleteProperty(cell, exec, propertyName);
 
     Arguments* thisObject = jsCast<Arguments*>(cell);
-    unsigned i = propertyName.asIndex();
-    if (i < thisObject->m_numArguments) {
-        RELEASE_ASSERT(i < PropertyName::NotAnIndex);
+    Optional<uint32_t> index = propertyName.asIndex();
+    if (index && index.value() < thisObject->m_numArguments) {
         if (!Base::deleteProperty(cell, exec, propertyName))
             return false;
-        if (thisObject->tryDeleteArgument(exec->vm(), i))
+        if (thisObject->tryDeleteArgument(exec->vm(), index.value()))
             return true;
     }
 
@@ -298,13 +297,13 @@ bool Arguments::deleteProperty(JSCell* cell, ExecState* exec, PropertyName prope
 bool Arguments::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool shouldThrow)
 {
     Arguments* thisObject = jsCast<Arguments*>(object);
-    unsigned i = propertyName.asIndex();
-    if (i < thisObject->m_numArguments) {
-        RELEASE_ASSERT(i < PropertyName::NotAnIndex);
+    Optional<uint32_t> optionalIndex = propertyName.asIndex();
+    if (optionalIndex && optionalIndex.value() < thisObject->m_numArguments) {
         // If the property is not yet present on the object, and is not yet marked as deleted, then add it now.
+        uint32_t index = optionalIndex.value();
         PropertySlot slot(thisObject);
-        if (!thisObject->isDeletedArgument(i) && !JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot)) {
-            JSValue value = thisObject->tryGetArgument(i);
+        if (!thisObject->isDeletedArgument(index) && !JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot)) {
+            JSValue value = thisObject->tryGetArgument(index);
             ASSERT(value);
             object->putDirectMayBeIndex(exec, propertyName, value);
         }
@@ -313,20 +312,20 @@ bool Arguments::defineOwnProperty(JSObject* object, ExecState* exec, PropertyNam
 
         // From ES 5.1, 10.6 Arguments Object
         // 5. If the value of isMapped is not undefined, then
-        if (thisObject->isArgument(i)) {
+        if (thisObject->isArgument(index)) {
             // a. If IsAccessorDescriptor(Desc) is true, then
             if (descriptor.isAccessorDescriptor()) {
                 // i. Call the [[Delete]] internal method of map passing P, and false as the arguments.
-                thisObject->tryDeleteArgument(exec->vm(), i);
+                thisObject->tryDeleteArgument(exec->vm(), index);
             } else { // b. Else
                 // i. If Desc.[[Value]] is present, then
                 // 1. Call the [[Put]] internal method of map passing P, Desc.[[Value]], and Throw as the arguments.
                 if (descriptor.value())
-                    thisObject->trySetArgument(exec->vm(), i, descriptor.value());
+                    thisObject->trySetArgument(exec->vm(), index, descriptor.value());
                 // ii. If Desc.[[Writable]] is present and its value is false, then
                 // 1. Call the [[Delete]] internal method of map passing P and false as arguments.
                 if (descriptor.writablePresent() && !descriptor.writable())
-                    thisObject->tryDeleteArgument(exec->vm(), i);
+                    thisObject->tryDeleteArgument(exec->vm(), index);
             }
         }
         return true;
index c799cc3..d8769c5 100644 (file)
@@ -742,10 +742,11 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec)
     Vector<uint32_t, 0, UnsafeVectorOverflow> keys;
     for (size_t i = 0; i < nameArray.size(); ++i) {
         PropertyName name = nameArray[i];
-        uint32_t index = name.asIndex();
-        if (index == PropertyName::NotAnIndex)
+        Optional<uint32_t> optionalIndex = name.asIndex();
+        if (!optionalIndex)
             continue;
-        
+
+        uint32_t index = optionalIndex.value();
         JSValue value = getOrHole(thisObj, exec, index);
         if (exec->hadException())
             return JSValue::encode(jsUndefined());
index 517721e..7307b31 100644 (file)
@@ -158,9 +158,9 @@ bool JSArray::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName
 
     // 4. Else if P is an array index (15.4), then
     // a. Let index be ToUint32(P).
-    unsigned index = propertyName.asIndex();
-    if (index != PropertyName::NotAnIndex) {
+    if (Optional<uint32_t> optionalIndex = propertyName.asIndex()) {
         // b. Reject if index >= oldLen and oldLenDesc.[[Writable]] is false.
+        uint32_t index = optionalIndex.value();
         if (index >= array->length() && !array->isLengthWritable())
             return reject(exec, throwException, "Attempting to define numeric property on array with non-writable length property.");
         // c. Let succeeded be the result of calling the default [[DefineOwnProperty]] internal method (8.12.9) on A passing P, Desc, and false as arguments.
index c233f4c..7686055 100644 (file)
@@ -119,9 +119,8 @@ void JSValue::putToPrimitive(ExecState* exec, PropertyName propertyName, JSValue
 {
     VM& vm = exec->vm();
 
-    unsigned index = propertyName.asIndex();
-    if (index != PropertyName::NotAnIndex) {
-        putToPrimitiveByIndex(exec, index, value, slot.isStrictMode());
+    if (Optional<uint32_t> index = propertyName.asIndex()) {
+        putToPrimitiveByIndex(exec, index.value(), value, slot.isStrictMode());
         return;
     }
 
index 6d0d21f..ad0716c 100644 (file)
@@ -302,9 +302,9 @@ bool JSGenericTypedArrayView<Adaptor>::getOwnPropertySlot(
         return true;
     }
     
-    unsigned index = propertyName.asIndex();
-    if (index != PropertyName::NotAnIndex && thisObject->canGetIndexQuickly(index)) {
-        slot.setValue(thisObject, DontDelete | ReadOnly, thisObject->getIndexQuickly(index));
+    Optional<uint32_t> index = propertyName.asIndex();
+    if (index && thisObject->canGetIndexQuickly(index.value())) {
+        slot.setValue(thisObject, DontDelete | ReadOnly, thisObject->getIndexQuickly(index.value()));
         return true;
     }
     
@@ -324,9 +324,8 @@ void JSGenericTypedArrayView<Adaptor>::put(
         return;
     }
     
-    unsigned index = propertyName.asIndex();
-    if (index != PropertyName::NotAnIndex) {
-        putByIndex(thisObject, exec, index, value, slot.isStrictMode());
+    if (Optional<uint32_t> index = propertyName.asIndex()) {
+        putByIndex(thisObject, exec, index.value(), value, slot.isStrictMode());
         return;
     }
     
@@ -343,8 +342,7 @@ bool JSGenericTypedArrayView<Adaptor>::defineOwnProperty(
     // This is matching Firefox behavior. In particular, it rejects all attempts to
     // defineOwnProperty for indexed properties on typed arrays, even if they're out
     // of bounds.
-    if (propertyName == exec->propertyNames().length
-        || propertyName.asIndex() != PropertyName::NotAnIndex)
+    if (propertyName == exec->propertyNames().length || propertyName.asIndex())
         return reject(exec, shouldThrow, "Attempting to write to a read-only typed array property.");
     
     return Base::defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow);
@@ -356,8 +354,7 @@ bool JSGenericTypedArrayView<Adaptor>::deleteProperty(
 {
     JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(cell);
     
-    if (propertyName == exec->propertyNames().length
-        || propertyName.asIndex() != PropertyName::NotAnIndex)
+    if (propertyName == exec->propertyNames().length || propertyName.asIndex())
         return false;
     
     return Base::deleteProperty(thisObject, exec, propertyName);
index 87c1919..4c18d36 100644 (file)
@@ -339,9 +339,8 @@ void JSObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSV
     
     // Try indexed put first. This is required for correctness, since loads on property names that appear like
     // valid indices will never look in the named property storage.
-    unsigned i = propertyName.asIndex();
-    if (i != PropertyName::NotAnIndex) {
-        putByIndex(thisObject, exec, i, value, slot.isStrictMode());
+    if (Optional<uint32_t> index = propertyName.asIndex()) {
+        putByIndex(thisObject, exec, index.value(), value, slot.isStrictMode());
         return;
     }
     
@@ -1198,9 +1197,8 @@ void JSObject::putDirectAccessor(ExecState* exec, PropertyName propertyName, JSV
 {
     ASSERT(value.isGetterSetter() && (attributes & Accessor));
 
-    unsigned index = propertyName.asIndex();
-    if (index != PropertyName::NotAnIndex) {
-        putDirectIndex(exec, index, value, attributes, PutDirectIndexLikePutDirect);
+    if (Optional<uint32_t> index = propertyName.asIndex()) {
+        putDirectIndex(exec, index.value(), value, attributes, PutDirectIndexLikePutDirect);
         return;
     }
 
@@ -1209,7 +1207,7 @@ void JSObject::putDirectAccessor(ExecState* exec, PropertyName propertyName, JSV
 
 void JSObject::putDirectCustomAccessor(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes)
 {
-    ASSERT(propertyName.asIndex() == PropertyName::NotAnIndex);
+    ASSERT(!propertyName.asIndex());
 
     PutPropertySlot slot(this);
     putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot);
@@ -1257,9 +1255,8 @@ bool JSObject::deleteProperty(JSCell* cell, ExecState* exec, PropertyName proper
 {
     JSObject* thisObject = jsCast<JSObject*>(cell);
     
-    unsigned i = propertyName.asIndex();
-    if (i != PropertyName::NotAnIndex)
-        return thisObject->methodTable(exec->vm())->deletePropertyByIndex(thisObject, exec, i);
+    if (Optional<uint32_t> index = propertyName.asIndex())
+        return thisObject->methodTable(exec->vm())->deletePropertyByIndex(thisObject, exec, index.value());
 
     if (!thisObject->staticFunctionsReified())
         thisObject->reifyStaticFunctionsForDelete(exec);
@@ -2502,11 +2499,10 @@ static bool putDescriptor(ExecState* exec, JSObject* target, PropertyName proper
 
 void JSObject::putDirectMayBeIndex(ExecState* exec, PropertyName propertyName, JSValue value)
 {
-    unsigned asIndex = propertyName.asIndex();
-    if (asIndex == PropertyName::NotAnIndex)
-        putDirect(exec->vm(), propertyName, value);
+    if (Optional<uint32_t> index = propertyName.asIndex())
+        putDirectIndex(exec, index.value(), value);
     else
-        putDirectIndex(exec, asIndex, value);
+        putDirect(exec->vm(), propertyName, value);
 }
 
 class DefineOwnPropertyScope {
@@ -2659,15 +2655,14 @@ bool JSObject::defineOwnNonIndexProperty(ExecState* exec, PropertyName propertyN
 bool JSObject::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool throwException)
 {
     // If it's an array index, then use the indexed property storage.
-    unsigned index = propertyName.asIndex();
-    if (index != PropertyName::NotAnIndex) {
+    if (Optional<uint32_t> index = propertyName.asIndex()) {
         // c. Let succeeded be the result of calling the default [[DefineOwnProperty]] internal method (8.12.9) on A passing P, Desc, and false as arguments.
         // d. Reject if succeeded is false.
         // e. If index >= oldLen
         // e.i. Set oldLenDesc.[[Value]] to index + 1.
         // e.ii. Call the default [[DefineOwnProperty]] internal method (8.12.9) on A passing "length", oldLenDesc, and false as arguments. This call will always return true.
         // f. Return true.
-        return object->defineOwnIndexedProperty(exec, index, descriptor, throwException);
+        return object->defineOwnIndexedProperty(exec, index.value(), descriptor, throwException);
     }
     
     return object->defineOwnNonIndexProperty(exec, propertyName, descriptor, throwException);
index c972139..b0873dc 100644 (file)
@@ -1244,9 +1244,8 @@ ALWAYS_INLINE bool JSObject::getOwnPropertySlot(JSObject* object, ExecState* exe
     Structure& structure = *object->structure(vm);
     if (object->inlineGetOwnPropertySlot(vm, structure, propertyName, slot))
         return true;
-    unsigned index = propertyName.asIndex();
-    if (index != PropertyName::NotAnIndex)
-        return getOwnPropertySlotByIndex(object, exec, index, slot);
+    if (Optional<uint32_t> index = propertyName.asIndex())
+        return getOwnPropertySlotByIndex(object, exec, index.value(), slot);
     return false;
 }
 
@@ -1274,9 +1273,8 @@ ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, PropertyName prope
         object = asObject(prototype);
     }
 
-    unsigned index = propertyName.asIndex();
-    if (index != PropertyName::NotAnIndex)
-        return getPropertySlot(exec, index, slot);
+    if (Optional<uint32_t> index = propertyName.asIndex())
+        return getPropertySlot(exec, index.value(), slot);
     return false;
 }
 
@@ -1320,7 +1318,7 @@ inline bool JSObject::putDirectInternal(VM& vm, PropertyName propertyName, JSVal
     ASSERT(value);
     ASSERT(value.isGetterSetter() == !!(attributes & Accessor));
     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
-    ASSERT(propertyName.asIndex() == PropertyName::NotAnIndex);
+    ASSERT(!propertyName.asIndex());
 
     Structure* structure = this->structure(vm);
     if (structure->isDictionary()) {
index 3ea2b7e..0078594 100644 (file)
@@ -425,10 +425,9 @@ bool JSString::getStringPropertyDescriptor(ExecState* exec, PropertyName propert
         return true;
     }
     
-    unsigned i = propertyName.asIndex();
-    if (i < m_length) {
-        ASSERT(i != PropertyName::NotAnIndex); // No need for an explicit check, the above test would always fail!
-        descriptor.setDescriptor(getIndex(exec, i), DontDelete | ReadOnly);
+    Optional<uint32_t> index = propertyName.asIndex();
+    if (index && index.value() < m_length) {
+        descriptor.setDescriptor(getIndex(exec, index.value()), DontDelete | ReadOnly);
         return true;
     }
     
index 0575447..665c09e 100644 (file)
@@ -626,10 +626,9 @@ ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, PropertyName
         return true;
     }
 
-    unsigned i = propertyName.asIndex();
-    if (i < m_length) {
-        ASSERT(i != PropertyName::NotAnIndex); // No need for an explicit check, the above test would always fail!
-        slot.setValue(this, DontDelete | ReadOnly, getIndex(exec, i));
+    Optional<uint32_t> index = propertyName.asIndex();
+    if (index && index.value() < m_length) {
+        slot.setValue(this, DontDelete | ReadOnly, getIndex(exec, index.value()));
         return true;
     }
 
index f6f5fe1..aaf14dd 100644 (file)
@@ -649,9 +649,8 @@ JSValue LiteralParser<CharType>::parse(ParserState initialState)
             {
                 JSObject* object = asObject(objectStack.last());
                 PropertyName ident = identifierStack.last();
-                unsigned i = ident.asIndex();
-                if (i != PropertyName::NotAnIndex)
-                    object->putDirectIndex(m_exec, i, lastValue);
+                if (Optional<uint32_t> index = ident.asIndex())
+                    object->putDirectIndex(m_exec, index.value(), lastValue);
                 else
                     object->putDirect(m_exec->vm(), ident, lastValue);
                 identifierStack.removeLast();
index 22a8ff8..35ec595 100644 (file)
 
 #include "Identifier.h"
 #include "PrivateName.h"
+#include <wtf/Optional.h>
 
 namespace JSC {
 
 template <typename CharType>
-ALWAYS_INLINE uint32_t toUInt32FromCharacters(const CharType* characters, unsigned length)
+ALWAYS_INLINE Optional<uint32_t> toUInt32FromCharacters(const CharType* characters, unsigned length)
 {
     // An empty string is not a number.
     if (!length)
-        return UINT_MAX;
+        return Nullopt;
 
     // Get the first character, turning it into a digit.
     uint32_t value = characters[0] - '0';
     if (value > 9)
-        return UINT_MAX;
+        return Nullopt;
     
     // Check for leading zeros. If the first characher is 0, then the
     // length of the string must be one - e.g. "042" is not equal to "42".
     if (!value && length > 1)
-        return UINT_MAX;
+        return Nullopt;
     
     while (--length) {
         // Multiply value by 10, checking for overflow out of 32 bits.
         if (value > 0xFFFFFFFFU / 10)
-            return UINT_MAX;
+            return Nullopt;
         value *= 10;
         
         // Get the next character, turning it into a digit.
         uint32_t newValue = *(++characters) - '0';
         if (newValue > 9)
-            return UINT_MAX;
+            return Nullopt;
         
         // Add in the old value, checking for overflow out of 32 bits.
         newValue += value;
         if (newValue < value)
-            return UINT_MAX;
+            return Nullopt;
         value = newValue;
     }
-    
+
+    if (value == UINT_MAX)
+        return Nullopt;
     return value;
 }
 
-ALWAYS_INLINE uint32_t toUInt32FromStringImpl(StringImpl* impl)
+ALWAYS_INLINE Optional<uint32_t> toUInt32FromStringImpl(StringImpl* impl)
 {
     if (impl->is8Bit())
         return toUInt32FromCharacters(impl->characters8(), impl->length());
@@ -109,11 +112,11 @@ public:
 
     static const uint32_t NotAnIndex = UINT_MAX;
 
-    uint32_t asIndex()
+    Optional<uint32_t> asIndex()
     {
-        return m_impl ? toUInt32FromStringImpl(m_impl) : NotAnIndex;
+        return m_impl ? toUInt32FromStringImpl(m_impl) : Nullopt;
     }
-    
+
     void dump(PrintStream& out) const
     {
         if (m_impl)
index 4475b89..c24217a 100644 (file)
@@ -33,8 +33,8 @@ void PropertyNameArray::add(StringImpl* identifier)
 {
     ASSERT(!identifier || identifier == StringImpl::empty() || identifier->isAtomic());
     if (!ASSERT_DISABLED) {
-        uint32_t index = PropertyName(Identifier(m_vm, identifier)).asIndex();
-        ASSERT_UNUSED(index, index == PropertyName::NotAnIndex || index >= m_previouslyEnumeratedLength);
+        Optional<uint32_t> index = PropertyName(Identifier(m_vm, identifier)).asIndex();
+        ASSERT_UNUSED(index, !index || index.value() >= m_previouslyEnumeratedLength);
     }
 
     if (m_alternateSet && m_alternateSet->contains(identifier))
index 5001bcc..5584792 100644 (file)
@@ -128,9 +128,8 @@ bool StringObject::deleteProperty(JSCell* cell, ExecState* exec, PropertyName pr
     StringObject* thisObject = jsCast<StringObject*>(cell);
     if (propertyName == exec->propertyNames().length)
         return false;
-    unsigned i = propertyName.asIndex();
-    if (thisObject->internalValue()->canGetIndex(i)) {
-        ASSERT(i != PropertyName::NotAnIndex); // No need for an explicit check, the above test would always fail!
+    Optional<uint32_t> index = propertyName.asIndex();
+    if (index && thisObject->internalValue()->canGetIndex(index.value())) {
         return false;
     }
     return JSObject::deleteProperty(thisObject, exec, propertyName);
index 86d0b6f..11da4ad 100644 (file)
@@ -1010,8 +1010,7 @@ void Structure::visitChildren(JSCell* cell, SlotVisitor& visitor)
 
 bool Structure::prototypeChainMayInterceptStoreTo(VM& vm, PropertyName propertyName)
 {
-    unsigned i = propertyName.asIndex();
-    if (i != PropertyName::NotAnIndex)
+    if (propertyName.asIndex())
         return anyObjectInChainMayInterceptIndexedAccesses();
     
     for (Structure* current = this; ;) {
index f73e71a..ab6db3e 100644 (file)
@@ -1,3 +1,30 @@
+2015-01-20  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        put_by_val_direct need to check the property is index or not for using putDirect / putDirectIndex
+        https://bugs.webkit.org/show_bug.cgi?id=140426
+
+        Reviewed by Geoffrey Garen.
+
+        Test: js/dfg-put-by-val-direct-with-edge-numbers.html
+
+        * bindings/js/JSDOMWindowCustom.cpp:
+        (WebCore::JSDOMWindow::getOwnPropertySlot):
+        * bindings/js/JSHTMLAllCollectionCustom.cpp:
+        (WebCore::callHTMLAllCollection):
+        (WebCore::JSHTMLAllCollection::item):
+        * bindings/scripts/CodeGeneratorJS.pm:
+        (GenerateGetOwnPropertySlotBody):
+        (GenerateImplementation):
+        * bindings/scripts/test/JS/JSFloat64Array.cpp:
+        (WebCore::JSFloat64Array::getOwnPropertySlot):
+        (WebCore::JSFloat64Array::getOwnPropertyDescriptor):
+        (WebCore::JSFloat64Array::put):
+        * bindings/scripts/test/JS/JSTestEventTarget.cpp:
+        (WebCore::JSTestEventTarget::getOwnPropertySlot):
+        * bridge/runtime_array.cpp:
+        (JSC::RuntimeArray::getOwnPropertySlot):
+        (JSC::RuntimeArray::put):
+
 2015-01-20  Chris Dumez  <cdumez@apple.com>
 
         Drop width / height shorthands code from StylePropertyShorthand.*
index 02608fa..f3a4292 100644 (file)
@@ -214,11 +214,10 @@ bool JSDOMWindow::getOwnPropertySlot(JSObject* object, ExecState* exec, Property
     // We need to test the correct priority order.
 
     // allow window[1] or parent[1] etc. (#56983)
-    unsigned i = propertyName.asIndex();
-    if (i < thisObject->impl().frame()->tree().scopedChildCount()) {
-        ASSERT(i != PropertyName::NotAnIndex);
+    Optional<uint32_t> index = propertyName.asIndex();
+    if (index && index.value() < thisObject->impl().frame()->tree().scopedChildCount()) {
         slot.setValue(thisObject, ReadOnly | DontDelete | DontEnum,
-            toJS(exec, thisObject->impl().frame()->tree().scopedChild(i)->document()->domWindow()));
+            toJS(exec, thisObject->impl().frame()->tree().scopedChild(index.value())->document()->domWindow()));
         return true;
     }
 
index 8122507..173ec2f 100644 (file)
@@ -65,9 +65,8 @@ static EncodedJSValue JSC_HOST_CALL callHTMLAllCollection(ExecState* exec)
     if (exec->argumentCount() == 1) {
         // Support for document.all(<index>) etc.
         String string = exec->argument(0).toString(exec)->value(exec);
-        unsigned index = toUInt32FromStringImpl(string.impl());
-        if (index != PropertyName::NotAnIndex)
-            return JSValue::encode(toJS(exec, jsCollection->globalObject(), collection.item(index)));
+        if (Optional<uint32_t> index = toUInt32FromStringImpl(string.impl()))
+            return JSValue::encode(toJS(exec, jsCollection->globalObject(), collection.item(index.value())));
 
         // Support for document.images('<name>') etc.
         return JSValue::encode(namedItems(exec, jsCollection, Identifier(exec, string)));
@@ -75,9 +74,8 @@ static EncodedJSValue JSC_HOST_CALL callHTMLAllCollection(ExecState* exec)
 
     // The second arg, if set, is the index of the item we want
     String string = exec->argument(0).toString(exec)->value(exec);
-    unsigned index = toUInt32FromStringImpl(exec->argument(1).toWTFString(exec).impl());
-    if (index != PropertyName::NotAnIndex) {
-        if (auto* item = collection.namedItemWithIndex(string, index))
+    if (Optional<uint32_t> index = toUInt32FromStringImpl(exec->argument(1).toWTFString(exec).impl())) {
+        if (auto* item = collection.namedItemWithIndex(string, index.value()))
             return JSValue::encode(toJS(exec, jsCollection->globalObject(), item));
     }
 
@@ -103,9 +101,8 @@ EncodedJSValue JSHTMLAllCollection::nameGetter(ExecState* exec, JSObject* slotBa
 
 JSValue JSHTMLAllCollection::item(ExecState* exec)
 {
-    uint32_t index = toUInt32FromStringImpl(exec->argument(0).toString(exec)->value(exec).impl());
-    if (index != PropertyName::NotAnIndex)
-        return toJS(exec, globalObject(), impl().item(index));
+    if (Optional<uint32_t> index = toUInt32FromStringImpl(exec->argument(0).toString(exec)->value(exec).impl()))
+        return toJS(exec, globalObject(), impl().item(index.value()));
     return namedItems(exec, this, Identifier(exec, exec->argument(0).toString(exec)->value(exec)));
 }
 
index e304da9..f70d6c1 100644 (file)
@@ -360,15 +360,16 @@ sub GenerateGetOwnPropertySlotBody
     }
 
     if ($indexedGetterFunction) {
-        push(@getOwnPropertySlotImpl, "    unsigned index = propertyName.asIndex();\n");
+        push(@getOwnPropertySlotImpl, "    Optional<uint32_t> optionalIndex = propertyName.asIndex();\n");
 
         # If the item function returns a string then we let the TreatReturnedNullStringAs handle the cases
         # where the index is out of range.
         if ($indexedGetterFunction->signature->type eq "DOMString") {
-            push(@getOwnPropertySlotImpl, "    if (index != PropertyName::NotAnIndex) {\n");
+            push(@getOwnPropertySlotImpl, "    if (optionalIndex) {\n");
         } else {
-            push(@getOwnPropertySlotImpl, "    if (index != PropertyName::NotAnIndex && index < thisObject->impl().length()) {\n");
+            push(@getOwnPropertySlotImpl, "    if (optionalIndex && optionalIndex.value() < thisObject->impl().length()) {\n");
         }
+        push(@getOwnPropertySlotImpl, "        unsigned index = optionalIndex.value();\n");
         # Assume that if there's a setter, the index will be writable
         if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
             push(@getOwnPropertySlotImpl, "        unsigned attributes = ${namespaceMaybe}DontDelete;\n");
@@ -2456,9 +2457,8 @@ sub GenerateImplementation
             push(@implContent, "    ${className}* thisObject = jsCast<${className}*>(cell);\n");
             push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
             if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
-                push(@implContent, "    unsigned index = propertyName.asIndex();\n");
-                push(@implContent, "    if (index != PropertyName::NotAnIndex) {\n");
-                push(@implContent, "        thisObject->indexSetter(exec, index, value);\n");
+                push(@implContent, "    if (Optional<uint32_t> index = propertyName.asIndex()) {\n");
+                push(@implContent, "        thisObject->indexSetter(exec, index.value(), value);\n");
                 push(@implContent, "        return;\n");
                 push(@implContent, "    }\n");
             }
index 1d59189..417f165 100644 (file)
@@ -174,9 +174,9 @@ bool JSFloat64Array::getOwnPropertySlot(JSObject* object, ExecState* exec, Prope
 {
     JSFloat64Array* thisObject = jsCast<JSFloat64Array*>(object);
     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
-    unsigned index = propertyName.asIndex();
-    if (index != PropertyName::NotAnIndex && index < static_cast<Float64Array*>(thisObject->impl())->length()) {
-        slot.setValue(thisObject, thisObject->getByIndex(exec, index));
+    Optional<uint32_t> index = propertyName.asIndex();
+    if (index && index.value() < static_cast<Float64Array*>(thisObject->impl())->length()) {
+        slot.setValue(thisObject, thisObject->getByIndex(exec, index.value()));
         return true;
     }
     return getStaticValueSlot<JSFloat64Array, Base>(exec, getJSFloat64ArrayTable(exec), thisObject, propertyName, slot);
@@ -186,9 +186,9 @@ bool JSFloat64Array::getOwnPropertyDescriptor(JSObject* object, ExecState* exec,
 {
     JSFloat64Array* thisObject = jsCast<JSFloat64Array*>(object);
     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
-    unsigned index = propertyName.asIndex();
-    if (index != PropertyName::NotAnIndex && index < static_cast<Float64Array*>(thisObject->impl())->length()) {
-        descriptor.setDescriptor(thisObject->getByIndex(exec, index), DontDelete);
+    Optional<uint32_t> index = propertyName.asIndex();
+    if (index && index.value() < static_cast<Float64Array*>(thisObject->impl())->length()) {
+        descriptor.setDescriptor(thisObject->getByIndex(exec, index.value()), DontDelete);
         return true;
     }
     return getStaticValueDescriptor<JSFloat64Array, Base>(exec, getJSFloat64ArrayTable(exec), thisObject, propertyName, descriptor);
@@ -215,9 +215,8 @@ void JSFloat64Array::put(JSCell* cell, ExecState* exec, PropertyName propertyNam
 {
     JSFloat64Array* thisObject = jsCast<JSFloat64Array*>(cell);
     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
-    unsigned index = propertyName.asIndex();
-    if (index != PropertyName::NotAnIndex) {
-        thisObject->indexSetter(exec, index, value);
+    if (Optional<uint32_t> index = propertyName.asIndex()) {
+        thisObject->indexSetter(exec, index.value(), value);
         return;
     }
     Base::put(thisObject, exec, propertyName, value, slot);
index e2c0478..9e8d368 100644 (file)
@@ -180,10 +180,10 @@ bool JSTestEventTarget::getOwnPropertySlot(JSObject* object, ExecState* exec, Pr
         slot.setCacheableCustom(thisObject, entry->attributes(), entry->propertyGetter());
         return true;
     }
-    unsigned index = propertyName.asIndex();
-    if (index != PropertyName::NotAnIndex && index < thisObject->impl().length()) {
+    Optional<uint32_t> index = propertyName.asIndex();
+    if (index && index.value() < thisObject->impl().length()) {
         unsigned attributes = DontDelete | ReadOnly;
-        slot.setValue(thisObject, attributes, toJS(exec, thisObject->globalObject(), thisObject->impl().item(index)));
+        slot.setValue(thisObject, attributes, toJS(exec, thisObject->globalObject(), thisObject->impl().item(index.value())));
         return true;
     }
     if (canGetItemsForName(exec, &thisObject->impl(), propertyName)) {
index 0222190..498b37e 100644 (file)
@@ -89,11 +89,10 @@ bool RuntimeArray::getOwnPropertySlot(JSObject* object, ExecState* exec, Propert
         return true;
     }
     
-    unsigned index = propertyName.asIndex();
-    if (index < thisObject->getLength()) {
-        ASSERT(index != PropertyName::NotAnIndex);
+    Optional<uint32_t> index = propertyName.asIndex();
+    if (index && index.value() < thisObject->getLength()) {
         slot.setValue(thisObject, DontDelete | DontEnum,
-            thisObject->getConcreteArray()->valueAt(exec, index));
+            thisObject->getConcreteArray()->valueAt(exec, index.value()));
         return true;
     }
     
@@ -120,9 +119,8 @@ void RuntimeArray::put(JSCell* cell, ExecState* exec, PropertyName propertyName,
         return;
     }
     
-    unsigned index = propertyName.asIndex();
-    if (index != PropertyName::NotAnIndex) {
-        thisObject->getConcreteArray()->setValueAt(exec, index, value);
+    if (Optional<uint32_t> index = propertyName.asIndex()) {
+        thisObject->getConcreteArray()->setValueAt(exec, index.value(), value);
         return;
     }