Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 5507 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5518 void StringHelper::GenerateHashInit(MacroAssembler* masm, | 5518 void StringHelper::GenerateHashInit(MacroAssembler* masm, |
| 5519 Register hash, | 5519 Register hash, |
| 5520 Register character, | 5520 Register character, |
| 5521 Register scratch) { | 5521 Register scratch) { |
| 5522 // hash = character + (character << 10); | 5522 // hash = character + (character << 10); |
| 5523 __ mov(hash, character); | 5523 __ mov(hash, character); |
| 5524 __ shl(hash, 10); | 5524 __ shl(hash, 10); |
| 5525 __ add(hash, Operand(character)); | 5525 __ add(hash, Operand(character)); |
| 5526 // hash ^= hash >> 6; | 5526 // hash ^= hash >> 6; |
| 5527 __ mov(scratch, hash); | 5527 __ mov(scratch, hash); |
| 5528 __ sar(scratch, 6); | 5528 __ shr(scratch, 6); |
|
Mads Ager (chromium)
2011/07/15 09:04:45
This looks wrong? The >> operator in C++ is arithm
| |
| 5529 __ xor_(hash, Operand(scratch)); | 5529 __ xor_(hash, Operand(scratch)); |
| 5530 } | 5530 } |
| 5531 | 5531 |
| 5532 | 5532 |
| 5533 void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm, | 5533 void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm, |
| 5534 Register hash, | 5534 Register hash, |
| 5535 Register character, | 5535 Register character, |
| 5536 Register scratch) { | 5536 Register scratch) { |
| 5537 // hash += character; | 5537 // hash += character; |
| 5538 __ add(hash, Operand(character)); | 5538 __ add(hash, Operand(character)); |
| 5539 // hash += hash << 10; | 5539 // hash += hash << 10; |
| 5540 __ mov(scratch, hash); | 5540 __ mov(scratch, hash); |
| 5541 __ shl(scratch, 10); | 5541 __ shl(scratch, 10); |
| 5542 __ add(hash, Operand(scratch)); | 5542 __ add(hash, Operand(scratch)); |
| 5543 // hash ^= hash >> 6; | 5543 // hash ^= hash >> 6; |
| 5544 __ mov(scratch, hash); | 5544 __ mov(scratch, hash); |
| 5545 __ sar(scratch, 6); | 5545 __ shr(scratch, 6); |
| 5546 __ xor_(hash, Operand(scratch)); | 5546 __ xor_(hash, Operand(scratch)); |
| 5547 } | 5547 } |
| 5548 | 5548 |
| 5549 | 5549 |
| 5550 void StringHelper::GenerateHashGetHash(MacroAssembler* masm, | 5550 void StringHelper::GenerateHashGetHash(MacroAssembler* masm, |
| 5551 Register hash, | 5551 Register hash, |
| 5552 Register scratch) { | 5552 Register scratch) { |
| 5553 // hash += hash << 3; | 5553 // hash += hash << 3; |
| 5554 __ mov(scratch, hash); | 5554 __ mov(scratch, hash); |
| 5555 __ shl(scratch, 3); | 5555 __ shl(scratch, 3); |
| 5556 __ add(hash, Operand(scratch)); | 5556 __ add(hash, Operand(scratch)); |
| 5557 // hash ^= hash >> 11; | 5557 // hash ^= hash >> 11; |
| 5558 __ mov(scratch, hash); | 5558 __ mov(scratch, hash); |
| 5559 __ sar(scratch, 11); | 5559 __ shr(scratch, 11); |
| 5560 __ xor_(hash, Operand(scratch)); | 5560 __ xor_(hash, Operand(scratch)); |
| 5561 // hash += hash << 15; | 5561 // hash += hash << 15; |
| 5562 __ mov(scratch, hash); | 5562 __ mov(scratch, hash); |
| 5563 __ shl(scratch, 15); | 5563 __ shl(scratch, 15); |
| 5564 __ add(hash, Operand(scratch)); | 5564 __ add(hash, Operand(scratch)); |
| 5565 | 5565 |
| 5566 // if (hash == 0) hash = 27; | 5566 // if (hash == 0) hash = 27; |
| 5567 Label hash_not_zero; | 5567 Label hash_not_zero; |
| 5568 __ test(hash, Operand(hash)); | 5568 __ test(hash, Operand(hash)); |
| 5569 __ j(not_zero, &hash_not_zero, Label::kNear); | 5569 __ j(not_zero, &hash_not_zero, Label::kNear); |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5747 __ bind(&compare_chars); | 5747 __ bind(&compare_chars); |
| 5748 GenerateAsciiCharsCompareLoop(masm, left, right, length, scratch2, | 5748 GenerateAsciiCharsCompareLoop(masm, left, right, length, scratch2, |
| 5749 &strings_not_equal, Label::kNear); | 5749 &strings_not_equal, Label::kNear); |
| 5750 | 5750 |
| 5751 // Characters are equal. | 5751 // Characters are equal. |
| 5752 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); | 5752 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); |
| 5753 __ ret(0); | 5753 __ ret(0); |
| 5754 } | 5754 } |
| 5755 | 5755 |
| 5756 | 5756 |
| 5757 void StringCompareStub::GenerateFlatAsciiStringEquals( | |
| 5758 MacroAssembler* masm, | |
| 5759 Register left, | |
| 5760 Register right, | |
| 5761 Register scratch1, | |
| 5762 Register scratch2, | |
| 5763 Label* strings_not_equal) { | |
| 5764 Register length = scratch1; | |
| 5765 | |
| 5766 // Compare lengths. | |
| 5767 __ mov(length, FieldOperand(left, String::kLengthOffset)); | |
| 5768 __ cmp(length, FieldOperand(right, String::kLengthOffset)); | |
| 5769 __ j(not_equal, strings_not_equal); | |
| 5770 | |
| 5771 // Check if the length is zero. | |
| 5772 Label strings_equal; | |
| 5773 STATIC_ASSERT(kSmiTag == 0); | |
| 5774 __ test(length, Operand(length)); | |
| 5775 __ j(zero, &strings_equal, Label::kNear); | |
| 5776 | |
| 5777 // Compare characters. | |
| 5778 GenerateAsciiCharsCompareLoop(masm, left, right, length, scratch2, | |
| 5779 strings_not_equal, Label::kNear); | |
| 5780 | |
| 5781 // Characters are equal. | |
| 5782 __ bind(&strings_equal); | |
| 5783 } | |
| 5784 | |
| 5785 | |
| 5757 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, | 5786 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, |
| 5758 Register left, | 5787 Register left, |
| 5759 Register right, | 5788 Register right, |
| 5760 Register scratch1, | 5789 Register scratch1, |
| 5761 Register scratch2, | 5790 Register scratch2, |
| 5762 Register scratch3) { | 5791 Register scratch3) { |
| 5763 Counters* counters = masm->isolate()->counters(); | 5792 Counters* counters = masm->isolate()->counters(); |
| 5764 __ IncrementCounter(counters->string_compare_native(), 1); | 5793 __ IncrementCounter(counters->string_compare_native(), 1); |
| 5765 | 5794 |
| 5766 // Find minimum length. | 5795 // Find minimum length. |
| (...skipping 484 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6251 __ shr(r0, String::kHashShift); | 6280 __ shr(r0, String::kHashShift); |
| 6252 __ push(r0); | 6281 __ push(r0); |
| 6253 __ CallStub(&stub); | 6282 __ CallStub(&stub); |
| 6254 | 6283 |
| 6255 __ test(r1, Operand(r1)); | 6284 __ test(r1, Operand(r1)); |
| 6256 __ j(zero, miss); | 6285 __ j(zero, miss); |
| 6257 __ jmp(done); | 6286 __ jmp(done); |
| 6258 } | 6287 } |
| 6259 | 6288 |
| 6260 | 6289 |
| 6290 void StringDictionaryLookupStub::GenerateLookupWithComparisons( | |
| 6291 MacroAssembler* masm, | |
| 6292 Register dictionary, | |
| 6293 Register name, | |
| 6294 Register scratch1, | |
| 6295 Register scratch2, | |
| 6296 Register scratch3, | |
| 6297 Label* found_in_dictionary, | |
| 6298 Label* not_found_in_dictionary, | |
| 6299 Label* call_runtime) { | |
| 6300 // Check whether the name is an ASCII symbol or an ASCII string. | |
| 6301 // Other types are not supported. | |
| 6302 Label name_is_symbol; | |
| 6303 __ mov(scratch1, FieldOperand(name, HeapObject::kMapOffset)); | |
| 6304 __ cmp(scratch1, masm->isolate()->factory()->ascii_symbol_map()); | |
| 6305 __ j(equal, &name_is_symbol); | |
| 6306 __ cmp(scratch1, masm->isolate()->factory()->ascii_string_map()); | |
| 6307 __ j(not_equal, call_runtime); | |
| 6308 | |
| 6309 // If the name is an ASCII string, it might not yet have its hash | |
| 6310 // code computed. | |
| 6311 Label name_has_hash_code; | |
| 6312 __ cmp(FieldOperand(name, String::kHashFieldOffset), | |
| 6313 Immediate(String::kEmptyHashField)); | |
| 6314 __ j(not_equal, &name_has_hash_code); | |
| 6315 | |
| 6316 // Load the string length and check it's not zero and not too big. | |
| 6317 __ mov(scratch1, FieldOperand(name, String::kLengthOffset)); | |
| 6318 __ SmiUntag(scratch1); | |
| 6319 __ test(scratch1, Operand(scratch1)); | |
| 6320 __ j(zero, call_runtime); | |
| 6321 __ cmp(scratch1, String::kMaxHashCalcLength); | |
| 6322 __ j(greater, call_runtime); | |
| 6323 | |
| 6324 // Load the first char and check it's not numeric. Numeric strings | |
| 6325 // have a different hashing algorithm. | |
| 6326 Label not_an_array_index; | |
| 6327 Register character = scratch2; | |
| 6328 __ movzx_b(character, FieldOperand(name, SeqAsciiString::kHeaderSize)); | |
| 6329 __ cmp(character, '9'); | |
| 6330 __ j(greater, ¬_an_array_index, Label::kNear); | |
| 6331 __ cmp(character, '0'); | |
| 6332 __ j(greater_equal, call_runtime); | |
| 6333 __ bind(¬_an_array_index); | |
| 6334 | |
| 6335 // Save the dictionary and the string length on the stack to free up | |
| 6336 // registers. | |
| 6337 __ push(dictionary); | |
| 6338 Operand length = Operand(esp, 0); | |
| 6339 __ push(scratch1); | |
| 6340 | |
| 6341 // Hash the first (already loaded) char. | |
| 6342 Register index = scratch1; | |
| 6343 __ Set(index, Immediate(0)); | |
| 6344 Register hash = dictionary; | |
| 6345 StringHelper::GenerateHashInit(masm, hash, character, scratch3); | |
| 6346 | |
| 6347 // Hash the rest in a loop. | |
| 6348 Label hash_loop, hash_loop_done; | |
| 6349 __ bind(&hash_loop); | |
| 6350 __ add(Operand(index), Immediate(1)); | |
| 6351 __ cmp(index, length); | |
| 6352 __ j(above_equal, &hash_loop_done, Label::kNear); | |
| 6353 __ movzx_b(character, FieldOperand(name, | |
| 6354 index, times_1, | |
| 6355 SeqAsciiString::kHeaderSize)); | |
| 6356 StringHelper::GenerateHashAddCharacter(masm, hash, character, scratch3); | |
| 6357 __ jmp(&hash_loop, Label::kNear); | |
| 6358 __ bind(&hash_loop_done); | |
| 6359 | |
| 6360 // Store the computed hash code in the name string. | |
| 6361 StringHelper::GenerateHashGetHash(masm, hash, scratch3); | |
| 6362 __ shl(hash, String::kHashShift); | |
| 6363 __ or_(hash, String::kIsNotArrayIndexMask); | |
| 6364 __ mov(FieldOperand(name, String::kHashFieldOffset), hash); | |
| 6365 // Restore the stack state. | |
| 6366 __ pop(dictionary); // Drop TOS. | |
| 6367 __ pop(dictionary); | |
| 6368 | |
| 6369 __ bind(&name_has_hash_code); | |
| 6370 GenerateUnrolledComparisons(masm, | |
| 6371 NAME_IS_ASCII_STRING_WITH_HASH, | |
| 6372 dictionary, | |
| 6373 name, | |
| 6374 scratch1, | |
| 6375 scratch2, | |
| 6376 scratch3, | |
| 6377 found_in_dictionary, | |
| 6378 not_found_in_dictionary, | |
| 6379 call_runtime); | |
| 6380 | |
| 6381 __ bind(&name_is_symbol); | |
| 6382 GenerateUnrolledComparisons(masm, | |
| 6383 NAME_IS_ASCII_SYMBOL, | |
| 6384 dictionary, | |
| 6385 name, | |
| 6386 scratch1, | |
| 6387 scratch2, | |
| 6388 scratch3, | |
| 6389 found_in_dictionary, | |
| 6390 not_found_in_dictionary, | |
| 6391 call_runtime); | |
| 6392 } | |
| 6393 | |
| 6394 | |
| 6395 void StringDictionaryLookupStub::GenerateUnrolledComparisons( | |
| 6396 MacroAssembler* masm, | |
| 6397 NameType name_type, | |
| 6398 Register dictionary, | |
| 6399 Register name, | |
| 6400 Register scratch1, | |
| 6401 Register scratch2, | |
| 6402 Register scratch3, | |
| 6403 Label* found_in_dictionary, | |
| 6404 Label* not_found_in_dictionary, | |
| 6405 Label* call_runtime) { | |
| 6406 // Compute the mask. | |
| 6407 Register mask = scratch1; | |
| 6408 __ mov(mask, FieldOperand(dictionary, kCapacityOffset)); | |
| 6409 __ SmiUntag(mask); | |
| 6410 __ dec(mask); | |
| 6411 | |
| 6412 // Generate an unrolled loop that performs a few probes before | |
| 6413 // giving up. Measurements done on Gmail indicate that 2 probes | |
| 6414 // cover ~93% of loads from dictionaries. | |
| 6415 for (int i = 0; i < kInlinedProbes; i++) { | |
| 6416 Register index = scratch2; | |
| 6417 Register candidate = scratch3; | |
| 6418 | |
| 6419 Label next_probe; | |
| 6420 // Compute the masked index: (hash + i + i * i) & mask. | |
| 6421 __ mov(index, FieldOperand(name, String::kHashFieldOffset)); | |
| 6422 __ shr(index, String::kHashShift); | |
| 6423 if (i > 0) { | |
| 6424 __ add(Operand(index), Immediate(StringDictionary::GetProbeOffset(i))); | |
| 6425 } | |
| 6426 __ and_(index, Operand(mask)); | |
| 6427 | |
| 6428 // Scale the index by multiplying by the entry size. | |
| 6429 ASSERT(StringDictionary::kEntrySize == 3); | |
| 6430 __ lea(index, Operand(index, index, times_2, 0)); // index *= 3 | |
| 6431 | |
| 6432 // Load the entry. | |
| 6433 __ mov(candidate, FieldOperand(dictionary, | |
| 6434 index, | |
| 6435 times_pointer_size, | |
| 6436 kElementsStartOffset)); | |
| 6437 | |
| 6438 // Fast identity check. | |
| 6439 __ cmp(name, Operand(candidate)); | |
| 6440 __ j(equal, found_in_dictionary); | |
| 6441 | |
| 6442 // Check for the end of the hash chain. | |
| 6443 __ cmp(candidate, masm->isolate()->factory()->undefined_value()); | |
| 6444 __ j(equal, not_found_in_dictionary); | |
| 6445 | |
| 6446 // Check for the deleted entry marker. | |
| 6447 __ cmp(candidate, masm->isolate()->factory()->null_value()); | |
| 6448 __ j(equal, &next_probe); | |
| 6449 | |
| 6450 // Load the instance type of the candidate. | |
| 6451 __ mov(scratch2, FieldOperand(candidate, HeapObject::kMapOffset)); | |
| 6452 __ movzx_b(scratch2, FieldOperand(scratch2, Map::kInstanceTypeOffset)); | |
| 6453 if (name_type == NAME_IS_ASCII_SYMBOL) { | |
| 6454 // If both name and candidate are symbols, we can go to the next | |
| 6455 // probe. | |
| 6456 __ test_b(Operand(scratch2), kIsSymbolMask); | |
| 6457 __ j(not_zero, &next_probe); | |
| 6458 // Check if the candidate is a sequential ASCII string. | |
| 6459 __ cmp(scratch2, static_cast<int32_t>(ASCII_STRING_TYPE)); | |
| 6460 __ j(not_equal, call_runtime); | |
| 6461 } else { | |
| 6462 ASSERT(name_type == NAME_IS_ASCII_STRING_WITH_HASH); | |
| 6463 // Check if the candidate is a sequential ASCII string or symbol. | |
| 6464 uint32_t candidate_mask = | |
| 6465 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask; | |
| 6466 uint32_t expected = | |
| 6467 kStringTag | kAsciiStringTag | kSeqStringTag; | |
| 6468 __ and_(scratch2, static_cast<int32_t>(candidate_mask)); | |
| 6469 __ cmp(scratch2, static_cast<int32_t>(expected)); | |
| 6470 __ j(not_equal, call_runtime); | |
| 6471 } | |
| 6472 | |
| 6473 // Compare sequential ASCII strings. | |
| 6474 Label strings_not_equal; | |
| 6475 __ push(dictionary); | |
| 6476 __ push(name); | |
| 6477 StringCompareStub::GenerateFlatAsciiStringEquals(masm, | |
| 6478 name, | |
| 6479 candidate, | |
| 6480 scratch2, | |
| 6481 dictionary, | |
| 6482 &strings_not_equal); | |
| 6483 __ pop(name); | |
| 6484 __ pop(dictionary); | |
| 6485 __ jmp(found_in_dictionary); | |
| 6486 __ bind(&strings_not_equal); | |
| 6487 __ pop(name); | |
| 6488 __ pop(dictionary); | |
| 6489 | |
| 6490 __ bind(&next_probe); | |
| 6491 } | |
| 6492 __ jmp(call_runtime); | |
| 6493 } | |
| 6494 | |
| 6495 | |
| 6261 void StringDictionaryLookupStub::Generate(MacroAssembler* masm) { | 6496 void StringDictionaryLookupStub::Generate(MacroAssembler* masm) { |
| 6262 // Stack frame on entry: | 6497 // Stack frame on entry: |
| 6263 // esp[0 * kPointerSize]: return address. | 6498 // esp[0 * kPointerSize]: return address. |
| 6264 // esp[1 * kPointerSize]: key's hash. | 6499 // esp[1 * kPointerSize]: key's hash. |
| 6265 // esp[2 * kPointerSize]: key. | 6500 // esp[2 * kPointerSize]: key. |
| 6266 // Registers: | 6501 // Registers: |
| 6267 // dictionary_: StringDictionary to probe. | 6502 // dictionary_: StringDictionary to probe. |
| 6268 // result_: used as scratch. | 6503 // result_: used as scratch. |
| 6269 // index_: will hold an index of entry if lookup is successful. | 6504 // index_: will hold an index of entry if lookup is successful. |
| 6270 // might alias with result_. | 6505 // might alias with result_. |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6339 __ Drop(1); | 6574 __ Drop(1); |
| 6340 __ ret(2 * kPointerSize); | 6575 __ ret(2 * kPointerSize); |
| 6341 | 6576 |
| 6342 __ bind(¬_in_dictionary); | 6577 __ bind(¬_in_dictionary); |
| 6343 __ mov(result_, Immediate(0)); | 6578 __ mov(result_, Immediate(0)); |
| 6344 __ Drop(1); | 6579 __ Drop(1); |
| 6345 __ ret(2 * kPointerSize); | 6580 __ ret(2 * kPointerSize); |
| 6346 } | 6581 } |
| 6347 | 6582 |
| 6348 | 6583 |
| 6584 void HasOwnPropertyStub::Generate(MacroAssembler* masm) { | |
| 6585 Register object = eax; | |
| 6586 Register map = ebx; | |
| 6587 Register name = ecx; | |
| 6588 Register scratch1 = edx; | |
| 6589 Register scratch2 = edi; | |
| 6590 Label call_runtime; | |
| 6591 | |
| 6592 // Load the arguments. | |
| 6593 __ mov(object, Operand(esp, 2 * kPointerSize)); | |
| 6594 __ mov(name, Operand(esp, 1 * kPointerSize)); | |
| 6595 | |
| 6596 if (FLAG_debug_code) { | |
| 6597 Label not_smi; | |
| 6598 __ JumpIfNotSmi(name, ¬_smi, Label::kNear); | |
| 6599 __ Abort("HasOwnPropertyStub: name is a smi"); | |
| 6600 __ bind(¬_smi); | |
| 6601 __ mov(scratch1, FieldOperand(name, HeapObject::kMapOffset)); | |
| 6602 __ test_b(FieldOperand(scratch1, Map::kInstanceTypeOffset), | |
| 6603 kIsNotStringMask); | |
| 6604 __ Assert(not_zero, "HasOwnPropertyStub: name is not a string"); | |
| 6605 } | |
| 6606 | |
| 6607 // Make sure the object is a non-special JS object with no elements, | |
| 6608 // interceptors, or hidden prototypes. | |
| 6609 // TODO(vitalyr): access check? | |
|
Mads Ager (chromium)
2011/07/15 09:04:45
Yes, I'm pretty sure you need to exclude objects t
| |
| 6610 __ JumpIfSmi(object, &call_runtime); | |
| 6611 __ mov(map, FieldOperand(object, HeapObject::kMapOffset)); | |
| 6612 __ 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
| |
| 6613 __ j(not_equal, &call_runtime); | |
| 6614 __ cmp(FieldOperand(object, JSObject::kElementsOffset), | |
| 6615 masm->isolate()->factory()->empty_fixed_array()); | |
| 6616 __ j(not_equal, &call_runtime); | |
| 6617 __ test_b(FieldOperand(map, Map::kBitFieldOffset), | |
| 6618 (1 << Map::kHasNamedInterceptor) | | |
| 6619 (1 << Map::kHasIndexedInterceptor)); | |
| 6620 __ j(not_zero, &call_runtime); | |
| 6621 __ mov(scratch1, FieldOperand(map, Map::kPrototypeOffset)); | |
| 6622 __ mov(scratch1, FieldOperand(scratch1, HeapObject::kMapOffset)); | |
| 6623 __ test_b(FieldOperand(scratch1, Map::kBitFieldOffset), | |
|
Mads Ager (chromium)
2011/07/15 09:04:45
You are disregarding objects with hidden prototype
| |
| 6624 (1 << Map::kIsHiddenPrototype)); | |
| 6625 __ j(not_zero, &call_runtime); | |
| 6626 | |
| 6627 // Does the object have fast properties? | |
| 6628 Label slow_properties; | |
| 6629 __ mov(scratch1, FieldOperand(object, JSObject::kPropertiesOffset)); | |
| 6630 __ cmp(FieldOperand(scratch1, HeapObject::kMapOffset), | |
| 6631 masm->isolate()->factory()->fixed_array_map()); | |
| 6632 __ j(not_equal, &slow_properties); | |
| 6633 | |
| 6634 // Handle fast properties. | |
| 6635 GenerateFastPropertiesCase(masm, | |
| 6636 map, | |
| 6637 name, | |
| 6638 object, | |
| 6639 scratch1, | |
| 6640 scratch2, | |
| 6641 &call_runtime); | |
| 6642 | |
|
Mads Ager (chromium)
2011/07/15 09:04:45
Add an abort here so it is clear that there is no
| |
| 6643 // Handle slow properties. | |
| 6644 __ bind(&slow_properties); | |
| 6645 GenerateSlowPropertiesCase(masm, | |
| 6646 object, | |
| 6647 name, | |
| 6648 map, | |
| 6649 scratch1, | |
| 6650 scratch2, | |
| 6651 &call_runtime); | |
| 6652 | |
|
Mads Ager (chromium)
2011/07/15 09:04:45
Ditto, add an abort?
| |
| 6653 __ bind(&call_runtime); | |
| 6654 __ TailCallRuntime(Runtime::kHasOwnProperty, 2, 1); | |
| 6655 } | |
| 6656 | |
| 6657 | |
| 6658 void HasOwnPropertyStub::GenerateFastPropertiesCase(MacroAssembler* masm, | |
| 6659 Register map, | |
| 6660 Register name, | |
| 6661 Register scratch1, | |
| 6662 Register scratch2, | |
| 6663 Register scratch3, | |
| 6664 Label* call_runtime) { | |
| 6665 // Load the descritor array from the map. | |
| 6666 Register descriptor_array = map; | |
| 6667 Label not_found_in_descriptors; | |
| 6668 __ mov(descriptor_array, | |
| 6669 FieldOperand(map, Map::kInstanceDescriptorsOrBitField3Offset)); | |
| 6670 map = no_reg; | |
| 6671 __ JumpIfSmi(descriptor_array, ¬_found_in_descriptors); | |
| 6672 | |
| 6673 // Check the name is a symbol or a sequential ASCII string. We don't | |
| 6674 // support comparison of other string types here. | |
| 6675 Label name_is_not_symbol; | |
| 6676 __ mov(scratch1, FieldOperand(name, HeapObject::kMapOffset)); | |
| 6677 __ movzx_b(scratch1, FieldOperand(scratch1, Map::kInstanceTypeOffset)); | |
| 6678 __ test_b(Operand(scratch1), kIsSymbolMask); | |
| 6679 __ j(zero, &name_is_not_symbol); | |
| 6680 GenerateDescriptorArrayLookup(masm, | |
| 6681 NAME_IS_SYMBOL, | |
| 6682 descriptor_array, | |
| 6683 name, | |
| 6684 scratch1, | |
| 6685 scratch2, | |
| 6686 scratch3, | |
| 6687 ¬_found_in_descriptors, | |
| 6688 call_runtime); | |
| 6689 __ bind(&name_is_not_symbol); | |
| 6690 uint32_t mask = kStringRepresentationMask | kStringEncodingMask; | |
| 6691 uint32_t expected = kSeqStringTag | kAsciiStringTag; | |
| 6692 __ and_(scratch1, static_cast<int32_t>(mask)); | |
| 6693 __ cmp(scratch1, static_cast<int32_t>(expected)); | |
| 6694 __ j(not_equal, call_runtime); | |
| 6695 GenerateDescriptorArrayLookup(masm, | |
| 6696 NAME_IS_SEQUENTIAL_ASCII, | |
| 6697 descriptor_array, | |
| 6698 name, | |
| 6699 scratch1, | |
| 6700 scratch2, | |
| 6701 scratch3, | |
| 6702 ¬_found_in_descriptors, | |
| 6703 call_runtime); | |
| 6704 | |
| 6705 // Did not find a descriptor corresponding to the given property | |
| 6706 // name. | |
| 6707 __ bind(¬_found_in_descriptors); | |
| 6708 __ mov(eax, masm->isolate()->factory()->false_value()); | |
| 6709 __ ret(2); | |
| 6710 } | |
| 6711 | |
| 6712 | |
| 6713 void HasOwnPropertyStub::GenerateDescriptorArrayLookup( | |
| 6714 MacroAssembler* masm, | |
| 6715 NameType name_type, | |
| 6716 Register descriptor_array, | |
| 6717 Register name, | |
| 6718 Register scratch1, | |
| 6719 Register scratch2, | |
| 6720 Register scratch3, | |
| 6721 Label* not_found_in_descriptors, | |
| 6722 Label* call_runtime) { | |
| 6723 // Setup the lookup loop. | |
| 6724 Register index = scratch1; | |
| 6725 __ Set(index, Immediate(Smi::FromInt(DescriptorArray::kFirstIndex - 1))); | |
| 6726 Operand length = FieldOperand(descriptor_array, FixedArray::kLengthOffset); | |
| 6727 | |
| 6728 // Loop over the descriptor array keys. Both index and length are | |
| 6729 // smi tagged. | |
| 6730 Register candidate = scratch2; | |
| 6731 Label loop, found_in_descriptors; | |
| 6732 __ bind(&loop); | |
| 6733 __ add(Operand(index), Immediate(Smi::FromInt(1))); | |
| 6734 __ cmp(index, length); | |
| 6735 __ j(greater_equal, not_found_in_descriptors); | |
| 6736 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); | |
| 6737 Operand candidate_operand = FieldOperand(descriptor_array, | |
| 6738 index, times_half_pointer_size, | |
| 6739 FixedArray::kHeaderSize); | |
| 6740 if (name_type == NAME_IS_SYMBOL) { | |
| 6741 // If the property name is a symbol, we can do a fast identity | |
| 6742 // check only, because descriptor arrays always contain symbols. | |
| 6743 __ cmp(name, candidate_operand); | |
| 6744 __ j(not_equal, &loop, Label::kNear); | |
| 6745 } else { | |
| 6746 ASSERT(name_type == NAME_IS_SEQUENTIAL_ASCII); | |
| 6747 // If the property name is a sequential ASCII string, check that | |
| 6748 // the descriptor name is a sequential ASCII symbol. | |
| 6749 Label strings_not_equal; | |
| 6750 __ mov(candidate, candidate_operand); | |
| 6751 __ cmp(FieldOperand(candidate, HeapObject::kMapOffset), | |
| 6752 masm->isolate()->factory()->ascii_symbol_map()); | |
| 6753 __ j(not_equal, call_runtime); | |
| 6754 | |
| 6755 // Compare name and candidate strings. We have to temporarily save | |
| 6756 // registers on the stack. | |
| 6757 __ push(name); | |
| 6758 __ push(descriptor_array); | |
| 6759 StringCompareStub::GenerateFlatAsciiStringEquals(masm, | |
| 6760 name, | |
| 6761 candidate, | |
| 6762 scratch3, | |
| 6763 descriptor_array, | |
| 6764 &strings_not_equal); | |
| 6765 __ pop(descriptor_array); | |
| 6766 __ pop(name); | |
| 6767 __ jmp(&found_in_descriptors); | |
| 6768 __ bind(&strings_not_equal); | |
| 6769 __ pop(descriptor_array); | |
| 6770 __ pop(name); | |
| 6771 __ jmp(&loop); | |
| 6772 } | |
| 6773 | |
| 6774 // Found a descriptor corresponding to the given property | |
| 6775 // name. Check the descriptor details to determine whether the | |
| 6776 // property exists or not. | |
| 6777 Register details = descriptor_array; | |
| 6778 Label do_return; | |
| 6779 __ bind(&found_in_descriptors); | |
| 6780 __ SmiUntag(index); | |
| 6781 __ sub(Operand(index), Immediate(DescriptorArray::kFirstIndex)); | |
| 6782 __ mov(details, FieldOperand(descriptor_array, | |
| 6783 DescriptorArray::kContentArrayOffset)); | |
| 6784 __ mov(details, FieldOperand(details, | |
| 6785 index, times_twice_pointer_size, | |
| 6786 FixedArray::kHeaderSize + kPointerSize)); | |
| 6787 __ SmiUntag(details); | |
| 6788 __ and_(details, PropertyDetails::TypeField::mask()); | |
| 6789 __ cmp(details, | |
| 6790 PropertyDetails::TypeField::encode(FIRST_PHANTOM_PROPERTY_TYPE)); | |
| 6791 __ mov(eax, masm->isolate()->factory()->true_value()); | |
| 6792 __ j(less, &do_return, Label::kNear); | |
| 6793 __ mov(eax, masm->isolate()->factory()->false_value()); | |
| 6794 __ bind(&do_return); | |
| 6795 __ ret(2); | |
| 6796 } | |
| 6797 | |
| 6798 | |
| 6799 void HasOwnPropertyStub::GenerateSlowPropertiesCase(MacroAssembler* masm, | |
| 6800 Register object, | |
| 6801 Register name, | |
| 6802 Register scratch1, | |
| 6803 Register scratch2, | |
| 6804 Register scratch3, | |
| 6805 Label* call_runtime) { | |
| 6806 Label found_in_dictionary, not_found_in_dictionary; | |
| 6807 Register dictionary = object; | |
| 6808 __ mov(dictionary, FieldOperand(object, JSObject::kPropertiesOffset)); | |
| 6809 StringDictionaryLookupStub::GenerateLookupWithComparisons( | |
| 6810 masm, | |
| 6811 dictionary, | |
| 6812 name, | |
| 6813 scratch1, | |
| 6814 scratch2, | |
| 6815 scratch3, | |
| 6816 &found_in_dictionary, | |
| 6817 ¬_found_in_dictionary, | |
| 6818 call_runtime); | |
| 6819 | |
| 6820 // Found a property with the given name in the property dictionary. | |
| 6821 __ bind(&found_in_dictionary); | |
| 6822 __ mov(eax, masm->isolate()->factory()->true_value()); | |
| 6823 __ ret(2); | |
| 6824 | |
| 6825 // Not found a property with the given name in the property dictionary. | |
| 6826 __ bind(¬_found_in_dictionary); | |
| 6827 __ mov(eax, masm->isolate()->factory()->false_value()); | |
| 6828 __ ret(2); | |
| 6829 } | |
| 6830 | |
| 6349 #undef __ | 6831 #undef __ |
| 6350 | 6832 |
| 6351 } } // namespace v8::internal | 6833 } } // namespace v8::internal |
| 6352 | 6834 |
| 6353 #endif // V8_TARGET_ARCH_IA32 | 6835 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |