OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
50 // must always call a backup property load that is complete. | 50 // must always call a backup property load that is complete. |
51 // This function is safe to call if the receiver has fast properties, | 51 // This function is safe to call if the receiver has fast properties, |
52 // or if name is not a symbol, and will jump to the miss_label in that case. | 52 // or if name is not a symbol, and will jump to the miss_label in that case. |
53 static void GenerateDictionaryLoad(MacroAssembler* masm, | 53 static void GenerateDictionaryLoad(MacroAssembler* masm, |
54 Label* miss_label, | 54 Label* miss_label, |
55 Register receiver, | 55 Register receiver, |
56 Register name, | 56 Register name, |
57 Register r0, | 57 Register r0, |
58 Register r1, | 58 Register r1, |
59 Register r2, | 59 Register r2, |
| 60 Register result, |
60 DictionaryCheck check_dictionary) { | 61 DictionaryCheck check_dictionary) { |
61 // Register use: | 62 // Register use: |
62 // | 63 // |
63 // name - holds the name of the property and is unchanged. | 64 // name - holds the name of the property and is unchanged. |
64 // receiver - holds the receiver and is unchanged. | 65 // receiver - holds the receiver and is unchanged. |
65 // Scratch registers: | 66 // Scratch registers: |
66 // r0 - used to hold the property dictionary. | 67 // r0 - used to hold the property dictionary. |
67 // | 68 // |
68 // r1 - used for the index into the property dictionary | 69 // r1 - used for the index into the property dictionary |
69 // - holds the result on exit. | |
70 // | 70 // |
71 // r2 - used to hold the capacity of the property dictionary. | 71 // r2 - used to hold the capacity of the property dictionary. |
| 72 // |
| 73 // result - holds the result on exit. |
72 | 74 |
73 Label done; | 75 Label done; |
74 | 76 |
75 // Check for the absence of an interceptor. | 77 // Check for the absence of an interceptor. |
76 // Load the map into r0. | 78 // Load the map into r0. |
77 __ mov(r0, FieldOperand(receiver, JSObject::kMapOffset)); | 79 __ mov(r0, FieldOperand(receiver, JSObject::kMapOffset)); |
78 | 80 |
79 // Bail out if the receiver has a named interceptor. | 81 // Bail out if the receiver has a named interceptor. |
80 __ test(FieldOperand(r0, Map::kBitFieldOffset), | 82 __ test(FieldOperand(r0, Map::kBitFieldOffset), |
81 Immediate(1 << Map::kHasNamedInterceptor)); | 83 Immediate(1 << Map::kHasNamedInterceptor)); |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
142 | 144 |
143 // Check that the value is a normal property. | 145 // Check that the value is a normal property. |
144 __ bind(&done); | 146 __ bind(&done); |
145 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; | 147 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; |
146 __ test(Operand(r0, r1, times_4, kDetailsOffset - kHeapObjectTag), | 148 __ test(Operand(r0, r1, times_4, kDetailsOffset - kHeapObjectTag), |
147 Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize)); | 149 Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize)); |
148 __ j(not_zero, miss_label, not_taken); | 150 __ j(not_zero, miss_label, not_taken); |
149 | 151 |
150 // Get the value at the masked, scaled index. | 152 // Get the value at the masked, scaled index. |
151 const int kValueOffset = kElementsStartOffset + kPointerSize; | 153 const int kValueOffset = kElementsStartOffset + kPointerSize; |
152 __ mov(r1, Operand(r0, r1, times_4, kValueOffset - kHeapObjectTag)); | 154 __ mov(result, Operand(r0, r1, times_4, kValueOffset - kHeapObjectTag)); |
153 } | 155 } |
154 | 156 |
155 | 157 |
156 static void GenerateNumberDictionaryLoad(MacroAssembler* masm, | 158 static void GenerateNumberDictionaryLoad(MacroAssembler* masm, |
157 Label* miss, | 159 Label* miss, |
158 Register elements, | 160 Register elements, |
159 Register key, | 161 Register key, |
160 Register r0, | 162 Register r0, |
161 Register r1, | 163 Register r1, |
162 Register r2) { | 164 Register r2, |
| 165 Register result) { |
163 // Register use: | 166 // Register use: |
164 // | 167 // |
165 // elements - holds the slow-case elements of the receiver and is unchanged. | 168 // elements - holds the slow-case elements of the receiver and is unchanged. |
166 // | 169 // |
167 // key - holds the smi key on entry and is unchanged if a branch is | 170 // key - holds the smi key on entry and is unchanged. |
168 // performed to the miss label. If the load succeeds and we | |
169 // fall through, key holds the result on exit. | |
170 // | 171 // |
171 // Scratch registers: | 172 // Scratch registers: |
172 // | 173 // |
173 // r0 - holds the untagged key on entry and holds the hash once computed. | 174 // r0 - holds the untagged key on entry and holds the hash once computed. |
174 // | 175 // |
175 // r1 - used to hold the capacity mask of the dictionary | 176 // r1 - used to hold the capacity mask of the dictionary |
176 // | 177 // |
177 // r2 - used for the index into the dictionary. | 178 // r2 - used for the index into the dictionary. |
| 179 // |
| 180 // result - holds the result on exit if the load succeeds and we fall through. |
| 181 |
178 Label done; | 182 Label done; |
179 | 183 |
180 // Compute the hash code from the untagged key. This must be kept in sync | 184 // Compute the hash code from the untagged key. This must be kept in sync |
181 // with ComputeIntegerHash in utils.h. | 185 // with ComputeIntegerHash in utils.h. |
182 // | 186 // |
183 // hash = ~hash + (hash << 15); | 187 // hash = ~hash + (hash << 15); |
184 __ mov(r1, r0); | 188 __ mov(r1, r0); |
185 __ not_(r0); | 189 __ not_(r0); |
186 __ shl(r1, 15); | 190 __ shl(r1, 15); |
187 __ add(r0, Operand(r1)); | 191 __ add(r0, Operand(r1)); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
239 const int kDetailsOffset = | 243 const int kDetailsOffset = |
240 NumberDictionary::kElementsStartOffset + 2 * kPointerSize; | 244 NumberDictionary::kElementsStartOffset + 2 * kPointerSize; |
241 ASSERT_EQ(NORMAL, 0); | 245 ASSERT_EQ(NORMAL, 0); |
242 __ test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset), | 246 __ test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset), |
243 Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize)); | 247 Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize)); |
244 __ j(not_zero, miss); | 248 __ j(not_zero, miss); |
245 | 249 |
246 // Get the value at the masked, scaled index. | 250 // Get the value at the masked, scaled index. |
247 const int kValueOffset = | 251 const int kValueOffset = |
248 NumberDictionary::kElementsStartOffset + kPointerSize; | 252 NumberDictionary::kElementsStartOffset + kPointerSize; |
249 __ mov(key, FieldOperand(elements, r2, times_pointer_size, kValueOffset)); | 253 __ mov(result, FieldOperand(elements, r2, times_pointer_size, kValueOffset)); |
250 } | 254 } |
251 | 255 |
252 | 256 |
253 // The offset from the inlined patch site to the start of the | 257 // The offset from the inlined patch site to the start of the |
254 // inlined load instruction. It is 7 bytes (test eax, imm) plus | 258 // inlined load instruction. It is 7 bytes (test eax, imm) plus |
255 // 6 bytes (jne slow_label). | 259 // 6 bytes (jne slow_label). |
256 const int LoadIC::kOffsetToLoadInstruction = 13; | 260 const int LoadIC::kOffsetToLoadInstruction = 13; |
257 | 261 |
258 | 262 |
259 void LoadIC::GenerateArrayLength(MacroAssembler* masm) { | 263 void LoadIC::GenerateArrayLength(MacroAssembler* masm) { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
291 // -- esp[0] : return address | 295 // -- esp[0] : return address |
292 // ----------------------------------- | 296 // ----------------------------------- |
293 Label miss; | 297 Label miss; |
294 | 298 |
295 StubCompiler::GenerateLoadFunctionPrototype(masm, eax, edx, ebx, &miss); | 299 StubCompiler::GenerateLoadFunctionPrototype(masm, eax, edx, ebx, &miss); |
296 __ bind(&miss); | 300 __ bind(&miss); |
297 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); | 301 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); |
298 } | 302 } |
299 | 303 |
300 | 304 |
| 305 // Checks the receiver for special cases (value type, slow case bits). |
| 306 // Falls through for regular JS object. |
| 307 static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm, |
| 308 Register receiver, |
| 309 Register r0, |
| 310 Label* slow) { |
| 311 // Register use: |
| 312 // receiver - holds the receiver and is unchanged. |
| 313 // Scratch registers: |
| 314 // r0 - used to hold the map of the receiver. |
| 315 |
| 316 // Check that the object isn't a smi. |
| 317 __ test(receiver, Immediate(kSmiTagMask)); |
| 318 __ j(zero, slow, not_taken); |
| 319 |
| 320 // Get the map of the receiver. |
| 321 __ mov(r0, FieldOperand(receiver, HeapObject::kMapOffset)); |
| 322 |
| 323 // Check bit field. |
| 324 __ test_b(FieldOperand(r0, Map::kBitFieldOffset), |
| 325 KeyedLoadIC::kSlowCaseBitFieldMask); |
| 326 __ j(not_zero, slow, not_taken); |
| 327 // Check that the object is some kind of JS object EXCEPT JS Value type. |
| 328 // In the case that the object is a value-wrapper object, |
| 329 // we enter the runtime system to make sure that indexing |
| 330 // into string objects works as intended. |
| 331 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); |
| 332 |
| 333 __ CmpInstanceType(r0, JS_OBJECT_TYPE); |
| 334 __ j(below, slow, not_taken); |
| 335 } |
| 336 |
| 337 |
| 338 // Loads an indexed element from a fast case array. |
| 339 static void GenerateFastArrayLoad(MacroAssembler* masm, |
| 340 Register receiver, |
| 341 Register key, |
| 342 Register scratch, |
| 343 Register result, |
| 344 Label* not_fast_array, |
| 345 Label* out_of_range) { |
| 346 // Register use: |
| 347 // receiver - holds the receiver and is unchanged. |
| 348 // key - holds the key and is unchanged (must be a smi). |
| 349 // Scratch registers: |
| 350 // scratch - used to hold elements of the receiver and the loaded value. |
| 351 // result - holds the result on exit if the load succeeds and |
| 352 // we fall through. |
| 353 |
| 354 __ mov(scratch, FieldOperand(receiver, JSObject::kElementsOffset)); |
| 355 // Check that the object is in fast mode (not dictionary). |
| 356 __ CheckMap(scratch, Factory::fixed_array_map(), not_fast_array, true); |
| 357 // Check that the key (index) is within bounds. |
| 358 __ cmp(key, FieldOperand(scratch, FixedArray::kLengthOffset)); |
| 359 __ j(above_equal, out_of_range); |
| 360 // Fast case: Do the load. |
| 361 ASSERT((kPointerSize == 4) && (kSmiTagSize == 1) && (kSmiTag == 0)); |
| 362 __ mov(scratch, FieldOperand(scratch, key, times_2, FixedArray::kHeaderSize)); |
| 363 __ cmp(Operand(scratch), Immediate(Factory::the_hole_value())); |
| 364 // In case the loaded value is the_hole we have to consult GetProperty |
| 365 // to ensure the prototype chain is searched. |
| 366 __ j(equal, out_of_range); |
| 367 if (!result.is(scratch)) { |
| 368 __ mov(result, scratch); |
| 369 } |
| 370 } |
| 371 |
| 372 |
| 373 // Checks whether a key is an array index string or a symbol string. |
| 374 // Falls through if a key is a symbol. |
| 375 static void GenerateKeyStringCheck(MacroAssembler* masm, |
| 376 Register key, |
| 377 Register map, |
| 378 Register hash, |
| 379 Label* index_string, |
| 380 Label* not_symbol) { |
| 381 // Register use: |
| 382 // key - holds the key and is unchanged. Assumed to be non-smi. |
| 383 // Scratch registers: |
| 384 // map - used to hold the map of the key. |
| 385 // hash - used to hold the hash of the key. |
| 386 __ CmpObjectType(key, FIRST_NONSTRING_TYPE, map); |
| 387 __ j(above_equal, not_symbol); |
| 388 |
| 389 // Is the string an array index, with cached numeric value? |
| 390 __ mov(hash, FieldOperand(key, String::kHashFieldOffset)); |
| 391 __ test(hash, Immediate(String::kContainsCachedArrayIndexMask)); |
| 392 __ j(zero, index_string, not_taken); |
| 393 |
| 394 // Is the string a symbol? |
| 395 ASSERT(kSymbolTag != 0); |
| 396 __ test_b(FieldOperand(map, Map::kInstanceTypeOffset), kIsSymbolMask); |
| 397 __ j(zero, not_symbol, not_taken); |
| 398 } |
| 399 |
| 400 |
| 401 // Picks out an array index from the hash field. |
| 402 // The generated code never falls through. |
| 403 static void GenerateIndexFromHash(MacroAssembler* masm, |
| 404 Register key, |
| 405 Register hash, |
| 406 Label* index_smi) { |
| 407 // Register use: |
| 408 // key - holds the overwritten key on exit. |
| 409 // hash - holds the key's hash. Clobbered. |
| 410 |
| 411 // The assert checks that the constants for the maximum number of digits |
| 412 // for an array index cached in the hash field and the number of bits |
| 413 // reserved for it does not conflict. |
| 414 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) < |
| 415 (1 << String::kArrayIndexValueBits)); |
| 416 // We want the smi-tagged index in key. kArrayIndexValueMask has zeros in |
| 417 // the low kHashShift bits. |
| 418 // key: string key |
| 419 // ebx: hash field. |
| 420 ASSERT(String::kHashShift >= kSmiTagSize); |
| 421 __ and_(hash, String::kArrayIndexValueMask); |
| 422 __ shr(hash, String::kHashShift - kSmiTagSize); |
| 423 // Here we actually clobber the key which will be used if calling into |
| 424 // runtime later. However as the new key is the numeric value of a string key |
| 425 // there is no difference in using either key. |
| 426 __ mov(key, hash); |
| 427 // Now jump to the place where smi keys are handled. |
| 428 __ jmp(index_smi); |
| 429 } |
| 430 |
| 431 |
301 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { | 432 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { |
302 // ----------- S t a t e ------------- | 433 // ----------- S t a t e ------------- |
303 // -- eax : key | 434 // -- eax : key |
304 // -- edx : receiver | 435 // -- edx : receiver |
305 // -- esp[0] : return address | 436 // -- esp[0] : return address |
306 // ----------------------------------- | 437 // ----------------------------------- |
307 Label slow, check_string, index_smi, index_string; | 438 Label slow, check_string, index_smi, index_string; |
308 Label check_pixel_array, probe_dictionary, check_number_dictionary; | 439 Label check_pixel_array, probe_dictionary, check_number_dictionary; |
309 | 440 |
310 // Check that the object isn't a smi. | 441 GenerateKeyedLoadReceiverCheck(masm, edx, ecx, &slow); |
311 __ test(edx, Immediate(kSmiTagMask)); | |
312 __ j(zero, &slow, not_taken); | |
313 | 442 |
314 // Get the map of the receiver. | |
315 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | |
316 | |
317 // Check bit field. | |
318 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), kSlowCaseBitFieldMask); | |
319 __ j(not_zero, &slow, not_taken); | |
320 // Check that the object is some kind of JS object EXCEPT JS Value type. | |
321 // In the case that the object is a value-wrapper object, | |
322 // we enter the runtime system to make sure that indexing | |
323 // into string objects work as intended. | |
324 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); | |
325 __ CmpInstanceType(ecx, JS_OBJECT_TYPE); | |
326 __ j(below, &slow, not_taken); | |
327 // Check that the key is a smi. | 443 // Check that the key is a smi. |
328 __ test(eax, Immediate(kSmiTagMask)); | 444 __ test(eax, Immediate(kSmiTagMask)); |
329 __ j(not_zero, &check_string, not_taken); | 445 __ j(not_zero, &check_string, not_taken); |
330 __ bind(&index_smi); | 446 __ bind(&index_smi); |
331 // Now the key is known to be a smi. This place is also jumped to from below | 447 // Now the key is known to be a smi. This place is also jumped to from |
332 // where a numeric string is converted to a smi. | 448 // where a numeric string is converted to a smi. |
333 __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset)); | 449 |
334 // Check that the object is in fast mode (not dictionary). | 450 GenerateFastArrayLoad(masm, |
335 __ CheckMap(ecx, Factory::fixed_array_map(), &check_pixel_array, true); | 451 edx, |
336 // Check that the key (index) is within bounds. | 452 eax, |
337 __ cmp(eax, FieldOperand(ecx, FixedArray::kLengthOffset)); | 453 ecx, |
338 __ j(above_equal, &slow); | 454 eax, |
339 // Fast case: Do the load. | 455 &check_pixel_array, |
340 ASSERT((kPointerSize == 4) && (kSmiTagSize == 1) && (kSmiTag == 0)); | 456 &slow); |
341 __ mov(ecx, FieldOperand(ecx, eax, times_2, FixedArray::kHeaderSize)); | |
342 __ cmp(Operand(ecx), Immediate(Factory::the_hole_value())); | |
343 // In case the loaded value is the_hole we have to consult GetProperty | |
344 // to ensure the prototype chain is searched. | |
345 __ j(equal, &slow); | |
346 __ mov(eax, ecx); | |
347 __ IncrementCounter(&Counters::keyed_load_generic_smi, 1); | 457 __ IncrementCounter(&Counters::keyed_load_generic_smi, 1); |
348 __ ret(0); | 458 __ ret(0); |
349 | 459 |
350 __ bind(&check_pixel_array); | 460 __ bind(&check_pixel_array); |
351 // Check whether the elements is a pixel array. | 461 // Check whether the elements is a pixel array. |
352 // edx: receiver | 462 // edx: receiver |
353 // eax: key | 463 // eax: key |
354 // ecx: elements | 464 // ecx: elements |
355 __ mov(ebx, eax); | 465 __ mov(ebx, eax); |
356 __ SmiUntag(ebx); | 466 __ SmiUntag(ebx); |
(...skipping 15 matching lines...) Expand all Loading... |
372 Label slow_pop_receiver; | 482 Label slow_pop_receiver; |
373 // Push receiver on the stack to free up a register for the dictionary | 483 // Push receiver on the stack to free up a register for the dictionary |
374 // probing. | 484 // probing. |
375 __ push(edx); | 485 __ push(edx); |
376 GenerateNumberDictionaryLoad(masm, | 486 GenerateNumberDictionaryLoad(masm, |
377 &slow_pop_receiver, | 487 &slow_pop_receiver, |
378 ecx, | 488 ecx, |
379 eax, | 489 eax, |
380 ebx, | 490 ebx, |
381 edx, | 491 edx, |
382 edi); | 492 edi, |
| 493 eax); |
383 // Pop receiver before returning. | 494 // Pop receiver before returning. |
384 __ pop(edx); | 495 __ pop(edx); |
385 __ ret(0); | 496 __ ret(0); |
386 | 497 |
387 __ bind(&slow_pop_receiver); | 498 __ bind(&slow_pop_receiver); |
388 // Pop the receiver from the stack and jump to runtime. | 499 // Pop the receiver from the stack and jump to runtime. |
389 __ pop(edx); | 500 __ pop(edx); |
390 | 501 |
391 __ bind(&slow); | 502 __ bind(&slow); |
392 // Slow case: jump to runtime. | 503 // Slow case: jump to runtime. |
393 // edx: receiver | 504 // edx: receiver |
394 // eax: key | 505 // eax: key |
395 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1); | 506 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1); |
396 GenerateRuntimeGetProperty(masm); | 507 GenerateRuntimeGetProperty(masm); |
397 | 508 |
398 __ bind(&check_string); | 509 __ bind(&check_string); |
399 // The key is not a smi. | 510 GenerateKeyStringCheck(masm, eax, ecx, ebx, &index_string, &slow); |
400 // Is it a string? | |
401 // edx: receiver | |
402 // eax: key | |
403 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ecx); | |
404 __ j(above_equal, &slow); | |
405 // Is the string an array index, with cached numeric value? | |
406 __ mov(ebx, FieldOperand(eax, String::kHashFieldOffset)); | |
407 __ test(ebx, Immediate(String::kContainsCachedArrayIndexMask)); | |
408 __ j(zero, &index_string, not_taken); | |
409 | |
410 // Is the string a symbol? | |
411 // ecx: key map. | |
412 ASSERT(kSymbolTag != 0); | |
413 __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kIsSymbolMask); | |
414 __ j(zero, &slow, not_taken); | |
415 | 511 |
416 // If the receiver is a fast-case object, check the keyed lookup | 512 // If the receiver is a fast-case object, check the keyed lookup |
417 // cache. Otherwise probe the dictionary. | 513 // cache. Otherwise probe the dictionary. |
418 __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset)); | 514 __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset)); |
419 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), | 515 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), |
420 Immediate(Factory::hash_table_map())); | 516 Immediate(Factory::hash_table_map())); |
421 __ j(equal, &probe_dictionary); | 517 __ j(equal, &probe_dictionary); |
422 | 518 |
423 // Load the map of the receiver, compute the keyed lookup cache hash | 519 // Load the map of the receiver, compute the keyed lookup cache hash |
424 // based on 32 bits of the map pointer and the string hash. | 520 // based on 32 bits of the map pointer and the string hash. |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
465 // Do a quick inline probe of the receiver's dictionary, if it | 561 // Do a quick inline probe of the receiver's dictionary, if it |
466 // exists. | 562 // exists. |
467 __ bind(&probe_dictionary); | 563 __ bind(&probe_dictionary); |
468 GenerateDictionaryLoad(masm, | 564 GenerateDictionaryLoad(masm, |
469 &slow, | 565 &slow, |
470 edx, | 566 edx, |
471 eax, | 567 eax, |
472 ebx, | 568 ebx, |
473 ecx, | 569 ecx, |
474 edi, | 570 edi, |
| 571 eax, |
475 DICTIONARY_CHECK_DONE); | 572 DICTIONARY_CHECK_DONE); |
476 __ mov(eax, ecx); | |
477 __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1); | 573 __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1); |
478 __ ret(0); | 574 __ ret(0); |
479 | 575 |
480 // If the hash field contains an array index pick it out. The assert checks | |
481 // that the constants for the maximum number of digits for an array index | |
482 // cached in the hash field and the number of bits reserved for it does not | |
483 // conflict. | |
484 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) < | |
485 (1 << String::kArrayIndexValueBits)); | |
486 __ bind(&index_string); | 576 __ bind(&index_string); |
487 // We want the smi-tagged index in eax. kArrayIndexValueMask has zeros in | 577 GenerateIndexFromHash(masm, eax, ebx, &index_smi); |
488 // the low kHashShift bits. | |
489 // eax: key (string). | |
490 // ebx: hash field. | |
491 // edx: receiver. | |
492 ASSERT(String::kHashShift >= kSmiTagSize); | |
493 __ and_(ebx, String::kArrayIndexValueMask); | |
494 __ shr(ebx, String::kHashShift - kSmiTagSize); | |
495 // Here we actually clobber the key (eax) which will be used if calling into | |
496 // runtime later. However as the new key is the numeric value of a string key | |
497 // there is no difference in using either key. | |
498 __ mov(eax, ebx); | |
499 // Now jump to the place where smi keys are handled. | |
500 __ jmp(&index_smi); | |
501 } | 578 } |
502 | 579 |
503 | 580 |
504 void KeyedLoadIC::GenerateString(MacroAssembler* masm) { | 581 void KeyedLoadIC::GenerateString(MacroAssembler* masm) { |
505 // ----------- S t a t e ------------- | 582 // ----------- S t a t e ------------- |
506 // -- eax : key (index) | 583 // -- eax : key (index) |
507 // -- edx : receiver | 584 // -- edx : receiver |
508 // -- esp[0] : return address | 585 // -- esp[0] : return address |
509 // ----------------------------------- | 586 // ----------------------------------- |
510 Label miss; | 587 Label miss; |
(...skipping 597 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1108 // -- ecx : name | 1185 // -- ecx : name |
1109 // -- edx : receiver | 1186 // -- edx : receiver |
1110 // -- esp[0] : return address | 1187 // -- esp[0] : return address |
1111 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 1188 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
1112 // -- ... | 1189 // -- ... |
1113 // -- esp[(argc + 1) * 4] : receiver | 1190 // -- esp[(argc + 1) * 4] : receiver |
1114 // ----------------------------------- | 1191 // ----------------------------------- |
1115 | 1192 |
1116 // Search dictionary - put result in register edi. | 1193 // Search dictionary - put result in register edi. |
1117 __ mov(edi, edx); | 1194 __ mov(edi, edx); |
1118 GenerateDictionaryLoad(masm, miss, edx, ecx, eax, edi, ebx, CHECK_DICTIONARY); | 1195 GenerateDictionaryLoad( |
| 1196 masm, miss, edx, ecx, eax, edi, ebx, edi, CHECK_DICTIONARY); |
1119 | 1197 |
1120 // Check that the result is not a smi. | 1198 // Check that the result is not a smi. |
1121 __ test(edi, Immediate(kSmiTagMask)); | 1199 __ test(edi, Immediate(kSmiTagMask)); |
1122 __ j(zero, miss, not_taken); | 1200 __ j(zero, miss, not_taken); |
1123 | 1201 |
1124 // Check that the value is a JavaScript function, fetching its map into eax. | 1202 // Check that the value is a JavaScript function, fetching its map into eax. |
1125 __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax); | 1203 __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax); |
1126 __ j(not_equal, miss, not_taken); | 1204 __ j(not_equal, miss, not_taken); |
1127 | 1205 |
1128 // Patch the receiver on stack with the global proxy if necessary. | 1206 // Patch the receiver on stack with the global proxy if necessary. |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1286 // -- ecx : name | 1364 // -- ecx : name |
1287 // -- esp[0] : return address | 1365 // -- esp[0] : return address |
1288 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 1366 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
1289 // -- ... | 1367 // -- ... |
1290 // -- esp[(argc + 1) * 4] : receiver | 1368 // -- esp[(argc + 1) * 4] : receiver |
1291 // ----------------------------------- | 1369 // ----------------------------------- |
1292 | 1370 |
1293 // Get the receiver of the function from the stack; 1 ~ return address. | 1371 // Get the receiver of the function from the stack; 1 ~ return address. |
1294 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 1372 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
1295 | 1373 |
1296 Label miss, skip_probe; | 1374 Label do_call, slow_call, slow_load, slow_reload_receiver; |
| 1375 Label check_number_dictionary, check_string, lookup_monomorphic_cache; |
| 1376 Label index_smi, index_string; |
1297 | 1377 |
1298 // Do not probe monomorphic cache if a key is a smi. | 1378 // Check that the key is a smi. |
1299 __ test(ecx, Immediate(kSmiTagMask)); | 1379 __ test(ecx, Immediate(kSmiTagMask)); |
1300 __ j(equal, &skip_probe, taken); | 1380 __ j(not_zero, &check_string, not_taken); |
1301 | 1381 |
1302 GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC, &skip_probe); | 1382 __ bind(&index_smi); |
| 1383 // Now the key is known to be a smi. This place is also jumped to from |
| 1384 // where a numeric string is converted to a smi. |
1303 | 1385 |
1304 __ bind(&skip_probe); | 1386 GenerateKeyedLoadReceiverCheck(masm, edx, eax, &slow_call); |
1305 | 1387 |
1306 __ mov(eax, ecx); | 1388 GenerateFastArrayLoad(masm, |
1307 __ EnterInternalFrame(); | 1389 edx, |
1308 __ push(ecx); | 1390 ecx, |
1309 __ call(Handle<Code>(Builtins::builtin(Builtins::KeyedLoadIC_Generic)), | 1391 eax, |
1310 RelocInfo::CODE_TARGET); | 1392 edi, |
1311 __ pop(ecx); | 1393 &check_number_dictionary, |
1312 __ LeaveInternalFrame(); | 1394 &slow_load); |
1313 __ mov(edi, eax); | 1395 __ IncrementCounter(&Counters::keyed_call_generic_smi_fast, 1); |
1314 | 1396 |
1315 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 1397 __ bind(&do_call); |
| 1398 // receiver in edx is not used after this point. |
| 1399 // ecx: key |
| 1400 // edi: function |
1316 | 1401 |
1317 // Check that the receiver isn't a smi. | 1402 // Check that the value in edi is a JavaScript function. |
1318 __ test(edx, Immediate(kSmiTagMask)); | |
1319 __ j(zero, &miss, not_taken); | |
1320 | |
1321 // Check that the receiver is a valid JS object. | |
1322 __ CmpObjectType(edx, FIRST_JS_OBJECT_TYPE, eax); | |
1323 __ j(below, &miss, not_taken); | |
1324 | |
1325 // Check that the value is a JavaScript function. | |
1326 __ test(edi, Immediate(kSmiTagMask)); | 1403 __ test(edi, Immediate(kSmiTagMask)); |
1327 __ j(zero, &miss, not_taken); | 1404 __ j(zero, &slow_call, not_taken); |
1328 __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax); | 1405 __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax); |
1329 __ j(not_equal, &miss, not_taken); | 1406 __ j(not_equal, &slow_call, not_taken); |
1330 | |
1331 // Invoke the function. | 1407 // Invoke the function. |
1332 ParameterCount actual(argc); | 1408 ParameterCount actual(argc); |
1333 __ InvokeFunction(edi, actual, JUMP_FUNCTION); | 1409 __ InvokeFunction(edi, actual, JUMP_FUNCTION); |
1334 | 1410 |
1335 __ bind(&miss); | 1411 __ bind(&check_number_dictionary); |
| 1412 // eax: elements |
| 1413 // ecx: smi key |
| 1414 // Check whether the elements is a number dictionary. |
| 1415 __ CheckMap(eax, Factory::hash_table_map(), &slow_load, true); |
| 1416 __ mov(ebx, ecx); |
| 1417 __ SmiUntag(ebx); |
| 1418 // ebx: untagged index |
| 1419 // Receiver in edx will be clobbered, need to reload it on miss. |
| 1420 GenerateNumberDictionaryLoad(masm, |
| 1421 &slow_reload_receiver, |
| 1422 eax, |
| 1423 ecx, |
| 1424 ebx, |
| 1425 edx, |
| 1426 edi, |
| 1427 edi); |
| 1428 __ IncrementCounter(&Counters::keyed_call_generic_smi_dict, 1); |
| 1429 __ jmp(&do_call); |
| 1430 |
| 1431 __ bind(&slow_reload_receiver); |
| 1432 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 1433 |
| 1434 __ bind(&slow_load); |
| 1435 // This branch is taken when calling KeyedCallIC_Miss is neither required |
| 1436 // nor beneficial. |
| 1437 __ IncrementCounter(&Counters::keyed_call_generic_slow_load, 1); |
| 1438 __ EnterInternalFrame(); |
| 1439 __ push(ecx); // save the key |
| 1440 __ push(edx); // pass the receiver |
| 1441 __ push(ecx); // pass the key |
| 1442 __ CallRuntime(Runtime::kKeyedGetProperty, 2); |
| 1443 __ pop(ecx); // restore the key |
| 1444 __ LeaveInternalFrame(); |
| 1445 __ mov(edi, eax); |
| 1446 __ jmp(&do_call); |
| 1447 |
| 1448 __ bind(&check_string); |
| 1449 GenerateKeyStringCheck(masm, ecx, eax, ebx, &index_string, &slow_call); |
| 1450 |
| 1451 // The key is known to be a symbol. |
| 1452 // If the receiver is a regular JS object with slow properties then do |
| 1453 // a quick inline probe of the receiver's dictionary. |
| 1454 // Otherwise do the monomorphic cache probe. |
| 1455 GenerateKeyedLoadReceiverCheck(masm, edx, eax, &lookup_monomorphic_cache); |
| 1456 |
| 1457 __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset)); |
| 1458 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), |
| 1459 Immediate(Factory::hash_table_map())); |
| 1460 __ j(not_equal, &lookup_monomorphic_cache, not_taken); |
| 1461 |
| 1462 GenerateDictionaryLoad(masm, |
| 1463 &slow_load, |
| 1464 edx, |
| 1465 ecx, |
| 1466 ebx, |
| 1467 eax, |
| 1468 edi, |
| 1469 edi, |
| 1470 DICTIONARY_CHECK_DONE); |
| 1471 __ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1); |
| 1472 __ jmp(&do_call); |
| 1473 |
| 1474 __ bind(&lookup_monomorphic_cache); |
| 1475 __ IncrementCounter(&Counters::keyed_call_generic_lookup_cache, 1); |
| 1476 GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC, &slow_call); |
| 1477 // Fall through on miss. |
| 1478 |
| 1479 __ bind(&slow_call); |
| 1480 // This branch is taken if: |
| 1481 // - the receiver requires boxing or access check, |
| 1482 // - the key is neither smi nor symbol, |
| 1483 // - the value loaded is not a function, |
| 1484 // - there is hope that the runtime will create a monomorphic call stub |
| 1485 // that will get fetched next time. |
| 1486 __ IncrementCounter(&Counters::keyed_call_generic_slow, 1); |
1336 GenerateMiss(masm, argc); | 1487 GenerateMiss(masm, argc); |
| 1488 |
| 1489 __ bind(&index_string); |
| 1490 GenerateIndexFromHash(masm, ecx, ebx, &index_smi); |
1337 } | 1491 } |
1338 | 1492 |
1339 | 1493 |
1340 void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) { | 1494 void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) { |
1341 Label miss; | 1495 Label miss; |
1342 GenerateCallNormal(masm, argc, &miss); | 1496 GenerateCallNormal(masm, argc, &miss); |
1343 __ bind(&miss); | 1497 __ bind(&miss); |
1344 GenerateMiss(masm, argc); | 1498 GenerateMiss(masm, argc); |
1345 } | 1499 } |
1346 | 1500 |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1403 | 1557 |
1404 // Search the dictionary placing the result in eax. | 1558 // Search the dictionary placing the result in eax. |
1405 __ bind(&probe); | 1559 __ bind(&probe); |
1406 GenerateDictionaryLoad(masm, | 1560 GenerateDictionaryLoad(masm, |
1407 &miss, | 1561 &miss, |
1408 eax, | 1562 eax, |
1409 ecx, | 1563 ecx, |
1410 edx, | 1564 edx, |
1411 edi, | 1565 edi, |
1412 ebx, | 1566 ebx, |
| 1567 edi, |
1413 CHECK_DICTIONARY); | 1568 CHECK_DICTIONARY); |
1414 __ mov(eax, edi); | 1569 __ mov(eax, edi); |
1415 __ ret(0); | 1570 __ ret(0); |
1416 | 1571 |
1417 // Global object access: Check access rights. | 1572 // Global object access: Check access rights. |
1418 __ bind(&global); | 1573 __ bind(&global); |
1419 __ CheckAccessGlobalProxy(eax, edx, &miss); | 1574 __ CheckAccessGlobalProxy(eax, edx, &miss); |
1420 __ jmp(&probe); | 1575 __ jmp(&probe); |
1421 | 1576 |
1422 // Cache miss: Jump to runtime. | 1577 // Cache miss: Jump to runtime. |
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1706 ExternalReference ref = ExternalReference(IC_Utility(kKeyedStoreIC_Miss)); | 1861 ExternalReference ref = ExternalReference(IC_Utility(kKeyedStoreIC_Miss)); |
1707 __ TailCallExternalReference(ref, 3, 1); | 1862 __ TailCallExternalReference(ref, 3, 1); |
1708 } | 1863 } |
1709 | 1864 |
1710 #undef __ | 1865 #undef __ |
1711 | 1866 |
1712 | 1867 |
1713 } } // namespace v8::internal | 1868 } } // namespace v8::internal |
1714 | 1869 |
1715 #endif // V8_TARGET_ARCH_IA32 | 1870 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |