| 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 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 299 #ifdef DEBUG | 299 #ifdef DEBUG |
| 300 if (strlen(FLAG_stop_at) > 0 && | 300 if (strlen(FLAG_stop_at) > 0 && |
| 301 function->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { | 301 function->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { |
| 302 frame_->SpillAll(); | 302 frame_->SpillAll(); |
| 303 __ int3(); | 303 __ int3(); |
| 304 } | 304 } |
| 305 #endif | 305 #endif |
| 306 | 306 |
| 307 // New scope to get automatic timing calculation. | 307 // New scope to get automatic timing calculation. |
| 308 { // NOLINT | 308 { // NOLINT |
| 309 HistogramTimerScope codegen_timer(&Counters::code_generation); | 309 HistogramTimerScope codegen_timer(&COUNTER(code_generation)); |
| 310 CodeGenState state(this); | 310 CodeGenState state(this); |
| 311 | 311 |
| 312 // Entry: | 312 // Entry: |
| 313 // Stack: receiver, arguments, return address. | 313 // Stack: receiver, arguments, return address. |
| 314 // rbp: caller's frame pointer | 314 // rbp: caller's frame pointer |
| 315 // rsp: stack pointer | 315 // rsp: stack pointer |
| 316 // rdi: called JS function | 316 // rdi: called JS function |
| 317 // rsi: callee's context | 317 // rsi: callee's context |
| 318 allocator_->Initialize(); | 318 allocator_->Initialize(); |
| 319 frame_->Enter(); | 319 frame_->Enter(); |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 461 | 461 |
| 462 // Code generation state must be reset. | 462 // Code generation state must be reset. |
| 463 ASSERT(state_ == NULL); | 463 ASSERT(state_ == NULL); |
| 464 ASSERT(loop_nesting() == 0); | 464 ASSERT(loop_nesting() == 0); |
| 465 ASSERT(!function_return_is_shadowed_); | 465 ASSERT(!function_return_is_shadowed_); |
| 466 function_return_.Unuse(); | 466 function_return_.Unuse(); |
| 467 DeleteFrame(); | 467 DeleteFrame(); |
| 468 | 468 |
| 469 // Process any deferred code using the register allocator. | 469 // Process any deferred code using the register allocator. |
| 470 if (!HasStackOverflow()) { | 470 if (!HasStackOverflow()) { |
| 471 HistogramTimerScope deferred_timer(&Counters::deferred_code_generation); | 471 HistogramTimerScope deferred_timer(&COUNTER(deferred_code_generation)); |
| 472 JumpTarget::set_compiling_deferred_code(true); | 472 JumpTarget::set_compiling_deferred_code(true); |
| 473 ProcessDeferred(); | 473 ProcessDeferred(); |
| 474 JumpTarget::set_compiling_deferred_code(false); | 474 JumpTarget::set_compiling_deferred_code(false); |
| 475 } | 475 } |
| 476 | 476 |
| 477 // There is no need to delete the register allocator, it is a | 477 // There is no need to delete the register allocator, it is a |
| 478 // stack-allocated local. | 478 // stack-allocated local. |
| 479 allocator_ = NULL; | 479 allocator_ = NULL; |
| 480 scope_ = NULL; | 480 scope_ = NULL; |
| 481 } | 481 } |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 578 // macro because the macro sometimes uses macro expansion to turn | 578 // macro because the macro sometimes uses macro expansion to turn |
| 579 // into something that can't return a value. This is encountered | 579 // into something that can't return a value. This is encountered |
| 580 // when doing generated code coverage tests. | 580 // when doing generated code coverage tests. |
| 581 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); | 581 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); |
| 582 // Here we use masm_-> instead of the __ macro because this is the | 582 // Here we use masm_-> instead of the __ macro because this is the |
| 583 // instruction that gets patched and coverage code gets in the way. | 583 // instruction that gets patched and coverage code gets in the way. |
| 584 // TODO(X64): Consider whether it's worth switching the test to a | 584 // TODO(X64): Consider whether it's worth switching the test to a |
| 585 // 7-byte NOP with non-zero immediate (0f 1f 80 xxxxxxxx) which won't | 585 // 7-byte NOP with non-zero immediate (0f 1f 80 xxxxxxxx) which won't |
| 586 // be generated normally. | 586 // be generated normally. |
| 587 masm_->testl(rax, Immediate(-delta_to_patch_site)); | 587 masm_->testl(rax, Immediate(-delta_to_patch_site)); |
| 588 __ IncrementCounter(&Counters::keyed_load_inline_miss, 1); | 588 __ IncrementCounter(&COUNTER(keyed_load_inline_miss), 1); |
| 589 | 589 |
| 590 if (!dst_.is(rax)) __ movq(dst_, rax); | 590 if (!dst_.is(rax)) __ movq(dst_, rax); |
| 591 __ pop(key_); | 591 __ pop(key_); |
| 592 __ pop(receiver_); | 592 __ pop(receiver_); |
| 593 } | 593 } |
| 594 | 594 |
| 595 | 595 |
| 596 class DeferredReferenceSetKeyedValue: public DeferredCode { | 596 class DeferredReferenceSetKeyedValue: public DeferredCode { |
| 597 public: | 597 public: |
| 598 DeferredReferenceSetKeyedValue(Register value, | 598 DeferredReferenceSetKeyedValue(Register value, |
| 599 Register key, | 599 Register key, |
| 600 Register receiver) | 600 Register receiver) |
| 601 : value_(value), key_(key), receiver_(receiver) { | 601 : value_(value), key_(key), receiver_(receiver) { |
| 602 set_comment("[ DeferredReferenceSetKeyedValue"); | 602 set_comment("[ DeferredReferenceSetKeyedValue"); |
| 603 } | 603 } |
| 604 | 604 |
| 605 virtual void Generate(); | 605 virtual void Generate(); |
| 606 | 606 |
| 607 Label* patch_site() { return &patch_site_; } | 607 Label* patch_site() { return &patch_site_; } |
| 608 | 608 |
| 609 private: | 609 private: |
| 610 Register value_; | 610 Register value_; |
| 611 Register key_; | 611 Register key_; |
| 612 Register receiver_; | 612 Register receiver_; |
| 613 Label patch_site_; | 613 Label patch_site_; |
| 614 }; | 614 }; |
| 615 | 615 |
| 616 | 616 |
| 617 void DeferredReferenceSetKeyedValue::Generate() { | 617 void DeferredReferenceSetKeyedValue::Generate() { |
| 618 __ IncrementCounter(&Counters::keyed_store_inline_miss, 1); | 618 __ IncrementCounter(&COUNTER(keyed_store_inline_miss), 1); |
| 619 // Push receiver and key arguments on the stack. | 619 // Push receiver and key arguments on the stack. |
| 620 __ push(receiver_); | 620 __ push(receiver_); |
| 621 __ push(key_); | 621 __ push(key_); |
| 622 // Move value argument to eax as expected by the IC stub. | 622 // Move value argument to eax as expected by the IC stub. |
| 623 if (!value_.is(rax)) __ movq(rax, value_); | 623 if (!value_.is(rax)) __ movq(rax, value_); |
| 624 // Call the IC stub. | 624 // Call the IC stub. |
| 625 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 625 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
| 626 __ Call(ic, RelocInfo::CODE_TARGET); | 626 __ Call(ic, RelocInfo::CODE_TARGET); |
| 627 // The delta from the start of the map-compare instructions (initial movq) | 627 // The delta from the start of the map-compare instructions (initial movq) |
| 628 // to the test instruction. We use masm_-> directly here instead of the | 628 // to the test instruction. We use masm_-> directly here instead of the |
| (...skipping 4637 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5266 // The call must be followed by a test rax instruction to indicate | 5266 // The call must be followed by a test rax instruction to indicate |
| 5267 // that the inobject property case was inlined. | 5267 // that the inobject property case was inlined. |
| 5268 // | 5268 // |
| 5269 // Store the delta to the map check instruction here in the test | 5269 // Store the delta to the map check instruction here in the test |
| 5270 // instruction. Use masm_-> instead of the __ macro since the | 5270 // instruction. Use masm_-> instead of the __ macro since the |
| 5271 // latter can't return a value. | 5271 // latter can't return a value. |
| 5272 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); | 5272 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); |
| 5273 // Here we use masm_-> instead of the __ macro because this is the | 5273 // Here we use masm_-> instead of the __ macro because this is the |
| 5274 // instruction that gets patched and coverage code gets in the way. | 5274 // instruction that gets patched and coverage code gets in the way. |
| 5275 masm_->testl(rax, Immediate(-delta_to_patch_site)); | 5275 masm_->testl(rax, Immediate(-delta_to_patch_site)); |
| 5276 __ IncrementCounter(&Counters::named_load_inline_miss, 1); | 5276 __ IncrementCounter(&COUNTER(named_load_inline_miss), 1); |
| 5277 | 5277 |
| 5278 if (!dst_.is(rax)) __ movq(dst_, rax); | 5278 if (!dst_.is(rax)) __ movq(dst_, rax); |
| 5279 __ pop(receiver_); | 5279 __ pop(receiver_); |
| 5280 } | 5280 } |
| 5281 | 5281 |
| 5282 | 5282 |
| 5283 void DeferredInlineSmiAdd::Generate() { | 5283 void DeferredInlineSmiAdd::Generate() { |
| 5284 GenericBinaryOpStub igostub(Token::ADD, overwrite_mode_, NO_SMI_CODE_IN_STUB); | 5284 GenericBinaryOpStub igostub(Token::ADD, overwrite_mode_, NO_SMI_CODE_IN_STUB); |
| 5285 igostub.GenerateCall(masm_, dst_, value_); | 5285 igostub.GenerateCall(masm_, dst_, value_); |
| 5286 if (!dst_.is(rax)) __ movq(dst_, rax); | 5286 if (!dst_.is(rax)) __ movq(dst_, rax); |
| (...skipping 610 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5897 // The delta from the patch label to the load offset must be | 5897 // The delta from the patch label to the load offset must be |
| 5898 // statically known. | 5898 // statically known. |
| 5899 ASSERT(masm->SizeOfCodeGeneratedSince(deferred->patch_site()) == | 5899 ASSERT(masm->SizeOfCodeGeneratedSince(deferred->patch_site()) == |
| 5900 LoadIC::kOffsetToLoadInstruction); | 5900 LoadIC::kOffsetToLoadInstruction); |
| 5901 // The initial (invalid) offset has to be large enough to force | 5901 // The initial (invalid) offset has to be large enough to force |
| 5902 // a 32-bit instruction encoding to allow patching with an | 5902 // a 32-bit instruction encoding to allow patching with an |
| 5903 // arbitrary offset. Use kMaxInt (minus kHeapObjectTag). | 5903 // arbitrary offset. Use kMaxInt (minus kHeapObjectTag). |
| 5904 int offset = kMaxInt; | 5904 int offset = kMaxInt; |
| 5905 masm->movq(value.reg(), FieldOperand(receiver.reg(), offset)); | 5905 masm->movq(value.reg(), FieldOperand(receiver.reg(), offset)); |
| 5906 | 5906 |
| 5907 __ IncrementCounter(&Counters::named_load_inline, 1); | 5907 __ IncrementCounter(&COUNTER(named_load_inline), 1); |
| 5908 deferred->BindExit(); | 5908 deferred->BindExit(); |
| 5909 cgen_->frame()->Push(&receiver); | 5909 cgen_->frame()->Push(&receiver); |
| 5910 cgen_->frame()->Push(&value); | 5910 cgen_->frame()->Push(&value); |
| 5911 } | 5911 } |
| 5912 break; | 5912 break; |
| 5913 } | 5913 } |
| 5914 | 5914 |
| 5915 case KEYED: { | 5915 case KEYED: { |
| 5916 Comment cmnt(masm, "[ Load from keyed Property"); | 5916 Comment cmnt(masm, "[ Load from keyed Property"); |
| 5917 Variable* var = expression_->AsVariableProxy()->AsVariable(); | 5917 Variable* var = expression_->AsVariableProxy()->AsVariable(); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5995 Result value = index; | 5995 Result value = index; |
| 5996 __ movq(value.reg(), | 5996 __ movq(value.reg(), |
| 5997 Operand(elements.reg(), | 5997 Operand(elements.reg(), |
| 5998 index.reg(), | 5998 index.reg(), |
| 5999 times_pointer_size, | 5999 times_pointer_size, |
| 6000 FixedArray::kHeaderSize - kHeapObjectTag)); | 6000 FixedArray::kHeaderSize - kHeapObjectTag)); |
| 6001 elements.Unuse(); | 6001 elements.Unuse(); |
| 6002 index.Unuse(); | 6002 index.Unuse(); |
| 6003 __ CompareRoot(value.reg(), Heap::kTheHoleValueRootIndex); | 6003 __ CompareRoot(value.reg(), Heap::kTheHoleValueRootIndex); |
| 6004 deferred->Branch(equal); | 6004 deferred->Branch(equal); |
| 6005 __ IncrementCounter(&Counters::keyed_load_inline, 1); | 6005 __ IncrementCounter(&COUNTER(keyed_load_inline), 1); |
| 6006 | 6006 |
| 6007 deferred->BindExit(); | 6007 deferred->BindExit(); |
| 6008 // Restore the receiver and key to the frame and push the | 6008 // Restore the receiver and key to the frame and push the |
| 6009 // result on top of it. | 6009 // result on top of it. |
| 6010 cgen_->frame()->Push(&receiver); | 6010 cgen_->frame()->Push(&receiver); |
| 6011 cgen_->frame()->Push(&key); | 6011 cgen_->frame()->Push(&key); |
| 6012 cgen_->frame()->Push(&value); | 6012 cgen_->frame()->Push(&value); |
| 6013 | 6013 |
| 6014 } else { | 6014 } else { |
| 6015 Comment cmnt(masm, "[ Load from keyed Property"); | 6015 Comment cmnt(masm, "[ Load from keyed Property"); |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6166 deferred->Branch(not_equal); | 6166 deferred->Branch(not_equal); |
| 6167 | 6167 |
| 6168 // Store the value. | 6168 // Store the value. |
| 6169 SmiIndex index = | 6169 SmiIndex index = |
| 6170 masm->SmiToIndex(kScratchRegister, key.reg(), kPointerSizeLog2); | 6170 masm->SmiToIndex(kScratchRegister, key.reg(), kPointerSizeLog2); |
| 6171 __ movq(Operand(tmp.reg(), | 6171 __ movq(Operand(tmp.reg(), |
| 6172 index.reg, | 6172 index.reg, |
| 6173 index.scale, | 6173 index.scale, |
| 6174 FixedArray::kHeaderSize - kHeapObjectTag), | 6174 FixedArray::kHeaderSize - kHeapObjectTag), |
| 6175 value.reg()); | 6175 value.reg()); |
| 6176 __ IncrementCounter(&Counters::keyed_store_inline, 1); | 6176 __ IncrementCounter(&COUNTER(keyed_store_inline), 1); |
| 6177 | 6177 |
| 6178 deferred->BindExit(); | 6178 deferred->BindExit(); |
| 6179 | 6179 |
| 6180 cgen_->frame()->Push(&receiver); | 6180 cgen_->frame()->Push(&receiver); |
| 6181 cgen_->frame()->Push(&key); | 6181 cgen_->frame()->Push(&key); |
| 6182 cgen_->frame()->Push(&value); | 6182 cgen_->frame()->Push(&value); |
| 6183 } else { | 6183 } else { |
| 6184 Result answer = cgen_->frame()->CallKeyedStoreIC(); | 6184 Result answer = cgen_->frame()->CallKeyedStoreIC(); |
| 6185 // Make sure that we do not have a test instruction after the | 6185 // Make sure that we do not have a test instruction after the |
| 6186 // call. A test instruction after the call is used to | 6186 // call. A test instruction after the call is used to |
| (...skipping 1243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7430 __ movq(left_arg, left); | 7430 __ movq(left_arg, left); |
| 7431 } else { | 7431 } else { |
| 7432 // Order of moves is not important. | 7432 // Order of moves is not important. |
| 7433 __ movq(left_arg, left); | 7433 __ movq(left_arg, left); |
| 7434 __ movq(right_arg, right); | 7434 __ movq(right_arg, right); |
| 7435 } | 7435 } |
| 7436 } | 7436 } |
| 7437 | 7437 |
| 7438 // Update flags to indicate that arguments are in registers. | 7438 // Update flags to indicate that arguments are in registers. |
| 7439 SetArgsInRegisters(); | 7439 SetArgsInRegisters(); |
| 7440 __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1); | 7440 __ IncrementCounter(&COUNTER(generic_binary_stub_calls_regs), 1); |
| 7441 } | 7441 } |
| 7442 | 7442 |
| 7443 // Call the stub. | 7443 // Call the stub. |
| 7444 __ CallStub(this); | 7444 __ CallStub(this); |
| 7445 } | 7445 } |
| 7446 | 7446 |
| 7447 | 7447 |
| 7448 void GenericBinaryOpStub::GenerateCall( | 7448 void GenericBinaryOpStub::GenerateCall( |
| 7449 MacroAssembler* masm, | 7449 MacroAssembler* masm, |
| 7450 Register left, | 7450 Register left, |
| (...skipping 11 matching lines...) Expand all Loading... |
| 7462 } else if (left.is(right_arg) && IsOperationCommutative()) { | 7462 } else if (left.is(right_arg) && IsOperationCommutative()) { |
| 7463 __ Move(left_arg, right); | 7463 __ Move(left_arg, right); |
| 7464 SetArgsReversed(); | 7464 SetArgsReversed(); |
| 7465 } else { | 7465 } else { |
| 7466 __ movq(left_arg, left); | 7466 __ movq(left_arg, left); |
| 7467 __ Move(right_arg, right); | 7467 __ Move(right_arg, right); |
| 7468 } | 7468 } |
| 7469 | 7469 |
| 7470 // Update flags to indicate that arguments are in registers. | 7470 // Update flags to indicate that arguments are in registers. |
| 7471 SetArgsInRegisters(); | 7471 SetArgsInRegisters(); |
| 7472 __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1); | 7472 __ IncrementCounter(&COUNTER(generic_binary_stub_calls_regs), 1); |
| 7473 } | 7473 } |
| 7474 | 7474 |
| 7475 // Call the stub. | 7475 // Call the stub. |
| 7476 __ CallStub(this); | 7476 __ CallStub(this); |
| 7477 } | 7477 } |
| 7478 | 7478 |
| 7479 | 7479 |
| 7480 void GenericBinaryOpStub::GenerateCall( | 7480 void GenericBinaryOpStub::GenerateCall( |
| 7481 MacroAssembler* masm, | 7481 MacroAssembler* masm, |
| 7482 Smi* left, | 7482 Smi* left, |
| (...skipping 10 matching lines...) Expand all Loading... |
| 7493 __ Move(left_arg, left); | 7493 __ Move(left_arg, left); |
| 7494 } else if (right.is(left_arg) && IsOperationCommutative()) { | 7494 } else if (right.is(left_arg) && IsOperationCommutative()) { |
| 7495 __ Move(right_arg, left); | 7495 __ Move(right_arg, left); |
| 7496 SetArgsReversed(); | 7496 SetArgsReversed(); |
| 7497 } else { | 7497 } else { |
| 7498 __ Move(left_arg, left); | 7498 __ Move(left_arg, left); |
| 7499 __ movq(right_arg, right); | 7499 __ movq(right_arg, right); |
| 7500 } | 7500 } |
| 7501 // Update flags to indicate that arguments are in registers. | 7501 // Update flags to indicate that arguments are in registers. |
| 7502 SetArgsInRegisters(); | 7502 SetArgsInRegisters(); |
| 7503 __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1); | 7503 __ IncrementCounter(&COUNTER(generic_binary_stub_calls_regs), 1); |
| 7504 } | 7504 } |
| 7505 | 7505 |
| 7506 // Call the stub. | 7506 // Call the stub. |
| 7507 __ CallStub(this); | 7507 __ CallStub(this); |
| 7508 } | 7508 } |
| 7509 | 7509 |
| 7510 | 7510 |
| 7511 void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) { | 7511 void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) { |
| 7512 // Perform fast-case smi code for the operation (rax <op> rbx) and | 7512 // Perform fast-case smi code for the operation (rax <op> rbx) and |
| 7513 // leave result in register rax. | 7513 // leave result in register rax. |
| (...skipping 455 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7969 masm.GetCode(&desc); | 7969 masm.GetCode(&desc); |
| 7970 // Call the function from C++. | 7970 // Call the function from C++. |
| 7971 return FUNCTION_CAST<ModuloFunction>(buffer); | 7971 return FUNCTION_CAST<ModuloFunction>(buffer); |
| 7972 } | 7972 } |
| 7973 | 7973 |
| 7974 #endif | 7974 #endif |
| 7975 | 7975 |
| 7976 #undef __ | 7976 #undef __ |
| 7977 | 7977 |
| 7978 } } // namespace v8::internal | 7978 } } // namespace v8::internal |
| OLD | NEW |