Commit 7f1eda50 authored by antonm@chromium.org's avatar antonm@chromium.org

Implement a custom call compiler for Array.pop.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4118 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent d0908674
......@@ -864,6 +864,55 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object,
}
Object* CallStubCompiler::CompileArrayPopCall(Object* object,
JSObject* holder,
JSFunction* function,
String* name,
CheckType check) {
// ----------- S t a t e -------------
// -- r2 : name
// -- lr : return address
// -----------------------------------
// TODO(642): faster implementation.
ASSERT(check == RECEIVER_MAP_CHECK);
Label miss;
// Get the receiver from the stack
const int argc = arguments().immediate();
__ ldr(r1, MemOperand(sp, argc * kPointerSize));
// Check that the receiver isn't a smi.
__ tst(r1, Operand(kSmiTagMask));
__ b(eq, &miss);
// Check that the maps haven't changed.
CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss);
if (object->IsGlobalObject()) {
__ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
__ str(r3, MemOperand(sp, argc * kPointerSize));
}
__ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop),
argc + 1,
1);
// Handle call cache miss.
__ bind(&miss);
Handle<Code> ic = ComputeCallMiss(arguments().immediate());
__ Jump(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
String* function_name = NULL;
if (function->shared()->name()->IsString()) {
function_name = String::cast(function->shared()->name());
}
return GetCode(CONSTANT_FUNCTION, function_name);
}
Object* CallStubCompiler::CompileCallConstant(Object* object,
JSObject* holder,
JSFunction* function,
......
......@@ -1221,6 +1221,8 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object,
// -- ...
// -- esp[(argc + 1) * 4] : receiver
// -----------------------------------
ASSERT(check == RECEIVER_MAP_CHECK);
Label miss;
// Get the receiver from the stack.
......@@ -1229,7 +1231,7 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object,
// Check that the receiver isn't a smi.
__ test(edx, Immediate(kSmiTagMask));
__ j(zero, &miss, not_taken);
__ j(zero, &miss);
CheckPrototypes(JSObject::cast(object), edx,
holder, ebx,
......@@ -1246,13 +1248,15 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object,
// Check that the elements are in fast mode (not dictionary).
__ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
Immediate(Factory::fixed_array_map()));
__ j(not_equal, &miss, not_taken);
__ j(not_equal, &miss);
if (argc == 1) { // Otherwise fall through to call builtin.
Label call_builtin, exit, with_rset_update;
// Get the array's length into eax and calculate new length.
__ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
STATIC_ASSERT(kSmiTagSize == 1);
STATIC_ASSERT(kSmiTag == 0);
__ add(Operand(eax), Immediate(argc << 1));
// Get the element's length into ecx.
......@@ -1310,6 +1314,90 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object,
}
Object* CallStubCompiler::CompileArrayPopCall(Object* object,
JSObject* holder,
JSFunction* function,
String* name,
CheckType check) {
// ----------- S t a t e -------------
// -- ecx : name
// -- esp[0] : return address
// -- esp[(argc - n) * 4] : arg[n] (zero-based)
// -- ...
// -- esp[(argc + 1) * 4] : receiver
// -----------------------------------
ASSERT(check == RECEIVER_MAP_CHECK);
Label miss, empty_array, call_builtin;
// Get the receiver from the stack.
const int argc = arguments().immediate();
__ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
// Check that the receiver isn't a smi.
__ test(edx, Immediate(kSmiTagMask));
__ j(zero, &miss);
CheckPrototypes(JSObject::cast(object), edx,
holder, ebx,
eax, name, &miss);
// Get the elements array of the object.
__ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset));
// Check that the elements are in fast mode (not dictionary).
__ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
Immediate(Factory::fixed_array_map()));
__ j(not_equal, &miss);
// Get the array's length into ecx and calculate new length.
__ mov(ecx, FieldOperand(edx, JSArray::kLengthOffset));
__ sub(Operand(ecx), Immediate(Smi::FromInt(1)));
__ j(negative, &empty_array);
// Get the last element.
STATIC_ASSERT(kSmiTagSize == 1);
STATIC_ASSERT(kSmiTag == 0);
__ mov(eax, FieldOperand(ebx,
ecx, times_half_pointer_size,
FixedArray::kHeaderSize));
__ cmp(Operand(eax), Immediate(Factory::the_hole_value()));
__ j(equal, &call_builtin);
// Set the array's length.
__ mov(FieldOperand(edx, JSArray::kLengthOffset), ecx);
// Fill with the hole.
__ mov(FieldOperand(ebx,
ecx, times_half_pointer_size,
FixedArray::kHeaderSize),
Immediate(Factory::the_hole_value()));
__ ret((argc + 1) * kPointerSize);
__ bind(&empty_array);
__ mov(eax, Immediate(Factory::undefined_value()));
__ ret((argc + 1) * kPointerSize);
__ bind(&call_builtin);
__ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop),
argc + 1,
1);
__ bind(&miss);
Handle<Code> ic = ComputeCallMiss(arguments().immediate());
__ jmp(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
String* function_name = NULL;
if (function->shared()->name()->IsString()) {
function_name = String::cast(function->shared()->name());
}
return GetCode(CONSTANT_FUNCTION, function_name);
}
Object* CallStubCompiler::CompileCallConstant(Object* object,
JSObject* holder,
JSFunction* function,
......
......@@ -1276,12 +1276,22 @@ static Object* CompileArrayPushCall(CallStubCompiler* compiler,
}
static Object* CompileArrayPopCall(CallStubCompiler* compiler,
Object* object,
JSObject* holder,
JSFunction* function,
String* name,
StubCompiler::CheckType check) {
return compiler->CompileArrayPopCall(object, holder, function, name, check);
}
static Object* Runtime_SpecialArrayFunctions(Arguments args) {
HandleScope scope;
ASSERT(args.length() == 1);
CONVERT_ARG_CHECKED(JSObject, holder, 0);
InstallBuiltin(holder, "pop", Builtins::ArrayPop);
InstallBuiltin(holder, "pop", Builtins::ArrayPop, CompileArrayPopCall);
InstallBuiltin(holder, "push", Builtins::ArrayPush, CompileArrayPushCall);
InstallBuiltin(holder, "shift", Builtins::ArrayShift);
InstallBuiltin(holder, "unshift", Builtins::ArrayUnshift);
......
......@@ -575,6 +575,12 @@ class CallStubCompiler: public StubCompiler {
String* name,
CheckType check);
Object* CompileArrayPopCall(Object* object,
JSObject* holder,
JSFunction* function,
String* name,
CheckType check);
private:
const ParameterCount arguments_;
const InLoopFlag in_loop_;
......
......@@ -697,6 +697,61 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object,
argc + 1,
1);
// Handle call cache miss.
__ bind(&miss);
Handle<Code> ic = ComputeCallMiss(arguments().immediate());
__ Jump(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
String* function_name = NULL;
if (function->shared()->name()->IsString()) {
function_name = String::cast(function->shared()->name());
}
return GetCode(CONSTANT_FUNCTION, function_name);
}
Object* CallStubCompiler::CompileArrayPopCall(Object* object,
JSObject* holder,
JSFunction* function,
String* name,
CheckType check) {
// ----------- S t a t e -------------
// rcx : function name
// rsp[0] : return address
// rsp[8] : argument argc
// rsp[16] : argument argc - 1
// ...
// rsp[argc * 8] : argument 1
// rsp[(argc + 1) * 8] : argument 0 = receiver
// -----------------------------------
// TODO(642): faster implementation.
ASSERT(check == RECEIVER_MAP_CHECK);
Label miss;
// Get the receiver from the stack.
const int argc = arguments().immediate();
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
// Check that the receiver isn't a smi.
__ JumpIfSmi(rdx, &miss);
// Check that the maps haven't changed.
CheckPrototypes(JSObject::cast(object), rdx, holder,
rbx, rax, name, &miss);
// Patch the receiver on the stack with the global proxy if
// necessary.
if (object->IsGlobalObject()) {
__ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
__ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
}
__ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop),
argc + 1,
1);
// Handle call cache miss.
__ bind(&miss);
......
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Check pops with various number of arguments.
(function() {
var a = [];
for (var i = 0; i < 7; i++) {
a = [7, 6, 5, 4, 3, 2, 1];
assertEquals(1, a.pop(), "1st pop");
assertEquals(6, a.length, "length 1st pop");
assertEquals(2, a.pop(1), "2nd pop");
assertEquals(5, a.length, "length 2nd pop");
assertEquals(3, a.pop(1, 2), "3rd pop");
assertEquals(4, a.length, "length 3rd pop");
assertEquals(4, a.pop(1, 2, 3), "4th pop");
assertEquals(3, a.length, "length 4th pop");
assertEquals(5, a.pop(), "5th pop");
assertEquals(2, a.length, "length 5th pop");
assertEquals(6, a.pop(), "6th pop");
assertEquals(1, a.length, "length 6th pop");
assertEquals(7, a.pop(), "7th pop");
assertEquals(0, a.length, "length 7th pop");
assertEquals(undefined, a.pop(), "8th pop");
assertEquals(0, a.length, "length 8th pop");
assertEquals(undefined, a.pop(1, 2, 3), "9th pop");
assertEquals(0, a.length, "length 9th pop");
}
})();
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