Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (176675 => 176676)
--- trunk/Source/_javascript_Core/ChangeLog 2014-12-02 19:26:48 UTC (rev 176675)
+++ trunk/Source/_javascript_Core/ChangeLog 2014-12-02 19:27:23 UTC (rev 176676)
@@ -1,3 +1,28 @@
+2014-12-02 Matthew Mirman <mmir...@apple.com>
+
+ Fixes inline cache fast path accessing nonexistant getters.
+ <rdar://problem/18416918>
+ https://bugs.webkit.org/show_bug.cgi?id=136961
+
+ Reviewed by Filip Pizlo.
+
+ Fixes a bug in inline caching where getters would have been able to
+ modify the property they are getting during
+ building the inline cache and then accessing that
+ property through the inline cache site causing a recursive
+ inline cache building and allowing the fast path of the cache to
+ try to load a getter for the property that no longer exists.
+
+ * jit/JITOperations.cpp: Switched use of get to getPropertySlot.
+ * runtime/JSCJSValue.h:
+ added getPropertySlot for when you don't want to perform the get quite yet but want
+ to fill out the slot.
+ * runtime/JSCJSValueInlines.h: Added implementation for getPropertySlot
+ (JSC::JSValue::get): changed to simply call getPropertySlot
+ (JSC::JSValue::getPropertySlot): added.
+ * tests/stress/recursive_property_redefine_during_inline_caching.js: Added test case for bug.
+ (test):
+
2014-12-01 Michael Saboff <msab...@apple.com>
Remove GetMyScope node from DFG
Modified: trunk/Source/_javascript_Core/jit/JITOperations.cpp (176675 => 176676)
--- trunk/Source/_javascript_Core/jit/JITOperations.cpp 2014-12-02 19:26:48 UTC (rev 176675)
+++ trunk/Source/_javascript_Core/jit/JITOperations.cpp 2014-12-02 19:27:23 UTC (rev 176676)
@@ -147,12 +147,12 @@
JSValue baseValue = JSValue::decode(base);
PropertySlot slot(baseValue);
- JSValue result = baseValue.get(exec, ident, slot);
-
+ bool hasResult = baseValue.getPropertySlot(exec, ident, slot);
+
if (accessType == static_cast<AccessType>(stubInfo->accessType))
buildGetByIDList(exec, baseValue, ident, slot, *stubInfo);
- return JSValue::encode(result);
+ return JSValue::encode(hasResult? slot.getValue(exec, ident) : jsUndefined());
}
EncodedJSValue JIT_OPERATION operationGetByIdOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue base, StringImpl* uid)
@@ -160,18 +160,15 @@
VM* vm = &exec->vm();
NativeCallFrameTracer tracer(vm, exec);
Identifier ident = uid->isEmptyUnique() ? Identifier::from(PrivateName(uid)) : Identifier(vm, uid);
- AccessType accessType = static_cast<AccessType>(stubInfo->accessType);
JSValue baseValue = JSValue::decode(base);
PropertySlot slot(baseValue);
JSValue result = baseValue.get(exec, ident, slot);
- if (accessType == static_cast<AccessType>(stubInfo->accessType)) {
- if (stubInfo->seen)
- repatchGetByID(exec, baseValue, ident, slot, *stubInfo);
- else
- stubInfo->seen = true;
- }
+ if (stubInfo->seen)
+ repatchGetByID(exec, baseValue, ident, slot, *stubInfo);
+ else
+ stubInfo->seen = true;
return JSValue::encode(result);
}
Modified: trunk/Source/_javascript_Core/runtime/JSCJSValue.h (176675 => 176676)
--- trunk/Source/_javascript_Core/runtime/JSCJSValue.h 2014-12-02 19:26:48 UTC (rev 176675)
+++ trunk/Source/_javascript_Core/runtime/JSCJSValue.h 2014-12-02 19:27:23 UTC (rev 176676)
@@ -262,6 +262,9 @@
JSValue get(ExecState*, PropertyName, PropertySlot&) const;
JSValue get(ExecState*, unsigned propertyName) const;
JSValue get(ExecState*, unsigned propertyName, PropertySlot&) const;
+
+ bool getPropertySlot(ExecState*, PropertyName, PropertySlot&) const;
+
void put(ExecState*, PropertyName, JSValue, PutPropertySlot&);
JS_EXPORT_PRIVATE void putToPrimitive(ExecState*, PropertyName, JSValue, PutPropertySlot&);
JS_EXPORT_PRIVATE void putToPrimitiveByIndex(ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
Modified: trunk/Source/_javascript_Core/runtime/JSCJSValueInlines.h (176675 => 176676)
--- trunk/Source/_javascript_Core/runtime/JSCJSValueInlines.h 2014-12-02 19:26:48 UTC (rev 176675)
+++ trunk/Source/_javascript_Core/runtime/JSCJSValueInlines.h 2014-12-02 19:27:23 UTC (rev 176676)
@@ -682,19 +682,23 @@
ALWAYS_INLINE JSValue JSValue::get(ExecState* exec, PropertyName propertyName, PropertySlot& slot) const
{
+ return getPropertySlot(exec, propertyName, slot) ?
+ slot.getValue(exec, propertyName) : jsUndefined();
+}
+
+ALWAYS_INLINE bool JSValue::getPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot) const
+{
// If this is a primitive, we'll need to synthesize the prototype -
// and if it's a string there are special properties to check first.
JSObject* object;
if (UNLIKELY(!isObject())) {
if (isCell() && asString(*this)->getStringPropertySlot(exec, propertyName, slot))
- return slot.getValue(exec, propertyName);
+ return true;
object = synthesizePrototype(exec);
} else
object = asObject(asCell());
- if (object->getPropertySlot(exec, propertyName, slot))
- return slot.getValue(exec, propertyName);
- return jsUndefined();
+ return object->getPropertySlot(exec, propertyName, slot);
}
ALWAYS_INLINE JSValue JSValue::get(ExecState* exec, unsigned propertyName) const
Added: trunk/Source/_javascript_Core/tests/stress/recursive_property_redefine_during_inline_caching.js (0 => 176676)
--- trunk/Source/_javascript_Core/tests/stress/recursive_property_redefine_during_inline_caching.js (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/recursive_property_redefine_during_inline_caching.js 2014-12-02 19:27:23 UTC (rev 176676)
@@ -0,0 +1,23 @@
+// to be run with useLLInt = false
+var o = {};
+
+function getSomeProperty(){
+ return o.someProperty;
+}
+
+var count = 0;
+function test(){
+ count++;
+ if (count == 3) {
+ Object.defineProperty(this, 'someProperty', { value : "okay" });
+ return getSomeProperty();
+ }
+ return "okay";
+}
+
+o.__defineGetter__('someProperty', test)
+
+for (var i = 0; i < 4; i++) {
+ if (getSomeProperty() != "okay")
+ throw ("Error: " + i);
+}