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

Review URL: http://codereview.chromium.org/6463025

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6707 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent e0422e54
...@@ -2116,6 +2116,9 @@ void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) { ...@@ -2116,6 +2116,9 @@ void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
void LCodeGen::DoApplyArguments(LApplyArguments* instr) { void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
Register receiver = ToRegister(instr->receiver()); 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->function()).is(edi));
ASSERT(ToRegister(instr->result()).is(eax)); ASSERT(ToRegister(instr->result()).is(eax));
...@@ -2125,14 +2128,19 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) { ...@@ -2125,14 +2128,19 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
__ cmp(receiver, Factory::null_value()); __ cmp(receiver, Factory::null_value());
__ j(equal, &global_receiver); __ j(equal, &global_receiver);
__ cmp(receiver, Factory::undefined_value()); __ 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); __ bind(&global_receiver);
__ mov(receiver, GlobalObjectOperand()); __ mov(receiver, GlobalObjectOperand());
__ bind(&receiver_ok); __ bind(&receiver_ok);
Register length = ToRegister(instr->length());
Register elements = ToRegister(instr->elements());
Label invoke; Label invoke;
// Copy the arguments to this function possibly from the // Copy the arguments to this function possibly from the
......
...@@ -1157,10 +1157,12 @@ LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) { ...@@ -1157,10 +1157,12 @@ LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
LOperand* receiver = UseFixed(instr->receiver(), eax); LOperand* receiver = UseFixed(instr->receiver(), eax);
LOperand* length = UseRegisterAtStart(instr->length()); LOperand* length = UseRegisterAtStart(instr->length());
LOperand* elements = UseRegisterAtStart(instr->elements()); LOperand* elements = UseRegisterAtStart(instr->elements());
LOperand* temp = FixedTemp(ebx);
LApplyArguments* result = new LApplyArguments(function, LApplyArguments* result = new LApplyArguments(function,
receiver, receiver,
length, length,
elements); elements,
temp);
return MarkAsCall(DefineFixed(result, eax), instr, CAN_DEOPTIMIZE_EAGERLY); return MarkAsCall(DefineFixed(result, eax), instr, CAN_DEOPTIMIZE_EAGERLY);
} }
......
...@@ -461,16 +461,18 @@ class LControlInstruction: public LTemplateInstruction<0, I, T> { ...@@ -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: public:
LApplyArguments(LOperand* function, LApplyArguments(LOperand* function,
LOperand* receiver, LOperand* receiver,
LOperand* length, LOperand* length,
LOperand* elements) { LOperand* elements,
LOperand* temp) {
inputs_[0] = function; inputs_[0] = function;
inputs_[1] = receiver; inputs_[1] = receiver;
inputs_[2] = length; inputs_[2] = length;
inputs_[3] = elements; inputs_[3] = elements;
temps_[0] = temp;
} }
DECLARE_CONCRETE_INSTRUCTION(ApplyArguments, "apply-arguments") DECLARE_CONCRETE_INSTRUCTION(ApplyArguments, "apply-arguments")
......
...@@ -46,4 +46,7 @@ function u() { ...@@ -46,4 +46,7 @@ function u() {
return f.apply(v, arguments); 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());
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment