| 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 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 154 __ stm(db_w, sp, cp.bit() | fp.bit() | lr.bit()); | 154 __ stm(db_w, sp, cp.bit() | fp.bit() | lr.bit()); |
| 155 __ Push(Smi::FromInt(StackFrame::STUB)); | 155 __ Push(Smi::FromInt(StackFrame::STUB)); |
| 156 // Adjust FP to point to saved FP. | 156 // Adjust FP to point to saved FP. |
| 157 __ add(fp, sp, Operand(2 * kPointerSize)); | 157 __ add(fp, sp, Operand(2 * kPointerSize)); |
| 158 } else { | 158 } else { |
| 159 PredictableCodeSizeScope predictible_code_size_scope( | 159 PredictableCodeSizeScope predictible_code_size_scope( |
| 160 masm_, kNoCodeAgeSequenceLength * Assembler::kInstrSize); | 160 masm_, kNoCodeAgeSequenceLength * Assembler::kInstrSize); |
| 161 // The following three instructions must remain together and unmodified | 161 // The following three instructions must remain together and unmodified |
| 162 // for code aging to work properly. | 162 // for code aging to work properly. |
| 163 __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit()); | 163 __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit()); |
| 164 // Load undefined value here, so the value is ready for the loop | 164 __ nop(ip.code()); |
| 165 // below. | |
| 166 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); | |
| 167 // Adjust FP to point to saved FP. | 165 // Adjust FP to point to saved FP. |
| 168 __ add(fp, sp, Operand(2 * kPointerSize)); | 166 __ add(fp, sp, Operand(2 * kPointerSize)); |
| 169 } | 167 } |
| 170 frame_is_built_ = true; | 168 frame_is_built_ = true; |
| 171 info_->AddNoFrameRange(0, masm_->pc_offset()); | 169 info_->AddNoFrameRange(0, masm_->pc_offset()); |
| 172 } | 170 } |
| 173 | 171 |
| 174 // Reserve space for the stack slots needed by the code. | 172 // Reserve space for the stack slots needed by the code. |
| 175 int slots = GetStackSlotCount(); | 173 int slots = GetStackSlotCount(); |
| 176 if (slots > 0) { | 174 if (slots > 0) { |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 336 if (!is_int24((masm()->pc_offset() / Assembler::kInstrSize) + | 334 if (!is_int24((masm()->pc_offset() / Assembler::kInstrSize) + |
| 337 deopt_jump_table_.length() * 7)) { | 335 deopt_jump_table_.length() * 7)) { |
| 338 Abort("Generated code is too large"); | 336 Abort("Generated code is too large"); |
| 339 } | 337 } |
| 340 | 338 |
| 341 if (deopt_jump_table_.length() > 0) { | 339 if (deopt_jump_table_.length() > 0) { |
| 342 Comment(";;; -------------------- Jump table --------------------"); | 340 Comment(";;; -------------------- Jump table --------------------"); |
| 343 } | 341 } |
| 344 Label table_start; | 342 Label table_start; |
| 345 __ bind(&table_start); | 343 __ bind(&table_start); |
| 346 Label needs_frame_not_call; | 344 Label needs_frame; |
| 347 Label needs_frame_is_call; | |
| 348 for (int i = 0; i < deopt_jump_table_.length(); i++) { | 345 for (int i = 0; i < deopt_jump_table_.length(); i++) { |
| 349 __ bind(&deopt_jump_table_[i].label); | 346 __ bind(&deopt_jump_table_[i].label); |
| 350 Address entry = deopt_jump_table_[i].address; | 347 Address entry = deopt_jump_table_[i].address; |
| 351 Deoptimizer::BailoutType type = deopt_jump_table_[i].bailout_type; | 348 Deoptimizer::BailoutType type = deopt_jump_table_[i].bailout_type; |
| 352 int id = Deoptimizer::GetDeoptimizationId(isolate(), entry, type); | 349 int id = Deoptimizer::GetDeoptimizationId(isolate(), entry, type); |
| 353 if (id == Deoptimizer::kNotDeoptimizationEntry) { | 350 if (id == Deoptimizer::kNotDeoptimizationEntry) { |
| 354 Comment(";;; jump table entry %d.", i); | 351 Comment(";;; jump table entry %d.", i); |
| 355 } else { | 352 } else { |
| 356 Comment(";;; jump table entry %d: deoptimization bailout %d.", i, id); | 353 Comment(";;; jump table entry %d: deoptimization bailout %d.", i, id); |
| 357 } | 354 } |
| 358 if (deopt_jump_table_[i].needs_frame) { | 355 if (deopt_jump_table_[i].needs_frame) { |
| 359 __ mov(ip, Operand(ExternalReference::ForDeoptEntry(entry))); | 356 __ mov(ip, Operand(ExternalReference::ForDeoptEntry(entry))); |
| 360 if (type == Deoptimizer::LAZY) { | 357 if (needs_frame.is_bound()) { |
| 361 if (needs_frame_is_call.is_bound()) { | 358 __ b(&needs_frame); |
| 362 __ b(&needs_frame_is_call); | |
| 363 } else { | |
| 364 __ bind(&needs_frame_is_call); | |
| 365 __ stm(db_w, sp, cp.bit() | fp.bit() | lr.bit()); | |
| 366 // This variant of deopt can only be used with stubs. Since we don't | |
| 367 // have a function pointer to install in the stack frame that we're | |
| 368 // building, install a special marker there instead. | |
| 369 ASSERT(info()->IsStub()); | |
| 370 __ mov(scratch0(), Operand(Smi::FromInt(StackFrame::STUB))); | |
| 371 __ push(scratch0()); | |
| 372 __ add(fp, sp, Operand(2 * kPointerSize)); | |
| 373 __ mov(lr, Operand(pc), LeaveCC, al); | |
| 374 __ mov(pc, ip); | |
| 375 } | |
| 376 } else { | 359 } else { |
| 377 if (needs_frame_not_call.is_bound()) { | 360 __ bind(&needs_frame); |
| 378 __ b(&needs_frame_not_call); | 361 __ stm(db_w, sp, cp.bit() | fp.bit() | lr.bit()); |
| 379 } else { | 362 // This variant of deopt can only be used with stubs. Since we don't |
| 380 __ bind(&needs_frame_not_call); | 363 // have a function pointer to install in the stack frame that we're |
| 381 __ stm(db_w, sp, cp.bit() | fp.bit() | lr.bit()); | 364 // building, install a special marker there instead. |
| 382 // This variant of deopt can only be used with stubs. Since we don't | 365 ASSERT(info()->IsStub()); |
| 383 // have a function pointer to install in the stack frame that we're | 366 __ mov(scratch0(), Operand(Smi::FromInt(StackFrame::STUB))); |
| 384 // building, install a special marker there instead. | 367 __ push(scratch0()); |
| 385 ASSERT(info()->IsStub()); | 368 __ add(fp, sp, Operand(2 * kPointerSize)); |
| 386 __ mov(scratch0(), Operand(Smi::FromInt(StackFrame::STUB))); | 369 __ mov(lr, Operand(pc), LeaveCC, al); |
| 387 __ push(scratch0()); | 370 __ mov(pc, ip); |
| 388 __ add(fp, sp, Operand(2 * kPointerSize)); | |
| 389 __ mov(pc, ip); | |
| 390 } | |
| 391 } | 371 } |
| 392 } else { | 372 } else { |
| 393 if (type == Deoptimizer::LAZY) { | 373 __ mov(lr, Operand(pc), LeaveCC, al); |
| 394 __ mov(lr, Operand(pc), LeaveCC, al); | 374 __ mov(pc, Operand(ExternalReference::ForDeoptEntry(entry))); |
| 395 __ mov(pc, Operand(ExternalReference::ForDeoptEntry(entry))); | |
| 396 } else { | |
| 397 __ mov(pc, Operand(ExternalReference::ForDeoptEntry(entry))); | |
| 398 } | |
| 399 } | 375 } |
| 400 masm()->CheckConstPool(false, false); | 376 masm()->CheckConstPool(false, false); |
| 401 } | 377 } |
| 402 | 378 |
| 403 // Force constant pool emission at the end of the deopt jump table to make | 379 // Force constant pool emission at the end of the deopt jump table to make |
| 404 // sure that no constant pools are emitted after. | 380 // sure that no constant pools are emitted after. |
| 405 masm()->CheckConstPool(true, false); | 381 masm()->CheckConstPool(true, false); |
| 406 | 382 |
| 407 // The deoptimization jump table is the last part of the instruction | 383 // The deoptimization jump table is the last part of the instruction |
| 408 // sequence. Mark the generated code as done unless we bailed out. | 384 // sequence. Mark the generated code as done unless we bailed out. |
| (...skipping 378 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 787 Deoptimizer::GetDeoptimizationEntry(isolate(), id, bailout_type); | 763 Deoptimizer::GetDeoptimizationEntry(isolate(), id, bailout_type); |
| 788 if (entry == NULL) { | 764 if (entry == NULL) { |
| 789 Abort("bailout was not prepared"); | 765 Abort("bailout was not prepared"); |
| 790 return; | 766 return; |
| 791 } | 767 } |
| 792 | 768 |
| 793 ASSERT(FLAG_deopt_every_n_times < 2); // Other values not supported on ARM. | 769 ASSERT(FLAG_deopt_every_n_times < 2); // Other values not supported on ARM. |
| 794 if (FLAG_deopt_every_n_times == 1 && | 770 if (FLAG_deopt_every_n_times == 1 && |
| 795 !info()->IsStub() && | 771 !info()->IsStub() && |
| 796 info()->opt_count() == id) { | 772 info()->opt_count() == id) { |
| 797 __ Jump(entry, RelocInfo::RUNTIME_ENTRY); | 773 ASSERT(frame_is_built_); |
| 774 __ Call(entry, RelocInfo::RUNTIME_ENTRY); |
| 798 return; | 775 return; |
| 799 } | 776 } |
| 800 | 777 |
| 801 if (FLAG_trap_on_deopt && info()->IsOptimizing()) { | 778 if (FLAG_trap_on_deopt && info()->IsOptimizing()) { |
| 802 __ stop("trap_on_deopt", cc); | 779 __ stop("trap_on_deopt", cc); |
| 803 } | 780 } |
| 804 | 781 |
| 805 ASSERT(info()->IsStub() || frame_is_built_); | 782 ASSERT(info()->IsStub() || frame_is_built_); |
| 806 bool needs_lazy_deopt = info()->IsStub(); | |
| 807 if (cc == al && frame_is_built_) { | 783 if (cc == al && frame_is_built_) { |
| 808 if (needs_lazy_deopt) { | 784 __ Call(entry, RelocInfo::RUNTIME_ENTRY); |
| 809 __ Call(entry, RelocInfo::RUNTIME_ENTRY); | |
| 810 } else { | |
| 811 __ Jump(entry, RelocInfo::RUNTIME_ENTRY); | |
| 812 } | |
| 813 } else { | 785 } else { |
| 814 // We often have several deopts to the same entry, reuse the last | 786 // We often have several deopts to the same entry, reuse the last |
| 815 // jump entry if this is the case. | 787 // jump entry if this is the case. |
| 816 if (deopt_jump_table_.is_empty() || | 788 if (deopt_jump_table_.is_empty() || |
| 817 (deopt_jump_table_.last().address != entry) || | 789 (deopt_jump_table_.last().address != entry) || |
| 818 (deopt_jump_table_.last().bailout_type != bailout_type) || | 790 (deopt_jump_table_.last().bailout_type != bailout_type) || |
| 819 (deopt_jump_table_.last().needs_frame != !frame_is_built_)) { | 791 (deopt_jump_table_.last().needs_frame != !frame_is_built_)) { |
| 820 Deoptimizer::JumpTableEntry table_entry(entry, | 792 Deoptimizer::JumpTableEntry table_entry(entry, |
| 821 bailout_type, | 793 bailout_type, |
| 822 !frame_is_built_); | 794 !frame_is_built_); |
| (...skipping 4510 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5333 if (!instr->hydrogen()->CanOmitPrototypeChecks()) { | 5305 if (!instr->hydrogen()->CanOmitPrototypeChecks()) { |
| 5334 for (int i = 0; i < prototypes->length(); i++) { | 5306 for (int i = 0; i < prototypes->length(); i++) { |
| 5335 __ LoadHeapObject(prototype_reg, prototypes->at(i)); | 5307 __ LoadHeapObject(prototype_reg, prototypes->at(i)); |
| 5336 __ ldr(map_reg, FieldMemOperand(prototype_reg, HeapObject::kMapOffset)); | 5308 __ ldr(map_reg, FieldMemOperand(prototype_reg, HeapObject::kMapOffset)); |
| 5337 DoCheckMapCommon(map_reg, maps->at(i), instr->environment()); | 5309 DoCheckMapCommon(map_reg, maps->at(i), instr->environment()); |
| 5338 } | 5310 } |
| 5339 } | 5311 } |
| 5340 } | 5312 } |
| 5341 | 5313 |
| 5342 | 5314 |
| 5343 void LCodeGen::DoAllocateObject(LAllocateObject* instr) { | |
| 5344 class DeferredAllocateObject: public LDeferredCode { | |
| 5345 public: | |
| 5346 DeferredAllocateObject(LCodeGen* codegen, LAllocateObject* instr) | |
| 5347 : LDeferredCode(codegen), instr_(instr) { } | |
| 5348 virtual void Generate() { codegen()->DoDeferredAllocateObject(instr_); } | |
| 5349 virtual LInstruction* instr() { return instr_; } | |
| 5350 private: | |
| 5351 LAllocateObject* instr_; | |
| 5352 }; | |
| 5353 | |
| 5354 DeferredAllocateObject* deferred = | |
| 5355 new(zone()) DeferredAllocateObject(this, instr); | |
| 5356 | |
| 5357 Register result = ToRegister(instr->result()); | |
| 5358 Register scratch = ToRegister(instr->temp()); | |
| 5359 Register scratch2 = ToRegister(instr->temp2()); | |
| 5360 Handle<JSFunction> constructor = instr->hydrogen()->constructor(); | |
| 5361 Handle<Map> initial_map = instr->hydrogen()->constructor_initial_map(); | |
| 5362 int instance_size = initial_map->instance_size(); | |
| 5363 ASSERT(initial_map->pre_allocated_property_fields() + | |
| 5364 initial_map->unused_property_fields() - | |
| 5365 initial_map->inobject_properties() == 0); | |
| 5366 | |
| 5367 __ Allocate(instance_size, result, scratch, scratch2, deferred->entry(), | |
| 5368 TAG_OBJECT); | |
| 5369 | |
| 5370 __ bind(deferred->exit()); | |
| 5371 if (FLAG_debug_code) { | |
| 5372 Label is_in_new_space; | |
| 5373 __ JumpIfInNewSpace(result, scratch, &is_in_new_space); | |
| 5374 __ Abort("Allocated object is not in new-space"); | |
| 5375 __ bind(&is_in_new_space); | |
| 5376 } | |
| 5377 | |
| 5378 // Load the initial map. | |
| 5379 Register map = scratch; | |
| 5380 __ LoadHeapObject(map, constructor); | |
| 5381 __ ldr(map, FieldMemOperand(map, JSFunction::kPrototypeOrInitialMapOffset)); | |
| 5382 | |
| 5383 // Initialize map and fields of the newly allocated object. | |
| 5384 ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE); | |
| 5385 __ str(map, FieldMemOperand(result, JSObject::kMapOffset)); | |
| 5386 __ LoadRoot(scratch, Heap::kEmptyFixedArrayRootIndex); | |
| 5387 __ str(scratch, FieldMemOperand(result, JSObject::kElementsOffset)); | |
| 5388 __ str(scratch, FieldMemOperand(result, JSObject::kPropertiesOffset)); | |
| 5389 if (initial_map->inobject_properties() != 0) { | |
| 5390 __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex); | |
| 5391 for (int i = 0; i < initial_map->inobject_properties(); i++) { | |
| 5392 int property_offset = JSObject::kHeaderSize + i * kPointerSize; | |
| 5393 __ str(scratch, FieldMemOperand(result, property_offset)); | |
| 5394 } | |
| 5395 } | |
| 5396 } | |
| 5397 | |
| 5398 | |
| 5399 void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) { | |
| 5400 Register result = ToRegister(instr->result()); | |
| 5401 Handle<Map> initial_map = instr->hydrogen()->constructor_initial_map(); | |
| 5402 int instance_size = initial_map->instance_size(); | |
| 5403 | |
| 5404 // TODO(3095996): Get rid of this. For now, we need to make the | |
| 5405 // result register contain a valid pointer because it is already | |
| 5406 // contained in the register pointer map. | |
| 5407 __ mov(result, Operand::Zero()); | |
| 5408 | |
| 5409 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); | |
| 5410 __ mov(r0, Operand(Smi::FromInt(instance_size))); | |
| 5411 __ push(r0); | |
| 5412 CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr); | |
| 5413 __ StoreToSafepointRegisterSlot(r0, result); | |
| 5414 } | |
| 5415 | |
| 5416 | |
| 5417 void LCodeGen::DoAllocate(LAllocate* instr) { | 5315 void LCodeGen::DoAllocate(LAllocate* instr) { |
| 5418 class DeferredAllocate: public LDeferredCode { | 5316 class DeferredAllocate: public LDeferredCode { |
| 5419 public: | 5317 public: |
| 5420 DeferredAllocate(LCodeGen* codegen, LAllocate* instr) | 5318 DeferredAllocate(LCodeGen* codegen, LAllocate* instr) |
| 5421 : LDeferredCode(codegen), instr_(instr) { } | 5319 : LDeferredCode(codegen), instr_(instr) { } |
| 5422 virtual void Generate() { codegen()->DoDeferredAllocate(instr_); } | 5320 virtual void Generate() { codegen()->DoDeferredAllocate(instr_); } |
| 5423 virtual LInstruction* instr() { return instr_; } | 5321 virtual LInstruction* instr() { return instr_; } |
| 5424 private: | 5322 private: |
| 5425 LAllocate* instr_; | 5323 LAllocate* instr_; |
| 5426 }; | 5324 }; |
| (...skipping 469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5896 __ sub(scratch, result, Operand::PointerOffsetFromSmiKey(index)); | 5794 __ sub(scratch, result, Operand::PointerOffsetFromSmiKey(index)); |
| 5897 __ ldr(result, FieldMemOperand(scratch, | 5795 __ ldr(result, FieldMemOperand(scratch, |
| 5898 FixedArray::kHeaderSize - kPointerSize)); | 5796 FixedArray::kHeaderSize - kPointerSize)); |
| 5899 __ bind(&done); | 5797 __ bind(&done); |
| 5900 } | 5798 } |
| 5901 | 5799 |
| 5902 | 5800 |
| 5903 #undef __ | 5801 #undef __ |
| 5904 | 5802 |
| 5905 } } // namespace v8::internal | 5803 } } // namespace v8::internal |
| OLD | NEW |