Chromium Code Reviews| 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 |