Revision: 6799
Author: [email protected]
Date: Tue Feb 15 10:57:37 2011
Log: Strict mode "this" transformation in Function.call/Function.apply.
In strict mode the transformation of "this" is skipped.

Code review feedback.
Testing memory operand against 8 bit IMM on ia32 and x64.

Review URL: http://codereview.chromium.org/6524006
http://code.google.com/p/v8/source/detail?r=6799

Modified:
 /branches/bleeding_edge/src/arm/builtins-arm.cc
 /branches/bleeding_edge/src/ia32/builtins-ia32.cc
 /branches/bleeding_edge/src/objects.h
 /branches/bleeding_edge/src/x64/builtins-x64.cc
 /branches/bleeding_edge/test/es5conform/es5conform.status
 /branches/bleeding_edge/test/mjsunit/strict-mode.js

=======================================
--- /branches/bleeding_edge/src/arm/builtins-arm.cc     Sun Feb 13 02:24:39 2011
+++ /branches/bleeding_edge/src/arm/builtins-arm.cc     Tue Feb 15 10:57:37 2011
@@ -1231,6 +1231,14 @@
     // Change context eagerly in case we need the global receiver.
     __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));

+    // Do not transform the receiver for strict mode functions.
+    __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
+ __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kCompilerHintsOffset));
+    __ tst(r2, Operand(1 << (SharedFunctionInfo::kStrictModeFunction +
+                             kSmiTagSize)));
+    __ b(ne, &shift_arguments);
+
+    // Compute the receiver in non-strict mode.
     __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
     __ ldr(r2, MemOperand(r2, -kPointerSize));
     // r0: actual number of arguments
@@ -1394,10 +1402,20 @@
   // Change context eagerly to get the right global object if necessary.
   __ ldr(r0, MemOperand(fp, kFunctionOffset));
   __ ldr(cp, FieldMemOperand(r0, JSFunction::kContextOffset));
+  // Load the shared function info while the function is still in r0.
+  __ ldr(r1, FieldMemOperand(r0, JSFunction::kSharedFunctionInfoOffset));

   // Compute the receiver.
   Label call_to_object, use_global_receiver, push_receiver;
   __ ldr(r0, MemOperand(fp, kRecvOffset));
+
+  // Do not transform the receiver for strict mode functions.
+ __ ldr(r1, FieldMemOperand(r1, SharedFunctionInfo::kCompilerHintsOffset));
+  __ tst(r1, Operand(1 << (SharedFunctionInfo::kStrictModeFunction +
+                           kSmiTagSize)));
+  __ b(ne, &push_receiver);
+
+  // Compute the receiver in non-strict mode.
   __ tst(r0, Operand(kSmiTagMask));
   __ b(eq, &call_to_object);
   __ LoadRoot(r1, Heap::kNullValueRootIndex);
=======================================
--- /branches/bleeding_edge/src/ia32/builtins-ia32.cc Mon Jan 3 03:39:22 2011 +++ /branches/bleeding_edge/src/ia32/builtins-ia32.cc Tue Feb 15 10:57:37 2011
@@ -589,6 +589,13 @@
     // Change context eagerly in case we need the global receiver.
     __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));

+    // Do not transform the receiver for strict mode functions.
+    __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
+    __ test_b(FieldOperand(ebx, SharedFunctionInfo::kStrictModeByteOffset),
+              1 << SharedFunctionInfo::kStrictModeBitWithinByte);
+    __ j(not_equal, &shift_arguments);
+
+    // Compute the receiver in non-strict mode.
     __ mov(ebx, Operand(esp, eax, times_4, 0));  // First argument.
     __ test(ebx, Immediate(kSmiTagMask));
     __ j(zero, &convert_to_object);
@@ -736,6 +743,14 @@
   // Compute the receiver.
   Label call_to_object, use_global_receiver, push_receiver;
   __ mov(ebx, Operand(ebp, 3 * kPointerSize));
+
+  // Do not transform the receiver for strict mode functions.
+  __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
+  __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset),
+            1 << SharedFunctionInfo::kStrictModeBitWithinByte);
+  __ j(not_equal, &push_receiver);
+
+  // Compute the receiver in non-strict mode.
   __ test(ebx, Immediate(kSmiTagMask));
   __ j(zero, &call_to_object);
   __ cmp(ebx, Factory::null_value());
=======================================
--- /branches/bleeding_edge/src/objects.h       Mon Feb 14 15:41:47 2011
+++ /branches/bleeding_edge/src/objects.h       Tue Feb 15 10:57:37 2011
@@ -4370,7 +4370,6 @@
kThisPropertyAssignmentsOffset + kPointerSize,
                               kSize> BodyDescriptor;

- private:
   // Bit positions in start_position_and_type.
   // The source code start position is in the 30 most significant bits of
   // the start_position_and_type field.
@@ -4389,6 +4388,35 @@
   static const int kOptimizationDisabled = 7;
   static const int kStrictModeFunction = 8;

+private:
+#if V8_HOST_ARCH_32_BIT
+  // On 32 bit platforms, compiler hints is a smi.
+  static const int kCompilerHintsSmiTagSize = kSmiTagSize;
+  static const int kCompilerHintsSize = kPointerSize;
+#else
+  // On 64 bit platforms, compiler hints is not a smi, see comment above.
+  static const int kCompilerHintsSmiTagSize = 0;
+  static const int kCompilerHintsSize = kIntSize;
+#endif
+
+public:
+  // Constants for optimizing codegen for strict mode function tests.
+  // Allows to use byte-widgh instructions.
+  static const int kStrictModeBitWithinByte =
+      (kStrictModeFunction + kCompilerHintsSmiTagSize) % kBitsPerByte;
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+  static const int kStrictModeByteOffset = kCompilerHintsOffset +
+    (kStrictModeFunction + kCompilerHintsSmiTagSize) / kBitsPerByte;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+  static const int kStrictModeByteOffset = kCompilerHintsOffset +
+    (kCompilerHintsSize - 1) -
+    ((kStrictModeFunction + kCompilerHintsSmiTagSize) / kBitsPerByte);
+#else
+#error Unknown byte ordering
+#endif
+
+private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(SharedFunctionInfo);
 };

=======================================
--- /branches/bleeding_edge/src/x64/builtins-x64.cc     Tue Feb 15 05:37:10 2011
+++ /branches/bleeding_edge/src/x64/builtins-x64.cc     Tue Feb 15 10:57:37 2011
@@ -651,6 +651,13 @@
     // Change context eagerly in case we need the global receiver.
     __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));

+    // Do not transform the receiver for strict mode functions.
+    __ movq(rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
+    __ testb(FieldOperand(rbx, SharedFunctionInfo::kStrictModeByteOffset),
+             Immediate(1 << SharedFunctionInfo::kStrictModeBitWithinByte));
+    __ j(not_equal, &shift_arguments);
+
+    // Compute the receiver in non-strict mode.
     __ movq(rbx, Operand(rsp, rax, times_pointer_size, 0));
     __ JumpIfSmi(rbx, &convert_to_object);

@@ -807,6 +814,14 @@
   // Compute the receiver.
   Label call_to_object, use_global_receiver, push_receiver;
   __ movq(rbx, Operand(rbp, kReceiverOffset));
+
+  // Do not transform the receiver for strict mode functions.
+  __ movq(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
+  __ testb(FieldOperand(rdx, SharedFunctionInfo::kStrictModeByteOffset),
+           Immediate(1 << SharedFunctionInfo::kStrictModeBitWithinByte));
+  __ j(not_equal, &push_receiver);
+
+  // Compute the receiver in non-strict mode.
   __ JumpIfSmi(rbx, &call_to_object);
   __ CompareRoot(rbx, Heap::kNullValueRootIndex);
   __ j(equal, &use_global_receiver);
=======================================
--- /branches/bleeding_edge/test/es5conform/es5conform.status Mon Feb 14 15:41:47 2011 +++ /branches/bleeding_edge/test/es5conform/es5conform.status Tue Feb 15 10:57:37 2011
@@ -239,15 +239,6 @@
 # Incorrect test - need double escape in eval.
 chapter07/7.8/7.8.4/7.8.4-1-s: FAIL

-# this is not coerced to an object in strict mode (Number)
-chapter10/10.4/10.4.3/10.4.3-1-1-s: FAIL
-# this is not coerced to an object in strict mode (string)
-chapter10/10.4/10.4.3/10.4.3-1-2-s: FAIL
-# this is not coerced to an object in strict mode (undefined)
-chapter10/10.4/10.4.3/10.4.3-1-3-s: FAIL
-# this is not coerced to an object in strict mode (boolean)
-chapter10/10.4/10.4.3/10.4.3-1-4-s: FAIL
-
 # arguments[i] remains same after changing actual parameters in strict mode
 chapter10/10.6/10.6-10-c-ii-1-s: FAIL
 # arguments[i] doesn't map to actual parameters in strict mode
@@ -436,53 +427,13 @@
 # Test fails to return true on success (invalid test case).
 chapter13/13.1/13.1-3-12-s: FAIL

-# 'use strict' directive - correct usage
-# depends on "this is not coerced to an object in strict mode (undefined)"
-chapter14/14.1/14.1-1-s: FAIL
-# "use strict" directive - correct usage double quotes
-# depends on "this is not coerced to an object in strict mode (undefined)"
-chapter14/14.1/14.1-2-s: FAIL
-# 'use strict' directive - may follow other directives
-# depends on "this is not coerced to an object in strict mode (undefined)"
-chapter14/14.1/14.1-8-s: FAIL
-# 'use strict' directive - may occur multiple times
-# depends on "this is not coerced to an object in strict mode (undefined)"
-chapter14/14.1/14.1-9-s: FAIL
-# other directives - may follow 'use strict' directive
-# depends on "this is not coerced to an object in strict mode (undefined)"
-chapter14/14.1/14.1-10-s: FAIL
-# comments may preceed 'use strict' directive
-# depends on "this is not coerced to an object in strict mode (undefined)"
-chapter14/14.1/14.1-11-s: FAIL
-# comments may follow 'use strict' directive
-# depends on "this is not coerced to an object in strict mode (undefined)"
-chapter14/14.1/14.1-12-s: FAIL
-# semicolon insertion works for'use strict' directive
-# depends on "this is not coerced to an object in strict mode (undefined)"
-chapter14/14.1/14.1-13-s: FAIL
-# semicolon insertion may come before 'use strict' directive
-# depends on "this is not coerced to an object in strict mode (undefined)"
-chapter14/14.1/14.1-14-s: FAIL
-# blank lines may come before 'use strict' directive
-# depends on "this is not coerced to an object in strict mode (undefined)"
-chapter14/14.1/14.1-15-s: FAIL
-
 # Duplicate combined parameter name allowed in Function constructor called
 # in strict mode if body not strict
 # Test fails to return true on success (invalid test case).
 chapter15/15.3/15.3.2/15.3.2.1/15.3.2.1-11-6-s: FAIL

-# Array.prototype.every - thisArg not passed to strict callbackfn
-chapter15/15.4/15.4.4/15.4.4.16/15.4.4.16-5-1-s: FAIL
-# Array.prototype.some - thisArg not passed to strict callbackfn
-chapter15/15.4/15.4.4/15.4.4.17/15.4.4.17-5-1-s: FAIL
-# Array.prototype.forEach - thisArg not passed to strict callbackfn
-chapter15/15.4/15.4.4/15.4.4.18/15.4.4.18-5-1-s: FAIL
-# Array.prototype.map - thisArg not passed to strict callbackfn
-chapter15/15.4/15.4.4/15.4.4.19/15.4.4.19-5-1-s: FAIL
-# Array.prototype.filter - thisArg not passed to strict callbackfn
-chapter15/15.4/15.4.4/15.4.4.20/15.4.4.20-5-1-s: FAIL
 # Array.prototype.reduce - null passed as thisValue to strict callbackfn
+# Invalid test case: http://es5conform.codeplex.com/workitem/29085
 chapter15/15.4/15.4.4/15.4.4.21/15.4.4.21-9-c-ii-4-s: FAIL

 [ $arch == mips ]
=======================================
--- /branches/bleeding_edge/test/mjsunit/strict-mode.js Mon Feb 14 15:41:47 2011 +++ /branches/bleeding_edge/test/mjsunit/strict-mode.js Tue Feb 15 10:57:37 2011
@@ -436,3 +436,45 @@
   assertThrows(function() { delete_element(object, 3.14); }, TypeError);
   assertEquals(object[3.14], "pi");
 })();
+
+// Not transforming this in Function.call and Function.apply.
+(function testThisTransform() {
+  function non_strict() {
+    return this;
+  }
+  function strict() {
+    "use strict";
+    return this;
+  }
+
+  var global_object = (function() { return this; })();
+  var object = {};
+
+  // Non-strict call.
+  assertTrue(non_strict.call(null) === global_object);
+  assertTrue(non_strict.call(undefined) === global_object);
+  assertEquals(typeof non_strict.call(7), "object");
+  assertEquals(typeof non_strict.call("Hello"), "object");
+  assertTrue(non_strict.call(object) === object);
+
+  // Non-strict apply.
+  assertTrue(non_strict.apply(null) === global_object);
+  assertTrue(non_strict.apply(undefined) === global_object);
+  assertEquals(typeof non_strict.apply(7), "object");
+  assertEquals(typeof non_strict.apply("Hello"), "object");
+  assertTrue(non_strict.apply(object) === object);
+
+  // Strict call.
+  assertTrue(strict.call(null) === null);
+  assertTrue(strict.call(undefined) === undefined);
+  assertEquals(typeof strict.call(7), "number");
+  assertEquals(typeof strict.call("Hello"), "string");
+  assertTrue(strict.call(object) === object);
+
+  // Strict apply.
+  assertTrue(strict.apply(null) === null);
+  assertTrue(strict.apply(undefined) === undefined);
+  assertEquals(typeof strict.apply(7), "number");
+  assertEquals(typeof strict.apply("Hello"), "string");
+  assertTrue(strict.apply(object) === object);
+})();

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to