Modified: trunk/Source/_javascript_Core/ChangeLog (185276 => 185277)
--- trunk/Source/_javascript_Core/ChangeLog 2015-06-06 00:04:40 UTC (rev 185276)
+++ trunk/Source/_javascript_Core/ChangeLog 2015-06-06 00:33:43 UTC (rev 185277)
@@ -1,3 +1,25 @@
+2015-06-05 Mark Lam <[email protected]>
+
+ Subclasses of JSNonFinalObject with gc'able children need to implement visitChildren().
+ https://bugs.webkit.org/show_bug.cgi?id=145709
+
+ Reviewed by Geoffrey Garen.
+
+ * jsc.cpp:
+ (functionSetElementRoot):
+ - The Element class has a member of type Root which extends JSDestructibleObject.
+ It should be stored in a WriteBarrier, and visited by visitChildren().
+
+ * runtime/ClonedArguments.cpp:
+ (JSC::ClonedArguments::materializeSpecialsIfNecessary):
+ (JSC::ClonedArguments::visitChildren):
+ * runtime/ClonedArguments.h:
+ - Add missing visitChildren().
+
+ * tests/stress/cloned-arguments-should-visit-callee-during-gc.js: Added.
+ (makeTransientFunction.transientFunc):
+ (makeTransientFunction):
+
2015-06-05 Geoffrey Garen <[email protected]>
DropAllLocks RELEASE_ASSERT on iOS
Modified: trunk/Source/_javascript_Core/jsc.cpp (185276 => 185277)
--- trunk/Source/_javascript_Core/jsc.cpp 2015-06-06 00:04:40 UTC (rev 185276)
+++ trunk/Source/_javascript_Core/jsc.cpp 2015-06-06 00:33:43 UTC (rev 185277)
@@ -130,28 +130,35 @@
class Element : public JSNonFinalObject {
public:
- Element(VM& vm, Structure* structure, Root* root)
+ Element(VM& vm, Structure* structure)
: Base(vm, structure)
- , m_root(root)
{
}
typedef JSNonFinalObject Base;
static const bool needsDestruction = false;
- Root* root() const { return m_root; }
- void setRoot(Root* root) { m_root = root; }
+ Root* root() const { return m_root.get(); }
+ void setRoot(VM& vm, Root* root) { m_root.set(vm, this, root); }
static Element* create(VM& vm, JSGlobalObject* globalObject, Root* root)
{
Structure* structure = createStructure(vm, globalObject, jsNull());
- Element* element = new (NotNull, allocateCell<Element>(vm.heap, sizeof(Element))) Element(vm, structure, root);
- element->finishCreation(vm);
+ Element* element = new (NotNull, allocateCell<Element>(vm.heap, sizeof(Element))) Element(vm, structure);
+ element->finishCreation(vm, root);
return element;
}
- void finishCreation(VM&);
+ void finishCreation(VM&, Root*);
+ static void visitChildren(JSCell* cell, SlotVisitor& visitor)
+ {
+ Element* thisObject = jsCast<Element*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ Base::visitChildren(thisObject, visitor);
+ visitor.append(&thisObject->m_root);
+ }
+
static ElementHandleOwner* handleOwner();
static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
@@ -162,7 +169,7 @@
DECLARE_INFO;
private:
- Root* m_root;
+ WriteBarrier<Root> m_root;
};
class ElementHandleOwner : public WeakHandleOwner {
@@ -421,9 +428,10 @@
return owner;
}
-void Element::finishCreation(VM& vm)
+void Element::finishCreation(VM& vm, Root* root)
{
Base::finishCreation(vm);
+ setRoot(vm, root);
m_root->setElement(this);
}
@@ -786,7 +794,7 @@
JSLockHolder lock(exec);
Element* element = jsCast<Element*>(exec->argument(0));
Root* root = jsCast<Root*>(exec->argument(1));
- element->setRoot(root);
+ element->setRoot(exec->vm(), root);
return JSValue::encode(jsUndefined());
}
Modified: trunk/Source/_javascript_Core/runtime/ClonedArguments.cpp (185276 => 185277)
--- trunk/Source/_javascript_Core/runtime/ClonedArguments.cpp 2015-06-06 00:04:40 UTC (rev 185276)
+++ trunk/Source/_javascript_Core/runtime/ClonedArguments.cpp 2015-06-06 00:33:43 UTC (rev 185277)
@@ -218,5 +218,13 @@
materializeSpecials(exec);
}
+void ClonedArguments::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ ClonedArguments* thisObject = jsCast<ClonedArguments*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ Base::visitChildren(thisObject, visitor);
+ visitor.append(&thisObject->m_callee);
+}
+
} // namespace JSC
Modified: trunk/Source/_javascript_Core/runtime/ClonedArguments.h (185276 => 185277)
--- trunk/Source/_javascript_Core/runtime/ClonedArguments.h 2015-06-06 00:04:40 UTC (rev 185276)
+++ trunk/Source/_javascript_Core/runtime/ClonedArguments.h 2015-06-06 00:33:43 UTC (rev 185277)
@@ -55,6 +55,8 @@
static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
+ static void visitChildren(JSCell*, SlotVisitor&);
+
DECLARE_INFO;
private:
Added: trunk/Source/_javascript_Core/tests/stress/cloned-arguments-should-visit-callee-during-gc.js (0 => 185277)
--- trunk/Source/_javascript_Core/tests/stress/cloned-arguments-should-visit-callee-during-gc.js (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/cloned-arguments-should-visit-callee-during-gc.js 2015-06-06 00:33:43 UTC (rev 185277)
@@ -0,0 +1,34 @@
+// Test that the ClonedArguments created by the Function.arguments will properly
+// keep its callee alive. This test should not crash and should not print any error
+// messages.
+
+var cachedArguments = [];
+var numberOfEntries = 1000;
+
+function makeTransientFunction(i) {
+ function transientFunc() {
+ cachedArguments[i] = transientFunc.arguments;
+ }
+ return transientFunc;
+}
+
+for (i = 0; i < numberOfEntries; i++) {
+ var transientFunc = makeTransientFunction(i);
+ transientFunc();
+ // At this point, the only reference to the transient function is from
+ // cachedArguments[i].callee.
+}
+
+gc();
+
+// Allocate a bunch of memory to stomp over the transient functions that may have been
+// erroneously collected. webkit.org/b/145709
+for (i = 0; i < numberOfEntries; i++) {
+ new Object();
+}
+
+for (i = 0; i < numberOfEntries; i++) {
+ var callee = cachedArguments[i].callee;
+ if (typeof callee != "function")
+ print("ERROR: callee is " + callee);
+}