OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
116 // o rdi: the JS function object being called (ie, ourselves) | 116 // o rdi: the JS function object being called (ie, ourselves) |
117 // o rsi: our context | 117 // o rsi: our context |
118 // o rbp: our caller's frame pointer | 118 // o rbp: our caller's frame pointer |
119 // o rsp: stack pointer (pointing to return address) | 119 // o rsp: stack pointer (pointing to return address) |
120 // | 120 // |
121 // The function builds a JS frame. Please see JavaScriptFrameConstants in | 121 // The function builds a JS frame. Please see JavaScriptFrameConstants in |
122 // frames-x64.h for its layout. | 122 // frames-x64.h for its layout. |
123 void FullCodeGenerator::Generate(CompilationInfo* info) { | 123 void FullCodeGenerator::Generate(CompilationInfo* info) { |
124 ASSERT(info_ == NULL); | 124 ASSERT(info_ == NULL); |
125 info_ = info; | 125 info_ = info; |
| 126 scope_ = info->scope(); |
126 SetFunctionPosition(function()); | 127 SetFunctionPosition(function()); |
127 Comment cmnt(masm_, "[ function compiled by full code generator"); | 128 Comment cmnt(masm_, "[ function compiled by full code generator"); |
128 | 129 |
129 #ifdef DEBUG | 130 #ifdef DEBUG |
130 if (strlen(FLAG_stop_at) > 0 && | 131 if (strlen(FLAG_stop_at) > 0 && |
131 info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { | 132 info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { |
132 __ int3(); | 133 __ int3(); |
133 } | 134 } |
134 #endif | 135 #endif |
135 | 136 |
136 // Strict mode functions and builtins need to replace the receiver | 137 // Strict mode functions and builtins need to replace the receiver |
137 // with undefined when called as functions (without an explicit | 138 // with undefined when called as functions (without an explicit |
138 // receiver object). rcx is zero for method calls and non-zero for | 139 // receiver object). rcx is zero for method calls and non-zero for |
139 // function calls. | 140 // function calls. |
140 if (info->is_strict_mode() || info->is_native()) { | 141 if (info->is_strict_mode() || info->is_native()) { |
141 Label ok; | 142 Label ok; |
142 __ testq(rcx, rcx); | 143 __ testq(rcx, rcx); |
143 __ j(zero, &ok, Label::kNear); | 144 __ j(zero, &ok, Label::kNear); |
144 // +1 for return address. | 145 // +1 for return address. |
145 int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize; | 146 int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize; |
146 __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex); | 147 __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex); |
147 __ movq(Operand(rsp, receiver_offset), kScratchRegister); | 148 __ movq(Operand(rsp, receiver_offset), kScratchRegister); |
148 __ bind(&ok); | 149 __ bind(&ok); |
149 } | 150 } |
150 | 151 |
151 __ push(rbp); // Caller's frame pointer. | 152 __ push(rbp); // Caller's frame pointer. |
152 __ movq(rbp, rsp); | 153 __ movq(rbp, rsp); |
153 __ push(rsi); // Callee's context. | 154 __ push(rsi); // Callee's context. |
154 __ push(rdi); // Callee's JS Function. | 155 __ push(rdi); // Callee's JS Function. |
155 | 156 |
156 { Comment cmnt(masm_, "[ Allocate locals"); | 157 { Comment cmnt(masm_, "[ Allocate locals"); |
157 int locals_count = scope()->num_stack_slots(); | 158 int locals_count = info->scope()->num_stack_slots(); |
158 if (locals_count == 1) { | 159 if (locals_count == 1) { |
159 __ PushRoot(Heap::kUndefinedValueRootIndex); | 160 __ PushRoot(Heap::kUndefinedValueRootIndex); |
160 } else if (locals_count > 1) { | 161 } else if (locals_count > 1) { |
161 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex); | 162 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex); |
162 for (int i = 0; i < locals_count; i++) { | 163 for (int i = 0; i < locals_count; i++) { |
163 __ push(rdx); | 164 __ push(rdx); |
164 } | 165 } |
165 } | 166 } |
166 } | 167 } |
167 | 168 |
168 bool function_in_register = true; | 169 bool function_in_register = true; |
169 | 170 |
170 // Possibly allocate a local context. | 171 // Possibly allocate a local context. |
171 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; | 172 int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
172 if (heap_slots > 0) { | 173 if (heap_slots > 0) { |
173 Comment cmnt(masm_, "[ Allocate local context"); | 174 Comment cmnt(masm_, "[ Allocate local context"); |
174 // Argument to NewContext is the function, which is still in rdi. | 175 // Argument to NewContext is the function, which is still in rdi. |
175 __ push(rdi); | 176 __ push(rdi); |
176 if (heap_slots <= FastNewContextStub::kMaximumSlots) { | 177 if (heap_slots <= FastNewContextStub::kMaximumSlots) { |
177 FastNewContextStub stub(heap_slots); | 178 FastNewContextStub stub(heap_slots); |
178 __ CallStub(&stub); | 179 __ CallStub(&stub); |
179 } else { | 180 } else { |
180 __ CallRuntime(Runtime::kNewFunctionContext, 1); | 181 __ CallRuntime(Runtime::kNewFunctionContext, 1); |
181 } | 182 } |
182 function_in_register = false; | 183 function_in_register = false; |
183 // Context is returned in both rax and rsi. It replaces the context | 184 // Context is returned in both rax and rsi. It replaces the context |
184 // passed to us. It's saved in the stack and kept live in rsi. | 185 // passed to us. It's saved in the stack and kept live in rsi. |
185 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi); | 186 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi); |
186 | 187 |
187 // Copy any necessary parameters into the context. | 188 // Copy any necessary parameters into the context. |
188 int num_parameters = scope()->num_parameters(); | 189 int num_parameters = info->scope()->num_parameters(); |
189 for (int i = 0; i < num_parameters; i++) { | 190 for (int i = 0; i < num_parameters; i++) { |
190 Slot* slot = scope()->parameter(i)->AsSlot(); | 191 Slot* slot = scope()->parameter(i)->AsSlot(); |
191 if (slot != NULL && slot->type() == Slot::CONTEXT) { | 192 if (slot != NULL && slot->type() == Slot::CONTEXT) { |
192 int parameter_offset = StandardFrameConstants::kCallerSPOffset + | 193 int parameter_offset = StandardFrameConstants::kCallerSPOffset + |
193 (num_parameters - 1 - i) * kPointerSize; | 194 (num_parameters - 1 - i) * kPointerSize; |
194 // Load parameter from stack. | 195 // Load parameter from stack. |
195 __ movq(rax, Operand(rbp, parameter_offset)); | 196 __ movq(rax, Operand(rbp, parameter_offset)); |
196 // Store it in the context. | 197 // Store it in the context. |
197 int context_offset = Context::SlotOffset(slot->index()); | 198 int context_offset = Context::SlotOffset(slot->index()); |
198 __ movq(Operand(rsi, context_offset), rax); | 199 __ movq(Operand(rsi, context_offset), rax); |
(...skipping 11 matching lines...) Expand all Loading... |
210 if (arguments != NULL) { | 211 if (arguments != NULL) { |
211 // Arguments object must be allocated after the context object, in | 212 // Arguments object must be allocated after the context object, in |
212 // case the "arguments" or ".arguments" variables are in the context. | 213 // case the "arguments" or ".arguments" variables are in the context. |
213 Comment cmnt(masm_, "[ Allocate arguments object"); | 214 Comment cmnt(masm_, "[ Allocate arguments object"); |
214 if (function_in_register) { | 215 if (function_in_register) { |
215 __ push(rdi); | 216 __ push(rdi); |
216 } else { | 217 } else { |
217 __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 218 __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
218 } | 219 } |
219 // The receiver is just before the parameters on the caller's stack. | 220 // The receiver is just before the parameters on the caller's stack. |
220 int offset = scope()->num_parameters() * kPointerSize; | 221 int num_parameters = info->scope()->num_parameters(); |
| 222 int offset = num_parameters * kPointerSize; |
221 __ lea(rdx, | 223 __ lea(rdx, |
222 Operand(rbp, StandardFrameConstants::kCallerSPOffset + offset)); | 224 Operand(rbp, StandardFrameConstants::kCallerSPOffset + offset)); |
223 __ push(rdx); | 225 __ push(rdx); |
224 __ Push(Smi::FromInt(scope()->num_parameters())); | 226 __ Push(Smi::FromInt(num_parameters)); |
225 // Arguments to ArgumentsAccessStub: | 227 // Arguments to ArgumentsAccessStub: |
226 // function, receiver address, parameter count. | 228 // function, receiver address, parameter count. |
227 // The stub will rewrite receiver and parameter count if the previous | 229 // The stub will rewrite receiver and parameter count if the previous |
228 // stack frame was an arguments adapter frame. | 230 // stack frame was an arguments adapter frame. |
229 ArgumentsAccessStub stub( | 231 ArgumentsAccessStub stub( |
230 is_strict_mode() ? ArgumentsAccessStub::NEW_STRICT | 232 is_strict_mode() ? ArgumentsAccessStub::NEW_STRICT |
231 : ArgumentsAccessStub::NEW_NON_STRICT_SLOW); | 233 : ArgumentsAccessStub::NEW_NON_STRICT_SLOW); |
232 __ CallStub(&stub); | 234 __ CallStub(&stub); |
233 | 235 |
234 Move(arguments->AsSlot(), rax, rbx, rdx); | 236 Move(arguments->AsSlot(), rax, rbx, rdx); |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
327 Label check_exit_codesize; | 329 Label check_exit_codesize; |
328 masm_->bind(&check_exit_codesize); | 330 masm_->bind(&check_exit_codesize); |
329 #endif | 331 #endif |
330 CodeGenerator::RecordPositions(masm_, function()->end_position() - 1); | 332 CodeGenerator::RecordPositions(masm_, function()->end_position() - 1); |
331 __ RecordJSReturn(); | 333 __ RecordJSReturn(); |
332 // Do not use the leave instruction here because it is too short to | 334 // Do not use the leave instruction here because it is too short to |
333 // patch with the code required by the debugger. | 335 // patch with the code required by the debugger. |
334 __ movq(rsp, rbp); | 336 __ movq(rsp, rbp); |
335 __ pop(rbp); | 337 __ pop(rbp); |
336 | 338 |
337 int arguments_bytes = (scope()->num_parameters() + 1) * kPointerSize; | 339 int arguments_bytes = (info_->scope()->num_parameters() + 1) * kPointerSize; |
338 __ Ret(arguments_bytes, rcx); | 340 __ Ret(arguments_bytes, rcx); |
339 | 341 |
340 #ifdef ENABLE_DEBUGGER_SUPPORT | 342 #ifdef ENABLE_DEBUGGER_SUPPORT |
341 // Add padding that will be overwritten by a debugger breakpoint. We | 343 // Add padding that will be overwritten by a debugger breakpoint. We |
342 // have just generated at least 7 bytes: "movq rsp, rbp; pop rbp; ret k" | 344 // have just generated at least 7 bytes: "movq rsp, rbp; pop rbp; ret k" |
343 // (3 + 1 + 3). | 345 // (3 + 1 + 3). |
344 const int kPadding = Assembler::kJSReturnSequenceLength - 7; | 346 const int kPadding = Assembler::kJSReturnSequenceLength - 7; |
345 for (int i = 0; i < kPadding; ++i) { | 347 for (int i = 0; i < kPadding; ++i) { |
346 masm_->int3(); | 348 masm_->int3(); |
347 } | 349 } |
(...skipping 1670 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2018 void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, | 2020 void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, |
2019 int arg_count) { | 2021 int arg_count) { |
2020 // Push copy of the first argument or undefined if it doesn't exist. | 2022 // Push copy of the first argument or undefined if it doesn't exist. |
2021 if (arg_count > 0) { | 2023 if (arg_count > 0) { |
2022 __ push(Operand(rsp, arg_count * kPointerSize)); | 2024 __ push(Operand(rsp, arg_count * kPointerSize)); |
2023 } else { | 2025 } else { |
2024 __ PushRoot(Heap::kUndefinedValueRootIndex); | 2026 __ PushRoot(Heap::kUndefinedValueRootIndex); |
2025 } | 2027 } |
2026 | 2028 |
2027 // Push the receiver of the enclosing function and do runtime call. | 2029 // Push the receiver of the enclosing function and do runtime call. |
2028 __ push(Operand(rbp, (2 + scope()->num_parameters()) * kPointerSize)); | 2030 __ push(Operand(rbp, (2 + info_->scope()->num_parameters()) * kPointerSize)); |
2029 | 2031 |
2030 // Push the strict mode flag. | 2032 // Push the strict mode flag. |
2031 __ Push(Smi::FromInt(strict_mode_flag())); | 2033 __ Push(Smi::FromInt(strict_mode_flag())); |
2032 | 2034 |
2033 __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP | 2035 __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP |
2034 ? Runtime::kResolvePossiblyDirectEvalNoLookup | 2036 ? Runtime::kResolvePossiblyDirectEvalNoLookup |
2035 : Runtime::kResolvePossiblyDirectEval, 4); | 2037 : Runtime::kResolvePossiblyDirectEval, 4); |
2036 } | 2038 } |
2037 | 2039 |
2038 | 2040 |
(...skipping 521 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2560 } | 2562 } |
2561 | 2563 |
2562 | 2564 |
2563 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) { | 2565 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) { |
2564 ASSERT(args->length() == 1); | 2566 ASSERT(args->length() == 1); |
2565 | 2567 |
2566 // ArgumentsAccessStub expects the key in rdx and the formal | 2568 // ArgumentsAccessStub expects the key in rdx and the formal |
2567 // parameter count in rax. | 2569 // parameter count in rax. |
2568 VisitForAccumulatorValue(args->at(0)); | 2570 VisitForAccumulatorValue(args->at(0)); |
2569 __ movq(rdx, rax); | 2571 __ movq(rdx, rax); |
2570 __ Move(rax, Smi::FromInt(scope()->num_parameters())); | 2572 __ Move(rax, Smi::FromInt(info_->scope()->num_parameters())); |
2571 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); | 2573 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); |
2572 __ CallStub(&stub); | 2574 __ CallStub(&stub); |
2573 context()->Plug(rax); | 2575 context()->Plug(rax); |
2574 } | 2576 } |
2575 | 2577 |
2576 | 2578 |
2577 void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) { | 2579 void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) { |
2578 ASSERT(args->length() == 0); | 2580 ASSERT(args->length() == 0); |
2579 | 2581 |
2580 Label exit; | 2582 Label exit; |
2581 // Get the number of formal parameters. | 2583 // Get the number of formal parameters. |
2582 __ Move(rax, Smi::FromInt(scope()->num_parameters())); | 2584 __ Move(rax, Smi::FromInt(info_->scope()->num_parameters())); |
2583 | 2585 |
2584 // Check if the calling frame is an arguments adaptor frame. | 2586 // Check if the calling frame is an arguments adaptor frame. |
2585 __ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); | 2587 __ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
2586 __ Cmp(Operand(rbx, StandardFrameConstants::kContextOffset), | 2588 __ Cmp(Operand(rbx, StandardFrameConstants::kContextOffset), |
2587 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); | 2589 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
2588 __ j(not_equal, &exit, Label::kNear); | 2590 __ j(not_equal, &exit, Label::kNear); |
2589 | 2591 |
2590 // Arguments adaptor case: Read the arguments length from the | 2592 // Arguments adaptor case: Read the arguments length from the |
2591 // adaptor frame. | 2593 // adaptor frame. |
2592 __ movq(rax, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset)); | 2594 __ movq(rax, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
(...skipping 1566 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4159 // as their closure, not the anonymous closure containing the global | 4161 // as their closure, not the anonymous closure containing the global |
4160 // code. Pass a smi sentinel and let the runtime look up the empty | 4162 // code. Pass a smi sentinel and let the runtime look up the empty |
4161 // function. | 4163 // function. |
4162 __ Push(Smi::FromInt(0)); | 4164 __ Push(Smi::FromInt(0)); |
4163 } else if (scope()->is_eval_scope()) { | 4165 } else if (scope()->is_eval_scope()) { |
4164 // Contexts created by a call to eval have the same closure as the | 4166 // Contexts created by a call to eval have the same closure as the |
4165 // context calling eval, not the anonymous closure containing the eval | 4167 // context calling eval, not the anonymous closure containing the eval |
4166 // code. Fetch it from the context. | 4168 // code. Fetch it from the context. |
4167 __ push(ContextOperand(rsi, Context::CLOSURE_INDEX)); | 4169 __ push(ContextOperand(rsi, Context::CLOSURE_INDEX)); |
4168 } else { | 4170 } else { |
4169 ASSERT(scope()->is_function_scope()); | 4171 ASSERT(scope()->is_function_scope() || scope()->is_catch_scope()); |
4170 __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 4172 __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
4171 } | 4173 } |
4172 } | 4174 } |
4173 | 4175 |
4174 | 4176 |
4175 // ---------------------------------------------------------------------------- | 4177 // ---------------------------------------------------------------------------- |
4176 // Non-local control flow support. | 4178 // Non-local control flow support. |
4177 | 4179 |
4178 | 4180 |
4179 void FullCodeGenerator::EnterFinallyBlock() { | 4181 void FullCodeGenerator::EnterFinallyBlock() { |
4180 ASSERT(!result_register().is(rdx)); | 4182 ASSERT(!result_register().is(rdx)); |
4181 ASSERT(!result_register().is(rcx)); | 4183 ASSERT(!result_register().is(rcx)); |
4182 // Cook return address on top of stack (smi encoded Code* delta) | 4184 // Cook return address on top of stack (smi encoded Code* delta) |
4183 __ movq(rdx, Operand(rsp, 0)); | 4185 __ pop(rdx); |
4184 __ Move(rcx, masm_->CodeObject()); | 4186 __ Move(rcx, masm_->CodeObject()); |
4185 __ subq(rdx, rcx); | 4187 __ subq(rdx, rcx); |
4186 __ Integer32ToSmi(rdx, rdx); | 4188 __ Integer32ToSmi(rdx, rdx); |
4187 __ movq(Operand(rsp, 0), rdx); | 4189 __ push(rdx); |
4188 // Store result register while executing finally block. | 4190 // Store result register while executing finally block. |
4189 __ push(result_register()); | 4191 __ push(result_register()); |
4190 } | 4192 } |
4191 | 4193 |
4192 | 4194 |
4193 void FullCodeGenerator::ExitFinallyBlock() { | 4195 void FullCodeGenerator::ExitFinallyBlock() { |
4194 ASSERT(!result_register().is(rdx)); | 4196 ASSERT(!result_register().is(rdx)); |
4195 ASSERT(!result_register().is(rcx)); | 4197 ASSERT(!result_register().is(rcx)); |
4196 // Restore result register from stack. | |
4197 __ pop(result_register()); | 4198 __ pop(result_register()); |
4198 // Uncook return address. | 4199 // Uncook return address. |
4199 __ movq(rdx, Operand(rsp, 0)); | 4200 __ pop(rdx); |
4200 __ SmiToInteger32(rdx, rdx); | 4201 __ SmiToInteger32(rdx, rdx); |
4201 __ Move(rcx, masm_->CodeObject()); | 4202 __ Move(rcx, masm_->CodeObject()); |
4202 __ addq(rdx, rcx); | 4203 __ addq(rdx, rcx); |
4203 __ movq(Operand(rsp, 0), rdx); | 4204 __ jmp(rdx); |
4204 // And return. | |
4205 __ ret(0); | |
4206 } | 4205 } |
4207 | 4206 |
4208 | 4207 |
4209 #undef __ | 4208 #undef __ |
4210 | 4209 |
4211 | 4210 |
4212 } } // namespace v8::internal | 4211 } } // namespace v8::internal |
4213 | 4212 |
4214 #endif // V8_TARGET_ARCH_X64 | 4213 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |