Reviewers: Mads Ager,

Description:
Make optimized Function.prototype.apply safe for non-JSObject first arguments.

If we have a property access of the form this.x, where the access site sees
the global object, we can specialize the IC stub so that it performs a map
check without first performing a heap object check.

Ensure that we do not get in JS code with a non-JSObject this value by
deoptimizing at Function.prototype.apply if the first argument is not a
JSObject.

BUG=v8:1128

Please review this at http://codereview.chromium.org/6463025/

SVN Base: https://v8.googlecode.com/svn/branches/bleeding_edge/build/ia32

Affected files:
  M src/ia32/lithium-codegen-ia32.cc
  M src/ia32/lithium-ia32.h
  M src/ia32/lithium-ia32.cc
  M test/mjsunit/compiler/regress-arguments.js


Index: src/ia32/lithium-codegen-ia32.cc
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index b6a6382017fa9d08088a5619383baa3ec456d672..d725191558b144e15f6617fce505103b825baa56 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -2116,6 +2116,9 @@ void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {

 void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
   Register receiver = ToRegister(instr->receiver());
+  Register length = ToRegister(instr->length());
+  Register elements = ToRegister(instr->elements());
+  Register temp = ToRegister(instr->TempAt(0));
   ASSERT(ToRegister(instr->function()).is(edi));
   ASSERT(ToRegister(instr->result()).is(eax));

@@ -2125,14 +2128,19 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
   __ cmp(receiver, Factory::null_value());
   __ j(equal, &global_receiver);
   __ cmp(receiver, Factory::undefined_value());
-  __ j(not_equal, &receiver_ok);
+  __ j(equal, &global_receiver);
+
+  // The receiver should be a JS object.
+  __ test(receiver, Immediate(kSmiTagMask));
+  DeoptimizeIf(equal, instr->environment());
+  __ CmpObjectType(receiver, FIRST_JS_OBJECT_TYPE, temp);
+  DeoptimizeIf(below, instr->environment());
+  __ jmp(&receiver_ok);
+
   __ bind(&global_receiver);
   __ mov(receiver, GlobalObjectOperand());
   __ bind(&receiver_ok);

-  Register length = ToRegister(instr->length());
-  Register elements = ToRegister(instr->elements());
-
   Label invoke;

   // Copy the arguments to this function possibly from the
Index: src/ia32/lithium-ia32.cc
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index 793a3f45ee224b063af93e32828a1b4a71607d39..f4502bc9b8b14d4aa80bc1336b86935cac8468dc 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -1157,10 +1157,12 @@ LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
   LOperand* receiver = UseFixed(instr->receiver(), eax);
   LOperand* length = UseRegisterAtStart(instr->length());
   LOperand* elements = UseRegisterAtStart(instr->elements());
+  LOperand* temp = FixedTemp(ebx);
   LApplyArguments* result = new LApplyArguments(function,
                                                 receiver,
                                                 length,
-                                                elements);
+                                                elements,
+                                                temp);
return MarkAsCall(DefineFixed(result, eax), instr, CAN_DEOPTIMIZE_EAGERLY);
 }

Index: src/ia32/lithium-ia32.h
diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h
index 56d031cd0b468726f4870f08a181f2c3801ec02c..87b25d15a8e7c9471ea4ea7b09547a71c4ff2d6a 100644
--- a/src/ia32/lithium-ia32.h
+++ b/src/ia32/lithium-ia32.h
@@ -461,16 +461,18 @@ class LControlInstruction: public LTemplateInstruction<0, I, T> {
 };


-class LApplyArguments: public LTemplateInstruction<1, 4, 0> {
+class LApplyArguments: public LTemplateInstruction<1, 4, 1> {
  public:
   LApplyArguments(LOperand* function,
                   LOperand* receiver,
                   LOperand* length,
-                  LOperand* elements) {
+                  LOperand* elements,
+                  LOperand* temp) {
     inputs_[0] = function;
     inputs_[1] = receiver;
     inputs_[2] = length;
     inputs_[3] = elements;
+    temps_[0] = temp;
   }

   DECLARE_CONCRETE_INSTRUCTION(ApplyArguments, "apply-arguments")
Index: test/mjsunit/compiler/regress-arguments.js
diff --git a/test/mjsunit/compiler/regress-arguments.js b/test/mjsunit/compiler/regress-arguments.js index 234d3fbc974dafd36a3fb915e58648fd55641434..ebae5a03998b2cb5dd63d7d0b519b93635d359cd 100644
--- a/test/mjsunit/compiler/regress-arguments.js
+++ b/test/mjsunit/compiler/regress-arguments.js
@@ -46,4 +46,7 @@ function u() {
  return f.apply(v, arguments);
 }

-for (var i=0; i<1000000; i++) assertEquals(void 0, u());
+Number.prototype.foo = 42;
+delete Number.prototype.foo;
+
+for (var i=0; i<100000; i++) assertEquals(void 0, u());


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

Reply via email to