From dc91c4218bfc3be5176ca59b8927258e0676a010 Mon Sep 17 00:00:00 2001 From: "kmillikin@chromium.org" Date: Wed, 9 Feb 2011 16:43:23 +0000 Subject: [PATCH] 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 --- src/ia32/lithium-codegen-ia32.cc | 16 ++++++++++++---- src/ia32/lithium-ia32.cc | 4 +++- src/ia32/lithium-ia32.h | 6 ++++-- test/mjsunit/compiler/regress-arguments.js | 5 ++++- 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index b6a6382..d725191 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 diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc index 793a3f4..f4502bc 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); } diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h index 56d031c..87b25d1 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") diff --git a/test/mjsunit/compiler/regress-arguments.js b/test/mjsunit/compiler/regress-arguments.js index 234d3fb..ebae5a0 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()); -- 2.7.4