| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 274 } | 274 } |
| 275 | 275 |
| 276 instr->CompileToNative(this); | 276 instr->CompileToNative(this); |
| 277 } | 277 } |
| 278 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size()); | 278 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size()); |
| 279 return !is_aborted(); | 279 return !is_aborted(); |
| 280 } | 280 } |
| 281 | 281 |
| 282 | 282 |
| 283 bool LCodeGen::GenerateJumpTable() { | 283 bool LCodeGen::GenerateJumpTable() { |
| 284 Label needs_frame_not_call; | 284 Label needs_frame; |
| 285 Label needs_frame_is_call; | |
| 286 if (jump_table_.length() > 0) { | 285 if (jump_table_.length() > 0) { |
| 287 Comment(";;; -------------------- Jump table --------------------"); | 286 Comment(";;; -------------------- Jump table --------------------"); |
| 288 } | 287 } |
| 289 for (int i = 0; i < jump_table_.length(); i++) { | 288 for (int i = 0; i < jump_table_.length(); i++) { |
| 290 __ bind(&jump_table_[i].label); | 289 __ bind(&jump_table_[i].label); |
| 291 Address entry = jump_table_[i].address; | 290 Address entry = jump_table_[i].address; |
| 292 Deoptimizer::BailoutType type = jump_table_[i].bailout_type; | 291 Deoptimizer::BailoutType type = jump_table_[i].bailout_type; |
| 293 int id = Deoptimizer::GetDeoptimizationId(isolate(), entry, type); | 292 int id = Deoptimizer::GetDeoptimizationId(isolate(), entry, type); |
| 294 if (id == Deoptimizer::kNotDeoptimizationEntry) { | 293 if (id == Deoptimizer::kNotDeoptimizationEntry) { |
| 295 Comment(";;; jump table entry %d.", i); | 294 Comment(";;; jump table entry %d.", i); |
| 296 } else { | 295 } else { |
| 297 Comment(";;; jump table entry %d: deoptimization bailout %d.", i, id); | 296 Comment(";;; jump table entry %d: deoptimization bailout %d.", i, id); |
| 298 } | 297 } |
| 299 if (jump_table_[i].needs_frame) { | 298 if (jump_table_[i].needs_frame) { |
| 300 __ movq(kScratchRegister, ExternalReference::ForDeoptEntry(entry)); | 299 __ movq(kScratchRegister, ExternalReference::ForDeoptEntry(entry)); |
| 301 if (type == Deoptimizer::LAZY) { | 300 if (needs_frame.is_bound()) { |
| 302 if (needs_frame_is_call.is_bound()) { | 301 __ jmp(&needs_frame); |
| 303 __ jmp(&needs_frame_is_call); | |
| 304 } else { | |
| 305 __ bind(&needs_frame_is_call); | |
| 306 __ push(rbp); | |
| 307 __ movq(rbp, rsp); | |
| 308 __ push(rsi); | |
| 309 // This variant of deopt can only be used with stubs. Since we don't | |
| 310 // have a function pointer to install in the stack frame that we're | |
| 311 // building, install a special marker there instead. | |
| 312 ASSERT(info()->IsStub()); | |
| 313 __ Move(rsi, Smi::FromInt(StackFrame::STUB)); | |
| 314 __ push(rsi); | |
| 315 __ movq(rsi, MemOperand(rsp, kPointerSize)); | |
| 316 __ call(kScratchRegister); | |
| 317 } | |
| 318 } else { | 302 } else { |
| 319 if (needs_frame_not_call.is_bound()) { | 303 __ bind(&needs_frame); |
| 320 __ jmp(&needs_frame_not_call); | 304 __ push(rbp); |
| 321 } else { | 305 __ movq(rbp, rsp); |
| 322 __ bind(&needs_frame_not_call); | 306 __ push(rsi); |
| 323 __ push(rbp); | 307 // This variant of deopt can only be used with stubs. Since we don't |
| 324 __ movq(rbp, rsp); | 308 // have a function pointer to install in the stack frame that we're |
| 325 __ push(rsi); | 309 // building, install a special marker there instead. |
| 326 // This variant of deopt can only be used with stubs. Since we don't | 310 ASSERT(info()->IsStub()); |
| 327 // have a function pointer to install in the stack frame that we're | 311 __ Move(rsi, Smi::FromInt(StackFrame::STUB)); |
| 328 // building, install a special marker there instead. | 312 __ push(rsi); |
| 329 ASSERT(info()->IsStub()); | 313 __ movq(rsi, MemOperand(rsp, kPointerSize)); |
| 330 __ Move(rsi, Smi::FromInt(StackFrame::STUB)); | 314 __ call(kScratchRegister); |
| 331 __ push(rsi); | |
| 332 __ movq(rsi, MemOperand(rsp, kPointerSize)); | |
| 333 __ jmp(kScratchRegister); | |
| 334 } | |
| 335 } | 315 } |
| 336 } else { | 316 } else { |
| 337 if (type == Deoptimizer::LAZY) { | 317 __ call(entry, RelocInfo::RUNTIME_ENTRY); |
| 338 __ call(entry, RelocInfo::RUNTIME_ENTRY); | |
| 339 } else { | |
| 340 __ jmp(entry, RelocInfo::RUNTIME_ENTRY); | |
| 341 } | |
| 342 } | 318 } |
| 343 } | 319 } |
| 344 return !is_aborted(); | 320 return !is_aborted(); |
| 345 } | 321 } |
| 346 | 322 |
| 347 | 323 |
| 348 bool LCodeGen::GenerateDeferredCode() { | 324 bool LCodeGen::GenerateDeferredCode() { |
| 349 ASSERT(is_generating()); | 325 ASSERT(is_generating()); |
| 350 if (deferred_.length() > 0) { | 326 if (deferred_.length() > 0) { |
| 351 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { | 327 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { |
| (...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 682 if (FLAG_trap_on_deopt && info()->IsOptimizing()) { | 658 if (FLAG_trap_on_deopt && info()->IsOptimizing()) { |
| 683 Label done; | 659 Label done; |
| 684 if (cc != no_condition) { | 660 if (cc != no_condition) { |
| 685 __ j(NegateCondition(cc), &done, Label::kNear); | 661 __ j(NegateCondition(cc), &done, Label::kNear); |
| 686 } | 662 } |
| 687 __ int3(); | 663 __ int3(); |
| 688 __ bind(&done); | 664 __ bind(&done); |
| 689 } | 665 } |
| 690 | 666 |
| 691 ASSERT(info()->IsStub() || frame_is_built_); | 667 ASSERT(info()->IsStub() || frame_is_built_); |
| 692 bool needs_lazy_deopt = info()->IsStub(); | |
| 693 if (cc == no_condition && frame_is_built_) { | 668 if (cc == no_condition && frame_is_built_) { |
| 694 if (needs_lazy_deopt) { | 669 __ call(entry, RelocInfo::RUNTIME_ENTRY); |
| 695 __ call(entry, RelocInfo::RUNTIME_ENTRY); | |
| 696 } else { | |
| 697 __ jmp(entry, RelocInfo::RUNTIME_ENTRY); | |
| 698 } | |
| 699 } else { | 670 } else { |
| 700 // We often have several deopts to the same entry, reuse the last | 671 // We often have several deopts to the same entry, reuse the last |
| 701 // jump entry if this is the case. | 672 // jump entry if this is the case. |
| 702 if (jump_table_.is_empty() || | 673 if (jump_table_.is_empty() || |
| 703 jump_table_.last().address != entry || | 674 jump_table_.last().address != entry || |
| 704 jump_table_.last().needs_frame != !frame_is_built_ || | 675 jump_table_.last().needs_frame != !frame_is_built_ || |
| 705 jump_table_.last().bailout_type != bailout_type) { | 676 jump_table_.last().bailout_type != bailout_type) { |
| 706 Deoptimizer::JumpTableEntry table_entry(entry, | 677 Deoptimizer::JumpTableEntry table_entry(entry, |
| 707 bailout_type, | 678 bailout_type, |
| 708 !frame_is_built_); | 679 !frame_is_built_); |
| (...skipping 4345 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5054 | 5025 |
| 5055 if (!instr->hydrogen()->CanOmitPrototypeChecks()) { | 5026 if (!instr->hydrogen()->CanOmitPrototypeChecks()) { |
| 5056 for (int i = 0; i < prototypes->length(); i++) { | 5027 for (int i = 0; i < prototypes->length(); i++) { |
| 5057 __ LoadHeapObject(reg, prototypes->at(i)); | 5028 __ LoadHeapObject(reg, prototypes->at(i)); |
| 5058 DoCheckMapCommon(reg, maps->at(i), instr); | 5029 DoCheckMapCommon(reg, maps->at(i), instr); |
| 5059 } | 5030 } |
| 5060 } | 5031 } |
| 5061 } | 5032 } |
| 5062 | 5033 |
| 5063 | 5034 |
| 5064 void LCodeGen::DoAllocateObject(LAllocateObject* instr) { | |
| 5065 class DeferredAllocateObject: public LDeferredCode { | |
| 5066 public: | |
| 5067 DeferredAllocateObject(LCodeGen* codegen, LAllocateObject* instr) | |
| 5068 : LDeferredCode(codegen), instr_(instr) { } | |
| 5069 virtual void Generate() { codegen()->DoDeferredAllocateObject(instr_); } | |
| 5070 virtual LInstruction* instr() { return instr_; } | |
| 5071 private: | |
| 5072 LAllocateObject* instr_; | |
| 5073 }; | |
| 5074 | |
| 5075 DeferredAllocateObject* deferred = | |
| 5076 new(zone()) DeferredAllocateObject(this, instr); | |
| 5077 | |
| 5078 Register result = ToRegister(instr->result()); | |
| 5079 Register scratch = ToRegister(instr->temp()); | |
| 5080 Handle<JSFunction> constructor = instr->hydrogen()->constructor(); | |
| 5081 Handle<Map> initial_map = instr->hydrogen()->constructor_initial_map(); | |
| 5082 int instance_size = initial_map->instance_size(); | |
| 5083 ASSERT(initial_map->pre_allocated_property_fields() + | |
| 5084 initial_map->unused_property_fields() - | |
| 5085 initial_map->inobject_properties() == 0); | |
| 5086 | |
| 5087 __ Allocate(instance_size, result, no_reg, scratch, deferred->entry(), | |
| 5088 TAG_OBJECT); | |
| 5089 | |
| 5090 __ bind(deferred->exit()); | |
| 5091 if (FLAG_debug_code) { | |
| 5092 Label is_in_new_space; | |
| 5093 __ JumpIfInNewSpace(result, scratch, &is_in_new_space); | |
| 5094 __ Abort("Allocated object is not in new-space"); | |
| 5095 __ bind(&is_in_new_space); | |
| 5096 } | |
| 5097 | |
| 5098 // Load the initial map. | |
| 5099 Register map = scratch; | |
| 5100 __ LoadHeapObject(scratch, constructor); | |
| 5101 __ movq(map, FieldOperand(scratch, JSFunction::kPrototypeOrInitialMapOffset)); | |
| 5102 | |
| 5103 if (FLAG_debug_code) { | |
| 5104 __ AssertNotSmi(map); | |
| 5105 __ cmpb(FieldOperand(map, Map::kInstanceSizeOffset), | |
| 5106 Immediate(instance_size >> kPointerSizeLog2)); | |
| 5107 __ Assert(equal, "Unexpected instance size"); | |
| 5108 __ cmpb(FieldOperand(map, Map::kPreAllocatedPropertyFieldsOffset), | |
| 5109 Immediate(initial_map->pre_allocated_property_fields())); | |
| 5110 __ Assert(equal, "Unexpected pre-allocated property fields count"); | |
| 5111 __ cmpb(FieldOperand(map, Map::kUnusedPropertyFieldsOffset), | |
| 5112 Immediate(initial_map->unused_property_fields())); | |
| 5113 __ Assert(equal, "Unexpected unused property fields count"); | |
| 5114 __ cmpb(FieldOperand(map, Map::kInObjectPropertiesOffset), | |
| 5115 Immediate(initial_map->inobject_properties())); | |
| 5116 __ Assert(equal, "Unexpected in-object property fields count"); | |
| 5117 } | |
| 5118 | |
| 5119 // Initialize map and fields of the newly allocated object. | |
| 5120 ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE); | |
| 5121 __ movq(FieldOperand(result, JSObject::kMapOffset), map); | |
| 5122 __ LoadRoot(scratch, Heap::kEmptyFixedArrayRootIndex); | |
| 5123 __ movq(FieldOperand(result, JSObject::kElementsOffset), scratch); | |
| 5124 __ movq(FieldOperand(result, JSObject::kPropertiesOffset), scratch); | |
| 5125 if (initial_map->inobject_properties() != 0) { | |
| 5126 __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex); | |
| 5127 for (int i = 0; i < initial_map->inobject_properties(); i++) { | |
| 5128 int property_offset = JSObject::kHeaderSize + i * kPointerSize; | |
| 5129 __ movq(FieldOperand(result, property_offset), scratch); | |
| 5130 } | |
| 5131 } | |
| 5132 } | |
| 5133 | |
| 5134 | |
| 5135 void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) { | |
| 5136 Register result = ToRegister(instr->result()); | |
| 5137 Handle<Map> initial_map = instr->hydrogen()->constructor_initial_map(); | |
| 5138 int instance_size = initial_map->instance_size(); | |
| 5139 | |
| 5140 // TODO(3095996): Get rid of this. For now, we need to make the | |
| 5141 // result register contain a valid pointer because it is already | |
| 5142 // contained in the register pointer map. | |
| 5143 __ Set(result, 0); | |
| 5144 | |
| 5145 PushSafepointRegistersScope scope(this); | |
| 5146 __ Push(Smi::FromInt(instance_size)); | |
| 5147 CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr); | |
| 5148 __ StoreToSafepointRegisterSlot(result, rax); | |
| 5149 } | |
| 5150 | |
| 5151 | |
| 5152 void LCodeGen::DoAllocate(LAllocate* instr) { | 5035 void LCodeGen::DoAllocate(LAllocate* instr) { |
| 5153 class DeferredAllocate: public LDeferredCode { | 5036 class DeferredAllocate: public LDeferredCode { |
| 5154 public: | 5037 public: |
| 5155 DeferredAllocate(LCodeGen* codegen, LAllocate* instr) | 5038 DeferredAllocate(LCodeGen* codegen, LAllocate* instr) |
| 5156 : LDeferredCode(codegen), instr_(instr) { } | 5039 : LDeferredCode(codegen), instr_(instr) { } |
| 5157 virtual void Generate() { codegen()->DoDeferredAllocate(instr_); } | 5040 virtual void Generate() { codegen()->DoDeferredAllocate(instr_); } |
| 5158 virtual LInstruction* instr() { return instr_; } | 5041 virtual LInstruction* instr() { return instr_; } |
| 5159 private: | 5042 private: |
| 5160 LAllocate* instr_; | 5043 LAllocate* instr_; |
| 5161 }; | 5044 }; |
| (...skipping 471 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5633 FixedArray::kHeaderSize - kPointerSize)); | 5516 FixedArray::kHeaderSize - kPointerSize)); |
| 5634 __ bind(&done); | 5517 __ bind(&done); |
| 5635 } | 5518 } |
| 5636 | 5519 |
| 5637 | 5520 |
| 5638 #undef __ | 5521 #undef __ |
| 5639 | 5522 |
| 5640 } } // namespace v8::internal | 5523 } } // namespace v8::internal |
| 5641 | 5524 |
| 5642 #endif // V8_TARGET_ARCH_X64 | 5525 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |