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

Unified Diff: src/ia32/code-stubs-ia32.cc

Issue 7356013: Implement Object.prototype.hasOwnProperty in generated code. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 9 years, 5 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
Index: src/ia32/code-stubs-ia32.cc
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index e3eb122bc6568641f8df5b2a8c58c20579c8bbba..c77c74de5980c37ab7170642520fabf22234739f 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -5525,7 +5525,7 @@ void StringHelper::GenerateHashInit(MacroAssembler* masm,
__ add(hash, Operand(character));
// hash ^= hash >> 6;
__ mov(scratch, hash);
- __ sar(scratch, 6);
+ __ shr(scratch, 6);
Mads Ager (chromium) 2011/07/15 09:04:45 This looks wrong? The >> operator in C++ is arithm
__ xor_(hash, Operand(scratch));
}
@@ -5542,7 +5542,7 @@ void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm,
__ add(hash, Operand(scratch));
// hash ^= hash >> 6;
__ mov(scratch, hash);
- __ sar(scratch, 6);
+ __ shr(scratch, 6);
__ xor_(hash, Operand(scratch));
}
@@ -5556,7 +5556,7 @@ void StringHelper::GenerateHashGetHash(MacroAssembler* masm,
__ add(hash, Operand(scratch));
// hash ^= hash >> 11;
__ mov(scratch, hash);
- __ sar(scratch, 11);
+ __ shr(scratch, 11);
__ xor_(hash, Operand(scratch));
// hash += hash << 15;
__ mov(scratch, hash);
@@ -5754,6 +5754,35 @@ void StringCompareStub::GenerateFlatAsciiStringEquals(MacroAssembler* masm,
}
+void StringCompareStub::GenerateFlatAsciiStringEquals(
+ MacroAssembler* masm,
+ Register left,
+ Register right,
+ Register scratch1,
+ Register scratch2,
+ Label* strings_not_equal) {
+ Register length = scratch1;
+
+ // Compare lengths.
+ __ mov(length, FieldOperand(left, String::kLengthOffset));
+ __ cmp(length, FieldOperand(right, String::kLengthOffset));
+ __ j(not_equal, strings_not_equal);
+
+ // Check if the length is zero.
+ Label strings_equal;
+ STATIC_ASSERT(kSmiTag == 0);
+ __ test(length, Operand(length));
+ __ j(zero, &strings_equal, Label::kNear);
+
+ // Compare characters.
+ GenerateAsciiCharsCompareLoop(masm, left, right, length, scratch2,
+ strings_not_equal, Label::kNear);
+
+ // Characters are equal.
+ __ bind(&strings_equal);
+}
+
+
void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
Register left,
Register right,
@@ -6258,6 +6287,212 @@ void StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
}
+void StringDictionaryLookupStub::GenerateLookupWithComparisons(
+ MacroAssembler* masm,
+ Register dictionary,
+ Register name,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ Label* found_in_dictionary,
+ Label* not_found_in_dictionary,
+ Label* call_runtime) {
+ // Check whether the name is an ASCII symbol or an ASCII string.
+ // Other types are not supported.
+ Label name_is_symbol;
+ __ mov(scratch1, FieldOperand(name, HeapObject::kMapOffset));
+ __ cmp(scratch1, masm->isolate()->factory()->ascii_symbol_map());
+ __ j(equal, &name_is_symbol);
+ __ cmp(scratch1, masm->isolate()->factory()->ascii_string_map());
+ __ j(not_equal, call_runtime);
+
+ // If the name is an ASCII string, it might not yet have its hash
+ // code computed.
+ Label name_has_hash_code;
+ __ cmp(FieldOperand(name, String::kHashFieldOffset),
+ Immediate(String::kEmptyHashField));
+ __ j(not_equal, &name_has_hash_code);
+
+ // Load the string length and check it's not zero and not too big.
+ __ mov(scratch1, FieldOperand(name, String::kLengthOffset));
+ __ SmiUntag(scratch1);
+ __ test(scratch1, Operand(scratch1));
+ __ j(zero, call_runtime);
+ __ cmp(scratch1, String::kMaxHashCalcLength);
+ __ j(greater, call_runtime);
+
+ // Load the first char and check it's not numeric. Numeric strings
+ // have a different hashing algorithm.
+ Label not_an_array_index;
+ Register character = scratch2;
+ __ movzx_b(character, FieldOperand(name, SeqAsciiString::kHeaderSize));
+ __ cmp(character, '9');
+ __ j(greater, &not_an_array_index, Label::kNear);
+ __ cmp(character, '0');
+ __ j(greater_equal, call_runtime);
+ __ bind(&not_an_array_index);
+
+ // Save the dictionary and the string length on the stack to free up
+ // registers.
+ __ push(dictionary);
+ Operand length = Operand(esp, 0);
+ __ push(scratch1);
+
+ // Hash the first (already loaded) char.
+ Register index = scratch1;
+ __ Set(index, Immediate(0));
+ Register hash = dictionary;
+ StringHelper::GenerateHashInit(masm, hash, character, scratch3);
+
+ // Hash the rest in a loop.
+ Label hash_loop, hash_loop_done;
+ __ bind(&hash_loop);
+ __ add(Operand(index), Immediate(1));
+ __ cmp(index, length);
+ __ j(above_equal, &hash_loop_done, Label::kNear);
+ __ movzx_b(character, FieldOperand(name,
+ index, times_1,
+ SeqAsciiString::kHeaderSize));
+ StringHelper::GenerateHashAddCharacter(masm, hash, character, scratch3);
+ __ jmp(&hash_loop, Label::kNear);
+ __ bind(&hash_loop_done);
+
+ // Store the computed hash code in the name string.
+ StringHelper::GenerateHashGetHash(masm, hash, scratch3);
+ __ shl(hash, String::kHashShift);
+ __ or_(hash, String::kIsNotArrayIndexMask);
+ __ mov(FieldOperand(name, String::kHashFieldOffset), hash);
+ // Restore the stack state.
+ __ pop(dictionary); // Drop TOS.
+ __ pop(dictionary);
+
+ __ bind(&name_has_hash_code);
+ GenerateUnrolledComparisons(masm,
+ NAME_IS_ASCII_STRING_WITH_HASH,
+ dictionary,
+ name,
+ scratch1,
+ scratch2,
+ scratch3,
+ found_in_dictionary,
+ not_found_in_dictionary,
+ call_runtime);
+
+ __ bind(&name_is_symbol);
+ GenerateUnrolledComparisons(masm,
+ NAME_IS_ASCII_SYMBOL,
+ dictionary,
+ name,
+ scratch1,
+ scratch2,
+ scratch3,
+ found_in_dictionary,
+ not_found_in_dictionary,
+ call_runtime);
+}
+
+
+void StringDictionaryLookupStub::GenerateUnrolledComparisons(
+ MacroAssembler* masm,
+ NameType name_type,
+ Register dictionary,
+ Register name,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ Label* found_in_dictionary,
+ Label* not_found_in_dictionary,
+ Label* call_runtime) {
+ // Compute the mask.
+ Register mask = scratch1;
+ __ mov(mask, FieldOperand(dictionary, kCapacityOffset));
+ __ SmiUntag(mask);
+ __ dec(mask);
+
+ // Generate an unrolled loop that performs a few probes before
+ // giving up. Measurements done on Gmail indicate that 2 probes
+ // cover ~93% of loads from dictionaries.
+ for (int i = 0; i < kInlinedProbes; i++) {
+ Register index = scratch2;
+ Register candidate = scratch3;
+
+ Label next_probe;
+ // Compute the masked index: (hash + i + i * i) & mask.
+ __ mov(index, FieldOperand(name, String::kHashFieldOffset));
+ __ shr(index, String::kHashShift);
+ if (i > 0) {
+ __ add(Operand(index), Immediate(StringDictionary::GetProbeOffset(i)));
+ }
+ __ and_(index, Operand(mask));
+
+ // Scale the index by multiplying by the entry size.
+ ASSERT(StringDictionary::kEntrySize == 3);
+ __ lea(index, Operand(index, index, times_2, 0)); // index *= 3
+
+ // Load the entry.
+ __ mov(candidate, FieldOperand(dictionary,
+ index,
+ times_pointer_size,
+ kElementsStartOffset));
+
+ // Fast identity check.
+ __ cmp(name, Operand(candidate));
+ __ j(equal, found_in_dictionary);
+
+ // Check for the end of the hash chain.
+ __ cmp(candidate, masm->isolate()->factory()->undefined_value());
+ __ j(equal, not_found_in_dictionary);
+
+ // Check for the deleted entry marker.
+ __ cmp(candidate, masm->isolate()->factory()->null_value());
+ __ j(equal, &next_probe);
+
+ // Load the instance type of the candidate.
+ __ mov(scratch2, FieldOperand(candidate, HeapObject::kMapOffset));
+ __ movzx_b(scratch2, FieldOperand(scratch2, Map::kInstanceTypeOffset));
+ if (name_type == NAME_IS_ASCII_SYMBOL) {
+ // If both name and candidate are symbols, we can go to the next
+ // probe.
+ __ test_b(Operand(scratch2), kIsSymbolMask);
+ __ j(not_zero, &next_probe);
+ // Check if the candidate is a sequential ASCII string.
+ __ cmp(scratch2, static_cast<int32_t>(ASCII_STRING_TYPE));
+ __ j(not_equal, call_runtime);
+ } else {
+ ASSERT(name_type == NAME_IS_ASCII_STRING_WITH_HASH);
+ // Check if the candidate is a sequential ASCII string or symbol.
+ uint32_t candidate_mask =
+ kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
+ uint32_t expected =
+ kStringTag | kAsciiStringTag | kSeqStringTag;
+ __ and_(scratch2, static_cast<int32_t>(candidate_mask));
+ __ cmp(scratch2, static_cast<int32_t>(expected));
+ __ j(not_equal, call_runtime);
+ }
+
+ // Compare sequential ASCII strings.
+ Label strings_not_equal;
+ __ push(dictionary);
+ __ push(name);
+ StringCompareStub::GenerateFlatAsciiStringEquals(masm,
+ name,
+ candidate,
+ scratch2,
+ dictionary,
+ &strings_not_equal);
+ __ pop(name);
+ __ pop(dictionary);
+ __ jmp(found_in_dictionary);
+ __ bind(&strings_not_equal);
+ __ pop(name);
+ __ pop(dictionary);
+
+ __ bind(&next_probe);
+ }
+ __ jmp(call_runtime);
+}
+
+
void StringDictionaryLookupStub::Generate(MacroAssembler* masm) {
// Stack frame on entry:
// esp[0 * kPointerSize]: return address.
@@ -6346,6 +6581,253 @@ void StringDictionaryLookupStub::Generate(MacroAssembler* masm) {
}
+void HasOwnPropertyStub::Generate(MacroAssembler* masm) {
+ Register object = eax;
+ Register map = ebx;
+ Register name = ecx;
+ Register scratch1 = edx;
+ Register scratch2 = edi;
+ Label call_runtime;
+
+ // Load the arguments.
+ __ mov(object, Operand(esp, 2 * kPointerSize));
+ __ mov(name, Operand(esp, 1 * kPointerSize));
+
+ if (FLAG_debug_code) {
+ Label not_smi;
+ __ JumpIfNotSmi(name, &not_smi, Label::kNear);
+ __ Abort("HasOwnPropertyStub: name is a smi");
+ __ bind(&not_smi);
+ __ mov(scratch1, FieldOperand(name, HeapObject::kMapOffset));
+ __ test_b(FieldOperand(scratch1, Map::kInstanceTypeOffset),
+ kIsNotStringMask);
+ __ Assert(not_zero, "HasOwnPropertyStub: name is not a string");
+ }
+
+ // Make sure the object is a non-special JS object with no elements,
+ // interceptors, or hidden prototypes.
+ // TODO(vitalyr): access check?
Mads Ager (chromium) 2011/07/15 09:04:45 Yes, I'm pretty sure you need to exclude objects t
+ __ JumpIfSmi(object, &call_runtime);
+ __ mov(map, FieldOperand(object, HeapObject::kMapOffset));
+ __ CmpInstanceType(map, JS_OBJECT_TYPE);
Mads Ager (chromium) 2011/07/15 09:04:45 Do you want to be that restrictive? You don't want
+ __ j(not_equal, &call_runtime);
+ __ cmp(FieldOperand(object, JSObject::kElementsOffset),
+ masm->isolate()->factory()->empty_fixed_array());
+ __ j(not_equal, &call_runtime);
+ __ test_b(FieldOperand(map, Map::kBitFieldOffset),
+ (1 << Map::kHasNamedInterceptor) |
+ (1 << Map::kHasIndexedInterceptor));
+ __ j(not_zero, &call_runtime);
+ __ mov(scratch1, FieldOperand(map, Map::kPrototypeOffset));
+ __ mov(scratch1, FieldOperand(scratch1, HeapObject::kMapOffset));
+ __ test_b(FieldOperand(scratch1, Map::kBitFieldOffset),
Mads Ager (chromium) 2011/07/15 09:04:45 You are disregarding objects with hidden prototype
+ (1 << Map::kIsHiddenPrototype));
+ __ j(not_zero, &call_runtime);
+
+ // Does the object have fast properties?
+ Label slow_properties;
+ __ mov(scratch1, FieldOperand(object, JSObject::kPropertiesOffset));
+ __ cmp(FieldOperand(scratch1, HeapObject::kMapOffset),
+ masm->isolate()->factory()->fixed_array_map());
+ __ j(not_equal, &slow_properties);
+
+ // Handle fast properties.
+ GenerateFastPropertiesCase(masm,
+ map,
+ name,
+ object,
+ scratch1,
+ scratch2,
+ &call_runtime);
+
Mads Ager (chromium) 2011/07/15 09:04:45 Add an abort here so it is clear that there is no
+ // Handle slow properties.
+ __ bind(&slow_properties);
+ GenerateSlowPropertiesCase(masm,
+ object,
+ name,
+ map,
+ scratch1,
+ scratch2,
+ &call_runtime);
+
Mads Ager (chromium) 2011/07/15 09:04:45 Ditto, add an abort?
+ __ bind(&call_runtime);
+ __ TailCallRuntime(Runtime::kHasOwnProperty, 2, 1);
+}
+
+
+void HasOwnPropertyStub::GenerateFastPropertiesCase(MacroAssembler* masm,
+ Register map,
+ Register name,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ Label* call_runtime) {
+ // Load the descritor array from the map.
+ Register descriptor_array = map;
+ Label not_found_in_descriptors;
+ __ mov(descriptor_array,
+ FieldOperand(map, Map::kInstanceDescriptorsOrBitField3Offset));
+ map = no_reg;
+ __ JumpIfSmi(descriptor_array, &not_found_in_descriptors);
+
+ // Check the name is a symbol or a sequential ASCII string. We don't
+ // support comparison of other string types here.
+ Label name_is_not_symbol;
+ __ mov(scratch1, FieldOperand(name, HeapObject::kMapOffset));
+ __ movzx_b(scratch1, FieldOperand(scratch1, Map::kInstanceTypeOffset));
+ __ test_b(Operand(scratch1), kIsSymbolMask);
+ __ j(zero, &name_is_not_symbol);
+ GenerateDescriptorArrayLookup(masm,
+ NAME_IS_SYMBOL,
+ descriptor_array,
+ name,
+ scratch1,
+ scratch2,
+ scratch3,
+ &not_found_in_descriptors,
+ call_runtime);
+ __ bind(&name_is_not_symbol);
+ uint32_t mask = kStringRepresentationMask | kStringEncodingMask;
+ uint32_t expected = kSeqStringTag | kAsciiStringTag;
+ __ and_(scratch1, static_cast<int32_t>(mask));
+ __ cmp(scratch1, static_cast<int32_t>(expected));
+ __ j(not_equal, call_runtime);
+ GenerateDescriptorArrayLookup(masm,
+ NAME_IS_SEQUENTIAL_ASCII,
+ descriptor_array,
+ name,
+ scratch1,
+ scratch2,
+ scratch3,
+ &not_found_in_descriptors,
+ call_runtime);
+
+ // Did not find a descriptor corresponding to the given property
+ // name.
+ __ bind(&not_found_in_descriptors);
+ __ mov(eax, masm->isolate()->factory()->false_value());
+ __ ret(2);
+}
+
+
+void HasOwnPropertyStub::GenerateDescriptorArrayLookup(
+ MacroAssembler* masm,
+ NameType name_type,
+ Register descriptor_array,
+ Register name,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ Label* not_found_in_descriptors,
+ Label* call_runtime) {
+ // Setup the lookup loop.
+ Register index = scratch1;
+ __ Set(index, Immediate(Smi::FromInt(DescriptorArray::kFirstIndex - 1)));
+ Operand length = FieldOperand(descriptor_array, FixedArray::kLengthOffset);
+
+ // Loop over the descriptor array keys. Both index and length are
+ // smi tagged.
+ Register candidate = scratch2;
+ Label loop, found_in_descriptors;
+ __ bind(&loop);
+ __ add(Operand(index), Immediate(Smi::FromInt(1)));
+ __ cmp(index, length);
+ __ j(greater_equal, not_found_in_descriptors);
+ STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
+ Operand candidate_operand = FieldOperand(descriptor_array,
+ index, times_half_pointer_size,
+ FixedArray::kHeaderSize);
+ if (name_type == NAME_IS_SYMBOL) {
+ // If the property name is a symbol, we can do a fast identity
+ // check only, because descriptor arrays always contain symbols.
+ __ cmp(name, candidate_operand);
+ __ j(not_equal, &loop, Label::kNear);
+ } else {
+ ASSERT(name_type == NAME_IS_SEQUENTIAL_ASCII);
+ // If the property name is a sequential ASCII string, check that
+ // the descriptor name is a sequential ASCII symbol.
+ Label strings_not_equal;
+ __ mov(candidate, candidate_operand);
+ __ cmp(FieldOperand(candidate, HeapObject::kMapOffset),
+ masm->isolate()->factory()->ascii_symbol_map());
+ __ j(not_equal, call_runtime);
+
+ // Compare name and candidate strings. We have to temporarily save
+ // registers on the stack.
+ __ push(name);
+ __ push(descriptor_array);
+ StringCompareStub::GenerateFlatAsciiStringEquals(masm,
+ name,
+ candidate,
+ scratch3,
+ descriptor_array,
+ &strings_not_equal);
+ __ pop(descriptor_array);
+ __ pop(name);
+ __ jmp(&found_in_descriptors);
+ __ bind(&strings_not_equal);
+ __ pop(descriptor_array);
+ __ pop(name);
+ __ jmp(&loop);
+ }
+
+ // Found a descriptor corresponding to the given property
+ // name. Check the descriptor details to determine whether the
+ // property exists or not.
+ Register details = descriptor_array;
+ Label do_return;
+ __ bind(&found_in_descriptors);
+ __ SmiUntag(index);
+ __ sub(Operand(index), Immediate(DescriptorArray::kFirstIndex));
+ __ mov(details, FieldOperand(descriptor_array,
+ DescriptorArray::kContentArrayOffset));
+ __ mov(details, FieldOperand(details,
+ index, times_twice_pointer_size,
+ FixedArray::kHeaderSize + kPointerSize));
+ __ SmiUntag(details);
+ __ and_(details, PropertyDetails::TypeField::mask());
+ __ cmp(details,
+ PropertyDetails::TypeField::encode(FIRST_PHANTOM_PROPERTY_TYPE));
+ __ mov(eax, masm->isolate()->factory()->true_value());
+ __ j(less, &do_return, Label::kNear);
+ __ mov(eax, masm->isolate()->factory()->false_value());
+ __ bind(&do_return);
+ __ ret(2);
+}
+
+
+void HasOwnPropertyStub::GenerateSlowPropertiesCase(MacroAssembler* masm,
+ Register object,
+ Register name,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ Label* call_runtime) {
+ Label found_in_dictionary, not_found_in_dictionary;
+ Register dictionary = object;
+ __ mov(dictionary, FieldOperand(object, JSObject::kPropertiesOffset));
+ StringDictionaryLookupStub::GenerateLookupWithComparisons(
+ masm,
+ dictionary,
+ name,
+ scratch1,
+ scratch2,
+ scratch3,
+ &found_in_dictionary,
+ &not_found_in_dictionary,
+ call_runtime);
+
+ // Found a property with the given name in the property dictionary.
+ __ bind(&found_in_dictionary);
+ __ mov(eax, masm->isolate()->factory()->true_value());
+ __ ret(2);
+
+ // Not found a property with the given name in the property dictionary.
+ __ bind(&not_found_in_dictionary);
+ __ mov(eax, masm->isolate()->factory()->false_value());
+ __ ret(2);
+}
+
#undef __
} } // namespace v8::internal

Powered by Google App Engine
This is Rietveld 408576698