Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(459)

Unified Diff: src/x64/stub-cache-x64.cc

Issue 1689010: X64: Faster push/pop implementation. (Closed)
Patch Set: Addressed review comments. Created 10 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/x64/macro-assembler-x64.cc ('k') | test/mjsunit/array-pop.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/x64/stub-cache-x64.cc
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
index 94f5efaaa98eeaa6b9625a726f89fb271d033511..918b72f494b3a8eba900131c49de10e3ca652f23 100644
--- a/src/x64/stub-cache-x64.cc
+++ b/src/x64/stub-cache-x64.cc
@@ -564,12 +564,14 @@ static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
// -- rsp[0] : return address
// -- rsp[8] : last argument in the internal frame of the caller
// -----------------------------------
- __ pop(scratch);
- __ Push(Smi::FromInt(0));
- __ Push(Smi::FromInt(0));
- __ Push(Smi::FromInt(0));
- __ Push(Smi::FromInt(0));
- __ push(scratch);
+ __ movq(scratch, Operand(rsp, 0));
+ __ subq(rsp, Immediate(4 * kPointerSize));
+ __ movq(Operand(rsp, 0), scratch);
+ __ Move(scratch, Smi::FromInt(0));
+ __ movq(Operand(rsp, 1 * kPointerSize), scratch);
+ __ movq(Operand(rsp, 2 * kPointerSize), scratch);
+ __ movq(Operand(rsp, 3 * kPointerSize), scratch);
+ __ movq(Operand(rsp, 4 * kPointerSize), scratch);
}
@@ -582,9 +584,9 @@ static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
// -- rsp[32] : first fast api call extra argument
// -- rsp[40] : last argument in the internal frame
// -----------------------------------
- __ pop(scratch);
- __ Drop(4);
- __ push(scratch);
+ __ movq(scratch, Operand(rsp, 0));
+ __ movq(Operand(rsp, 4 * kPointerSize), scratch);
+ __ addq(rsp, Immediate(kPointerSize * 4));
}
@@ -853,129 +855,6 @@ static Object* GenerateCheckPropertyCell(MacroAssembler* masm,
#define __ ACCESS_MASM((masm()))
-
-Object* CallStubCompiler::CompileArrayPushCall(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
- // -----------------------------------
-
- // If object is not an array, bail out to regular call.
- if (!object->IsJSArray()) {
- return Heap::undefined_value();
- }
-
- // TODO(639): 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_ArrayPush),
- 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
- // -----------------------------------
-
- // If object is not an array, bail out to regular call.
- if (!object->IsJSArray()) {
- return Heap::undefined_value();
- }
-
- // 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);
- 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,
@@ -1190,6 +1069,257 @@ Object* CallStubCompiler::CompileCallField(JSObject* object,
}
+Object* CallStubCompiler::CompileArrayPushCall(Object* object,
+ JSObject* holder,
+ JSFunction* function,
+ String* name,
+ CheckType check) {
+ // ----------- S t a t e -------------
+ // -- rcx : name
+ // -- rsp[0] : return address
+ // -- rsp[(argc - n) * 8] : arg[n] (zero-based)
+ // -- ...
+ // -- rsp[(argc + 1) * 8] : receiver
+ // -----------------------------------
+ ASSERT(check == RECEIVER_MAP_CHECK);
+
+ // If object is not an array, bail out to regular call.
+ if (!object->IsJSArray()) {
+ return Heap::undefined_value();
+ }
+
+ 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);
+
+ CheckPrototypes(JSObject::cast(object),
+ rdx,
+ holder,
+ rbx,
+ rax,
+ name,
+ &miss);
+
+ if (argc == 0) {
+ // Noop, return the length.
+ __ movq(rax, FieldOperand(rdx, JSArray::kLengthOffset));
+ __ ret((argc + 1) * kPointerSize);
+ } else {
+ // Get the elements array of the object.
+ __ movq(rbx, FieldOperand(rdx, JSArray::kElementsOffset));
+
+ // Check that the elements are in fast mode (not dictionary).
+ __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset),
+ Factory::fixed_array_map());
+ __ j(not_equal, &miss);
+
+ if (argc == 1) { // Otherwise fall through to call builtin.
+ Label call_builtin, exit, with_rset_update, attempt_to_grow_elements;
+
+ // Get the array's length into rax and calculate new length.
+ __ movq(rax, FieldOperand(rdx, JSArray::kLengthOffset));
+ STATIC_ASSERT(FixedArray::kMaxLength < Smi::kMaxValue);
+ __ SmiAddConstant(rax, rax, Smi::FromInt(argc));
+
+ // Get the element's length into rcx.
+ __ movl(rcx, FieldOperand(rbx, FixedArray::kLengthOffset));
+ __ Integer32ToSmi(rcx, rcx);
+
+ // Check if we could survive without allocation.
+ __ SmiCompare(rax, rcx);
+ __ j(greater, &attempt_to_grow_elements);
+
+ // Save new length.
+ __ movq(FieldOperand(rdx, JSArray::kLengthOffset), rax);
+
+ // Push the element.
+ __ movq(rcx, Operand(rsp, argc * kPointerSize));
+ SmiIndex index =
+ masm()->SmiToIndex(kScratchRegister, rax, times_pointer_size);
+ __ lea(rdx, FieldOperand(rbx,
+ index.reg, index.scale,
+ FixedArray::kHeaderSize - argc * kPointerSize));
+ __ movq(Operand(rdx, 0), rcx);
+
+ // Check if value is a smi.
+ __ JumpIfNotSmi(rcx, &with_rset_update);
+
+ __ bind(&exit);
+ __ ret((argc + 1) * kPointerSize);
+
+ __ bind(&with_rset_update);
+
+ __ InNewSpace(rbx, rcx, equal, &exit);
+
+ RecordWriteStub stub(rbx, rdx, rcx);
+ __ CallStub(&stub);
+ __ ret((argc + 1) * kPointerSize);
+
+ __ bind(&attempt_to_grow_elements);
+ ExternalReference new_space_allocation_top =
+ ExternalReference::new_space_allocation_top_address();
+ ExternalReference new_space_allocation_limit =
+ ExternalReference::new_space_allocation_limit_address();
+
+ const int kAllocationDelta = 4;
+ // Load top.
+ __ movq(rcx, new_space_allocation_top);
+ __ movq(rcx, Operand(rcx, 0));
+
+ // Check if it's the end of elements.
+ index = masm()->SmiToIndex(kScratchRegister, rax, times_pointer_size);
+ __ lea(rdx, FieldOperand(rbx,
+ index.reg, index.scale,
+ FixedArray::kHeaderSize - argc * kPointerSize));
+ __ cmpq(rdx, rcx);
+ __ j(not_equal, &call_builtin);
+ __ addq(rcx, Immediate(kAllocationDelta * kPointerSize));
+ __ movq(kScratchRegister, new_space_allocation_limit);
+ __ cmpq(rcx, Operand(kScratchRegister, 0));
+ __ j(above, &call_builtin);
+
+ // We fit and could grow elements.
+ __ movq(kScratchRegister, new_space_allocation_top);
+ __ movq(Operand(kScratchRegister, 0), rcx);
+ __ movq(rcx, Operand(rsp, argc * kPointerSize));
+
+ // Push the argument...
+ __ movq(Operand(rdx, 0), rcx);
+ // ... and fill the rest with holes.
+ __ Move(kScratchRegister, Factory::the_hole_value());
+ for (int i = 1; i < kAllocationDelta; i++) {
+ __ movq(Operand(rdx, i * kPointerSize), kScratchRegister);
+ }
+
+ // Restore receiver to rdx as finish sequence assumes it's here.
+ __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
+
+ // Increment element's and array's sizes.
+ __ addq(FieldOperand(rbx, FixedArray::kLengthOffset),
+ Immediate(kAllocationDelta));
+ __ movq(FieldOperand(rdx, JSArray::kLengthOffset), rax);
+
+ // Elements are in new space, so no remembered set updates are necessary.
+ __ ret((argc + 1) * kPointerSize);
+
+ __ bind(&call_builtin);
+ }
+
+ __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush),
+ 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::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);
+
+ // If object is not an array, bail out to regular call.
+ if (!object->IsJSArray()) {
+ return Heap::undefined_value();
+ }
+
+ Label miss, return_undefined, call_builtin;
+
+ // 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);
+
+ CheckPrototypes(JSObject::cast(object), rdx,
+ holder, rbx,
+ rax, name, &miss);
+
+ // Get the elements array of the object.
+ __ movq(rbx, FieldOperand(rdx, JSArray::kElementsOffset));
+
+ // Check that the elements are in fast mode (not dictionary).
+ __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset), Factory::fixed_array_map());
+ __ j(not_equal, &miss);
+
+ // Get the array's length into rcx and calculate new length.
+ __ movq(rcx, FieldOperand(rdx, JSArray::kLengthOffset));
+ __ SmiSubConstant(rcx, rcx, Smi::FromInt(1));
+ __ SmiTest(rcx);
+ __ j(negative, &return_undefined);
+
+ // Get the last element.
+ __ Move(r9, Factory::the_hole_value());
+ SmiIndex index =
+ masm()->SmiToIndex(r8, rcx, times_pointer_size);
+ __ movq(rax, FieldOperand(rbx,
+ index.reg, index.scale,
+ FixedArray::kHeaderSize));
+ // Check if element is already the hole.
+ __ cmpq(rax, r9);
+ __ j(equal, &call_builtin);
+
+ // Set the array's length.
+ __ movq(FieldOperand(rdx, JSArray::kLengthOffset), rcx);
+
+ // Fill with the hole and return original value..
+ __ movq(FieldOperand(rbx,
+ index.reg, index.scale,
+ FixedArray::kHeaderSize),
+ r9);
+ __ ret((argc + 1) * kPointerSize);
+
+ __ bind(&return_undefined);
+
+ __ Move(rax, 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::CompileCallInterceptor(JSObject* object,
JSObject* holder,
String* name) {
@@ -2043,8 +2173,13 @@ Register StubCompiler::CheckPrototypes(JSObject* object,
Label* miss) {
// Check that the maps haven't changed.
Register result =
- __ CheckMaps(object, object_reg, holder, holder_reg, scratch,
- save_at_depth, miss);
+ masm()->CheckMaps(object,
+ object_reg,
+ holder,
+ holder_reg,
+ scratch,
+ save_at_depth,
+ miss);
// If we've skipped any global objects, it's not enough to verify
// that their maps haven't changed. We also need to check that the
« no previous file with comments | « src/x64/macro-assembler-x64.cc ('k') | test/mjsunit/array-pop.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698