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