From 70c7e513afa8f5f73cab6614442f861d72d0126e Mon Sep 17 00:00:00 2001 From: "whesse@chromium.org" Date: Thu, 18 Feb 2010 10:09:54 +0000 Subject: [PATCH] Change KeyedLoadIC interface on ia32 to take receiver and name in registers. Review URL: http://codereview.chromium.org/601080 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3895 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/ia32/builtins-ia32.cc | 7 +- src/ia32/codegen-ia32.cc | 36 +++-- src/ia32/full-codegen-ia32.cc | 38 +++-- src/ia32/ic-ia32.cc | 278 ++++++++++++++++----------------- src/ia32/stub-cache-ia32.cc | 58 +++---- src/ia32/virtual-frame-ia32.cc | 22 ++- 6 files changed, 223 insertions(+), 216 deletions(-) diff --git a/src/ia32/builtins-ia32.cc b/src/ia32/builtins-ia32.cc index fd3077966d..54ef382a39 100644 --- a/src/ia32/builtins-ia32.cc +++ b/src/ia32/builtins-ia32.cc @@ -645,9 +645,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { __ mov(eax, Operand(ebp, kIndexOffset)); __ jmp(&entry); __ bind(&loop); - __ mov(ecx, Operand(ebp, 2 * kPointerSize)); // load arguments - __ push(ecx); - __ push(eax); + __ mov(edx, Operand(ebp, 2 * kPointerSize)); // load arguments // Use inline caching to speed up access to arguments. Handle ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); @@ -657,8 +655,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { // we have generated an inline version of the keyed load. In this // case, we know that we are not generating a test instruction next. - // Remove IC arguments from the stack and push the nth argument. - __ add(Operand(esp), Immediate(2 * kPointerSize)); + // Push the nth argument. __ push(eax); // Update the index on the stack and in register eax. diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc index 2d733a827e..82286829b7 100644 --- a/src/ia32/codegen-ia32.cc +++ b/src/ia32/codegen-ia32.cc @@ -5021,9 +5021,9 @@ void CodeGenerator::VisitCall(Call* node) { LoadGlobalReceiver(); } else { Load(property->obj()); + frame_->Dup(); Load(property->key()); Result function = EmitKeyedLoad(false); - frame_->Drop(); // Key. Result receiver = frame_->Pop(); frame_->Push(&function); frame_->Push(&receiver); @@ -6474,9 +6474,25 @@ class DeferredReferenceGetKeyedValue: public DeferredCode { void DeferredReferenceGetKeyedValue::Generate() { - __ push(receiver_); // First IC argument. - __ push(key_); // Second IC argument. - + if (!receiver_.is(eax)) { + // Register eax is available for key. + if (!key_.is(eax)) { + __ mov(eax, key_); + } + if (!receiver_.is(edx)) { + __ mov(edx, receiver_); + } + } else if (!key_.is(edx)) { + // Register edx is available for receiver. + if (!receiver_.is(edx)) { + __ mov(edx, receiver_); + } + if (!key_.is(eax)) { + __ mov(eax, key_); + } + } else { + __ xchg(edx, eax); + } // Calculate the delta from the IC call instruction to the map check // cmp instruction in the inlined version. This delta is stored in // a test(eax, delta) instruction after the call so that we can find @@ -6500,8 +6516,6 @@ void DeferredReferenceGetKeyedValue::Generate() { __ IncrementCounter(&Counters::keyed_load_inline_miss, 1); if (!dst_.is(eax)) __ mov(dst_, eax); - __ pop(key_); - __ pop(receiver_); } @@ -6639,10 +6653,6 @@ Result CodeGenerator::EmitKeyedLoad(bool is_global) { __ IncrementCounter(&Counters::keyed_load_inline, 1); deferred->BindExit(); - // Restore the receiver and key to the frame and push the - // result on top of it. - frame_->Push(&receiver); - frame_->Push(&key); return value; } else { Comment cmnt(masm_, "[ Load from keyed Property"); @@ -6781,13 +6791,17 @@ void Reference::GetValue() { } case KEYED: { + if (persist_after_get_) { + cgen_->frame()->PushElementAt(1); + cgen_->frame()->PushElementAt(1); + } Variable* var = expression_->AsVariableProxy()->AsVariable(); bool is_global = var != NULL; ASSERT(!is_global || var->is_global()); Result value = cgen_->EmitKeyedLoad(is_global); cgen_->frame()->Push(&value); if (!persist_after_get_) { - cgen_->UnloadReference(this); + set_unloaded(); } break; } diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index c6bb78b4b0..df6ae8a7b6 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -845,7 +845,7 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var, // Load the object. MemOperand object_loc = EmitSlotSearch(object_slot, eax); - __ push(object_loc); + __ mov(edx, object_loc); // Assert that the key is a smi. Literal* key_literal = property->key()->AsLiteral(); @@ -853,7 +853,7 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var, ASSERT(key_literal->handle()->IsSmi()); // Load the key. - __ push(Immediate(key_literal->handle())); + __ mov(eax, Immediate(key_literal->handle())); // Do a keyed property load. Handle ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); @@ -862,7 +862,7 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var, // call. It is treated specially by the LoadIC code. __ nop(); // Drop key and object left on the stack by IC. - DropAndApply(2, context, eax); + Apply(context, eax); } } @@ -1189,10 +1189,10 @@ void FullCodeGenerator::VisitProperty(Property* expr) { Apply(context_, eax); } else { VisitForValue(expr->obj(), kStack); - VisitForValue(expr->key(), kStack); + VisitForValue(expr->key(), kAccumulator); + __ pop(edx); EmitKeyedPropertyLoad(expr); - // Drop key and receiver left on the stack by IC. - DropAndApply(2, context_, eax); + Apply(context_, eax); } } @@ -1263,25 +1263,31 @@ void FullCodeGenerator::VisitCall(Call* expr) { // Call to a keyed property, use keyed load IC followed by function // call. VisitForValue(prop->obj(), kStack); - VisitForValue(prop->key(), kStack); + VisitForValue(prop->key(), kAccumulator); // Record source code position for IC call. SetSourcePosition(prop->position()); + if (prop->is_synthetic()) { + __ pop(edx); // We do not need to keep the receiver. + } else { + __ mov(edx, Operand(esp, 0)); // Keep receiver, to call function on. + } + Handle ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); __ call(ic, RelocInfo::CODE_TARGET); // By emitting a nop we make sure that we do not have a "test eax,..." // instruction after the call it is treated specially by the LoadIC code. __ nop(); - // Drop key left on the stack by IC. - __ Drop(1); - // Pop receiver. - __ pop(ebx); - // Push result (function). - __ push(eax); - // Push receiver object on stack. if (prop->is_synthetic()) { + // Push result (function). + __ push(eax); + // Push Global receiver. __ mov(ecx, CodeGenerator::GlobalObject()); __ push(FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset)); } else { + // Pop receiver. + __ pop(ebx); + // Push result (function). + __ push(eax); __ push(ebx); } EmitCallWithStub(expr); @@ -1570,7 +1576,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { EmitNamedPropertyLoad(prop); } else { VisitForValue(prop->obj(), kStack); - VisitForValue(prop->key(), kStack); + VisitForValue(prop->key(), kAccumulator); + __ mov(edx, Operand(esp, 0)); + __ push(eax); EmitKeyedPropertyLoad(prop); } } diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc index 6c663617e8..10adbaead1 100644 --- a/src/ia32/ic-ia32.cc +++ b/src/ia32/ic-ia32.cc @@ -219,26 +219,22 @@ void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) { void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { // ----------- S t a t e ------------- + // -- eax : key + // -- edx : receiver // -- esp[0] : return address - // -- esp[4] : name - // -- esp[8] : receiver // ----------------------------------- Label slow, check_string, index_int, index_string; Label check_pixel_array, probe_dictionary; - // Load name and receiver. - __ mov(eax, Operand(esp, kPointerSize)); - __ mov(ecx, Operand(esp, 2 * kPointerSize)); - // Check that the object isn't a smi. - __ test(ecx, Immediate(kSmiTagMask)); + __ test(edx, Immediate(kSmiTagMask)); __ j(zero, &slow, not_taken); // Get the map of the receiver. - __ mov(edx, FieldOperand(ecx, HeapObject::kMapOffset)); + __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); // Check bit field. - __ movzx_b(ebx, FieldOperand(edx, Map::kBitFieldOffset)); + __ movzx_b(ebx, FieldOperand(ecx, Map::kBitFieldOffset)); __ test(ebx, Immediate(kSlowCaseBitFieldMask)); __ j(not_zero, &slow, not_taken); // Check that the object is some kind of JS object EXCEPT JS Value type. @@ -246,56 +242,58 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { // we enter the runtime system to make sure that indexing // into string objects work as intended. ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); - __ movzx_b(edx, FieldOperand(edx, Map::kInstanceTypeOffset)); - __ cmp(edx, JS_OBJECT_TYPE); - __ j(less, &slow, not_taken); + __ CmpInstanceType(ecx, JS_OBJECT_TYPE); + __ j(below, &slow, not_taken); // Check that the key is a smi. __ test(eax, Immediate(kSmiTagMask)); __ j(not_zero, &check_string, not_taken); - __ sar(eax, kSmiTagSize); + __ mov(ebx, eax); + __ SmiUntag(ebx); // Get the elements array of the object. __ bind(&index_int); - __ mov(ecx, FieldOperand(ecx, JSObject::kElementsOffset)); + __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset)); // Check that the object is in fast mode (not dictionary). - __ cmp(FieldOperand(ecx, HeapObject::kMapOffset), - Immediate(Factory::fixed_array_map())); - __ j(not_equal, &check_pixel_array); + __ CheckMap(ecx, Factory::fixed_array_map(), &check_pixel_array, true); // Check that the key (index) is within bounds. - __ cmp(eax, FieldOperand(ecx, FixedArray::kLengthOffset)); + __ cmp(ebx, FieldOperand(ecx, FixedArray::kLengthOffset)); __ j(above_equal, &slow); // Fast case: Do the load. - __ mov(eax, - Operand(ecx, eax, times_4, FixedArray::kHeaderSize - kHeapObjectTag)); - __ cmp(Operand(eax), Immediate(Factory::the_hole_value())); + __ mov(ecx, FieldOperand(ecx, ebx, times_4, FixedArray::kHeaderSize)); + __ cmp(Operand(ecx), Immediate(Factory::the_hole_value())); // In case the loaded value is the_hole we have to consult GetProperty // to ensure the prototype chain is searched. __ j(equal, &slow); + __ mov(eax, ecx); __ IncrementCounter(&Counters::keyed_load_generic_smi, 1); __ ret(0); - // Check whether the elements is a pixel array. - // eax: untagged index - // ecx: elements array __ bind(&check_pixel_array); - __ cmp(FieldOperand(ecx, HeapObject::kMapOffset), - Immediate(Factory::pixel_array_map())); - __ j(not_equal, &slow); - __ cmp(eax, FieldOperand(ecx, PixelArray::kLengthOffset)); + // Check whether the elements is a pixel array. + // edx: receiver + // ebx: untagged index + // eax: key + // ecx: elements + __ CheckMap(ecx, Factory::pixel_array_map(), &slow, true); + __ cmp(ebx, FieldOperand(ecx, PixelArray::kLengthOffset)); __ j(above_equal, &slow); - __ mov(ecx, FieldOperand(ecx, PixelArray::kExternalPointerOffset)); - __ movzx_b(eax, Operand(ecx, eax, times_1, 0)); - __ shl(eax, kSmiTagSize); + __ mov(eax, FieldOperand(ecx, PixelArray::kExternalPointerOffset)); + __ movzx_b(eax, Operand(eax, ebx, times_1, 0)); + __ SmiTag(eax); __ ret(0); - // Slow case: Load name and receiver from stack and jump to runtime. __ bind(&slow); + // Slow case: jump to runtime. + // edx: receiver + // eax: key __ IncrementCounter(&Counters::keyed_load_generic_slow, 1); GenerateRuntimeGetProperty(masm); __ bind(&check_string); // The key is not a smi. // Is it a string? - __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx); + // edx: receiver + // eax: key + __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ecx); __ j(above_equal, &slow); // Is the string an array index, with cached numeric value? __ mov(ebx, FieldOperand(eax, String::kHashFieldOffset)); @@ -303,55 +301,58 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { __ j(not_zero, &index_string, not_taken); // Is the string a symbol? - __ movzx_b(ebx, FieldOperand(edx, Map::kInstanceTypeOffset)); + __ movzx_b(ebx, FieldOperand(ecx, Map::kInstanceTypeOffset)); ASSERT(kSymbolTag != 0); __ test(ebx, Immediate(kIsSymbolMask)); __ j(zero, &slow, not_taken); // If the receiver is a fast-case object, check the keyed lookup - // cache. Otherwise probe the dictionary leaving result in ecx. - __ mov(ebx, FieldOperand(ecx, JSObject::kPropertiesOffset)); + // cache. Otherwise probe the dictionary. + __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset)); __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), Immediate(Factory::hash_table_map())); __ j(equal, &probe_dictionary); // Load the map of the receiver, compute the keyed lookup cache hash // based on 32 bits of the map pointer and the string hash. - __ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset)); - __ mov(edx, ebx); - __ shr(edx, KeyedLookupCache::kMapHashShift); - __ mov(eax, FieldOperand(eax, String::kHashFieldOffset)); - __ shr(eax, String::kHashShift); - __ xor_(edx, Operand(eax)); - __ and_(edx, KeyedLookupCache::kCapacityMask); + __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); + __ mov(ecx, ebx); + __ shr(ecx, KeyedLookupCache::kMapHashShift); + __ mov(edi, FieldOperand(eax, String::kHashFieldOffset)); + __ shr(edi, String::kHashShift); + __ xor_(ecx, Operand(edi)); + __ and_(ecx, KeyedLookupCache::kCapacityMask); // Load the key (consisting of map and symbol) from the cache and // check for match. ExternalReference cache_keys = ExternalReference::keyed_lookup_cache_keys(); - __ mov(edi, edx); + __ mov(edi, ecx); __ shl(edi, kPointerSizeLog2 + 1); __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys)); __ j(not_equal, &slow); __ add(Operand(edi), Immediate(kPointerSize)); - __ mov(edi, Operand::StaticArray(edi, times_1, cache_keys)); - __ cmp(edi, Operand(esp, kPointerSize)); + __ cmp(eax, Operand::StaticArray(edi, times_1, cache_keys)); __ j(not_equal, &slow); // Get field offset and check that it is an in-object property. + // edx : receiver + // ebx : receiver's map + // eax : key + // ecx : lookup cache index ExternalReference cache_field_offsets = ExternalReference::keyed_lookup_cache_field_offsets(); - __ mov(eax, - Operand::StaticArray(edx, times_pointer_size, cache_field_offsets)); - __ movzx_b(edx, FieldOperand(ebx, Map::kInObjectPropertiesOffset)); - __ cmp(eax, Operand(edx)); + __ mov(edi, + Operand::StaticArray(ecx, times_pointer_size, cache_field_offsets)); + __ movzx_b(ecx, FieldOperand(ebx, Map::kInObjectPropertiesOffset)); + __ cmp(edi, Operand(ecx)); __ j(above_equal, &slow); // Load in-object property. - __ sub(eax, Operand(edx)); - __ movzx_b(edx, FieldOperand(ebx, Map::kInstanceSizeOffset)); - __ add(eax, Operand(edx)); - __ mov(eax, FieldOperand(ecx, eax, times_pointer_size, 0)); + __ sub(edi, Operand(ecx)); + __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset)); + __ add(ecx, Operand(edi)); + __ mov(eax, FieldOperand(edx, ecx, times_pointer_size, 0)); __ ret(0); // Do a quick inline probe of the receiver's dictionary, if it @@ -359,14 +360,14 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { __ bind(&probe_dictionary); GenerateDictionaryLoad(masm, &slow, - ecx, + edx, eax, ebx, - edx, + ecx, edi, DICTIONARY_CHECK_DONE); - GenerateCheckNonObjectOrLoaded(masm, &slow, edx, ebx); - __ mov(eax, Operand(edx)); + GenerateCheckNonObjectOrLoaded(masm, &slow, ecx, ebx); + __ mov(eax, ecx); __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1); __ ret(0); @@ -377,51 +378,47 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) < (1 << String::kArrayIndexValueBits)); __ bind(&index_string); - __ mov(eax, Operand(ebx)); - __ and_(eax, String::kArrayIndexHashMask); - __ shr(eax, String::kHashShift); + __ and_(ebx, String::kArrayIndexHashMask); + __ shr(ebx, String::kHashShift); __ jmp(&index_int); } void KeyedLoadIC::GenerateString(MacroAssembler* masm) { // ----------- S t a t e ------------- + // -- eax : key + // -- edx : receiver // -- esp[0] : return address - // -- esp[4] : key - // -- esp[8] : receiver // ----------------------------------- Label miss, index_ok; // Pop return address. // Performing the load early is better in the common case. - __ pop(eax); + __ pop(ebx); - __ mov(ebx, Operand(esp, 1 * kPointerSize)); - __ test(ebx, Immediate(kSmiTagMask)); + __ test(edx, Immediate(kSmiTagMask)); __ j(zero, &miss); - __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset)); + __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); __ test(ecx, Immediate(kIsNotStringMask)); __ j(not_zero, &miss); // Check if key is a smi or a heap number. - __ mov(edx, Operand(esp, 0)); - __ test(edx, Immediate(kSmiTagMask)); + __ test(eax, Immediate(kSmiTagMask)); __ j(zero, &index_ok); - __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset)); + __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); __ cmp(ecx, Factory::heap_number_map()); __ j(not_equal, &miss); __ bind(&index_ok); - // Duplicate receiver and key since they are expected on the stack after - // the KeyedLoadIC call. - __ push(ebx); // receiver - __ push(edx); // key - __ push(eax); // return address + // Push receiver and key on the stack, and make a tail call. + __ push(edx); // receiver + __ push(eax); // key + __ push(ebx); // return address __ InvokeBuiltin(Builtins::STRING_CHAR_AT, JUMP_FUNCTION); __ bind(&miss); - __ push(eax); + __ push(ebx); GenerateMiss(masm); } @@ -429,18 +426,14 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) { void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm, ExternalArrayType array_type) { // ----------- S t a t e ------------- + // -- eax : key + // -- edx : receiver // -- esp[0] : return address - // -- esp[4] : key - // -- esp[8] : receiver // ----------------------------------- Label slow, failed_allocation; - // Load name and receiver. - __ mov(eax, Operand(esp, kPointerSize)); - __ mov(ecx, Operand(esp, 2 * kPointerSize)); - // Check that the object isn't a smi. - __ test(ecx, Immediate(kSmiTagMask)); + __ test(edx, Immediate(kSmiTagMask)); __ j(zero, &slow, not_taken); // Check that the key is a smi. @@ -448,59 +441,56 @@ void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm, __ j(not_zero, &slow, not_taken); // Get the map of the receiver. - __ mov(edx, FieldOperand(ecx, HeapObject::kMapOffset)); + __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); // Check that the receiver does not require access checks. We need // to check this explicitly since this generic stub does not perform // map checks. - __ movzx_b(ebx, FieldOperand(edx, Map::kBitFieldOffset)); + __ movzx_b(ebx, FieldOperand(ecx, Map::kBitFieldOffset)); __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded)); __ j(not_zero, &slow, not_taken); - // Get the instance type from the map of the receiver. - __ movzx_b(edx, FieldOperand(edx, Map::kInstanceTypeOffset)); - // Check that the object is a JS object. - __ cmp(edx, JS_OBJECT_TYPE); + __ CmpInstanceType(ecx, JS_OBJECT_TYPE); __ j(not_equal, &slow, not_taken); // Check that the elements array is the appropriate type of // ExternalArray. - // eax: index (as a smi) - // ecx: JSObject - __ mov(ecx, FieldOperand(ecx, JSObject::kElementsOffset)); + __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); Handle map(Heap::MapForExternalArrayType(array_type)); - __ cmp(FieldOperand(ecx, HeapObject::kMapOffset), + __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), Immediate(map)); __ j(not_equal, &slow, not_taken); + // eax: key, known to be a smi. + // edx: receiver, known to be a JSObject. + // ebx: elements object, known to be an external array. // Check that the index is in range. - __ sar(eax, kSmiTagSize); // Untag the index. - __ cmp(eax, FieldOperand(ecx, ExternalArray::kLengthOffset)); + __ mov(ecx, eax); + __ SmiUntag(ecx); // Untag the index. + __ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset)); // Unsigned comparison catches both negative and too-large values. __ j(above_equal, &slow); - // eax: untagged index - // ecx: elements array - __ mov(ecx, FieldOperand(ecx, ExternalArray::kExternalPointerOffset)); - // ecx: base pointer of external storage + __ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset)); + // ebx: base pointer of external storage switch (array_type) { case kExternalByteArray: - __ movsx_b(eax, Operand(ecx, eax, times_1, 0)); + __ movsx_b(ecx, Operand(ebx, ecx, times_1, 0)); break; case kExternalUnsignedByteArray: - __ movzx_b(eax, Operand(ecx, eax, times_1, 0)); + __ movzx_b(ecx, Operand(ebx, ecx, times_1, 0)); break; case kExternalShortArray: - __ movsx_w(eax, Operand(ecx, eax, times_2, 0)); + __ movsx_w(ecx, Operand(ebx, ecx, times_2, 0)); break; case kExternalUnsignedShortArray: - __ movzx_w(eax, Operand(ecx, eax, times_2, 0)); + __ movzx_w(ecx, Operand(ebx, ecx, times_2, 0)); break; case kExternalIntArray: case kExternalUnsignedIntArray: - __ mov(eax, Operand(ecx, eax, times_4, 0)); + __ mov(ecx, Operand(ebx, ecx, times_4, 0)); break; case kExternalFloatArray: - __ fld_s(Operand(ecx, eax, times_4, 0)); + __ fld_s(Operand(ebx, ecx, times_4, 0)); break; default: UNREACHABLE(); @@ -508,7 +498,7 @@ void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm, } // For integer array types: - // eax: value + // ecx: value // For floating-point array type: // FP(0): value @@ -519,21 +509,19 @@ void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm, // it to a HeapNumber. Label box_int; if (array_type == kExternalIntArray) { - // See Smi::IsValid for why this works. - __ mov(ebx, eax); - __ add(Operand(ebx), Immediate(0x40000000)); - __ cmp(ebx, 0x80000000); - __ j(above_equal, &box_int); + __ cmp(ecx, 0xC0000000); + __ j(sign, &box_int); } else { ASSERT_EQ(array_type, kExternalUnsignedIntArray); // The test is different for unsigned int values. Since we need - // the Smi-encoded result to be treated as unsigned, we can't + // the value to be in the range of a positive smi, we can't // handle either of the top two bits being set in the value. - __ test(eax, Immediate(0xC0000000)); + __ test(ecx, Immediate(0xC0000000)); __ j(not_zero, &box_int); } - __ shl(eax, kSmiTagSize); + __ mov(eax, ecx); + __ SmiTag(eax); __ ret(0); __ bind(&box_int); @@ -541,34 +529,37 @@ void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm, // Allocate a HeapNumber for the int and perform int-to-double // conversion. if (array_type == kExternalIntArray) { - __ push(eax); + __ push(ecx); __ fild_s(Operand(esp, 0)); - __ pop(eax); + __ pop(ecx); } else { ASSERT(array_type == kExternalUnsignedIntArray); // Need to zero-extend the value. // There's no fild variant for unsigned values, so zero-extend // to a 64-bit int manually. __ push(Immediate(0)); - __ push(eax); + __ push(ecx); __ fild_d(Operand(esp, 0)); - __ pop(eax); - __ pop(eax); + __ pop(ecx); + __ pop(ecx); } // FP(0): value - __ AllocateHeapNumber(eax, ebx, ecx, &failed_allocation); + __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation); // Set the value. + __ mov(eax, ecx); __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); __ ret(0); } else if (array_type == kExternalFloatArray) { // For the floating-point array type, we need to always allocate a // HeapNumber. - __ AllocateHeapNumber(eax, ebx, ecx, &failed_allocation); + __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation); // Set the value. + __ mov(eax, ecx); __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); __ ret(0); } else { - __ shl(eax, kSmiTagSize); + __ mov(eax, ecx); + __ SmiTag(eax); __ ret(0); } @@ -579,7 +570,7 @@ void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm, __ fincstp(); // Fall through to slow case. - // Slow case: Load name and receiver from stack and jump to runtime. + // Slow case: Load key and receiver from stack and jump to runtime. __ bind(&slow); __ IncrementCounter(&Counters::keyed_load_external_array_slow, 1); GenerateRuntimeGetProperty(masm); @@ -588,19 +579,14 @@ void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm, void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) { // ----------- S t a t e ------------- - // -- eax : value + // -- eax : key + // -- edx : receiver // -- esp[0] : return address - // -- esp[4] : key - // -- esp[8] : receiver // ----------------------------------- Label slow; - // Load key and receiver. - __ mov(eax, Operand(esp, kPointerSize)); - __ mov(ecx, Operand(esp, 2 * kPointerSize)); - // Check that the receiver isn't a smi. - __ test(ecx, Immediate(kSmiTagMask)); + __ test(edx, Immediate(kSmiTagMask)); __ j(zero, &slow, not_taken); // Check that the key is a smi. @@ -608,20 +594,20 @@ void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) { __ j(not_zero, &slow, not_taken); // Get the map of the receiver. - __ mov(edx, FieldOperand(ecx, HeapObject::kMapOffset)); + __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); // Check that it has indexed interceptor and access checks // are not enabled for this object. - __ movzx_b(edx, FieldOperand(edx, Map::kBitFieldOffset)); - __ and_(Operand(edx), Immediate(kSlowCaseBitFieldMask)); - __ cmp(Operand(edx), Immediate(1 << Map::kHasIndexedInterceptor)); + __ movzx_b(ecx, FieldOperand(ecx, Map::kBitFieldOffset)); + __ and_(Operand(ecx), Immediate(kSlowCaseBitFieldMask)); + __ cmp(Operand(ecx), Immediate(1 << Map::kHasIndexedInterceptor)); __ j(not_zero, &slow, not_taken); // Everything is fine, call runtime. - __ pop(edx); - __ push(ecx); // receiver + __ pop(ecx); + __ push(edx); // receiver __ push(eax); // key - __ push(edx); // return address + __ push(ecx); // return address // Perform tail call to the entry. __ TailCallRuntime(ExternalReference( @@ -1380,14 +1366,14 @@ Object* KeyedLoadIC_Miss(Arguments args); void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { // ----------- S t a t e ------------- + // -- eax : key + // -- edx : receiver // -- esp[0] : return address - // -- esp[4] : name - // -- esp[8] : receiver // ----------------------------------- __ pop(ebx); - __ push(Operand(esp, kPointerSize)); // receiver - __ push(Operand(esp, kPointerSize)); // name + __ push(edx); // receiver + __ push(eax); // name __ push(ebx); // return address // Perform tail call to the entry. @@ -1397,14 +1383,14 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { // ----------- S t a t e ------------- + // -- eax : key + // -- edx : receiver // -- esp[0] : return address - // -- esp[4] : name - // -- esp[8] : receiver // ----------------------------------- __ pop(ebx); - __ push(Operand(esp, 1 * kPointerSize)); // receiver - __ push(Operand(esp, 1 * kPointerSize)); // name + __ push(edx); // receiver + __ push(eax); // name __ push(ebx); // return address // Perform tail call to the entry. diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc index d80e300060..427a0bbac3 100644 --- a/src/ia32/stub-cache-ia32.cc +++ b/src/ia32/stub-cache-ia32.cc @@ -1877,21 +1877,19 @@ Object* KeyedLoadStubCompiler::CompileLoadField(String* name, JSObject* holder, int index) { // ----------- S t a t e ------------- + // -- eax : key + // -- edx : receiver // -- esp[0] : return address - // -- esp[4] : name - // -- esp[8] : receiver // ----------------------------------- Label miss; - __ mov(eax, Operand(esp, kPointerSize)); - __ mov(ecx, Operand(esp, 2 * kPointerSize)); __ IncrementCounter(&Counters::keyed_load_field, 1); // Check that the name has not changed. __ cmp(Operand(eax), Immediate(Handle(name))); __ j(not_equal, &miss, not_taken); - GenerateLoadField(receiver, holder, ecx, ebx, edx, index, name, &miss); + GenerateLoadField(receiver, holder, edx, ebx, ecx, index, name, &miss); __ bind(&miss); __ DecrementCounter(&Counters::keyed_load_field, 1); @@ -1907,14 +1905,12 @@ Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name, JSObject* holder, AccessorInfo* callback) { // ----------- S t a t e ------------- + // -- eax : key + // -- edx : receiver // -- esp[0] : return address - // -- esp[4] : name - // -- esp[8] : receiver // ----------------------------------- Label miss; - __ mov(eax, Operand(esp, kPointerSize)); - __ mov(ecx, Operand(esp, 2 * kPointerSize)); __ IncrementCounter(&Counters::keyed_load_callback, 1); // Check that the name has not changed. @@ -1922,7 +1918,7 @@ Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name, __ j(not_equal, &miss, not_taken); Failure* failure = Failure::InternalError(); - bool success = GenerateLoadCallback(receiver, holder, ecx, eax, ebx, edx, + bool success = GenerateLoadCallback(receiver, holder, edx, eax, ebx, ecx, callback, name, &miss, &failure); if (!success) return failure; @@ -1940,21 +1936,19 @@ Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name, JSObject* holder, Object* value) { // ----------- S t a t e ------------- + // -- eax : key + // -- edx : receiver // -- esp[0] : return address - // -- esp[4] : name - // -- esp[8] : receiver // ----------------------------------- Label miss; - __ mov(eax, Operand(esp, kPointerSize)); - __ mov(ecx, Operand(esp, 2 * kPointerSize)); __ IncrementCounter(&Counters::keyed_load_constant_function, 1); // Check that the name has not changed. __ cmp(Operand(eax), Immediate(Handle(name))); __ j(not_equal, &miss, not_taken); - GenerateLoadConstant(receiver, holder, ecx, ebx, edx, + GenerateLoadConstant(receiver, holder, edx, ebx, ecx, value, name, &miss); __ bind(&miss); __ DecrementCounter(&Counters::keyed_load_constant_function, 1); @@ -1969,14 +1963,12 @@ Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, JSObject* holder, String* name) { // ----------- S t a t e ------------- + // -- eax : key + // -- edx : receiver // -- esp[0] : return address - // -- esp[4] : name - // -- esp[8] : receiver // ----------------------------------- Label miss; - __ mov(eax, Operand(esp, kPointerSize)); - __ mov(ecx, Operand(esp, 2 * kPointerSize)); __ IncrementCounter(&Counters::keyed_load_interceptor, 1); // Check that the name has not changed. @@ -1988,9 +1980,9 @@ Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, GenerateLoadInterceptor(receiver, holder, &lookup, - ecx, - eax, edx, + eax, + ecx, ebx, name, &miss); @@ -2007,21 +1999,19 @@ Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) { // ----------- S t a t e ------------- + // -- eax : key + // -- edx : receiver // -- esp[0] : return address - // -- esp[4] : name - // -- esp[8] : receiver // ----------------------------------- Label miss; - __ mov(eax, Operand(esp, kPointerSize)); - __ mov(ecx, Operand(esp, 2 * kPointerSize)); __ IncrementCounter(&Counters::keyed_load_array_length, 1); // Check that the name has not changed. __ cmp(Operand(eax), Immediate(Handle(name))); __ j(not_equal, &miss, not_taken); - GenerateLoadArrayLength(masm(), ecx, edx, &miss); + GenerateLoadArrayLength(masm(), edx, ecx, &miss); __ bind(&miss); __ DecrementCounter(&Counters::keyed_load_array_length, 1); GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); @@ -2033,21 +2023,19 @@ Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) { Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { // ----------- S t a t e ------------- + // -- eax : key + // -- edx : receiver // -- esp[0] : return address - // -- esp[4] : name - // -- esp[8] : receiver // ----------------------------------- Label miss; - __ mov(eax, Operand(esp, kPointerSize)); - __ mov(ecx, Operand(esp, 2 * kPointerSize)); __ IncrementCounter(&Counters::keyed_load_string_length, 1); // Check that the name has not changed. __ cmp(Operand(eax), Immediate(Handle(name))); __ j(not_equal, &miss, not_taken); - GenerateLoadStringLength(masm(), ecx, edx, ebx, &miss); + GenerateLoadStringLength(masm(), edx, ecx, ebx, &miss); __ bind(&miss); __ DecrementCounter(&Counters::keyed_load_string_length, 1); GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); @@ -2059,21 +2047,19 @@ Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) { // ----------- S t a t e ------------- + // -- eax : key + // -- edx : receiver // -- esp[0] : return address - // -- esp[4] : name - // -- esp[8] : receiver // ----------------------------------- Label miss; - __ mov(eax, Operand(esp, kPointerSize)); - __ mov(ecx, Operand(esp, 2 * kPointerSize)); __ IncrementCounter(&Counters::keyed_load_function_prototype, 1); // Check that the name has not changed. __ cmp(Operand(eax), Immediate(Handle(name))); __ j(not_equal, &miss, not_taken); - GenerateLoadFunctionPrototype(masm(), ecx, edx, ebx, &miss); + GenerateLoadFunctionPrototype(masm(), edx, ecx, ebx, &miss); __ bind(&miss); __ DecrementCounter(&Counters::keyed_load_function_prototype, 1); GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); diff --git a/src/ia32/virtual-frame-ia32.cc b/src/ia32/virtual-frame-ia32.cc index 2caea10e65..d2485392f5 100644 --- a/src/ia32/virtual-frame-ia32.cc +++ b/src/ia32/virtual-frame-ia32.cc @@ -924,10 +924,26 @@ Result VirtualFrame::CallLoadIC(RelocInfo::Mode mode) { Result VirtualFrame::CallKeyedLoadIC(RelocInfo::Mode mode) { - // Key and receiver are on top of the frame. The IC expects them on - // the stack. It does not drop them. + // Key and receiver are on top of the frame. Put them in eax and edx. + Result key = Pop(); + Result receiver = Pop(); + PrepareForCall(0, 0); + + if (!key.is_register() || !key.reg().is(edx)) { + // Register edx is available for receiver. + receiver.ToRegister(edx); + key.ToRegister(eax); + } else if (!receiver.is_register() || !receiver.reg().is(eax)) { + // Register eax is available for key. + key.ToRegister(eax); + receiver.ToRegister(edx); + } else { + __ xchg(edx, eax); + } + key.Unuse(); + receiver.Unuse(); + Handle ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); - PrepareForCall(2, 0); // Two stack args, neither callee-dropped. return RawCallCodeObject(ic, mode); }