Fix inlining of strict mode constructors.
authormstarzinger@chromium.org <mstarzinger@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 5 Mar 2012 12:46:50 +0000 (12:46 +0000)
committermstarzinger@chromium.org <mstarzinger@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 5 Mar 2012 12:46:50 +0000 (12:46 +0000)
Inlined strict mode functions (that are not called as methods) will get
their receiver reset to undefined. This should not happen when inlining
constructors.

This change also simplifies the test suite to reuse the same closures
into which constructors get inlined and use gc() to force V8 to forget
collected type feedback.

R=vegorov@chromium.org
TEST=mjsunit/compiler/inline-construct

Review URL: https://chromiumcodereview.appspot.com/9597017

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10920 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/hydrogen.cc
test/mjsunit/compiler/inline-construct.js

index 9c83380492f6158b14d3c181c345980ddb44936d..805e08762f0298c957dd8edfc467e0f3caa33366 100644 (file)
@@ -7693,7 +7693,7 @@ HEnvironment* HEnvironment::CopyForInlining(
   // builtin function, pass undefined as the receiver for function
   // calls (instead of the global receiver).
   if ((target->shared()->native() || !function->is_classic_mode()) &&
-      call_kind == CALL_AS_FUNCTION) {
+      call_kind == CALL_AS_FUNCTION && !is_construct) {
     inner->SetValueAt(0, undefined);
   }
   inner->SetValueAt(arity + 1, LookupContext());
index 16e19a7d7c885e40b96bdce069bf2b3fbd2017ea..af9e69c94020e2ea44283e689d9dd0d0b4809223 100644 (file)
@@ -25,7 +25,7 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Flags: --allow-natives-syntax --inline-construct
+// Flags: --allow-natives-syntax --expose-gc --inline-construct
 
 // Test inlining of constructor calls.
 
@@ -47,29 +47,37 @@ function TestInlinedConstructor(closure) {
   assertEquals(4, counter.value);
 }
 
+function TestInAllContexts(constructor) {
+  function value_context(a, b, counter) {
+    var obj = new constructor(a, b, counter);
+    return obj.x;
+  }
+  function test_context(a, b, counter) {
+    if (!new constructor(a, b, counter)) {
+      assertUnreachable("should not happen");
+    }
+    return a + b;
+  }
+  function effect_context(a, b, counter) {
+    new constructor(a, b, counter);
+    return a + b;
+  }
+  TestInlinedConstructor(value_context);
+  TestInlinedConstructor(test_context);
+  TestInlinedConstructor(effect_context);
+  %DeoptimizeFunction(value_context);
+  %DeoptimizeFunction(test_context);
+  %DeoptimizeFunction(effect_context);
+  gc();  // Makes V8 forget about type information for *_context.
+}
+
 
 // Test constructor returning nothing in all contexts.
 function c1(a, b, counter) {
   this.x = a + b;
   counter.value++;
 }
-function c1_value_context(a, b, counter) {
-  var obj = new c1(a, b, counter);
-  return obj.x;
-}
-function c1_test_context(a, b, counter) {
-  if (!new c1(a, b, counter)) {
-    assertUnreachable("should not happen");
-  }
-  return a + b;
-}
-function c1_effect_context(a, b, counter) {
-  new c1(a, b, counter);
-  return a + b;
-}
-TestInlinedConstructor(c1_value_context);
-TestInlinedConstructor(c1_test_context);
-TestInlinedConstructor(c1_effect_context);
+TestInAllContexts(c1);
 
 
 // Test constructor returning an object in all contexts.
@@ -79,23 +87,7 @@ function c2(a, b, counter) {
   counter.value++;
   return obj;
 }
-function c2_value_context(a, b, counter) {
-  var obj = new c2(a, b, counter);
-  return obj.x;
-}
-function c2_test_context(a, b, counter) {
-  if (!new c2(a, b, counter)) {
-    assertUnreachable("should not happen");
-  }
-  return a + b;
-}
-function c2_effect_context(a, b, counter) {
-  new c2(a, b, counter);
-  return a + b;
-}
-TestInlinedConstructor(c2_value_context);
-TestInlinedConstructor(c2_test_context);
-TestInlinedConstructor(c2_effect_context);
+TestInAllContexts(c2);
 
 
 // Test constructor returning a primitive value in all contexts.
@@ -104,23 +96,7 @@ function c3(a, b, counter) {
   counter.value++;
   return "not an object";
 }
-function c3_value_context(a, b, counter) {
-  var obj = new c3(a, b, counter);
-  return obj.x;
-}
-function c3_test_context(a, b, counter) {
-  if (!new c3(a, b, counter)) {
-    assertUnreachable("should not happen");
-  }
-  return a + b;
-}
-function c3_effect_context(a, b, counter) {
-  new c3(a, b, counter);
-  return a + b;
-}
-TestInlinedConstructor(c3_value_context);
-TestInlinedConstructor(c3_test_context);
-TestInlinedConstructor(c3_effect_context);
+TestInAllContexts(c3);
 
 
 // Test constructor called with too many arguments.
@@ -163,8 +139,14 @@ function c_unsupported_syntax(a, b, counter) {
     throw new Error();
   }
 }
-function f_unsupported_syntax(a, b, counter) {
-  var obj = new c_unsupported_syntax(a, b, counter);
-  return obj.x;
+TestInAllContexts(c_unsupported_syntax);
+
+
+// Regression test: Inlined constructors called as functions do not get their
+// implicit receiver object set to undefined, even in strict mode.
+function c_strict(a, b, counter) {
+  "use strict";
+  this.x = a + b;
+  counter.value++;
 }
-TestInlinedConstructor(f_unsupported_syntax);
+TestInAllContexts(c_strict);