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 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
245 SaveFPRegsMode fp_mode, | 245 SaveFPRegsMode fp_mode, |
246 RememberedSetAction remembered_set_action, | 246 RememberedSetAction remembered_set_action, |
247 SmiCheck smi_check) { | 247 SmiCheck smi_check) { |
248 ASSERT(!AreAliased(object, address, value, t8)); | 248 ASSERT(!AreAliased(object, address, value, t8)); |
249 ASSERT(!AreAliased(object, address, value, t9)); | 249 ASSERT(!AreAliased(object, address, value, t9)); |
250 // The compiled code assumes that record write doesn't change the | 250 // The compiled code assumes that record write doesn't change the |
251 // context register, so we check that none of the clobbered | 251 // context register, so we check that none of the clobbered |
252 // registers are cp. | 252 // registers are cp. |
253 ASSERT(!address.is(cp) && !value.is(cp)); | 253 ASSERT(!address.is(cp) && !value.is(cp)); |
254 | 254 |
| 255 if (emit_debug_code()) { |
| 256 lw(at, MemOperand(address)); |
| 257 Assert( |
| 258 eq, "Wrong address or value passed to RecordWrite", at, Operand(value)); |
| 259 } |
| 260 |
255 Label done; | 261 Label done; |
256 | 262 |
257 if (smi_check == INLINE_SMI_CHECK) { | 263 if (smi_check == INLINE_SMI_CHECK) { |
258 ASSERT_EQ(0, kSmiTag); | 264 ASSERT_EQ(0, kSmiTag); |
259 JumpIfSmi(value, &done); | 265 JumpIfSmi(value, &done); |
260 } | 266 } |
261 | 267 |
262 CheckPageFlag(value, | 268 CheckPageFlag(value, |
263 value, // Used as scratch. | 269 value, // Used as scratch. |
264 MemoryChunk::kPointersToHereAreInterestingMask, | 270 MemoryChunk::kPointersToHereAreInterestingMask, |
(...skipping 25 matching lines...) Expand all Loading... |
290 } | 296 } |
291 } | 297 } |
292 | 298 |
293 | 299 |
294 void MacroAssembler::RememberedSetHelper(Register object, // For debug tests. | 300 void MacroAssembler::RememberedSetHelper(Register object, // For debug tests. |
295 Register address, | 301 Register address, |
296 Register scratch, | 302 Register scratch, |
297 SaveFPRegsMode fp_mode, | 303 SaveFPRegsMode fp_mode, |
298 RememberedSetFinalAction and_then) { | 304 RememberedSetFinalAction and_then) { |
299 Label done; | 305 Label done; |
300 if (FLAG_debug_code) { | 306 if (emit_debug_code()) { |
301 Label ok; | 307 Label ok; |
302 JumpIfNotInNewSpace(object, scratch, &ok); | 308 JumpIfNotInNewSpace(object, scratch, &ok); |
303 stop("Remembered set pointer is in new space"); | 309 stop("Remembered set pointer is in new space"); |
304 bind(&ok); | 310 bind(&ok); |
305 } | 311 } |
306 // Load store buffer top. | 312 // Load store buffer top. |
307 ExternalReference store_buffer = | 313 ExternalReference store_buffer = |
308 ExternalReference::store_buffer_top(isolate()); | 314 ExternalReference::store_buffer_top(isolate()); |
309 li(t8, Operand(store_buffer)); | 315 li(t8, Operand(store_buffer)); |
310 lw(scratch, MemOperand(t8)); | 316 lw(scratch, MemOperand(t8)); |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
402 Context::SECURITY_TOKEN_INDEX * kPointerSize; | 408 Context::SECURITY_TOKEN_INDEX * kPointerSize; |
403 | 409 |
404 lw(scratch, FieldMemOperand(scratch, token_offset)); | 410 lw(scratch, FieldMemOperand(scratch, token_offset)); |
405 lw(at, FieldMemOperand(at, token_offset)); | 411 lw(at, FieldMemOperand(at, token_offset)); |
406 Branch(miss, ne, scratch, Operand(at)); | 412 Branch(miss, ne, scratch, Operand(at)); |
407 | 413 |
408 bind(&same_contexts); | 414 bind(&same_contexts); |
409 } | 415 } |
410 | 416 |
411 | 417 |
| 418 void MacroAssembler::GetNumberHash(Register reg0, Register scratch) { |
| 419 // First of all we assign the hash seed to scratch. |
| 420 LoadRoot(scratch, Heap::kHashSeedRootIndex); |
| 421 SmiUntag(scratch); |
| 422 |
| 423 // Xor original key with a seed. |
| 424 xor_(reg0, reg0, scratch); |
| 425 |
| 426 // Compute the hash code from the untagged key. This must be kept in sync |
| 427 // with ComputeIntegerHash in utils.h. |
| 428 // |
| 429 // hash = ~hash + (hash << 15); |
| 430 nor(scratch, reg0, zero_reg); |
| 431 sll(at, reg0, 15); |
| 432 addu(reg0, scratch, at); |
| 433 |
| 434 // hash = hash ^ (hash >> 12); |
| 435 srl(at, reg0, 12); |
| 436 xor_(reg0, reg0, at); |
| 437 |
| 438 // hash = hash + (hash << 2); |
| 439 sll(at, reg0, 2); |
| 440 addu(reg0, reg0, at); |
| 441 |
| 442 // hash = hash ^ (hash >> 4); |
| 443 srl(at, reg0, 4); |
| 444 xor_(reg0, reg0, at); |
| 445 |
| 446 // hash = hash * 2057; |
| 447 li(scratch, Operand(2057)); |
| 448 mul(reg0, reg0, scratch); |
| 449 |
| 450 // hash = hash ^ (hash >> 16); |
| 451 srl(at, reg0, 16); |
| 452 xor_(reg0, reg0, at); |
| 453 } |
| 454 |
| 455 |
412 void MacroAssembler::LoadFromNumberDictionary(Label* miss, | 456 void MacroAssembler::LoadFromNumberDictionary(Label* miss, |
413 Register elements, | 457 Register elements, |
414 Register key, | 458 Register key, |
415 Register result, | 459 Register result, |
416 Register reg0, | 460 Register reg0, |
417 Register reg1, | 461 Register reg1, |
418 Register reg2) { | 462 Register reg2) { |
419 // Register use: | 463 // Register use: |
420 // | 464 // |
421 // elements - holds the slow-case elements of the receiver on entry. | 465 // elements - holds the slow-case elements of the receiver on entry. |
(...skipping 11 matching lines...) Expand all Loading... |
433 // Scratch registers: | 477 // Scratch registers: |
434 // | 478 // |
435 // reg0 - holds the untagged key on entry and holds the hash once computed. | 479 // reg0 - holds the untagged key on entry and holds the hash once computed. |
436 // | 480 // |
437 // reg1 - Used to hold the capacity mask of the dictionary. | 481 // reg1 - Used to hold the capacity mask of the dictionary. |
438 // | 482 // |
439 // reg2 - Used for the index into the dictionary. | 483 // reg2 - Used for the index into the dictionary. |
440 // at - Temporary (avoid MacroAssembler instructions also using 'at'). | 484 // at - Temporary (avoid MacroAssembler instructions also using 'at'). |
441 Label done; | 485 Label done; |
442 | 486 |
443 // Compute the hash code from the untagged key. This must be kept in sync | 487 GetNumberHash(reg0, reg1); |
444 // with ComputeIntegerHash in utils.h. | |
445 // | |
446 // hash = ~hash + (hash << 15); | |
447 nor(reg1, reg0, zero_reg); | |
448 sll(at, reg0, 15); | |
449 addu(reg0, reg1, at); | |
450 | |
451 // hash = hash ^ (hash >> 12); | |
452 srl(at, reg0, 12); | |
453 xor_(reg0, reg0, at); | |
454 | |
455 // hash = hash + (hash << 2); | |
456 sll(at, reg0, 2); | |
457 addu(reg0, reg0, at); | |
458 | |
459 // hash = hash ^ (hash >> 4); | |
460 srl(at, reg0, 4); | |
461 xor_(reg0, reg0, at); | |
462 | |
463 // hash = hash * 2057; | |
464 li(reg1, Operand(2057)); | |
465 mul(reg0, reg0, reg1); | |
466 | |
467 // hash = hash ^ (hash >> 16); | |
468 srl(at, reg0, 16); | |
469 xor_(reg0, reg0, at); | |
470 | 488 |
471 // Compute the capacity mask. | 489 // Compute the capacity mask. |
472 lw(reg1, FieldMemOperand(elements, NumberDictionary::kCapacityOffset)); | 490 lw(reg1, FieldMemOperand(elements, SeededNumberDictionary::kCapacityOffset)); |
473 sra(reg1, reg1, kSmiTagSize); | 491 sra(reg1, reg1, kSmiTagSize); |
474 Subu(reg1, reg1, Operand(1)); | 492 Subu(reg1, reg1, Operand(1)); |
475 | 493 |
476 // Generate an unrolled loop that performs a few probes before giving up. | 494 // Generate an unrolled loop that performs a few probes before giving up. |
477 static const int kProbes = 4; | 495 static const int kProbes = 4; |
478 for (int i = 0; i < kProbes; i++) { | 496 for (int i = 0; i < kProbes; i++) { |
479 // Use reg2 for index calculations and keep the hash intact in reg0. | 497 // Use reg2 for index calculations and keep the hash intact in reg0. |
480 mov(reg2, reg0); | 498 mov(reg2, reg0); |
481 // Compute the masked index: (hash + i + i * i) & mask. | 499 // Compute the masked index: (hash + i + i * i) & mask. |
482 if (i > 0) { | 500 if (i > 0) { |
483 Addu(reg2, reg2, Operand(NumberDictionary::GetProbeOffset(i))); | 501 Addu(reg2, reg2, Operand(SeededNumberDictionary::GetProbeOffset(i))); |
484 } | 502 } |
485 and_(reg2, reg2, reg1); | 503 and_(reg2, reg2, reg1); |
486 | 504 |
487 // Scale the index by multiplying by the element size. | 505 // Scale the index by multiplying by the element size. |
488 ASSERT(NumberDictionary::kEntrySize == 3); | 506 ASSERT(SeededNumberDictionary::kEntrySize == 3); |
489 sll(at, reg2, 1); // 2x. | 507 sll(at, reg2, 1); // 2x. |
490 addu(reg2, reg2, at); // reg2 = reg2 * 3. | 508 addu(reg2, reg2, at); // reg2 = reg2 * 3. |
491 | 509 |
492 // Check if the key is identical to the name. | 510 // Check if the key is identical to the name. |
493 sll(at, reg2, kPointerSizeLog2); | 511 sll(at, reg2, kPointerSizeLog2); |
494 addu(reg2, elements, at); | 512 addu(reg2, elements, at); |
495 | 513 |
496 lw(at, FieldMemOperand(reg2, NumberDictionary::kElementsStartOffset)); | 514 lw(at, FieldMemOperand(reg2, SeededNumberDictionary::kElementsStartOffset)); |
497 if (i != kProbes - 1) { | 515 if (i != kProbes - 1) { |
498 Branch(&done, eq, key, Operand(at)); | 516 Branch(&done, eq, key, Operand(at)); |
499 } else { | 517 } else { |
500 Branch(miss, ne, key, Operand(at)); | 518 Branch(miss, ne, key, Operand(at)); |
501 } | 519 } |
502 } | 520 } |
503 | 521 |
504 bind(&done); | 522 bind(&done); |
505 // Check that the value is a normal property. | 523 // Check that the value is a normal property. |
506 // reg2: elements + (index * kPointerSize). | 524 // reg2: elements + (index * kPointerSize). |
507 const int kDetailsOffset = | 525 const int kDetailsOffset = |
508 NumberDictionary::kElementsStartOffset + 2 * kPointerSize; | 526 SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize; |
509 lw(reg1, FieldMemOperand(reg2, kDetailsOffset)); | 527 lw(reg1, FieldMemOperand(reg2, kDetailsOffset)); |
510 And(at, reg1, Operand(Smi::FromInt(PropertyDetails::TypeField::kMask))); | 528 And(at, reg1, Operand(Smi::FromInt(PropertyDetails::TypeField::kMask))); |
511 Branch(miss, ne, at, Operand(zero_reg)); | 529 Branch(miss, ne, at, Operand(zero_reg)); |
512 | 530 |
513 // Get the value at the masked, scaled index and return. | 531 // Get the value at the masked, scaled index and return. |
514 const int kValueOffset = | 532 const int kValueOffset = |
515 NumberDictionary::kElementsStartOffset + kPointerSize; | 533 SeededNumberDictionary::kElementsStartOffset + kPointerSize; |
516 lw(result, FieldMemOperand(reg2, kValueOffset)); | 534 lw(result, FieldMemOperand(reg2, kValueOffset)); |
517 } | 535 } |
518 | 536 |
519 | 537 |
520 // --------------------------------------------------------------------------- | 538 // --------------------------------------------------------------------------- |
521 // Instruction macros. | 539 // Instruction macros. |
522 | 540 |
523 void MacroAssembler::Addu(Register rd, Register rs, const Operand& rt) { | 541 void MacroAssembler::Addu(Register rd, Register rs, const Operand& rt) { |
524 if (rt.is_reg()) { | 542 if (rt.is_reg()) { |
525 addu(rd, rs, rt.rm()); | 543 addu(rd, rs, rt.rm()); |
(...skipping 3728 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4254 void MacroAssembler::LeaveFrame(StackFrame::Type type) { | 4272 void MacroAssembler::LeaveFrame(StackFrame::Type type) { |
4255 mov(sp, fp); | 4273 mov(sp, fp); |
4256 lw(fp, MemOperand(sp, 0 * kPointerSize)); | 4274 lw(fp, MemOperand(sp, 0 * kPointerSize)); |
4257 lw(ra, MemOperand(sp, 1 * kPointerSize)); | 4275 lw(ra, MemOperand(sp, 1 * kPointerSize)); |
4258 addiu(sp, sp, 2 * kPointerSize); | 4276 addiu(sp, sp, 2 * kPointerSize); |
4259 } | 4277 } |
4260 | 4278 |
4261 | 4279 |
4262 void MacroAssembler::EnterExitFrame(bool save_doubles, | 4280 void MacroAssembler::EnterExitFrame(bool save_doubles, |
4263 int stack_space) { | 4281 int stack_space) { |
4264 // Setup the frame structure on the stack. | 4282 // Set up the frame structure on the stack. |
4265 STATIC_ASSERT(2 * kPointerSize == ExitFrameConstants::kCallerSPDisplacement); | 4283 STATIC_ASSERT(2 * kPointerSize == ExitFrameConstants::kCallerSPDisplacement); |
4266 STATIC_ASSERT(1 * kPointerSize == ExitFrameConstants::kCallerPCOffset); | 4284 STATIC_ASSERT(1 * kPointerSize == ExitFrameConstants::kCallerPCOffset); |
4267 STATIC_ASSERT(0 * kPointerSize == ExitFrameConstants::kCallerFPOffset); | 4285 STATIC_ASSERT(0 * kPointerSize == ExitFrameConstants::kCallerFPOffset); |
4268 | 4286 |
4269 // This is how the stack will look: | 4287 // This is how the stack will look: |
4270 // fp + 2 (==kCallerSPDisplacement) - old stack's end | 4288 // fp + 2 (==kCallerSPDisplacement) - old stack's end |
4271 // [fp + 1 (==kCallerPCOffset)] - saved old ra | 4289 // [fp + 1 (==kCallerPCOffset)] - saved old ra |
4272 // [fp + 0 (==kCallerFPOffset)] - saved old fp | 4290 // [fp + 0 (==kCallerFPOffset)] - saved old fp |
4273 // [fp - 1 (==kSPOffset)] - sp of the called function | 4291 // [fp - 1 (==kSPOffset)] - sp of the called function |
4274 // [fp - 2 (==kCodeOffset)] - CodeObject | 4292 // [fp - 2 (==kCodeOffset)] - CodeObject |
4275 // fp - (2 + stack_space + alignment) == sp == [fp - kSPOffset] - top of the | 4293 // fp - (2 + stack_space + alignment) == sp == [fp - kSPOffset] - top of the |
4276 // new stack (will contain saved ra) | 4294 // new stack (will contain saved ra) |
4277 | 4295 |
4278 // Save registers. | 4296 // Save registers. |
4279 addiu(sp, sp, -4 * kPointerSize); | 4297 addiu(sp, sp, -4 * kPointerSize); |
4280 sw(ra, MemOperand(sp, 3 * kPointerSize)); | 4298 sw(ra, MemOperand(sp, 3 * kPointerSize)); |
4281 sw(fp, MemOperand(sp, 2 * kPointerSize)); | 4299 sw(fp, MemOperand(sp, 2 * kPointerSize)); |
4282 addiu(fp, sp, 2 * kPointerSize); // Setup new frame pointer. | 4300 addiu(fp, sp, 2 * kPointerSize); // Set up new frame pointer. |
4283 | 4301 |
4284 if (emit_debug_code()) { | 4302 if (emit_debug_code()) { |
4285 sw(zero_reg, MemOperand(fp, ExitFrameConstants::kSPOffset)); | 4303 sw(zero_reg, MemOperand(fp, ExitFrameConstants::kSPOffset)); |
4286 } | 4304 } |
4287 | 4305 |
4288 li(t8, Operand(CodeObject())); // Accessed from ExitFrame::code_slot. | 4306 li(t8, Operand(CodeObject())); // Accessed from ExitFrame::code_slot. |
4289 sw(t8, MemOperand(fp, ExitFrameConstants::kCodeOffset)); | 4307 sw(t8, MemOperand(fp, ExitFrameConstants::kCodeOffset)); |
4290 | 4308 |
4291 // Save the frame pointer and the context in top. | 4309 // Save the frame pointer and the context in top. |
4292 li(t8, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate()))); | 4310 li(t8, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate()))); |
(...skipping 526 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4819 ASSERT(strcmp(Marking::kImpossibleBitPattern, "01") == 0); | 4837 ASSERT(strcmp(Marking::kImpossibleBitPattern, "01") == 0); |
4820 | 4838 |
4821 Label done; | 4839 Label done; |
4822 | 4840 |
4823 // Since both black and grey have a 1 in the first position and white does | 4841 // Since both black and grey have a 1 in the first position and white does |
4824 // not have a 1 there we only need to check one bit. | 4842 // not have a 1 there we only need to check one bit. |
4825 lw(load_scratch, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize)); | 4843 lw(load_scratch, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize)); |
4826 And(t8, mask_scratch, load_scratch); | 4844 And(t8, mask_scratch, load_scratch); |
4827 Branch(&done, ne, t8, Operand(zero_reg)); | 4845 Branch(&done, ne, t8, Operand(zero_reg)); |
4828 | 4846 |
4829 if (FLAG_debug_code) { | 4847 if (emit_debug_code()) { |
4830 // Check for impossible bit pattern. | 4848 // Check for impossible bit pattern. |
4831 Label ok; | 4849 Label ok; |
4832 // sll may overflow, making the check conservative. | 4850 // sll may overflow, making the check conservative. |
4833 sll(t8, mask_scratch, 1); | 4851 sll(t8, mask_scratch, 1); |
4834 And(t8, load_scratch, t8); | 4852 And(t8, load_scratch, t8); |
4835 Branch(&ok, eq, t8, Operand(zero_reg)); | 4853 Branch(&ok, eq, t8, Operand(zero_reg)); |
4836 stop("Impossible marking bit pattern"); | 4854 stop("Impossible marking bit pattern"); |
4837 bind(&ok); | 4855 bind(&ok); |
4838 } | 4856 } |
4839 | 4857 |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5027 opcode == BGTZL); | 5045 opcode == BGTZL); |
5028 opcode = (cond == eq) ? BEQ : BNE; | 5046 opcode = (cond == eq) ? BEQ : BNE; |
5029 instr = (instr & ~kOpcodeMask) | opcode; | 5047 instr = (instr & ~kOpcodeMask) | opcode; |
5030 masm_.emit(instr); | 5048 masm_.emit(instr); |
5031 } | 5049 } |
5032 | 5050 |
5033 | 5051 |
5034 } } // namespace v8::internal | 5052 } } // namespace v8::internal |
5035 | 5053 |
5036 #endif // V8_TARGET_ARCH_MIPS | 5054 #endif // V8_TARGET_ARCH_MIPS |
OLD | NEW |