OLD | NEW |
---|---|
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 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 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
250 } | 250 } |
251 #endif | 251 #endif |
252 | 252 |
253 | 253 |
254 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { | 254 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { |
255 // ----------- S t a t e ------------- | 255 // ----------- S t a t e ------------- |
256 // -- rsp[0] : return address | 256 // -- rsp[0] : return address |
257 // -- rsp[8] : name | 257 // -- rsp[8] : name |
258 // -- rsp[16] : receiver | 258 // -- rsp[16] : receiver |
259 // ----------------------------------- | 259 // ----------------------------------- |
260 Label slow, fast, check_string, index_int, index_string; | 260 Label slow, check_string, index_int, index_string, check_pixel_array; |
261 | 261 |
262 // Load name and receiver. | 262 // Load name and receiver. |
263 __ movq(rax, Operand(rsp, kPointerSize)); | 263 __ movq(rax, Operand(rsp, kPointerSize)); |
264 __ movq(rcx, Operand(rsp, 2 * kPointerSize)); | 264 __ movq(rcx, Operand(rsp, 2 * kPointerSize)); |
265 | 265 |
266 // Check that the object isn't a smi. | 266 // Check that the object isn't a smi. |
267 __ JumpIfSmi(rcx, &slow); | 267 __ JumpIfSmi(rcx, &slow); |
268 | 268 |
269 // Check that the object is some kind of JS object EXCEPT JS Value type. | 269 // Check that the object is some kind of JS object EXCEPT JS Value type. |
270 // In the case that the object is a value-wrapper object, | 270 // In the case that the object is a value-wrapper object, |
271 // we enter the runtime system to make sure that indexing | 271 // we enter the runtime system to make sure that indexing |
272 // into string objects work as intended. | 272 // into string objects work as intended. |
273 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); | 273 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); |
274 __ CmpObjectType(rcx, JS_OBJECT_TYPE, rdx); | 274 __ CmpObjectType(rcx, JS_OBJECT_TYPE, rdx); |
275 __ j(below, &slow); | 275 __ j(below, &slow); |
276 // Check that the receiver does not require access checks. We need | 276 // Check that the receiver does not require access checks. We need |
277 // to check this explicitly since this generic stub does not perform | 277 // to check this explicitly since this generic stub does not perform |
278 // map checks. The map is already in rdx. | 278 // map checks. The map is already in rdx. |
279 __ testb(FieldOperand(rdx, Map::kBitFieldOffset), | 279 __ testb(FieldOperand(rdx, Map::kBitFieldOffset), |
280 Immediate(1 << Map::kIsAccessCheckNeeded)); | 280 Immediate(1 << Map::kIsAccessCheckNeeded)); |
281 __ j(not_zero, &slow); | 281 __ j(not_zero, &slow); |
282 | 282 |
283 // Check that the key is a smi. | 283 // Check that the key is a smi. |
284 __ JumpIfNotSmi(rax, &check_string); | 284 __ JumpIfNotSmi(rax, &check_string); |
285 __ SmiToInteger32(rax, rax); | 285 __ SmiToInteger32(rax, rax); |
286 // Get the elements array of the object. | 286 // Get the elements array of the object. |
287 __ bind(&index_int); | 287 __ bind(&index_int); |
288 __ movq(rcx, FieldOperand(rcx, JSObject::kElementsOffset)); | 288 __ movq(rcx, FieldOperand(rcx, JSObject::kElementsOffset)); |
289 // Check that the object is in fast mode (not dictionary). | 289 // Check that the object is in fast mode (not dictionary). |
290 __ Cmp(FieldOperand(rcx, HeapObject::kMapOffset), Factory::fixed_array_map()); | 290 __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset), |
291 __ j(not_equal, &slow); | 291 Heap::kFixedArrayMapRootIndex); |
292 __ j(not_equal, &check_pixel_array); | |
292 // Check that the key (index) is within bounds. | 293 // Check that the key (index) is within bounds. |
293 __ cmpl(rax, FieldOperand(rcx, FixedArray::kLengthOffset)); | 294 __ cmpl(rax, FieldOperand(rcx, FixedArray::kLengthOffset)); |
294 __ j(below, &fast); // Unsigned comparison rejects negative indices. | 295 __ j(above_equal, &slow); // Unsigned comparison rejects negative indices. |
296 // Fast case: Do the load. | |
297 __ movq(rax, Operand(rcx, rax, times_pointer_size, | |
298 FixedArray::kHeaderSize - kHeapObjectTag)); | |
299 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); | |
300 // In case the loaded value is the_hole we have to consult GetProperty | |
301 // to ensure the prototype chain is searched. | |
302 __ j(equal, &slow); | |
303 __ IncrementCounter(&Counters::keyed_load_generic_smi, 1); | |
304 __ ret(0); | |
305 | |
306 // Check whether the elements is a pixel array. | |
307 // rax: untagged index | |
308 // rcx: elements array | |
309 __ bind(&check_pixel_array); | |
310 __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset), | |
311 Heap::kPixelArrayMapRootIndex); | |
312 __ j(not_equal, &slow); | |
313 __ cmpl(rax, FieldOperand(rcx, PixelArray::kLengthOffset)); | |
314 __ j(above_equal, &slow); | |
315 __ movq(rcx, FieldOperand(rcx, PixelArray::kExternalPointerOffset)); | |
316 __ movb(rax, Operand(rcx, rax, times_1, 0)); | |
317 __ Integer32ToSmi(rax, rax); | |
318 __ ret(0); | |
319 | |
295 // Slow case: Load name and receiver from stack and jump to runtime. | 320 // Slow case: Load name and receiver from stack and jump to runtime. |
296 __ bind(&slow); | 321 __ bind(&slow); |
297 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1); | 322 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1); |
298 KeyedLoadIC::Generate(masm, ExternalReference(Runtime::kKeyedGetProperty)); | 323 KeyedLoadIC::Generate(masm, ExternalReference(Runtime::kKeyedGetProperty)); |
299 __ bind(&check_string); | 324 __ bind(&check_string); |
300 // The key is not a smi. | 325 // The key is not a smi. |
301 // Is it a string? | 326 // Is it a string? |
302 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rdx); | 327 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rdx); |
303 __ j(above_equal, &slow); | 328 __ j(above_equal, &slow); |
304 // Is the string an array index, with cached numeric value? | 329 // Is the string an array index, with cached numeric value? |
(...skipping 20 matching lines...) Expand all Loading... | |
325 (1 << (String::kShortLengthShift - String::kHashShift))); | 350 (1 << (String::kShortLengthShift - String::kHashShift))); |
326 __ bind(&index_string); | 351 __ bind(&index_string); |
327 const int kLengthFieldLimit = | 352 const int kLengthFieldLimit = |
328 (String::kMaxCachedArrayIndexLength + 1) << String::kShortLengthShift; | 353 (String::kMaxCachedArrayIndexLength + 1) << String::kShortLengthShift; |
329 __ cmpl(rbx, Immediate(kLengthFieldLimit)); | 354 __ cmpl(rbx, Immediate(kLengthFieldLimit)); |
330 __ j(above_equal, &slow); | 355 __ j(above_equal, &slow); |
331 __ movl(rax, rbx); | 356 __ movl(rax, rbx); |
332 __ and_(rax, Immediate((1 << String::kShortLengthShift) - 1)); | 357 __ and_(rax, Immediate((1 << String::kShortLengthShift) - 1)); |
333 __ shrl(rax, Immediate(String::kLongLengthShift)); | 358 __ shrl(rax, Immediate(String::kLongLengthShift)); |
334 __ jmp(&index_int); | 359 __ jmp(&index_int); |
335 // Fast case: Do the load. | |
336 __ bind(&fast); | |
337 __ movq(rax, Operand(rcx, rax, times_pointer_size, | |
338 FixedArray::kHeaderSize - kHeapObjectTag)); | |
339 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); | |
340 // In case the loaded value is the_hole we have to consult GetProperty | |
341 // to ensure the prototype chain is searched. | |
342 __ j(equal, &slow); | |
343 __ IncrementCounter(&Counters::keyed_load_generic_smi, 1); | |
344 __ ret(0); | |
345 } | 360 } |
346 | 361 |
347 | 362 |
348 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { | 363 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { |
349 // ----------- S t a t e ------------- | 364 // ----------- S t a t e ------------- |
350 // -- rsp[0] : return address | 365 // -- rsp[0] : return address |
351 // -- rsp[8] : name | 366 // -- rsp[8] : name |
352 // -- rsp[16] : receiver | 367 // -- rsp[16] : receiver |
353 // ----------------------------------- | 368 // ----------------------------------- |
354 Generate(masm, ExternalReference(IC_Utility(kKeyedLoadIC_Miss))); | 369 Generate(masm, ExternalReference(IC_Utility(kKeyedLoadIC_Miss))); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
395 } | 410 } |
396 | 411 |
397 | 412 |
398 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) { | 413 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) { |
399 // ----------- S t a t e ------------- | 414 // ----------- S t a t e ------------- |
400 // -- rax : value | 415 // -- rax : value |
401 // -- rsp[0] : return address | 416 // -- rsp[0] : return address |
402 // -- rsp[8] : key | 417 // -- rsp[8] : key |
403 // -- rsp[16] : receiver | 418 // -- rsp[16] : receiver |
404 // ----------------------------------- | 419 // ----------------------------------- |
405 Label slow, fast, array, extra; | 420 Label slow, fast, array, extra, check_pixel_array; |
406 | 421 |
407 // Get the receiver from the stack. | 422 // Get the receiver from the stack. |
408 __ movq(rdx, Operand(rsp, 2 * kPointerSize)); // 2 ~ return address, key | 423 __ movq(rdx, Operand(rsp, 2 * kPointerSize)); // 2 ~ return address, key |
409 // Check that the object isn't a smi. | 424 // Check that the object isn't a smi. |
410 __ JumpIfSmi(rdx, &slow); | 425 __ JumpIfSmi(rdx, &slow); |
411 // Get the map from the receiver. | 426 // Get the map from the receiver. |
412 __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset)); | 427 __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset)); |
413 // Check that the receiver does not require access checks. We need | 428 // Check that the receiver does not require access checks. We need |
414 // to do this because this generic stub does not perform map checks. | 429 // to do this because this generic stub does not perform map checks. |
415 __ testb(FieldOperand(rcx, Map::kBitFieldOffset), | 430 __ testb(FieldOperand(rcx, Map::kBitFieldOffset), |
(...skipping 12 matching lines...) Expand all Loading... | |
428 // Check that the object is some kind of JS object. | 443 // Check that the object is some kind of JS object. |
429 __ CmpInstanceType(rcx, FIRST_JS_OBJECT_TYPE); | 444 __ CmpInstanceType(rcx, FIRST_JS_OBJECT_TYPE); |
430 __ j(below, &slow); | 445 __ j(below, &slow); |
431 | 446 |
432 // Object case: Check key against length in the elements array. | 447 // Object case: Check key against length in the elements array. |
433 // rax: value | 448 // rax: value |
434 // rdx: JSObject | 449 // rdx: JSObject |
435 // rbx: index (as a smi), zero-extended. | 450 // rbx: index (as a smi), zero-extended. |
436 __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset)); | 451 __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset)); |
437 // Check that the object is in fast mode (not dictionary). | 452 // Check that the object is in fast mode (not dictionary). |
438 __ Cmp(FieldOperand(rcx, HeapObject::kMapOffset), Factory::fixed_array_map()); | 453 __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset), |
439 __ j(not_equal, &slow); | 454 Heap::kFixedArrayMapRootIndex); |
455 __ j(not_equal, &check_pixel_array); | |
440 // Untag the key (for checking against untagged length in the fixed array). | 456 // Untag the key (for checking against untagged length in the fixed array). |
441 __ SmiToInteger32(rdx, rbx); | 457 __ SmiToInteger32(rdx, rbx); |
442 __ cmpl(rdx, FieldOperand(rcx, Array::kLengthOffset)); | 458 __ cmpl(rdx, FieldOperand(rcx, Array::kLengthOffset)); |
443 // rax: value | 459 // rax: value |
444 // rcx: FixedArray | 460 // rcx: FixedArray |
445 // rbx: index (as a smi) | 461 // rbx: index (as a smi) |
446 __ j(below, &fast); | 462 __ j(below, &fast); |
447 | 463 |
448 | |
449 // Slow case: Push extra copies of the arguments (3). | 464 // Slow case: Push extra copies of the arguments (3). |
450 __ bind(&slow); | 465 __ bind(&slow); |
451 __ pop(rcx); | 466 __ pop(rcx); |
452 __ push(Operand(rsp, 1 * kPointerSize)); | 467 __ push(Operand(rsp, 1 * kPointerSize)); |
453 __ push(Operand(rsp, 1 * kPointerSize)); | 468 __ push(Operand(rsp, 1 * kPointerSize)); |
454 __ push(rax); | 469 __ push(rax); |
455 __ push(rcx); | 470 __ push(rcx); |
456 // Do tail-call to runtime routine. | 471 // Do tail-call to runtime routine. |
457 __ TailCallRuntime(ExternalReference(Runtime::kSetProperty), 3, 1); | 472 __ TailCallRuntime(ExternalReference(Runtime::kSetProperty), 3, 1); |
458 | 473 |
474 // Check whether the elements is a pixel array. | |
475 // rax: value | |
476 // rcx: elements array | |
477 // rbx: index (as a smi), zero-extended. | |
478 __ bind(&check_pixel_array); | |
479 __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset), | |
480 Heap::kPixelArrayMapRootIndex); | |
481 __ j(not_equal, &slow); | |
482 // Check that the value is a smi. If a conversion is needed call into the | |
483 // runtime to convert and clamp. | |
484 __ JumpIfNotSmi(rax, &slow); | |
485 __ SmiToInteger32(rbx, rbx); | |
486 __ cmpl(rbx, FieldOperand(rcx, PixelArray::kLengthOffset)); | |
487 __ j(above_equal, &slow); | |
488 __ movq(rdx, rax); // Save the value. | |
489 __ SmiToInteger32(rax, rax); | |
490 { // Clamp the value to [0..255]. | |
491 Label done, is_negative; | |
492 __ testl(rax, Immediate(0xFFFFFF00)); | |
493 __ j(zero, &done); | |
494 __ j(negative, &is_negative); | |
Lasse Reichstein
2009/09/30 16:50:40
A thought: It might be faster to do the out-of-ran
Søren Thygesen Gjesse
2009/09/30 20:27:06
Nice jump-free clamping. I will try to see if it h
| |
495 __ movl(rax, Immediate(255)); | |
496 __ jmp(&done); | |
497 __ bind(&is_negative); | |
498 __ xorl(rax, rax); // Clear rax. | |
499 __ bind(&done); | |
500 } | |
501 __ movq(rcx, FieldOperand(rcx, PixelArray::kExternalPointerOffset)); | |
502 __ movb(Operand(rcx, rbx, times_1, 0), rax); | |
503 __ movq(rax, rdx); // Return the original value. | |
504 __ ret(0); | |
459 | 505 |
460 // Extra capacity case: Check if there is extra capacity to | 506 // Extra capacity case: Check if there is extra capacity to |
461 // perform the store and update the length. Used for adding one | 507 // perform the store and update the length. Used for adding one |
462 // element to the array by writing to array[array.length]. | 508 // element to the array by writing to array[array.length]. |
463 __ bind(&extra); | 509 __ bind(&extra); |
464 // rax: value | 510 // rax: value |
465 // rdx: JSArray | 511 // rdx: JSArray |
466 // rcx: FixedArray | 512 // rcx: FixedArray |
467 // rbx: index (as a smi) | 513 // rbx: index (as a smi) |
468 // flags: compare (rbx, rdx.length()) | 514 // flags: compare (rbx, rdx.length()) |
469 __ j(not_equal, &slow); // do not leave holes in the array | 515 __ j(not_equal, &slow); // do not leave holes in the array |
470 __ SmiToInteger64(rbx, rbx); | 516 __ SmiToInteger64(rbx, rbx); |
471 __ cmpl(rbx, FieldOperand(rcx, FixedArray::kLengthOffset)); | 517 __ cmpl(rbx, FieldOperand(rcx, FixedArray::kLengthOffset)); |
472 __ j(above_equal, &slow); | 518 __ j(above_equal, &slow); |
473 // Increment and restore smi-tag. | 519 // Increment and restore smi-tag. |
474 __ Integer64AddToSmi(rbx, rbx, 1); | 520 __ Integer64AddToSmi(rbx, rbx, 1); |
475 __ movq(FieldOperand(rdx, JSArray::kLengthOffset), rbx); | 521 __ movq(FieldOperand(rdx, JSArray::kLengthOffset), rbx); |
476 __ SmiSubConstant(rbx, rbx, 1, NULL); | 522 __ SmiSubConstant(rbx, rbx, 1, NULL); |
477 __ jmp(&fast); | 523 __ jmp(&fast); |
478 | 524 |
479 | |
480 // Array case: Get the length and the elements array from the JS | 525 // Array case: Get the length and the elements array from the JS |
481 // array. Check that the array is in fast mode; if it is the | 526 // array. Check that the array is in fast mode; if it is the |
482 // length is always a smi. | 527 // length is always a smi. |
483 __ bind(&array); | 528 __ bind(&array); |
484 // rax: value | 529 // rax: value |
485 // rdx: JSArray | 530 // rdx: JSArray |
486 // rbx: index (as a smi) | 531 // rbx: index (as a smi) |
487 __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset)); | 532 __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset)); |
488 __ Cmp(FieldOperand(rcx, HeapObject::kMapOffset), Factory::fixed_array_map()); | 533 __ Cmp(FieldOperand(rcx, HeapObject::kMapOffset), Factory::fixed_array_map()); |
489 __ j(not_equal, &slow); | 534 __ j(not_equal, &slow); |
490 | 535 |
491 // Check the key against the length in the array, compute the | 536 // Check the key against the length in the array, compute the |
492 // address to store into and fall through to fast case. | 537 // address to store into and fall through to fast case. |
493 __ cmpl(rbx, FieldOperand(rdx, JSArray::kLengthOffset)); | 538 __ cmpl(rbx, FieldOperand(rdx, JSArray::kLengthOffset)); |
494 __ j(above_equal, &extra); | 539 __ j(above_equal, &extra); |
495 | 540 |
496 | |
497 // Fast case: Do the store. | 541 // Fast case: Do the store. |
498 __ bind(&fast); | 542 __ bind(&fast); |
499 // rax: value | 543 // rax: value |
500 // rcx: FixedArray | 544 // rcx: FixedArray |
501 // rbx: index (as a smi) | 545 // rbx: index (as a smi) |
502 __ movq(Operand(rcx, rbx, times_half_pointer_size, | 546 __ movq(Operand(rcx, rbx, times_half_pointer_size, |
503 FixedArray::kHeaderSize - kHeapObjectTag), | 547 FixedArray::kHeaderSize - kHeapObjectTag), |
504 rax); | 548 rax); |
505 // Update write barrier for the elements array address. | 549 // Update write barrier for the elements array address. |
506 __ movq(rdx, rax); | 550 __ movq(rdx, rax); |
(...skipping 461 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
968 | 1012 |
969 // Cache miss: Jump to runtime. | 1013 // Cache miss: Jump to runtime. |
970 Generate(masm, ExternalReference(IC_Utility(kStoreIC_Miss))); | 1014 Generate(masm, ExternalReference(IC_Utility(kStoreIC_Miss))); |
971 } | 1015 } |
972 | 1016 |
973 | 1017 |
974 #undef __ | 1018 #undef __ |
975 | 1019 |
976 | 1020 |
977 } } // namespace v8::internal | 1021 } } // namespace v8::internal |
OLD | NEW |