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 Darin Adler.
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 checks toString-ed Identifier is index or not to choose putDirect / putDirectIndex.
* dfg/DFGOperations.cpp:
(JSC::DFG::putByVal):
(JSC::DFG::operationPutByValInternal):
* jit/JITOperations.cpp:
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* runtime/Identifier.h:
(JSC::isIndex):
(JSC::parseIndex):
* tests/stress/dfg-put-by-val-direct-with-edge-numbers.js: Added.
(lookupWithKey):
(toStringThrowsError.toString):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@182452 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 0994bb8..5ab5963 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,27 @@
+2015-04-06 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 Darin Adler.
+
+ 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 checks toString-ed Identifier is index or not to choose putDirect / putDirectIndex.
+
+ * dfg/DFGOperations.cpp:
+ (JSC::DFG::putByVal):
+ (JSC::DFG::operationPutByValInternal):
+ * jit/JITOperations.cpp:
+ * llint/LLIntSlowPaths.cpp:
+ (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+ * runtime/Identifier.h:
+ (JSC::isIndex):
+ (JSC::parseIndex):
+ * tests/stress/dfg-put-by-val-direct-with-edge-numbers.js: Added.
+ (lookupWithKey):
+ (toStringThrowsError.toString):
+
2015-04-06 Alberto Garcia <berto@igalia.com>
[GTK] Fix HPPA build
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp
index a0726c1..ff16903 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp
@@ -69,6 +69,7 @@
{
VM& vm = exec->vm();
NativeCallFrameTracer tracer(&vm, exec);
+ ASSERT(isIndex(index));
if (direct) {
RELEASE_ASSERT(baseValue.isObject());
asObject(baseValue)->putDirectIndex(exec, index, value, 0, strict ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
@@ -99,6 +100,8 @@
JSValue value = JSValue::decode(encodedValue);
if (LIKELY(property.isUInt32())) {
+ // Despite its name, JSValue::isUInt32 will return true only for positive boxed int32_t; all those values are valid array indices.
+ ASSERT(isIndex(property.asUInt32()));
putByVal<strict, direct>(exec, baseValue, property.asUInt32(), value);
return;
}
@@ -106,7 +109,7 @@
if (property.isDouble()) {
double propertyAsDouble = property.asDouble();
uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble);
- if (propertyAsDouble == propertyAsUInt32) {
+ if (propertyAsDouble == propertyAsUInt32 && isIndex(propertyAsUInt32)) {
putByVal<strict, direct>(exec, baseValue, propertyAsUInt32, value);
return;
}
@@ -114,14 +117,18 @@
// Don't put to an object if toString throws an exception.
auto propertyName = property.toPropertyKey(exec);
- if (!vm->exception()) {
- PutPropertySlot slot(baseValue, strict);
- if (direct) {
- RELEASE_ASSERT(baseValue.isObject());
+ if (vm->exception())
+ return;
+
+ PutPropertySlot slot(baseValue, strict);
+ if (direct) {
+ RELEASE_ASSERT(baseValue.isObject());
+ if (Optional<uint32_t> index = parseIndex(propertyName))
+ asObject(baseValue)->putDirectIndex(exec, index.value(), value, 0, strict ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
+ else
asObject(baseValue)->putDirect(*vm, propertyName, value, slot);
- } else
- baseValue.put(exec, propertyName, value, slot);
- }
+ } else
+ baseValue.put(exec, propertyName, value, slot);
}
template<typename ViewClass>
@@ -285,7 +292,7 @@
} else if (property.isDouble()) {
double propertyAsDouble = property.asDouble();
uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble);
- if (propertyAsUInt32 == propertyAsDouble)
+ if (propertyAsUInt32 == propertyAsDouble && isIndex(propertyAsUInt32))
return getByVal(exec, base, propertyAsUInt32);
} else if (property.isString()) {
Structure& structure = *base->structure(vm);
diff --git a/Source/JavaScriptCore/jit/JITOperations.cpp b/Source/JavaScriptCore/jit/JITOperations.cpp
index 58b8636..5e90d48 100644
--- a/Source/JavaScriptCore/jit/JITOperations.cpp
+++ b/Source/JavaScriptCore/jit/JITOperations.cpp
@@ -53,6 +53,7 @@
#include "JSWithScope.h"
#include "LegacyProfiler.h"
#include "ObjectConstructor.h"
+#include "PropertyName.h"
#include "Repatch.h"
#include "RepatchBuffer.h"
#include "TestRunnerUtils.h"
@@ -497,16 +498,34 @@
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 {
- auto property = subscript.toPropertyKey(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);
+ // Despite its name, JSValue::isUInt32 will return true only for positive boxed int32_t; all those values are valid array indices.
+ ASSERT(isIndex(subscript.asUInt32()));
+ baseObject->putDirectIndex(callFrame, subscript.asUInt32(), value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
+ return;
+ }
+
+ if (subscript.isDouble()) {
+ double subscriptAsDouble = subscript.asDouble();
+ uint32_t subscriptAsUInt32 = static_cast<uint32_t>(subscriptAsDouble);
+ if (subscriptAsDouble == subscriptAsUInt32 && isIndex(subscriptAsUInt32)) {
+ baseObject->putDirectIndex(callFrame, subscriptAsUInt32, value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
+ return;
}
}
+
+ // Don't put to an object if toString threw an exception.
+ auto property = subscript.toPropertyKey(callFrame);
+ if (callFrame->vm().exception())
+ return;
+
+ if (Optional<uint32_t> index = parseIndex(property))
+ baseObject->putDirectIndex(callFrame, index.value(), value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
+ else {
+ PutPropertySlot slot(baseObject, isStrictMode);
+ baseObject->putDirect(callFrame->vm(), property, value, slot);
+ }
}
void JIT_OPERATION operationPutByVal(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue)
{
diff --git a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
index 279285a..27b98698 100644
--- a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
+++ b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
@@ -796,16 +796,34 @@
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 {
- auto property = subscript.toPropertyKey(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);
+ // Despite its name, JSValue::isUInt32 will return true only for positive boxed int32_t; all those values are valid array indices.
+ ASSERT(isIndex(subscript.asUInt32()));
+ baseObject->putDirectIndex(exec, subscript.asUInt32(), 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 && isIndex(subscriptAsUInt32)) {
+ baseObject->putDirectIndex(exec, subscriptAsUInt32, value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
+ LLINT_END();
}
}
+
+ // Don't put to an object if toString threw an exception.
+ auto property = subscript.toPropertyKey(exec);
+ if (exec->vm().exception())
+ LLINT_END();
+
+ if (Optional<uint32_t> index = parseIndex(property))
+ baseObject->putDirectIndex(exec, index.value(), value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
+ else {
+ PutPropertySlot slot(baseObject, isStrictMode);
+ baseObject->putDirect(exec->vm(), property, value, slot);
+ }
LLINT_END();
}
diff --git a/Source/JavaScriptCore/runtime/Identifier.h b/Source/JavaScriptCore/runtime/Identifier.h
index 507b755..f5e168f 100644
--- a/Source/JavaScriptCore/runtime/Identifier.h
+++ b/Source/JavaScriptCore/runtime/Identifier.h
@@ -32,6 +32,11 @@
class ExecState;
+ALWAYS_INLINE bool isIndex(uint32_t index)
+{
+ return index != 0xFFFFFFFFU;
+}
+
template <typename CharType>
ALWAYS_INLINE Optional<uint32_t> parseIndex(const CharType* characters, unsigned length)
{
@@ -67,7 +72,7 @@
value = newValue;
}
- if (value == 0xFFFFFFFFU)
+ if (!isIndex(value))
return Nullopt;
return value;
}
diff --git a/Source/JavaScriptCore/tests/stress/dfg-put-by-val-direct-with-edge-numbers.js b/Source/JavaScriptCore/tests/stress/dfg-put-by-val-direct-with-edge-numbers.js
new file mode 100644
index 0000000..ebf21e2
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/dfg-put-by-val-direct-with-edge-numbers.js
@@ -0,0 +1,104 @@
+// Test that a object accepts DFG PutByValueDirect operation with edge numbers.
+
+function lookupWithKey(key) {
+ var object = {
+ [key]: 42
+ };
+ return object[key];
+}
+noInline(lookupWithKey);
+
+for (var i = 0; i < 10000; ++i) {
+ [
+ // 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, not array index
+ 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()
+ (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,
+ 0x80000000 + 0.5, // out of int32_t, double
+
+ // 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",
+ (0x80000000 + 0.5).toString()
+ ].forEach(function (key) {
+ var value = lookupWithKey(key);
+ if (value !== 42)
+ throw new Error('bad value: ' + value);
+ });
+}
+
+function lookupWithKey2(key) {
+ var object = {
+ [key]: 42
+ };
+ return object[key];
+}
+noInline(lookupWithKey2);
+
+var toStringThrowsError = {
+ toString: function () {
+ throw new Error('ng');
+ }
+};
+
+for (var i = 0; i < 10000; ++i) {
+ var error = null;
+ try {
+ lookupWithKey2(toStringThrowsError);
+ } catch (e) {
+ error = e;
+ }
+ if (!error)
+ throw new Error('not thrown');
+ if (String(error) !== 'Error: ng')
+ throw new Error('bad error: ' + String(error));
+}