REGRESSION: d3 Bullet Charts demo doesn't work (call with argument assignment is broken)
https://bugs.webkit.org/show_bug.cgi?id=75911
Source/JavaScriptCore:
* bytecompiler/BytecodeGenerator.h:
(JSC::BytecodeGenerator::emitNodeForLeftHandSide): Cleanup: No need to
explicitly cast to our return type in C++.
* bytecompiler/NodesCodegen.cpp:
(JSC::FunctionCallResolveNode::emitBytecode):
(JSC::ApplyFunctionCallDotNode::emitBytecode): Make sure to copy our function
into a temporary register before evaluating our arguments, since argument
evaluation might include function calls or assignments that overwrite our callee by name.
LayoutTests:
Reviewed by Filip Pizlo.
* fast/js/function-argument-evaluation-expected.txt: Added.
* fast/js/function-argument-evaluation.html: Added.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@104762 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index ca713e6..e122b9e 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,13 @@
+2012-01-09 Geoffrey Garen <ggaren@apple.com>
+
+ REGRESSION: d3 Bullet Charts demo doesn't work (call with argument assignment is broken)
+ https://bugs.webkit.org/show_bug.cgi?id=75911
+
+ Reviewed by Filip Pizlo.
+
+ * fast/js/function-argument-evaluation-expected.txt: Added.
+ * fast/js/function-argument-evaluation.html: Added.
+
2012-01-11 Adam Barth <abarth@webkit.org>
IETC audio-interface-inherit.129 claims NETWORK_NO_SOURCE should not be overrideable
diff --git a/LayoutTests/fast/js/function-argument-evaluation-expected.txt b/LayoutTests/fast/js/function-argument-evaluation-expected.txt
new file mode 100644
index 0000000..7253602
--- /dev/null
+++ b/LayoutTests/fast/js/function-argument-evaluation-expected.txt
@@ -0,0 +1,7 @@
+This page tests function calls whose argument expressions overwrite the callee.
+
+If the test passes, you'll see PASS messages below.
+
+PASS: test1(callback, 1) should be 1 and is.
+PASS: test2(callback, 1) should be 1 and is.
+
diff --git a/LayoutTests/fast/js/function-argument-evaluation.html b/LayoutTests/fast/js/function-argument-evaluation.html
new file mode 100644
index 0000000..37d023b
--- /dev/null
+++ b/LayoutTests/fast/js/function-argument-evaluation.html
@@ -0,0 +1,48 @@
+<p>This page tests function calls whose argument expressions overwrite the callee.</p>
+<p>If the test passes, you'll see PASS messages below.
+</p>
+<pre id="console"></pre>
+
+<script>
+function log(s)
+{
+ document.getElementById("console").appendChild(document.createTextNode(s + "\n"));
+}
+
+function shouldBe(aDescription, a, b)
+{
+ if (a === b) {
+ log("PASS: " + aDescription + " should be " + b + " and is.");
+ } else {
+ log("FAIL: " + aDescription + " should be " + b + " but instead is " + a + ".");
+ }
+}
+
+function test1(callback, x) {
+ try {
+ return callback.apply(this, [ callback = x ]);
+ } catch(e) {
+ return e;
+ }
+};
+
+function test2(callback, x) {
+ try {
+ return callback(callback = x);
+ } catch(e) {
+ return e;
+ }
+};
+
+(function () {
+ if (window.layoutTestController)
+ layoutTestController.dumpAsText();
+
+ var callback = function callback(x) {
+ return x;
+ };
+
+ shouldBe("test1(callback, 1)", test1(callback, 1), 1);
+ shouldBe("test2(callback, 1)", test2(callback, 1), 1);
+})();
+</script>
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 4702ef5..810bac5 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,18 @@
+2012-01-09 Geoffrey Garen <ggaren@apple.com>
+
+ REGRESSION: d3 Bullet Charts demo doesn't work (call with argument assignment is broken)
+ https://bugs.webkit.org/show_bug.cgi?id=75911
+
+ * bytecompiler/BytecodeGenerator.h:
+ (JSC::BytecodeGenerator::emitNodeForLeftHandSide): Cleanup: No need to
+ explicitly cast to our return type in C++.
+
+ * bytecompiler/NodesCodegen.cpp:
+ (JSC::FunctionCallResolveNode::emitBytecode):
+ (JSC::ApplyFunctionCallDotNode::emitBytecode): Make sure to copy our function
+ into a temporary register before evaluating our arguments, since argument
+ evaluation might include function calls or assignments that overwrite our callee by name.
+
2012-01-11 Michael Saboff <msaboff@apple.com>
v8-regexp spends 35% of its time allocating and copying internal regexp results data
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
index 3ff5f23..ce8d8f8 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
@@ -274,7 +274,7 @@
return dst;
}
- return PassRefPtr<RegisterID>(emitNode(n));
+ return emitNode(n);
}
RegisterID* emitLoad(RegisterID* dst, bool);
diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
index a0127d8..132f666 100644
--- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
+++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
@@ -365,9 +365,10 @@
RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
if (RefPtr<RegisterID> local = generator.registerFor(m_ident)) {
+ RefPtr<RegisterID> function = generator.emitMove(generator.tempDestination(dst), local.get());
CallArguments callArguments(generator, m_args);
generator.emitLoad(callArguments.thisRegister(), jsUndefined());
- return generator.emitCall(generator.finalDestinationOrIgnored(dst, callArguments.thisRegister()), local.get(), callArguments, divot(), startOffset(), endOffset());
+ return generator.emitCall(generator.finalDestinationOrIgnored(dst, callArguments.thisRegister()), function.get(), callArguments, divot(), startOffset(), endOffset());
}
int index = 0;
@@ -505,6 +506,7 @@
RefPtr<RegisterID> profileHookRegister;
if (generator.shouldEmitProfileHooks())
profileHookRegister = generator.newTemporary();
+ RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get());
RefPtr<RegisterID> thisRegister = generator.emitNode(m_args->m_listNode->m_expr);
RefPtr<RegisterID> argsRegister;
ArgumentListNode* args = m_args->m_listNode->m_next;
@@ -518,7 +520,7 @@
while ((args = args->m_next))
generator.emitNode(args->m_expr);
- generator.emitCallVarargs(finalDestinationOrIgnored.get(), base.get(), thisRegister.get(), argsRegister.get(), generator.newTemporary(), profileHookRegister.get(), divot(), startOffset(), endOffset());
+ generator.emitCallVarargs(finalDestinationOrIgnored.get(), realFunction.get(), thisRegister.get(), argsRegister.get(), generator.newTemporary(), profileHookRegister.get(), divot(), startOffset(), endOffset());
}
generator.emitJump(end.get());
}