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 edi: the JS function object being called (ie, ourselves) | 116 // o edi: the JS function object being called (ie, ourselves) |
117 // o esi: our context | 117 // o esi: our context |
118 // o ebp: our caller's frame pointer | 118 // o ebp: our caller's frame pointer |
119 // o esp: stack pointer (pointing to return address) | 119 // o esp: 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-ia32.h for its layout. | 122 // frames-ia32.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). ecx is zero for method calls and non-zero for | 139 // receiver object). ecx 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 __ test(ecx, Operand(ecx)); | 143 __ test(ecx, Operand(ecx)); |
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 __ mov(Operand(esp, receiver_offset), | 147 __ mov(Operand(esp, receiver_offset), |
147 Immediate(isolate()->factory()->undefined_value())); | 148 Immediate(isolate()->factory()->undefined_value())); |
148 __ bind(&ok); | 149 __ bind(&ok); |
149 } | 150 } |
150 | 151 |
151 __ push(ebp); // Caller's frame pointer. | 152 __ push(ebp); // Caller's frame pointer. |
152 __ mov(ebp, esp); | 153 __ mov(ebp, esp); |
153 __ push(esi); // Callee's context. | 154 __ push(esi); // Callee's context. |
154 __ push(edi); // Callee's JS Function. | 155 __ push(edi); // 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 __ push(Immediate(isolate()->factory()->undefined_value())); | 160 __ push(Immediate(isolate()->factory()->undefined_value())); |
160 } else if (locals_count > 1) { | 161 } else if (locals_count > 1) { |
161 __ mov(eax, Immediate(isolate()->factory()->undefined_value())); | 162 __ mov(eax, Immediate(isolate()->factory()->undefined_value())); |
162 for (int i = 0; i < locals_count; i++) { | 163 for (int i = 0; i < locals_count; i++) { |
163 __ push(eax); | 164 __ push(eax); |
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 edi. | 175 // Argument to NewContext is the function, which is still in edi. |
175 __ push(edi); | 176 __ push(edi); |
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 eax and esi. It replaces the context | 184 // Context is returned in both eax and esi. It replaces the context |
184 // passed to us. It's saved in the stack and kept live in esi. | 185 // passed to us. It's saved in the stack and kept live in esi. |
185 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); | 186 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); |
186 | 187 |
187 // Copy parameters into context if necessary. | 188 // Copy parameters into context if necessary. |
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 __ mov(eax, Operand(ebp, parameter_offset)); | 196 __ mov(eax, Operand(ebp, 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 __ mov(Operand(esi, context_offset), eax); | 199 __ mov(Operand(esi, context_offset), eax); |
199 // Update the write barrier. This clobbers all involved | 200 // Update the write barrier. This clobbers all involved |
200 // registers, so we have use a third register to avoid | 201 // registers, so we have use a third register to avoid |
201 // clobbering esi. | 202 // clobbering esi. |
202 __ mov(ecx, esi); | 203 __ mov(ecx, esi); |
203 __ RecordWrite(ecx, context_offset, eax, ebx); | 204 __ RecordWrite(ecx, context_offset, eax, ebx); |
204 } | 205 } |
205 } | 206 } |
206 } | 207 } |
207 | 208 |
208 Variable* arguments = scope()->arguments(); | 209 Variable* arguments = scope()->arguments(); |
209 if (arguments != NULL) { | 210 if (arguments != NULL) { |
210 // Function uses arguments object. | 211 // Function uses arguments object. |
211 Comment cmnt(masm_, "[ Allocate arguments object"); | 212 Comment cmnt(masm_, "[ Allocate arguments object"); |
212 if (function_in_register) { | 213 if (function_in_register) { |
213 __ push(edi); | 214 __ push(edi); |
214 } else { | 215 } else { |
215 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 216 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
216 } | 217 } |
217 // Receiver is just before the parameters on the caller's stack. | 218 // Receiver is just before the parameters on the caller's stack. |
218 int offset = scope()->num_parameters() * kPointerSize; | 219 int num_parameters = info->scope()->num_parameters(); |
| 220 int offset = num_parameters * kPointerSize; |
219 __ lea(edx, | 221 __ lea(edx, |
220 Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset)); | 222 Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset)); |
221 __ push(edx); | 223 __ push(edx); |
222 __ SafePush(Immediate(Smi::FromInt(scope()->num_parameters()))); | 224 __ SafePush(Immediate(Smi::FromInt(num_parameters))); |
223 // Arguments to ArgumentsAccessStub and/or New...: | 225 // Arguments to ArgumentsAccessStub and/or New...: |
224 // function, receiver address, parameter count. | 226 // function, receiver address, parameter count. |
225 // The stub will rewrite receiver and parameter count if the previous | 227 // The stub will rewrite receiver and parameter count if the previous |
226 // stack frame was an arguments adapter frame. | 228 // stack frame was an arguments adapter frame. |
227 ArgumentsAccessStub::Type type; | 229 ArgumentsAccessStub::Type type; |
228 if (is_strict_mode()) { | 230 if (is_strict_mode()) { |
229 type = ArgumentsAccessStub::NEW_STRICT; | 231 type = ArgumentsAccessStub::NEW_STRICT; |
230 } else if (function()->has_duplicate_parameters()) { | 232 } else if (function()->has_duplicate_parameters()) { |
231 type = ArgumentsAccessStub::NEW_NON_STRICT_SLOW; | 233 type = ArgumentsAccessStub::NEW_NON_STRICT_SLOW; |
232 } else { | 234 } else { |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
337 Label check_exit_codesize; | 339 Label check_exit_codesize; |
338 masm_->bind(&check_exit_codesize); | 340 masm_->bind(&check_exit_codesize); |
339 #endif | 341 #endif |
340 SetSourcePosition(function()->end_position() - 1); | 342 SetSourcePosition(function()->end_position() - 1); |
341 __ RecordJSReturn(); | 343 __ RecordJSReturn(); |
342 // Do not use the leave instruction here because it is too short to | 344 // Do not use the leave instruction here because it is too short to |
343 // patch with the code required by the debugger. | 345 // patch with the code required by the debugger. |
344 __ mov(esp, ebp); | 346 __ mov(esp, ebp); |
345 __ pop(ebp); | 347 __ pop(ebp); |
346 | 348 |
347 int arguments_bytes = (scope()->num_parameters() + 1) * kPointerSize; | 349 int arguments_bytes = (info_->scope()->num_parameters() + 1) * kPointerSize; |
348 __ Ret(arguments_bytes, ecx); | 350 __ Ret(arguments_bytes, ecx); |
349 #ifdef ENABLE_DEBUGGER_SUPPORT | 351 #ifdef ENABLE_DEBUGGER_SUPPORT |
350 // Check that the size of the code used for returning is large enough | 352 // Check that the size of the code used for returning is large enough |
351 // for the debugger's requirements. | 353 // for the debugger's requirements. |
352 ASSERT(Assembler::kJSReturnSequenceLength <= | 354 ASSERT(Assembler::kJSReturnSequenceLength <= |
353 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); | 355 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); |
354 #endif | 356 #endif |
355 } | 357 } |
356 } | 358 } |
357 | 359 |
(...skipping 1696 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2054 void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, | 2056 void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, |
2055 int arg_count) { | 2057 int arg_count) { |
2056 // Push copy of the first argument or undefined if it doesn't exist. | 2058 // Push copy of the first argument or undefined if it doesn't exist. |
2057 if (arg_count > 0) { | 2059 if (arg_count > 0) { |
2058 __ push(Operand(esp, arg_count * kPointerSize)); | 2060 __ push(Operand(esp, arg_count * kPointerSize)); |
2059 } else { | 2061 } else { |
2060 __ push(Immediate(isolate()->factory()->undefined_value())); | 2062 __ push(Immediate(isolate()->factory()->undefined_value())); |
2061 } | 2063 } |
2062 | 2064 |
2063 // Push the receiver of the enclosing function. | 2065 // Push the receiver of the enclosing function. |
2064 __ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize)); | 2066 __ push(Operand(ebp, (2 + info_->scope()->num_parameters()) * kPointerSize)); |
2065 | 2067 |
2066 // Push the strict mode flag. | 2068 // Push the strict mode flag. |
2067 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); | 2069 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); |
2068 | 2070 |
2069 __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP | 2071 __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP |
2070 ? Runtime::kResolvePossiblyDirectEvalNoLookup | 2072 ? Runtime::kResolvePossiblyDirectEvalNoLookup |
2071 : Runtime::kResolvePossiblyDirectEval, 4); | 2073 : Runtime::kResolvePossiblyDirectEval, 4); |
2072 } | 2074 } |
2073 | 2075 |
2074 | 2076 |
(...skipping 522 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2597 } | 2599 } |
2598 | 2600 |
2599 | 2601 |
2600 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) { | 2602 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) { |
2601 ASSERT(args->length() == 1); | 2603 ASSERT(args->length() == 1); |
2602 | 2604 |
2603 // ArgumentsAccessStub expects the key in edx and the formal | 2605 // ArgumentsAccessStub expects the key in edx and the formal |
2604 // parameter count in eax. | 2606 // parameter count in eax. |
2605 VisitForAccumulatorValue(args->at(0)); | 2607 VisitForAccumulatorValue(args->at(0)); |
2606 __ mov(edx, eax); | 2608 __ mov(edx, eax); |
2607 __ SafeSet(eax, Immediate(Smi::FromInt(scope()->num_parameters()))); | 2609 __ SafeSet(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters()))); |
2608 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); | 2610 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); |
2609 __ CallStub(&stub); | 2611 __ CallStub(&stub); |
2610 context()->Plug(eax); | 2612 context()->Plug(eax); |
2611 } | 2613 } |
2612 | 2614 |
2613 | 2615 |
2614 void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) { | 2616 void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) { |
2615 ASSERT(args->length() == 0); | 2617 ASSERT(args->length() == 0); |
2616 | 2618 |
2617 Label exit; | 2619 Label exit; |
2618 // Get the number of formal parameters. | 2620 // Get the number of formal parameters. |
2619 __ SafeSet(eax, Immediate(Smi::FromInt(scope()->num_parameters()))); | 2621 __ SafeSet(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters()))); |
2620 | 2622 |
2621 // Check if the calling frame is an arguments adaptor frame. | 2623 // Check if the calling frame is an arguments adaptor frame. |
2622 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); | 2624 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); |
2623 __ cmp(Operand(ebx, StandardFrameConstants::kContextOffset), | 2625 __ cmp(Operand(ebx, StandardFrameConstants::kContextOffset), |
2624 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); | 2626 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
2625 __ j(not_equal, &exit); | 2627 __ j(not_equal, &exit); |
2626 | 2628 |
2627 // Arguments adaptor case: Read the arguments length from the | 2629 // Arguments adaptor case: Read the arguments length from the |
2628 // adaptor frame. | 2630 // adaptor frame. |
2629 __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset)); | 2631 __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
(...skipping 1551 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4181 // as their closure, not the anonymous closure containing the global | 4183 // as their closure, not the anonymous closure containing the global |
4182 // code. Pass a smi sentinel and let the runtime look up the empty | 4184 // code. Pass a smi sentinel and let the runtime look up the empty |
4183 // function. | 4185 // function. |
4184 __ push(Immediate(Smi::FromInt(0))); | 4186 __ push(Immediate(Smi::FromInt(0))); |
4185 } else if (scope()->is_eval_scope()) { | 4187 } else if (scope()->is_eval_scope()) { |
4186 // Contexts created by a call to eval have the same closure as the | 4188 // Contexts created by a call to eval have the same closure as the |
4187 // context calling eval, not the anonymous closure containing the eval | 4189 // context calling eval, not the anonymous closure containing the eval |
4188 // code. Fetch it from the context. | 4190 // code. Fetch it from the context. |
4189 __ push(ContextOperand(esi, Context::CLOSURE_INDEX)); | 4191 __ push(ContextOperand(esi, Context::CLOSURE_INDEX)); |
4190 } else { | 4192 } else { |
4191 ASSERT(scope()->is_function_scope()); | 4193 ASSERT(scope()->is_function_scope() || scope()->is_catch_scope()); |
4192 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 4194 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
4193 } | 4195 } |
4194 } | 4196 } |
4195 | 4197 |
4196 | 4198 |
4197 // ---------------------------------------------------------------------------- | 4199 // ---------------------------------------------------------------------------- |
4198 // Non-local control flow support. | 4200 // Non-local control flow support. |
4199 | 4201 |
4200 void FullCodeGenerator::EnterFinallyBlock() { | 4202 void FullCodeGenerator::EnterFinallyBlock() { |
4201 // Cook return address on top of stack (smi encoded Code* delta) | 4203 // Cook return address on top of stack (smi encoded Code* delta) |
4202 ASSERT(!result_register().is(edx)); | 4204 ASSERT(!result_register().is(edx)); |
4203 __ mov(edx, Operand(esp, 0)); | 4205 __ pop(edx); |
4204 __ sub(Operand(edx), Immediate(masm_->CodeObject())); | 4206 __ sub(Operand(edx), Immediate(masm_->CodeObject())); |
4205 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); | 4207 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); |
4206 ASSERT_EQ(0, kSmiTag); | 4208 ASSERT_EQ(0, kSmiTag); |
4207 __ add(edx, Operand(edx)); // Convert to smi. | 4209 __ SmiTag(edx); |
4208 __ mov(Operand(esp, 0), edx); | 4210 __ push(edx); |
4209 // Store result register while executing finally block. | 4211 // Store result register while executing finally block. |
4210 __ push(result_register()); | 4212 __ push(result_register()); |
4211 } | 4213 } |
4212 | 4214 |
4213 | 4215 |
4214 void FullCodeGenerator::ExitFinallyBlock() { | 4216 void FullCodeGenerator::ExitFinallyBlock() { |
4215 ASSERT(!result_register().is(edx)); | 4217 ASSERT(!result_register().is(edx)); |
4216 // Restore result register from stack. | |
4217 __ pop(result_register()); | 4218 __ pop(result_register()); |
4218 // Uncook return address. | 4219 // Uncook return address. |
4219 __ mov(edx, Operand(esp, 0)); | 4220 __ pop(edx); |
4220 __ sar(edx, 1); // Convert smi to int. | 4221 __ SmiUntag(edx); |
4221 __ add(Operand(edx), Immediate(masm_->CodeObject())); | 4222 __ add(Operand(edx), Immediate(masm_->CodeObject())); |
4222 __ mov(Operand(esp, 0), edx); | 4223 __ jmp(Operand(edx)); |
4223 // And return. | |
4224 __ ret(0); | |
4225 } | 4224 } |
4226 | 4225 |
4227 | 4226 |
4228 #undef __ | 4227 #undef __ |
4229 | 4228 |
4230 } } // namespace v8::internal | 4229 } } // namespace v8::internal |
4231 | 4230 |
4232 #endif // V8_TARGET_ARCH_IA32 | 4231 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |