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 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
112 int length = builder.position(); | 112 int length = builder.position(); |
113 Vector<char> copy = Vector<char>::New(length + 1); | 113 Vector<char> copy = Vector<char>::New(length + 1); |
114 memcpy(copy.start(), builder.Finalize(), copy.length()); | 114 memcpy(copy.start(), builder.Finalize(), copy.length()); |
115 masm()->RecordComment(copy.start()); | 115 masm()->RecordComment(copy.start()); |
116 } | 116 } |
117 | 117 |
118 | 118 |
119 bool LCodeGen::GeneratePrologue() { | 119 bool LCodeGen::GeneratePrologue() { |
120 ASSERT(is_generating()); | 120 ASSERT(is_generating()); |
121 | 121 |
122 ProfileEntryHookStub::MaybeCallEntryHook(masm_); | 122 if (info()->IsOptimizing()) { |
123 ProfileEntryHookStub::MaybeCallEntryHook(masm_); | |
123 | 124 |
124 #ifdef DEBUG | 125 #ifdef DEBUG |
125 if (strlen(FLAG_stop_at) > 0 && | 126 if (strlen(FLAG_stop_at) > 0 && |
126 info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { | 127 info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { |
127 __ int3(); | 128 __ int3(); |
128 } | 129 } |
129 #endif | 130 #endif |
130 | 131 |
131 // Strict mode functions need to replace the receiver with undefined | 132 // Strict mode functions need to replace the receiver with undefined |
132 // when called as functions (without an explicit receiver | 133 // when called as functions (without an explicit receiver |
133 // object). rcx is zero for method calls and non-zero for function | 134 // object). rcx is zero for method calls and non-zero for function |
134 // calls. | 135 // calls. |
135 if (!info_->is_classic_mode() || info_->is_native()) { | 136 if (!info_->is_classic_mode() || info_->is_native()) { |
136 Label begin; | 137 Label begin; |
137 __ bind(&begin); | 138 __ bind(&begin); |
138 Label ok; | 139 Label ok; |
139 __ testq(rcx, rcx); | 140 __ testq(rcx, rcx); |
140 __ j(zero, &ok, Label::kNear); | 141 __ j(zero, &ok, Label::kNear); |
141 // +1 for return address. | 142 // +1 for return address. |
142 int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize; | 143 int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize; |
143 __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex); | 144 __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex); |
144 __ movq(Operand(rsp, receiver_offset), kScratchRegister); | 145 __ movq(Operand(rsp, receiver_offset), kScratchRegister); |
145 __ bind(&ok); | 146 __ bind(&ok); |
146 ASSERT(!FLAG_age_code || | 147 ASSERT(!FLAG_age_code || |
147 (kSizeOfOptimizedStrictModePrologue == ok.pos() - begin.pos())); | 148 (kSizeOfOptimizedStrictModePrologue == ok.pos() - begin.pos())); |
149 } | |
148 } | 150 } |
149 | 151 |
150 __ push(rbp); // Caller's frame pointer. | 152 if (NeedsEagerFrame()) { |
151 __ movq(rbp, rsp); | 153 ASSERT(!frame_is_built_); |
152 __ push(rsi); // Callee's context. | 154 frame_is_built_ = true; |
153 __ push(rdi); // Callee's JS function. | 155 __ push(rbp); // Caller's frame pointer. |
156 __ movq(rbp, rsp); | |
157 if (info()->IsStub()) { | |
158 __ push(rsi); // Callee's context. | |
Jakob Kummerow
2012/11/28 16:28:22
nit: could hoist this out of the if/else blocks.
danno
2012/11/30 16:23:24
Done.
| |
159 __ Push(Smi::FromInt(StackFrame::STUB)); | |
160 } else { | |
161 __ push(rsi); // Callee's context. | |
162 __ push(rdi); // Callee's JS function. | |
163 } | |
164 } | |
154 | 165 |
155 // Reserve space for the stack slots needed by the code. | 166 // Reserve space for the stack slots needed by the code. |
156 int slots = GetStackSlotCount(); | 167 int slots = GetStackSlotCount(); |
157 if (slots > 0) { | 168 if (slots > 0) { |
158 if (FLAG_debug_code) { | 169 if (FLAG_debug_code) { |
159 __ Set(rax, slots); | 170 __ Set(rax, slots); |
160 __ movq(kScratchRegister, kSlotsZapValue, RelocInfo::NONE); | 171 __ movq(kScratchRegister, kSlotsZapValue, RelocInfo::NONE); |
161 Label loop; | 172 Label loop; |
162 __ bind(&loop); | 173 __ bind(&loop); |
163 __ push(kScratchRegister); | 174 __ push(kScratchRegister); |
164 __ decl(rax); | 175 __ decl(rax); |
165 __ j(not_zero, &loop); | 176 __ j(not_zero, &loop); |
166 } else { | 177 } else { |
167 __ subq(rsp, Immediate(slots * kPointerSize)); | 178 __ subq(rsp, Immediate(slots * kPointerSize)); |
168 #ifdef _MSC_VER | 179 #ifdef _MSC_VER |
169 // On windows, you may not access the stack more than one page below | 180 // On windows, you may not access the stack more than one page below |
170 // the most recently mapped page. To make the allocated area randomly | 181 // the most recently mapped page. To make the allocated area randomly |
171 // accessible, we write to each page in turn (the value is irrelevant). | 182 // accessible, we write to each page in turn (the value is irrelevant). |
172 const int kPageSize = 4 * KB; | 183 const int kPageSize = 4 * KB; |
173 for (int offset = slots * kPointerSize - kPageSize; | 184 for (int offset = slots * kPointerSize - kPageSize; |
174 offset > 0; | 185 offset > 0; |
175 offset -= kPageSize) { | 186 offset -= kPageSize) { |
176 __ movq(Operand(rsp, offset), rax); | 187 __ movq(Operand(rsp, offset), rax); |
177 } | 188 } |
178 #endif | 189 #endif |
179 } | 190 } |
180 } | 191 } |
181 | 192 |
182 // Possibly allocate a local context. | 193 // Possibly allocate a local context. |
183 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; | 194 int heap_slots = info_->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
184 if (heap_slots > 0) { | 195 if (heap_slots > 0) { |
185 Comment(";;; Allocate local context"); | 196 Comment(";;; Allocate local context"); |
186 // Argument to NewContext is the function, which is still in rdi. | 197 // Argument to NewContext is the function, which is still in rdi. |
187 __ push(rdi); | 198 __ push(rdi); |
188 if (heap_slots <= FastNewContextStub::kMaximumSlots) { | 199 if (heap_slots <= FastNewContextStub::kMaximumSlots) { |
189 FastNewContextStub stub(heap_slots); | 200 FastNewContextStub stub(heap_slots); |
190 __ CallStub(&stub); | 201 __ CallStub(&stub); |
191 } else { | 202 } else { |
192 __ CallRuntime(Runtime::kNewFunctionContext, 1); | 203 __ CallRuntime(Runtime::kNewFunctionContext, 1); |
193 } | 204 } |
(...skipping 15 matching lines...) Expand all Loading... | |
209 int context_offset = Context::SlotOffset(var->index()); | 220 int context_offset = Context::SlotOffset(var->index()); |
210 __ movq(Operand(rsi, context_offset), rax); | 221 __ movq(Operand(rsi, context_offset), rax); |
211 // Update the write barrier. This clobbers rax and rbx. | 222 // Update the write barrier. This clobbers rax and rbx. |
212 __ RecordWriteContextSlot(rsi, context_offset, rax, rbx, kSaveFPRegs); | 223 __ RecordWriteContextSlot(rsi, context_offset, rax, rbx, kSaveFPRegs); |
213 } | 224 } |
214 } | 225 } |
215 Comment(";;; End allocate local context"); | 226 Comment(";;; End allocate local context"); |
216 } | 227 } |
217 | 228 |
218 // Trace the call. | 229 // Trace the call. |
219 if (FLAG_trace) { | 230 if (FLAG_trace && info()->IsOptimizing()) { |
220 __ CallRuntime(Runtime::kTraceEnter, 0); | 231 __ CallRuntime(Runtime::kTraceEnter, 0); |
221 } | 232 } |
222 return !is_aborted(); | 233 return !is_aborted(); |
223 } | 234 } |
224 | 235 |
225 | 236 |
226 bool LCodeGen::GenerateBody() { | 237 bool LCodeGen::GenerateBody() { |
227 ASSERT(is_generating()); | 238 ASSERT(is_generating()); |
228 bool emit_instructions = true; | 239 bool emit_instructions = true; |
229 for (current_instruction_ = 0; | 240 for (current_instruction_ = 0; |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
262 } | 273 } |
263 instr->CompileToNative(this); | 274 instr->CompileToNative(this); |
264 } | 275 } |
265 } | 276 } |
266 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size()); | 277 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size()); |
267 return !is_aborted(); | 278 return !is_aborted(); |
268 } | 279 } |
269 | 280 |
270 | 281 |
271 bool LCodeGen::GenerateJumpTable() { | 282 bool LCodeGen::GenerateJumpTable() { |
283 Label needs_frame_not_call; | |
284 bool has_generated_needs_frame_not_call = false; | |
Jakob Kummerow
2012/11/28 16:28:22
see comments on ia32 version. In short:
1) if you
danno
2012/11/30 16:23:24
Done.
| |
285 Label needs_frame_is_call; | |
286 bool has_generated_needs_frame_is_call = false; | |
272 for (int i = 0; i < jump_table_.length(); i++) { | 287 for (int i = 0; i < jump_table_.length(); i++) { |
273 __ bind(&jump_table_[i].label); | 288 __ bind(&jump_table_[i].label); |
274 __ Jump(jump_table_[i].address, RelocInfo::RUNTIME_ENTRY); | 289 Address entry = jump_table_[i].address; |
290 if (jump_table_[i].needs_frame) { | |
291 __ movq(kScratchRegister, ExternalReference::ForDeoptEntry(entry)); | |
292 if (jump_table_[i].is_lazy_deopt) { | |
293 if (!has_generated_needs_frame_is_call) { | |
294 has_generated_needs_frame_is_call = true; | |
295 __ bind(&needs_frame_is_call); | |
296 __ push(rbp); | |
297 __ movq(rbp, rsp); | |
298 __ push(rsi); | |
299 // If there is not frame, we don't have access to the JSFunction that | |
300 // needs to be put into the frame. | |
301 ASSERT(info()->IsStub()); | |
302 __ Move(rsi, Smi::FromInt(StackFrame::STUB)); | |
303 __ push(rsi); | |
304 __ movq(rsi, MemOperand(rsp, kPointerSize)); | |
305 __ call(kScratchRegister); | |
306 } else { | |
307 __ jmp(&needs_frame_is_call); | |
308 } | |
309 } else { | |
310 if (!has_generated_needs_frame_not_call) { | |
311 has_generated_needs_frame_not_call = true; | |
312 __ bind(&needs_frame_not_call); | |
313 __ push(rbp); | |
314 __ movq(rbp, rsp); | |
315 __ push(r8); | |
316 // If there is not frame, we don't have access to the JSFunction that | |
317 // needs to be put into the frame. | |
318 ASSERT(info()->IsStub()); | |
319 __ Move(rsi, Smi::FromInt(StackFrame::STUB)); | |
320 __ push(rsi); | |
321 __ movq(rsi, MemOperand(rsp, kPointerSize)); | |
322 __ jmp(kScratchRegister); | |
323 } else { | |
324 __ jmp(&needs_frame_not_call); | |
325 } | |
326 } | |
327 } else { | |
328 if (jump_table_[i].is_lazy_deopt) { | |
329 __ Call(entry, RelocInfo::RUNTIME_ENTRY); | |
330 } else { | |
331 __ Jump(entry, RelocInfo::RUNTIME_ENTRY); | |
332 } | |
333 } | |
275 } | 334 } |
276 return !is_aborted(); | 335 return !is_aborted(); |
277 } | 336 } |
278 | 337 |
279 | 338 |
280 bool LCodeGen::GenerateDeferredCode() { | 339 bool LCodeGen::GenerateDeferredCode() { |
281 ASSERT(is_generating()); | 340 ASSERT(is_generating()); |
282 if (deferred_.length() > 0) { | 341 if (deferred_.length() > 0) { |
283 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { | 342 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { |
284 LDeferredCode* code = deferred_[i]; | 343 LDeferredCode* code = deferred_[i]; |
285 __ bind(code->entry()); | 344 __ bind(code->entry()); |
345 if (NeedsDeferredFrame()) { | |
346 Comment(";;; Deferred build frame", | |
347 code->instruction_index(), | |
348 code->instr()->Mnemonic()); | |
349 ASSERT(!frame_is_built_); | |
350 ASSERT(info()->IsStub()); | |
351 frame_is_built_ = true; | |
352 // Build the frame in such a way that esi isn't trashed. | |
353 __ push(rbp); // Caller's frame pointer. | |
354 __ push(Operand(rbp, StandardFrameConstants::kContextOffset)); | |
355 __ Push(Smi::FromInt(StackFrame::STUB)); | |
356 __ lea(rbp, Operand(rsp, 2 * kPointerSize)); | |
357 } | |
286 Comment(";;; Deferred code @%d: %s.", | 358 Comment(";;; Deferred code @%d: %s.", |
287 code->instruction_index(), | 359 code->instruction_index(), |
288 code->instr()->Mnemonic()); | 360 code->instr()->Mnemonic()); |
289 code->Generate(); | 361 code->Generate(); |
362 if (NeedsDeferredFrame()) { | |
363 Comment(";;; Deferred destory frame", | |
Jakob Kummerow
2012/11/28 16:28:22
nit: "destroy"
danno
2012/11/30 16:23:24
Done.
| |
364 code->instruction_index(), | |
365 code->instr()->Mnemonic()); | |
366 ASSERT(frame_is_built_); | |
367 frame_is_built_ = false; | |
368 __ movq(rsp, rbp); | |
369 __ pop(rbp); | |
370 } | |
290 __ jmp(code->exit()); | 371 __ jmp(code->exit()); |
291 } | 372 } |
292 } | 373 } |
293 | 374 |
294 // Deferred code is the last part of the instruction sequence. Mark | 375 // Deferred code is the last part of the instruction sequence. Mark |
295 // the generated code as done unless we bailed out. | 376 // the generated code as done unless we bailed out. |
296 if (!is_aborted()) status_ = DONE; | 377 if (!is_aborted()) status_ = DONE; |
297 return !is_aborted(); | 378 return !is_aborted(); |
298 } | 379 } |
299 | 380 |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
392 // arguments index points to the first element of a sequence of tagged | 473 // arguments index points to the first element of a sequence of tagged |
393 // values on the stack that represent the arguments. This needs to be | 474 // values on the stack that represent the arguments. This needs to be |
394 // kept in sync with the LArgumentsElements implementation. | 475 // kept in sync with the LArgumentsElements implementation. |
395 *arguments_index = -environment->parameter_count(); | 476 *arguments_index = -environment->parameter_count(); |
396 *arguments_count = environment->parameter_count(); | 477 *arguments_count = environment->parameter_count(); |
397 | 478 |
398 WriteTranslation(environment->outer(), | 479 WriteTranslation(environment->outer(), |
399 translation, | 480 translation, |
400 arguments_index, | 481 arguments_index, |
401 arguments_count); | 482 arguments_count); |
402 int closure_id = *info()->closure() != *environment->closure() | 483 bool has_closure_id = !info()->closure().is_null() && |
484 *info()->closure() != *environment->closure(); | |
485 int closure_id = has_closure_id | |
403 ? DefineDeoptimizationLiteral(environment->closure()) | 486 ? DefineDeoptimizationLiteral(environment->closure()) |
404 : Translation::kSelfLiteralId; | 487 : Translation::kSelfLiteralId; |
405 | 488 |
406 switch (environment->frame_type()) { | 489 switch (environment->frame_type()) { |
407 case JS_FUNCTION: | 490 case JS_FUNCTION: |
408 translation->BeginJSFrame(environment->ast_id(), closure_id, height); | 491 translation->BeginJSFrame(environment->ast_id(), closure_id, height); |
409 break; | 492 break; |
410 case JS_CONSTRUCT: | 493 case JS_CONSTRUCT: |
411 translation->BeginConstructStubFrame(closure_id, translation_size); | 494 translation->BeginConstructStubFrame(closure_id, translation_size); |
412 break; | 495 break; |
413 case JS_GETTER: | 496 case JS_GETTER: |
414 ASSERT(translation_size == 1); | 497 ASSERT(translation_size == 1); |
415 ASSERT(height == 0); | 498 ASSERT(height == 0); |
416 translation->BeginGetterStubFrame(closure_id); | 499 translation->BeginGetterStubFrame(closure_id); |
417 break; | 500 break; |
418 case JS_SETTER: | 501 case JS_SETTER: |
419 ASSERT(translation_size == 2); | 502 ASSERT(translation_size == 2); |
420 ASSERT(height == 0); | 503 ASSERT(height == 0); |
421 translation->BeginSetterStubFrame(closure_id); | 504 translation->BeginSetterStubFrame(closure_id); |
422 break; | 505 break; |
423 case ARGUMENTS_ADAPTOR: | 506 case ARGUMENTS_ADAPTOR: |
424 translation->BeginArgumentsAdaptorFrame(closure_id, translation_size); | 507 translation->BeginArgumentsAdaptorFrame(closure_id, translation_size); |
425 break; | 508 break; |
509 case STUB: | |
510 translation->BeginCompiledStubFrame(); | |
511 break; | |
426 } | 512 } |
427 | 513 |
428 // Inlined frames which push their arguments cause the index to be | 514 // Inlined frames which push their arguments cause the index to be |
429 // bumped and a new stack area to be used for materialization. | 515 // bumped and a new stack area to be used for materialization. |
430 if (environment->entry() != NULL && | 516 if (environment->entry() != NULL && |
431 environment->entry()->arguments_pushed()) { | 517 environment->entry()->arguments_pushed()) { |
432 *arguments_index = *arguments_index < 0 | 518 *arguments_index = *arguments_index < 0 |
433 ? GetStackSlotCount() | 519 ? GetStackSlotCount() |
434 : *arguments_index + *arguments_count; | 520 : *arguments_index + *arguments_count; |
435 *arguments_count = environment->entry()->arguments_count() + 1; | 521 *arguments_count = environment->entry()->arguments_count() + 1; |
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
606 (mode == Safepoint::kLazyDeopt) ? pc_offset : -1); | 692 (mode == Safepoint::kLazyDeopt) ? pc_offset : -1); |
607 deoptimizations_.Add(environment, environment->zone()); | 693 deoptimizations_.Add(environment, environment->zone()); |
608 } | 694 } |
609 } | 695 } |
610 | 696 |
611 | 697 |
612 void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) { | 698 void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) { |
613 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); | 699 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); |
614 ASSERT(environment->HasBeenRegistered()); | 700 ASSERT(environment->HasBeenRegistered()); |
615 int id = environment->deoptimization_index(); | 701 int id = environment->deoptimization_index(); |
616 Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER); | 702 ASSERT(info()->IsOptimizing() || info()->IsStub()); |
703 Deoptimizer::BailoutType bailout_type = info()->IsStub() | |
704 ? Deoptimizer::LAZY | |
705 : Deoptimizer::EAGER; | |
706 Address entry = Deoptimizer::GetDeoptimizationEntry(id, bailout_type); | |
617 if (entry == NULL) { | 707 if (entry == NULL) { |
618 Abort("bailout was not prepared"); | 708 Abort("bailout was not prepared"); |
619 return; | 709 return; |
620 } | 710 } |
621 | 711 |
712 ASSERT(info()->IsStub() || frame_is_built_); | |
713 bool lazy_deopt = info()->IsStub(); | |
622 if (cc == no_condition) { | 714 if (cc == no_condition) { |
623 __ Jump(entry, RelocInfo::RUNTIME_ENTRY); | 715 if (lazy_deopt) { |
716 __ Call(entry, RelocInfo::RUNTIME_ENTRY); | |
717 } else { | |
718 __ Jump(entry, RelocInfo::RUNTIME_ENTRY); | |
719 } | |
624 } else { | 720 } else { |
625 // We often have several deopts to the same entry, reuse the last | 721 // We often have several deopts to the same entry, reuse the last |
626 // jump entry if this is the case. | 722 // jump entry if this is the case. |
627 if (jump_table_.is_empty() || | 723 if (jump_table_.is_empty() || |
628 jump_table_.last().address != entry) { | 724 jump_table_.last().address != entry || |
629 jump_table_.Add(JumpTableEntry(entry), zone()); | 725 jump_table_.last().needs_frame != !frame_is_built_ || |
726 jump_table_.last().is_lazy_deopt != lazy_deopt) { | |
727 JumpTableEntry table_entry(entry, !frame_is_built_, lazy_deopt); | |
728 jump_table_.Add(table_entry, zone()); | |
630 } | 729 } |
631 __ j(cc, &jump_table_.last().label); | 730 __ j(cc, &jump_table_.last().label); |
632 } | 731 } |
633 } | 732 } |
634 | 733 |
635 | 734 |
636 void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) { | 735 void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) { |
637 int length = deoptimizations_.length(); | 736 int length = deoptimizations_.length(); |
638 if (length == 0) return; | 737 if (length == 0) return; |
639 Handle<DeoptimizationInputData> data = | 738 Handle<DeoptimizationInputData> data = |
(...skipping 1644 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2284 __ j(condition, &true_value, Label::kNear); | 2383 __ j(condition, &true_value, Label::kNear); |
2285 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex); | 2384 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex); |
2286 __ jmp(&done, Label::kNear); | 2385 __ jmp(&done, Label::kNear); |
2287 __ bind(&true_value); | 2386 __ bind(&true_value); |
2288 __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex); | 2387 __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex); |
2289 __ bind(&done); | 2388 __ bind(&done); |
2290 } | 2389 } |
2291 | 2390 |
2292 | 2391 |
2293 void LCodeGen::DoReturn(LReturn* instr) { | 2392 void LCodeGen::DoReturn(LReturn* instr) { |
2294 if (FLAG_trace) { | 2393 if (FLAG_trace && info()->IsOptimizing()) { |
2295 // Preserve the return value on the stack and rely on the runtime | 2394 // Preserve the return value on the stack and rely on the runtime |
2296 // call to return the value in the same register. | 2395 // call to return the value in the same register. |
2297 __ push(rax); | 2396 __ push(rax); |
2298 __ CallRuntime(Runtime::kTraceExit, 1); | 2397 __ CallRuntime(Runtime::kTraceExit, 1); |
2299 } | 2398 } |
2300 __ movq(rsp, rbp); | 2399 if (NeedsEagerFrame()) { |
2301 __ pop(rbp); | 2400 __ movq(rsp, rbp); |
2302 __ Ret((GetParameterCount() + 1) * kPointerSize, rcx); | 2401 __ pop(rbp); |
2402 } | |
2403 if (info()->IsStub()) { | |
2404 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | |
2405 __ Ret(0, r10); | |
2406 } else { | |
2407 __ Ret((GetParameterCount() + 1) * kPointerSize, rcx); | |
2408 } | |
2303 } | 2409 } |
2304 | 2410 |
2305 | 2411 |
2306 void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) { | 2412 void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) { |
2307 Register result = ToRegister(instr->result()); | 2413 Register result = ToRegister(instr->result()); |
2308 __ LoadGlobalCell(result, instr->hydrogen()->cell()); | 2414 __ LoadGlobalCell(result, instr->hydrogen()->cell()); |
2309 if (instr->hydrogen()->RequiresHoleCheck()) { | 2415 if (instr->hydrogen()->RequiresHoleCheck()) { |
2310 __ CompareRoot(result, Heap::kTheHoleValueRootIndex); | 2416 __ CompareRoot(result, Heap::kTheHoleValueRootIndex); |
2311 DeoptimizeIf(equal, instr->environment()); | 2417 DeoptimizeIf(equal, instr->environment()); |
2312 } | 2418 } |
(...skipping 2210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4523 } else { | 4629 } else { |
4524 __ Cmp(reg, target); | 4630 __ Cmp(reg, target); |
4525 } | 4631 } |
4526 DeoptimizeIf(not_equal, instr->environment()); | 4632 DeoptimizeIf(not_equal, instr->environment()); |
4527 } | 4633 } |
4528 | 4634 |
4529 | 4635 |
4530 void LCodeGen::DoCheckMapCommon(Register reg, | 4636 void LCodeGen::DoCheckMapCommon(Register reg, |
4531 Handle<Map> map, | 4637 Handle<Map> map, |
4532 CompareMapMode mode, | 4638 CompareMapMode mode, |
4533 LEnvironment* env) { | 4639 LInstruction* instr) { |
4534 Label success; | 4640 Label success; |
4535 __ CompareMap(reg, map, &success, mode); | 4641 __ CompareMap(reg, map, &success, mode); |
4536 DeoptimizeIf(not_equal, env); | 4642 DeoptimizeIf(not_equal, instr->environment()); |
4537 __ bind(&success); | 4643 __ bind(&success); |
4538 } | 4644 } |
4539 | 4645 |
4540 | 4646 |
4541 void LCodeGen::DoCheckMaps(LCheckMaps* instr) { | 4647 void LCodeGen::DoCheckMaps(LCheckMaps* instr) { |
4542 LOperand* input = instr->value(); | 4648 LOperand* input = instr->value(); |
4543 ASSERT(input->IsRegister()); | 4649 ASSERT(input->IsRegister()); |
4544 Register reg = ToRegister(input); | 4650 Register reg = ToRegister(input); |
4545 | 4651 |
4546 Label success; | 4652 Label success; |
4547 SmallMapList* map_set = instr->hydrogen()->map_set(); | 4653 SmallMapList* map_set = instr->hydrogen()->map_set(); |
4548 for (int i = 0; i < map_set->length() - 1; i++) { | 4654 for (int i = 0; i < map_set->length() - 1; i++) { |
4549 Handle<Map> map = map_set->at(i); | 4655 Handle<Map> map = map_set->at(i); |
4550 __ CompareMap(reg, map, &success, REQUIRE_EXACT_MAP); | 4656 __ CompareMap(reg, map, &success, REQUIRE_EXACT_MAP); |
4551 __ j(equal, &success); | 4657 __ j(equal, &success); |
4552 } | 4658 } |
4553 Handle<Map> map = map_set->last(); | 4659 Handle<Map> map = map_set->last(); |
4554 DoCheckMapCommon(reg, map, REQUIRE_EXACT_MAP, instr->environment()); | 4660 DoCheckMapCommon(reg, map, REQUIRE_EXACT_MAP, instr); |
4555 __ bind(&success); | 4661 __ bind(&success); |
4556 } | 4662 } |
4557 | 4663 |
4558 | 4664 |
4559 void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) { | 4665 void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) { |
4560 XMMRegister value_reg = ToDoubleRegister(instr->unclamped()); | 4666 XMMRegister value_reg = ToDoubleRegister(instr->unclamped()); |
4561 Register result_reg = ToRegister(instr->result()); | 4667 Register result_reg = ToRegister(instr->result()); |
4562 __ ClampDoubleToUint8(value_reg, xmm0, result_reg); | 4668 __ ClampDoubleToUint8(value_reg, xmm0, result_reg); |
4563 } | 4669 } |
4564 | 4670 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4611 | 4717 |
4612 Handle<JSObject> holder = instr->holder(); | 4718 Handle<JSObject> holder = instr->holder(); |
4613 Handle<JSObject> current_prototype = instr->prototype(); | 4719 Handle<JSObject> current_prototype = instr->prototype(); |
4614 | 4720 |
4615 // Load prototype object. | 4721 // Load prototype object. |
4616 __ LoadHeapObject(reg, current_prototype); | 4722 __ LoadHeapObject(reg, current_prototype); |
4617 | 4723 |
4618 // Check prototype maps up to the holder. | 4724 // Check prototype maps up to the holder. |
4619 while (!current_prototype.is_identical_to(holder)) { | 4725 while (!current_prototype.is_identical_to(holder)) { |
4620 DoCheckMapCommon(reg, Handle<Map>(current_prototype->map()), | 4726 DoCheckMapCommon(reg, Handle<Map>(current_prototype->map()), |
4621 ALLOW_ELEMENT_TRANSITION_MAPS, instr->environment()); | 4727 ALLOW_ELEMENT_TRANSITION_MAPS, instr); |
4622 current_prototype = | 4728 current_prototype = |
4623 Handle<JSObject>(JSObject::cast(current_prototype->GetPrototype())); | 4729 Handle<JSObject>(JSObject::cast(current_prototype->GetPrototype())); |
4624 // Load next prototype object. | 4730 // Load next prototype object. |
4625 __ LoadHeapObject(reg, current_prototype); | 4731 __ LoadHeapObject(reg, current_prototype); |
4626 } | 4732 } |
4627 | 4733 |
4628 // Check the holder map. | 4734 // Check the holder map. |
4629 DoCheckMapCommon(reg, Handle<Map>(current_prototype->map()), | 4735 DoCheckMapCommon(reg, Handle<Map>(current_prototype->map()), |
4630 ALLOW_ELEMENT_TRANSITION_MAPS, instr->environment()); | 4736 ALLOW_ELEMENT_TRANSITION_MAPS, instr); |
4631 } | 4737 } |
4632 | 4738 |
4633 | 4739 |
4634 void LCodeGen::DoAllocateObject(LAllocateObject* instr) { | 4740 void LCodeGen::DoAllocateObject(LAllocateObject* instr) { |
4635 class DeferredAllocateObject: public LDeferredCode { | 4741 class DeferredAllocateObject: public LDeferredCode { |
4636 public: | 4742 public: |
4637 DeferredAllocateObject(LCodeGen* codegen, LAllocateObject* instr) | 4743 DeferredAllocateObject(LCodeGen* codegen, LAllocateObject* instr) |
4638 : LDeferredCode(codegen), instr_(instr) { } | 4744 : LDeferredCode(codegen), instr_(instr) { } |
4639 virtual void Generate() { codegen()->DoDeferredAllocateObject(instr_); } | 4745 virtual void Generate() { codegen()->DoDeferredAllocateObject(instr_); } |
4640 virtual LInstruction* instr() { return instr_; } | 4746 virtual LInstruction* instr() { return instr_; } |
(...skipping 515 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5156 __ movq(temp, Operand(rax, StandardFrameConstants::kCallerFPOffset)); | 5262 __ movq(temp, Operand(rax, StandardFrameConstants::kCallerFPOffset)); |
5157 | 5263 |
5158 // Check the marker in the calling frame. | 5264 // Check the marker in the calling frame. |
5159 __ bind(&check_frame_marker); | 5265 __ bind(&check_frame_marker); |
5160 __ Cmp(Operand(temp, StandardFrameConstants::kMarkerOffset), | 5266 __ Cmp(Operand(temp, StandardFrameConstants::kMarkerOffset), |
5161 Smi::FromInt(StackFrame::CONSTRUCT)); | 5267 Smi::FromInt(StackFrame::CONSTRUCT)); |
5162 } | 5268 } |
5163 | 5269 |
5164 | 5270 |
5165 void LCodeGen::EnsureSpaceForLazyDeopt(int space_needed) { | 5271 void LCodeGen::EnsureSpaceForLazyDeopt(int space_needed) { |
5272 if (info()->IsStub()) return; | |
5166 // Ensure that we have enough space after the previous lazy-bailout | 5273 // Ensure that we have enough space after the previous lazy-bailout |
5167 // instruction for patching the code here. | 5274 // instruction for patching the code here. |
5168 int current_pc = masm()->pc_offset(); | 5275 int current_pc = masm()->pc_offset(); |
5169 if (current_pc < last_lazy_deopt_pc_ + space_needed) { | 5276 if (current_pc < last_lazy_deopt_pc_ + space_needed) { |
5170 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc; | 5277 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc; |
5171 __ Nop(padding_size); | 5278 __ Nop(padding_size); |
5172 } | 5279 } |
5173 } | 5280 } |
5174 | 5281 |
5175 | 5282 |
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5381 FixedArray::kHeaderSize - kPointerSize)); | 5488 FixedArray::kHeaderSize - kPointerSize)); |
5382 __ bind(&done); | 5489 __ bind(&done); |
5383 } | 5490 } |
5384 | 5491 |
5385 | 5492 |
5386 #undef __ | 5493 #undef __ |
5387 | 5494 |
5388 } } // namespace v8::internal | 5495 } } // namespace v8::internal |
5389 | 5496 |
5390 #endif // V8_TARGET_ARCH_X64 | 5497 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |