| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 325 deopt_jump_table_.length() * 12)) { | 325 deopt_jump_table_.length() * 12)) { |
| 326 Abort("Generated code is too large"); | 326 Abort("Generated code is too large"); |
| 327 } | 327 } |
| 328 | 328 |
| 329 if (deopt_jump_table_.length() > 0) { | 329 if (deopt_jump_table_.length() > 0) { |
| 330 Comment(";;; -------------------- Jump table --------------------"); | 330 Comment(";;; -------------------- Jump table --------------------"); |
| 331 } | 331 } |
| 332 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); | 332 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); |
| 333 Label table_start; | 333 Label table_start; |
| 334 __ bind(&table_start); | 334 __ bind(&table_start); |
| 335 Label needs_frame_not_call; | 335 Label needs_frame; |
| 336 Label needs_frame_is_call; | |
| 337 for (int i = 0; i < deopt_jump_table_.length(); i++) { | 336 for (int i = 0; i < deopt_jump_table_.length(); i++) { |
| 338 __ bind(&deopt_jump_table_[i].label); | 337 __ bind(&deopt_jump_table_[i].label); |
| 339 Address entry = deopt_jump_table_[i].address; | 338 Address entry = deopt_jump_table_[i].address; |
| 340 Deoptimizer::BailoutType type = deopt_jump_table_[i].bailout_type; | 339 Deoptimizer::BailoutType type = deopt_jump_table_[i].bailout_type; |
| 341 int id = Deoptimizer::GetDeoptimizationId(isolate(), entry, type); | 340 int id = Deoptimizer::GetDeoptimizationId(isolate(), entry, type); |
| 342 if (id == Deoptimizer::kNotDeoptimizationEntry) { | 341 if (id == Deoptimizer::kNotDeoptimizationEntry) { |
| 343 Comment(";;; jump table entry %d.", i); | 342 Comment(";;; jump table entry %d.", i); |
| 344 } else { | 343 } else { |
| 345 Comment(";;; jump table entry %d: deoptimization bailout %d.", i, id); | 344 Comment(";;; jump table entry %d: deoptimization bailout %d.", i, id); |
| 346 } | 345 } |
| 347 __ li(t9, Operand(ExternalReference::ForDeoptEntry(entry))); | 346 __ li(t9, Operand(ExternalReference::ForDeoptEntry(entry))); |
| 348 if (deopt_jump_table_[i].needs_frame) { | 347 if (deopt_jump_table_[i].needs_frame) { |
| 349 if (type == Deoptimizer::LAZY) { | 348 if (needs_frame.is_bound()) { |
| 350 if (needs_frame_is_call.is_bound()) { | 349 __ Branch(&needs_frame); |
| 351 __ Branch(&needs_frame_is_call); | |
| 352 } else { | |
| 353 __ bind(&needs_frame_is_call); | |
| 354 __ MultiPush(cp.bit() | fp.bit() | ra.bit()); | |
| 355 // This variant of deopt can only be used with stubs. Since we don't | |
| 356 // have a function pointer to install in the stack frame that we're | |
| 357 // building, install a special marker there instead. | |
| 358 ASSERT(info()->IsStub()); | |
| 359 __ li(scratch0(), Operand(Smi::FromInt(StackFrame::STUB))); | |
| 360 __ push(scratch0()); | |
| 361 __ Addu(fp, sp, Operand(2 * kPointerSize)); | |
| 362 __ Call(t9); | |
| 363 } | |
| 364 } else { | 350 } else { |
| 365 if (needs_frame_not_call.is_bound()) { | 351 __ bind(&needs_frame); |
| 366 __ Branch(&needs_frame_not_call); | 352 __ MultiPush(cp.bit() | fp.bit() | ra.bit()); |
| 367 } else { | 353 // This variant of deopt can only be used with stubs. Since we don't |
| 368 __ bind(&needs_frame_not_call); | 354 // have a function pointer to install in the stack frame that we're |
| 369 __ MultiPush(cp.bit() | fp.bit() | ra.bit()); | 355 // building, install a special marker there instead. |
| 370 // This variant of deopt can only be used with stubs. Since we don't | 356 ASSERT(info()->IsStub()); |
| 371 // have a function pointer to install in the stack frame that we're | 357 __ li(scratch0(), Operand(Smi::FromInt(StackFrame::STUB))); |
| 372 // building, install a special marker there instead. | 358 __ push(scratch0()); |
| 373 ASSERT(info()->IsStub()); | 359 __ Addu(fp, sp, Operand(2 * kPointerSize)); |
| 374 __ li(scratch0(), Operand(Smi::FromInt(StackFrame::STUB))); | 360 __ Call(t9); |
| 375 __ push(scratch0()); | |
| 376 __ Addu(fp, sp, Operand(2 * kPointerSize)); | |
| 377 __ Jump(t9); | |
| 378 } | |
| 379 } | 361 } |
| 380 } else { | 362 } else { |
| 381 if (type == Deoptimizer::LAZY) { | 363 __ Call(t9); |
| 382 __ Call(t9); | |
| 383 } else { | |
| 384 __ Jump(t9); | |
| 385 } | |
| 386 } | 364 } |
| 387 } | 365 } |
| 388 __ RecordComment("]"); | 366 __ RecordComment("]"); |
| 389 | 367 |
| 390 // The deoptimization jump table is the last part of the instruction | 368 // The deoptimization jump table is the last part of the instruction |
| 391 // sequence. Mark the generated code as done unless we bailed out. | 369 // sequence. Mark the generated code as done unless we bailed out. |
| 392 if (!is_aborted()) status_ = DONE; | 370 if (!is_aborted()) status_ = DONE; |
| 393 return !is_aborted(); | 371 return !is_aborted(); |
| 394 } | 372 } |
| 395 | 373 |
| (...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 759 Deoptimizer::GetDeoptimizationEntry(isolate(), id, bailout_type); | 737 Deoptimizer::GetDeoptimizationEntry(isolate(), id, bailout_type); |
| 760 if (entry == NULL) { | 738 if (entry == NULL) { |
| 761 Abort("bailout was not prepared"); | 739 Abort("bailout was not prepared"); |
| 762 return; | 740 return; |
| 763 } | 741 } |
| 764 | 742 |
| 765 ASSERT(FLAG_deopt_every_n_times < 2); // Other values not supported on MIPS. | 743 ASSERT(FLAG_deopt_every_n_times < 2); // Other values not supported on MIPS. |
| 766 if (FLAG_deopt_every_n_times == 1 && | 744 if (FLAG_deopt_every_n_times == 1 && |
| 767 !info()->IsStub() && | 745 !info()->IsStub() && |
| 768 info()->opt_count() == id) { | 746 info()->opt_count() == id) { |
| 769 __ Jump(entry, RelocInfo::RUNTIME_ENTRY); | 747 ASSERT(frame_is_built_); |
| 748 __ Call(entry, RelocInfo::RUNTIME_ENTRY); |
| 770 return; | 749 return; |
| 771 } | 750 } |
| 772 | 751 |
| 773 if (FLAG_trap_on_deopt && info()->IsOptimizing()) { | 752 if (FLAG_trap_on_deopt && info()->IsOptimizing()) { |
| 774 Label skip; | 753 Label skip; |
| 775 if (cc != al) { | 754 if (cc != al) { |
| 776 __ Branch(&skip, NegateCondition(cc), src1, src2); | 755 __ Branch(&skip, NegateCondition(cc), src1, src2); |
| 777 } | 756 } |
| 778 __ stop("trap_on_deopt"); | 757 __ stop("trap_on_deopt"); |
| 779 __ bind(&skip); | 758 __ bind(&skip); |
| 780 } | 759 } |
| 781 | 760 |
| 782 ASSERT(info()->IsStub() || frame_is_built_); | 761 ASSERT(info()->IsStub() || frame_is_built_); |
| 783 bool needs_lazy_deopt = info()->IsStub(); | |
| 784 if (cc == al && frame_is_built_) { | 762 if (cc == al && frame_is_built_) { |
| 785 if (needs_lazy_deopt) { | 763 __ Call(entry, RelocInfo::RUNTIME_ENTRY, cc, src1, src2); |
| 786 __ Call(entry, RelocInfo::RUNTIME_ENTRY, cc, src1, src2); | |
| 787 } else { | |
| 788 __ Jump(entry, RelocInfo::RUNTIME_ENTRY, cc, src1, src2); | |
| 789 } | |
| 790 } else { | 764 } else { |
| 791 // We often have several deopts to the same entry, reuse the last | 765 // We often have several deopts to the same entry, reuse the last |
| 792 // jump entry if this is the case. | 766 // jump entry if this is the case. |
| 793 if (deopt_jump_table_.is_empty() || | 767 if (deopt_jump_table_.is_empty() || |
| 794 (deopt_jump_table_.last().address != entry) || | 768 (deopt_jump_table_.last().address != entry) || |
| 795 (deopt_jump_table_.last().bailout_type != bailout_type) || | 769 (deopt_jump_table_.last().bailout_type != bailout_type) || |
| 796 (deopt_jump_table_.last().needs_frame != !frame_is_built_)) { | 770 (deopt_jump_table_.last().needs_frame != !frame_is_built_)) { |
| 797 Deoptimizer::JumpTableEntry table_entry(entry, | 771 Deoptimizer::JumpTableEntry table_entry(entry, |
| 798 bailout_type, | 772 bailout_type, |
| 799 !frame_is_built_); | 773 !frame_is_built_); |
| (...skipping 4491 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5291 if (!instr->hydrogen()->CanOmitPrototypeChecks()) { | 5265 if (!instr->hydrogen()->CanOmitPrototypeChecks()) { |
| 5292 for (int i = 0; i < prototypes->length(); i++) { | 5266 for (int i = 0; i < prototypes->length(); i++) { |
| 5293 __ LoadHeapObject(prototype_reg, prototypes->at(i)); | 5267 __ LoadHeapObject(prototype_reg, prototypes->at(i)); |
| 5294 __ lw(map_reg, FieldMemOperand(prototype_reg, HeapObject::kMapOffset)); | 5268 __ lw(map_reg, FieldMemOperand(prototype_reg, HeapObject::kMapOffset)); |
| 5295 DoCheckMapCommon(map_reg, maps->at(i), instr->environment()); | 5269 DoCheckMapCommon(map_reg, maps->at(i), instr->environment()); |
| 5296 } | 5270 } |
| 5297 } | 5271 } |
| 5298 } | 5272 } |
| 5299 | 5273 |
| 5300 | 5274 |
| 5301 void LCodeGen::DoAllocateObject(LAllocateObject* instr) { | |
| 5302 class DeferredAllocateObject: public LDeferredCode { | |
| 5303 public: | |
| 5304 DeferredAllocateObject(LCodeGen* codegen, LAllocateObject* instr) | |
| 5305 : LDeferredCode(codegen), instr_(instr) { } | |
| 5306 virtual void Generate() { codegen()->DoDeferredAllocateObject(instr_); } | |
| 5307 virtual LInstruction* instr() { return instr_; } | |
| 5308 private: | |
| 5309 LAllocateObject* instr_; | |
| 5310 }; | |
| 5311 | |
| 5312 DeferredAllocateObject* deferred = | |
| 5313 new(zone()) DeferredAllocateObject(this, instr); | |
| 5314 | |
| 5315 Register result = ToRegister(instr->result()); | |
| 5316 Register scratch = ToRegister(instr->temp()); | |
| 5317 Register scratch2 = ToRegister(instr->temp2()); | |
| 5318 Handle<JSFunction> constructor = instr->hydrogen()->constructor(); | |
| 5319 Handle<Map> initial_map = instr->hydrogen()->constructor_initial_map(); | |
| 5320 int instance_size = initial_map->instance_size(); | |
| 5321 ASSERT(initial_map->pre_allocated_property_fields() + | |
| 5322 initial_map->unused_property_fields() - | |
| 5323 initial_map->inobject_properties() == 0); | |
| 5324 | |
| 5325 __ Allocate(instance_size, result, scratch, scratch2, deferred->entry(), | |
| 5326 TAG_OBJECT); | |
| 5327 | |
| 5328 __ bind(deferred->exit()); | |
| 5329 if (FLAG_debug_code) { | |
| 5330 Label is_in_new_space; | |
| 5331 __ JumpIfInNewSpace(result, scratch, &is_in_new_space); | |
| 5332 __ Abort("Allocated object is not in new-space"); | |
| 5333 __ bind(&is_in_new_space); | |
| 5334 } | |
| 5335 | |
| 5336 // Load the initial map. | |
| 5337 Register map = scratch; | |
| 5338 __ LoadHeapObject(map, constructor); | |
| 5339 __ lw(map, FieldMemOperand(map, JSFunction::kPrototypeOrInitialMapOffset)); | |
| 5340 | |
| 5341 // Initialize map and fields of the newly allocated object. | |
| 5342 ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE); | |
| 5343 __ sw(map, FieldMemOperand(result, JSObject::kMapOffset)); | |
| 5344 __ LoadRoot(scratch, Heap::kEmptyFixedArrayRootIndex); | |
| 5345 __ sw(scratch, FieldMemOperand(result, JSObject::kElementsOffset)); | |
| 5346 __ sw(scratch, FieldMemOperand(result, JSObject::kPropertiesOffset)); | |
| 5347 if (initial_map->inobject_properties() != 0) { | |
| 5348 __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex); | |
| 5349 for (int i = 0; i < initial_map->inobject_properties(); i++) { | |
| 5350 int property_offset = JSObject::kHeaderSize + i * kPointerSize; | |
| 5351 __ sw(scratch, FieldMemOperand(result, property_offset)); | |
| 5352 } | |
| 5353 } | |
| 5354 } | |
| 5355 | |
| 5356 | |
| 5357 void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) { | |
| 5358 Register result = ToRegister(instr->result()); | |
| 5359 Handle<Map> initial_map = instr->hydrogen()->constructor_initial_map(); | |
| 5360 int instance_size = initial_map->instance_size(); | |
| 5361 | |
| 5362 // TODO(3095996): Get rid of this. For now, we need to make the | |
| 5363 // result register contain a valid pointer because it is already | |
| 5364 // contained in the register pointer map. | |
| 5365 __ mov(result, zero_reg); | |
| 5366 | |
| 5367 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); | |
| 5368 __ li(a0, Operand(Smi::FromInt(instance_size))); | |
| 5369 __ push(a0); | |
| 5370 CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr); | |
| 5371 __ StoreToSafepointRegisterSlot(v0, result); | |
| 5372 } | |
| 5373 | |
| 5374 | |
| 5375 void LCodeGen::DoAllocate(LAllocate* instr) { | 5275 void LCodeGen::DoAllocate(LAllocate* instr) { |
| 5376 class DeferredAllocate: public LDeferredCode { | 5276 class DeferredAllocate: public LDeferredCode { |
| 5377 public: | 5277 public: |
| 5378 DeferredAllocate(LCodeGen* codegen, LAllocate* instr) | 5278 DeferredAllocate(LCodeGen* codegen, LAllocate* instr) |
| 5379 : LDeferredCode(codegen), instr_(instr) { } | 5279 : LDeferredCode(codegen), instr_(instr) { } |
| 5380 virtual void Generate() { codegen()->DoDeferredAllocate(instr_); } | 5280 virtual void Generate() { codegen()->DoDeferredAllocate(instr_); } |
| 5381 virtual LInstruction* instr() { return instr_; } | 5281 virtual LInstruction* instr() { return instr_; } |
| 5382 private: | 5282 private: |
| 5383 LAllocate* instr_; | 5283 LAllocate* instr_; |
| 5384 }; | 5284 }; |
| (...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5727 DeoptimizeIf(al, instr->environment(), zero_reg, Operand(zero_reg)); | 5627 DeoptimizeIf(al, instr->environment(), zero_reg, Operand(zero_reg)); |
| 5728 } | 5628 } |
| 5729 } | 5629 } |
| 5730 | 5630 |
| 5731 | 5631 |
| 5732 void LCodeGen::DoDummyUse(LDummyUse* instr) { | 5632 void LCodeGen::DoDummyUse(LDummyUse* instr) { |
| 5733 // Nothing to see here, move on! | 5633 // Nothing to see here, move on! |
| 5734 } | 5634 } |
| 5735 | 5635 |
| 5736 | 5636 |
| 5737 void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) { | |
| 5738 Register object = ToRegister(instr->object()); | |
| 5739 Register key = ToRegister(instr->key()); | |
| 5740 Register strict = scratch0(); | |
| 5741 __ li(strict, Operand(Smi::FromInt(strict_mode_flag()))); | |
| 5742 __ Push(object, key, strict); | |
| 5743 ASSERT(instr->HasPointerMap()); | |
| 5744 LPointerMap* pointers = instr->pointer_map(); | |
| 5745 RecordPosition(pointers->position()); | |
| 5746 SafepointGenerator safepoint_generator( | |
| 5747 this, pointers, Safepoint::kLazyDeopt); | |
| 5748 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator); | |
| 5749 } | |
| 5750 | |
| 5751 | |
| 5752 void LCodeGen::DoIn(LIn* instr) { | |
| 5753 Register obj = ToRegister(instr->object()); | |
| 5754 Register key = ToRegister(instr->key()); | |
| 5755 __ Push(key, obj); | |
| 5756 ASSERT(instr->HasPointerMap()); | |
| 5757 LPointerMap* pointers = instr->pointer_map(); | |
| 5758 RecordPosition(pointers->position()); | |
| 5759 SafepointGenerator safepoint_generator(this, pointers, Safepoint::kLazyDeopt); | |
| 5760 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator); | |
| 5761 } | |
| 5762 | |
| 5763 | |
| 5764 void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) { | 5637 void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) { |
| 5765 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); | 5638 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); |
| 5766 __ CallRuntimeSaveDoubles(Runtime::kStackGuard); | 5639 __ CallRuntimeSaveDoubles(Runtime::kStackGuard); |
| 5767 RecordSafepointWithLazyDeopt( | 5640 RecordSafepointWithLazyDeopt( |
| 5768 instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); | 5641 instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); |
| 5769 ASSERT(instr->HasEnvironment()); | 5642 ASSERT(instr->HasEnvironment()); |
| 5770 LEnvironment* env = instr->environment(); | 5643 LEnvironment* env = instr->environment(); |
| 5771 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); | 5644 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); |
| 5772 } | 5645 } |
| 5773 | 5646 |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5921 __ Subu(scratch, result, scratch); | 5794 __ Subu(scratch, result, scratch); |
| 5922 __ lw(result, FieldMemOperand(scratch, | 5795 __ lw(result, FieldMemOperand(scratch, |
| 5923 FixedArray::kHeaderSize - kPointerSize)); | 5796 FixedArray::kHeaderSize - kPointerSize)); |
| 5924 __ bind(&done); | 5797 __ bind(&done); |
| 5925 } | 5798 } |
| 5926 | 5799 |
| 5927 | 5800 |
| 5928 #undef __ | 5801 #undef __ |
| 5929 | 5802 |
| 5930 } } // namespace v8::internal | 5803 } } // namespace v8::internal |
| OLD | NEW |