Only send null or undefined as receiver for es5 natives, not generally
authorricow@chromium.org <ricow@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 13 May 2011 07:26:44 +0000 (07:26 +0000)
committerricow@chromium.org <ricow@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 13 May 2011 07:26:44 +0000 (07:26 +0000)
for builtin functions.
Review URL: http://codereview.chromium.org/7012012

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

src/arm/builtins-arm.cc
src/heap.cc
src/ia32/builtins-ia32.cc
src/objects-inl.h
src/objects.h
src/runtime.cc
src/runtime.h
src/v8natives.js
src/x64/builtins-x64.cc
test/cctest/test-api.cc
test/mjsunit/regress/regress-1369.js

index 3198092e3beff5db947bb48b96dd783fefbdba14..1b2b919305526b745bb7d47154b775effb993885 100644 (file)
@@ -1243,15 +1243,10 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
                              kSmiTagSize)));
     __ b(ne, &shift_arguments);
 
-    // Do not transform the receiver for native (shared already in r2).
-    __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kScriptOffset));
-    __ LoadRoot(r3, Heap::kUndefinedValueRootIndex);
-    __ cmp(r2, r3);
-    __ b(eq, &shift_arguments);
-    __ ldr(r2, FieldMemOperand(r2, Script::kTypeOffset));
-    __ mov(r2, Operand(r2, ASR, kSmiTagSize));
-    __ cmp(r2, Operand(Script::TYPE_NATIVE));
-    __ b(eq, &shift_arguments);
+    // Do not transform the receiver for native (Compilerhints already in r3).
+    __ tst(r3, Operand(1 << (SharedFunctionInfo::kES5Native +
+                             kSmiTagSize)));
+    __ b(ne, &shift_arguments);
 
     // Compute the receiver in non-strict mode.
     __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
@@ -1262,7 +1257,7 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
     __ tst(r2, Operand(kSmiTagMask));
     __ b(eq, &convert_to_object);
 
-    // Heap::kUndefinedValueRootIndex is already in r3.
+    __ LoadRoot(r3, Heap::kUndefinedValueRootIndex);
     __ cmp(r2, r3);
     __ b(eq, &use_global_receiver);
     __ LoadRoot(r3, Heap::kNullValueRootIndex);
@@ -1431,15 +1426,10 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
                            kSmiTagSize)));
   __ b(ne, &push_receiver);
 
-  // Do not transform the receiver for native (shared already in r1).
-  __ ldr(r1, FieldMemOperand(r1, SharedFunctionInfo::kScriptOffset));
-  __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
-  __ cmp(r1, r2);
-  __ b(eq, &push_receiver);
-  __ ldr(r1, FieldMemOperand(r1, Script::kTypeOffset));
-  __ mov(r1, Operand(r1, ASR, kSmiTagSize));
-  __ cmp(r1, Operand(Script::TYPE_NATIVE));
-  __ b(eq, &push_receiver);
+  // Do not transform the receiver for strict mode functions.
+  __ tst(r2, Operand(1 << (SharedFunctionInfo::kES5Native +
+                           kSmiTagSize)));
+  __ b(ne, &push_receiver);
 
   // Compute the receiver in non-strict mode.
   __ tst(r0, Operand(kSmiTagMask));
@@ -1447,8 +1437,8 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
   __ LoadRoot(r1, Heap::kNullValueRootIndex);
   __ cmp(r0, r1);
   __ b(eq, &use_global_receiver);
-  // Heap::kUndefinedValueRootIndex is already in r2.
-  __ cmp(r0, r2);
+  __ LoadRoot(r1, Heap::kUndefinedValueRootIndex);
+  __ cmp(r0, r1);
   __ b(eq, &use_global_receiver);
 
   // Check if the receiver is already a JavaScript object.
index 1f11f5aac20f32dbb78c4499def247f8f1f5405d..8f21669cc715f3f85dd68f0f27df54426168f4dc 100644 (file)
@@ -2377,6 +2377,7 @@ MaybeObject* Heap::AllocateSharedFunctionInfo(Object* name) {
   share->set_num_literals(0);
   share->set_end_position(0);
   share->set_function_token_position(0);
+  share->set_es5_native(false);
   return result;
 }
 
index 2af5c2086c1f8776f7ba2544553ca5697ec1ab70..44f0a977dca4e227046c37cb8596c6fcb4ec71bd 100644 (file)
@@ -600,13 +600,9 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
     __ j(not_equal, &shift_arguments);
 
     // Do not transform the receiver for natives (shared already in ebx).
-    __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kScriptOffset));
-    __ cmp(ebx, factory->undefined_value());
-    __ j(equal, &shift_arguments);
-    __ mov(ebx, FieldOperand(ebx, Script::kTypeOffset));
-    __ SmiUntag(ebx);
-    __ cmp(ebx, Script::TYPE_NATIVE);
-    __ j(equal, &shift_arguments);
+    __ test_b(FieldOperand(ebx, SharedFunctionInfo::kES5NativeByteOffset),
+              1 << SharedFunctionInfo::kES5NativeBitWithinByte);
+    __ j(not_equal, &shift_arguments);
 
     // Compute the receiver in non-strict mode.
     __ mov(ebx, Operand(esp, eax, times_4, 0));  // First argument.
@@ -767,13 +763,9 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
   Factory* factory = masm->isolate()->factory();
 
   // Do not transform the receiver for natives (shared already in ecx).
-  __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kScriptOffset));
-  __ cmp(ecx, factory->undefined_value());
-  __ j(equal, &push_receiver);
-  __ mov(ecx, FieldOperand(ecx, Script::kTypeOffset));
-  __ SmiUntag(ecx);
-  __ cmp(ecx, Script::TYPE_NATIVE);
-  __ j(equal, &push_receiver);
+  __ test_b(FieldOperand(ecx, SharedFunctionInfo::kES5NativeByteOffset),
+            1 << SharedFunctionInfo::kES5NativeBitWithinByte);
+  __ j(not_equal, &push_receiver);
 
   // Compute the receiver in non-strict mode.
   __ test(ebx, Immediate(kSmiTagMask));
index a49aaec24e1e652153d764e82d9d4af7a8f6bc36..f4de359b4694719eae23f67739371cb2d5060a44 100644 (file)
@@ -3218,6 +3218,18 @@ void SharedFunctionInfo::set_strict_mode(bool value) {
 }
 
 
+bool SharedFunctionInfo::es5_native() {
+  return BooleanBit::get(compiler_hints(), kES5Native);
+}
+
+
+void SharedFunctionInfo::set_es5_native(bool value) {
+  set_compiler_hints(BooleanBit::set(compiler_hints(),
+                                     kES5Native,
+                                     value));
+}
+
+
 ACCESSORS(CodeCache, default_cache, FixedArray, kDefaultCacheOffset)
 ACCESSORS(CodeCache, normal_type_cache, Object, kNormalTypeCacheOffset)
 
index fca694aa97ed4e89e5180db1c44887084c91d709..3570579714a17e5df626a4c59575b63f8a990f0d 100644 (file)
@@ -4349,6 +4349,13 @@ class SharedFunctionInfo: public HeapObject {
   inline bool strict_mode();
   inline void set_strict_mode(bool value);
 
+  // Indicates whether the function is a native ES5 function.
+  // These needs special threatment in .call and .apply since
+  // null passed as the receiver should not be translated to the
+  // global object.
+  inline bool es5_native();
+  inline void set_es5_native(bool value);
+
   // Indicates whether or not the code in the shared function support
   // deoptimization.
   inline bool has_deoptimization_support();
@@ -4529,6 +4536,7 @@ class SharedFunctionInfo: public HeapObject {
   static const int kCodeAgeMask = 0x7;
   static const int kOptimizationDisabled = 6;
   static const int kStrictModeFunction = 7;
+  static const int kES5Native = 8;
 
  private:
 #if V8_HOST_ARCH_32_BIT
@@ -4542,18 +4550,27 @@ class SharedFunctionInfo: public HeapObject {
 #endif
 
  public:
-  // Constants for optimizing codegen for strict mode function tests.
+  // Constants for optimizing codegen for strict mode function and
+  // es5 native tests.
   // Allows to use byte-widgh instructions.
   static const int kStrictModeBitWithinByte =
       (kStrictModeFunction + kCompilerHintsSmiTagSize) % kBitsPerByte;
 
+  static const int kES5NativeBitWithinByte =
+      (kES5Native + kCompilerHintsSmiTagSize) % kBitsPerByte;
+
 #if __BYTE_ORDER == __LITTLE_ENDIAN
   static const int kStrictModeByteOffset = kCompilerHintsOffset +
-    (kStrictModeFunction + kCompilerHintsSmiTagSize) / kBitsPerByte;
+      (kStrictModeFunction + kCompilerHintsSmiTagSize) / kBitsPerByte;
+  static const int kES5NativeByteOffset = kCompilerHintsOffset +
+      (kES5Native + kCompilerHintsSmiTagSize) / kBitsPerByte;
 #elif __BYTE_ORDER == __BIG_ENDIAN
   static const int kStrictModeByteOffset = kCompilerHintsOffset +
-    (kCompilerHintsSize - 1) -
-    ((kStrictModeFunction + kCompilerHintsSmiTagSize) / kBitsPerByte);
+      (kCompilerHintsSize - 1) -
+      ((kStrictModeFunction + kCompilerHintsSmiTagSize) / kBitsPerByte);
+  static const int kES5NativeByteOffset = kCompilerHintsOffset +
+      (kCompilerHintsSize - 1) -
+      ((kES5Native + kCompilerHintsSmiTagSize) / kBitsPerByte);
 #else
 #error Unknown byte ordering
 #endif
index 29d31dbdd544c5a8168bc3204de8f26917c126ac..2093983aedc48fd8cb5bc89a27489b4305ae2c83 100644 (file)
@@ -4107,6 +4107,23 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
 }
 
 
+// Set the ES5 native flag on the function.
+// This is used to decide if we should transform null and undefined
+// into the global object when doing call and apply.
+RUNTIME_FUNCTION(MaybeObject*, Runtime_SetES5Flag) {
+  NoHandleAllocation ha;
+  RUNTIME_ASSERT(args.length() == 1);
+
+  Handle<Object> object = args.at<Object>(0);
+
+  if (object->IsJSFunction()) {
+    JSFunction* func = JSFunction::cast(*object);
+    func->shared()->set_es5_native(true);
+  }
+  return isolate->heap()->undefined_value();
+}
+
+
 // Set a local property, even if it is READ_ONLY.  If the property does not
 // exist, it will be added with attributes NONE.
 RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
index 0641abd447f8b8a5278b05b4ba453f543ded33fd..a61e68134ced3120ac20a78f2b6011105aeede9b 100644 (file)
@@ -92,6 +92,7 @@ namespace internal {
   F(CompileForOnStackReplacement, 1, 1) \
   F(SetNewFunctionAttributes, 1, 1) \
   F(AllocateInNewSpace, 1, 1) \
+  F(SetES5Flag, 1, 1) \
   \
   /* Array join support */ \
   F(PushIfAbsent, 2, 1) \
index f5c251ee033988be9c57514ca8f988b9a302231f..8db736c732df02d29c3142d09033078165c54228 100644 (file)
@@ -56,6 +56,7 @@ function InstallFunctions(object, attributes, functions) {
     %FunctionSetName(f, key);
     %FunctionRemovePrototype(f);
     %SetProperty(object, key, f, attributes);
+    %SetES5Flag(f);
   }
   %ToFastProperties(object);
 }
index e45ef3e522467223a9f3134bf8a4f8bb6ece7fa7..57cde6520612c2cae306dc7b20ef7af63daf5ef7 100644 (file)
@@ -660,12 +660,9 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
 
     // Do not transform the receiver for natives.
     // SharedFunctionInfo is already loaded into rbx.
-    __ movq(rbx, FieldOperand(rbx, SharedFunctionInfo::kScriptOffset));
-    __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
-    __ j(equal, &shift_arguments);
-    __ SmiCompare(FieldOperand(rbx, Script::kTypeOffset),
-               Smi::FromInt(Script::TYPE_NATIVE));
-    __ j(equal, &shift_arguments);
+    __ testb(FieldOperand(rbx, SharedFunctionInfo::kES5NativeByteOffset),
+             Immediate(1 << SharedFunctionInfo::kES5NativeBitWithinByte));
+    __ j(not_zero, &shift_arguments);
 
     // Compute the receiver in non-strict mode.
     __ movq(rbx, Operand(rsp, rax, times_pointer_size, 0));
@@ -832,13 +829,9 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
   __ j(not_equal, &push_receiver);
 
   // Do not transform the receiver for natives.
-  // SharedFunctionInfo is already loaded into rdx.
-  __ movq(rdx, FieldOperand(rdx, SharedFunctionInfo::kScriptOffset));
-  __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex);
-  __ j(equal, &push_receiver);
-  __ SmiCompare(FieldOperand(rdx, Script::kTypeOffset),
-             Smi::FromInt(Script::TYPE_NATIVE));
-  __ j(equal, &push_receiver);
+  __ testb(FieldOperand(rdx, SharedFunctionInfo::kES5NativeByteOffset),
+           Immediate(1 << SharedFunctionInfo::kES5NativeBitWithinByte));
+  __ j(not_zero, &push_receiver);
 
   // Compute the receiver in non-strict mode.
   __ JumpIfSmi(rbx, &call_to_object);
index 88f8b2abcc879f7ed30043ad8e953725faab3edc..cf84538d830120829bcee127a9e2be3a8998e0b0 100644 (file)
@@ -14452,5 +14452,4 @@ THREADED_TEST(CallAPIFunctionOnNonObject) {
   context->Global()->Set(v8_str("f"), function);
   TryCatch try_catch;
   CompileRun("f.call(2)");
-  CHECK(try_catch.HasCaught());
 }
index f18e37bf82248f3db7cf7b44af30ae93a4e1991e..48a8e7ede043a63073be00ca6d646e4db1f3b253 100644 (file)
@@ -27,5 +27,5 @@
 
 // Flags: --expose-gc
 
-assertThrows('gc.call(1)');
-assertThrows('gc.call("asdf")');
+assertDoesNotThrow('gc.call(1)');
+assertDoesNotThrow('gc.call("asdf")');