| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 73 // CodeGenerator implementation | 73 // CodeGenerator implementation |
| 74 | 74 |
| 75 CodeGenerator::CodeGenerator(int buffer_size, Handle<Script> script, | 75 CodeGenerator::CodeGenerator(int buffer_size, Handle<Script> script, |
| 76 bool is_eval) | 76 bool is_eval) |
| 77 : is_eval_(is_eval), | 77 : is_eval_(is_eval), |
| 78 script_(script), | 78 script_(script), |
| 79 deferred_(8), | 79 deferred_(8), |
| 80 masm_(new MacroAssembler(NULL, buffer_size)), | 80 masm_(new MacroAssembler(NULL, buffer_size)), |
| 81 scope_(NULL), | 81 scope_(NULL), |
| 82 frame_(NULL), | 82 frame_(NULL), |
| 83 allocator_(NULL), |
| 83 cc_reg_(no_condition), | 84 cc_reg_(no_condition), |
| 84 state_(NULL), | 85 state_(NULL), |
| 85 is_inside_try_(false), | 86 is_inside_try_(false), |
| 86 break_stack_height_(0), | 87 break_stack_height_(0), |
| 87 loop_nesting_(0), | 88 loop_nesting_(0), |
| 88 function_return_is_shadowed_(false) { | 89 function_return_is_shadowed_(false) { |
| 89 } | 90 } |
| 90 | 91 |
| 91 | 92 |
| 92 // Calling conventions: | 93 // Calling conventions: |
| 93 // ebp: frame pointer | 94 // ebp: frame pointer |
| 94 // esp: stack pointer | 95 // esp: stack pointer |
| 95 // edi: caller's parameter pointer | 96 // edi: caller's parameter pointer |
| 96 // esi: callee's context | 97 // esi: callee's context |
| 97 | 98 |
| 98 void CodeGenerator::GenCode(FunctionLiteral* fun) { | 99 void CodeGenerator::GenCode(FunctionLiteral* fun) { |
| 99 // Record the position for debugging purposes. | 100 // Record the position for debugging purposes. |
| 100 __ RecordPosition(fun->start_position()); | 101 __ RecordPosition(fun->start_position()); |
| 101 | 102 |
| 102 ZoneList<Statement*>* body = fun->body(); | 103 ZoneList<Statement*>* body = fun->body(); |
| 103 | 104 |
| 104 // Initialize state. | 105 // Initialize state. |
| 105 ASSERT(scope_ == NULL); | 106 ASSERT(scope_ == NULL); |
| 106 scope_ = fun->scope(); | 107 scope_ = fun->scope(); |
| 107 ASSERT(frame_ == NULL); | 108 ASSERT(frame_ == NULL); |
| 108 set_frame(new VirtualFrame(this)); | 109 set_frame(new VirtualFrame(this)); |
| 110 ASSERT(allocator_ == NULL); |
| 111 RegisterAllocator register_allocator(this); |
| 112 allocator_ = ®ister_allocator; |
| 109 cc_reg_ = no_condition; | 113 cc_reg_ = no_condition; |
| 110 function_return_.set_code_generator(this); | 114 function_return_.set_code_generator(this); |
| 111 function_return_is_shadowed_ = false; | 115 function_return_is_shadowed_ = false; |
| 112 | 116 |
| 113 // Adjust for function-level loop nesting. | 117 // Adjust for function-level loop nesting. |
| 114 loop_nesting_ += fun->loop_nesting(); | 118 loop_nesting_ += fun->loop_nesting(); |
| 115 | 119 |
| 116 { | 120 { |
| 117 CodeGenState state(this); | 121 CodeGenState state(this); |
| 118 | 122 |
| 119 // Entry | 123 // Entry |
| 120 // stack: function, receiver, arguments, return address | 124 // stack: function, receiver, arguments, return address |
| 121 // esp: stack pointer | 125 // esp: stack pointer |
| 122 // ebp: frame pointer | 126 // ebp: frame pointer |
| 123 // edi: caller's parameter pointer | 127 // edi: caller's parameter pointer |
| 124 // esi: callee's context | 128 // esi: callee's context |
| 125 | 129 |
| 130 allocator_->Initialize(); |
| 126 frame_->Enter(); | 131 frame_->Enter(); |
| 127 // tos: code slot | 132 // tos: code slot |
| 128 #ifdef DEBUG | 133 #ifdef DEBUG |
| 129 if (strlen(FLAG_stop_at) > 0 && | 134 if (strlen(FLAG_stop_at) > 0 && |
| 130 fun->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { | 135 fun->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { |
| 136 frame_->SpillAll(); |
| 131 __ int3(); | 137 __ int3(); |
| 132 } | 138 } |
| 133 #endif | 139 #endif |
| 134 | 140 |
| 135 // This section now only allocates and copies the formals into the | 141 // Allocate space for locals and initialize them. |
| 136 // arguments object. It saves the address in ecx, which is saved | 142 frame_->AllocateStackSlots(scope_->num_stack_slots()); |
| 137 // at any point before either garbage collection or ecx is | |
| 138 // overwritten. The flag arguments_array_allocated communicates | |
| 139 // with the store into the arguments variable and guards the lazy | |
| 140 // pushes of ecx to TOS. The flag arguments_array_saved notes | |
| 141 // when the push has happened. | |
| 142 bool arguments_object_allocated = false; | |
| 143 bool arguments_object_saved = false; | |
| 144 | 143 |
| 145 // Allocate arguments object. | 144 // Allocate the arguments object and copy the parameters into it. |
| 146 // The arguments object pointer needs to be saved in ecx, since we need | |
| 147 // to store arguments into the context. | |
| 148 if (scope_->arguments() != NULL) { | 145 if (scope_->arguments() != NULL) { |
| 149 ASSERT(scope_->arguments_shadow() != NULL); | 146 ASSERT(scope_->arguments_shadow() != NULL); |
| 150 Comment cmnt(masm_, "[ allocate arguments object"); | 147 Comment cmnt(masm_, "[ Allocate arguments object"); |
| 151 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); | 148 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); |
| 149 frame_->SpillAll(); |
| 152 __ lea(eax, frame_->Receiver()); | 150 __ lea(eax, frame_->Receiver()); |
| 153 frame_->EmitPush(frame_->Function()); | 151 frame_->EmitPush(frame_->Function()); |
| 154 frame_->EmitPush(eax); | 152 frame_->EmitPush(eax); |
| 155 frame_->EmitPush(Immediate(Smi::FromInt(scope_->num_parameters()))); | 153 frame_->EmitPush(Immediate(Smi::FromInt(scope_->num_parameters()))); |
| 156 frame_->CallStub(&stub, 3); | 154 frame_->CallStub(&stub, 3); |
| 157 __ mov(ecx, Operand(eax)); | 155 frame_->Push(eax); |
| 158 arguments_object_allocated = true; | |
| 159 } | 156 } |
| 160 | 157 |
| 161 // Allocate space for locals and initialize them. | |
| 162 frame_->AllocateStackSlots(scope_->num_stack_slots()); | |
| 163 | |
| 164 if (scope_->num_heap_slots() > 0) { | 158 if (scope_->num_heap_slots() > 0) { |
| 165 frame_->SpillAll(); | |
| 166 Comment cmnt(masm_, "[ allocate local context"); | 159 Comment cmnt(masm_, "[ allocate local context"); |
| 167 // Save the arguments object pointer, if any. | |
| 168 if (arguments_object_allocated && !arguments_object_saved) { | |
| 169 frame_->EmitPush(ecx); | |
| 170 arguments_object_saved = true; | |
| 171 } | |
| 172 // Allocate local context. | 160 // Allocate local context. |
| 173 // Get outer context and create a new context based on it. | 161 // Get outer context and create a new context based on it. |
| 162 frame_->SpillAll(); |
| 174 frame_->EmitPush(frame_->Function()); | 163 frame_->EmitPush(frame_->Function()); |
| 175 frame_->CallRuntime(Runtime::kNewContext, 1); // eax holds the result | 164 frame_->CallRuntime(Runtime::kNewContext, 1); // eax holds the result |
| 176 | 165 |
| 177 if (kDebug) { | 166 if (kDebug) { |
| 178 JumpTarget verified_true(this); | 167 JumpTarget verified_true(this); |
| 179 // Verify eax and esi are the same in debug mode | 168 // Verify eax and esi are the same in debug mode |
| 180 __ cmp(eax, Operand(esi)); | 169 __ cmp(eax, Operand(esi)); |
| 181 verified_true.Branch(equal); | 170 verified_true.Branch(equal); |
| 182 __ int3(); | 171 __ int3(); |
| 183 verified_true.Bind(); | 172 verified_true.Bind(); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 198 // needs to be copied into the context, it must be the last argument | 187 // needs to be copied into the context, it must be the last argument |
| 199 // passed to the parameter that needs to be copied. This is a rare | 188 // passed to the parameter that needs to be copied. This is a rare |
| 200 // case so we don't check for it, instead we rely on the copying | 189 // case so we don't check for it, instead we rely on the copying |
| 201 // order: such a parameter is copied repeatedly into the same | 190 // order: such a parameter is copied repeatedly into the same |
| 202 // context location and thus the last value is what is seen inside | 191 // context location and thus the last value is what is seen inside |
| 203 // the function. | 192 // the function. |
| 204 for (int i = 0; i < scope_->num_parameters(); i++) { | 193 for (int i = 0; i < scope_->num_parameters(); i++) { |
| 205 Variable* par = scope_->parameter(i); | 194 Variable* par = scope_->parameter(i); |
| 206 Slot* slot = par->slot(); | 195 Slot* slot = par->slot(); |
| 207 if (slot != NULL && slot->type() == Slot::CONTEXT) { | 196 if (slot != NULL && slot->type() == Slot::CONTEXT) { |
| 197 frame_->SpillAll(); |
| 208 ASSERT(!scope_->is_global_scope()); // no parameters in global scope | 198 ASSERT(!scope_->is_global_scope()); // no parameters in global scope |
| 209 __ mov(eax, frame_->ParameterAt(i)); | 199 __ mov(eax, frame_->ParameterAt(i)); |
| 210 // Loads ecx with context; used below in RecordWrite. | 200 // Loads ecx with context; used below in RecordWrite. |
| 211 __ mov(SlotOperand(slot, edx), eax); | 201 __ mov(SlotOperand(slot, edx), eax); |
| 212 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | 202 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
| 213 __ RecordWrite(edx, offset, eax, ebx); | 203 __ RecordWrite(edx, offset, eax, ebx); |
| 214 } | 204 } |
| 215 } | 205 } |
| 216 } | 206 } |
| 217 | 207 |
| 218 // This section stores the pointer to the arguments object that | 208 // This section stores the pointer to the arguments object that |
| 219 // was allocated and copied into above. If the address was not | 209 // was allocated and copied into above. If the address was not |
| 220 // saved to TOS, we push ecx onto the stack. | 210 // saved to TOS, we push ecx onto the stack. |
| 221 // | 211 // |
| 222 // Store the arguments object. This must happen after context | 212 // Store the arguments object. This must happen after context |
| 223 // initialization because the arguments object may be stored in the | 213 // initialization because the arguments object may be stored in the |
| 224 // context. | 214 // context. |
| 225 if (arguments_object_allocated) { | 215 if (scope_->arguments() != NULL) { |
| 226 ASSERT(scope_->arguments() != NULL); | 216 frame_->SpillAll(); |
| 227 ASSERT(scope_->arguments_shadow() != NULL); | |
| 228 Comment cmnt(masm_, "[ store arguments object"); | 217 Comment cmnt(masm_, "[ store arguments object"); |
| 229 { Reference shadow_ref(this, scope_->arguments_shadow()); | 218 { Reference shadow_ref(this, scope_->arguments_shadow()); |
| 230 ASSERT(shadow_ref.is_slot()); | 219 ASSERT(shadow_ref.is_slot()); |
| 231 { Reference arguments_ref(this, scope_->arguments()); | 220 { Reference arguments_ref(this, scope_->arguments()); |
| 232 ASSERT(arguments_ref.is_slot()); | 221 ASSERT(arguments_ref.is_slot()); |
| 233 // If the newly-allocated arguments object is already on the | 222 // Here we rely on the convenient property that references to slot |
| 234 // stack, we make use of the convenient property that references | 223 // take up zero space in the frame (ie, it doesn't matter that the |
| 235 // representing slots take up no space on the expression stack | 224 // stored value is actually below the reference on the frame). |
| 236 // (ie, it doesn't matter that the stored value is actually below | |
| 237 // the reference). | |
| 238 // | |
| 239 // If the newly-allocated argument object is not already on | |
| 240 // the stack, we rely on the property that loading a | |
| 241 // zero-sized reference will not clobber the ecx register. | |
| 242 if (!arguments_object_saved) { | |
| 243 frame_->SpillAll(); | |
| 244 frame_->EmitPush(ecx); | |
| 245 } | |
| 246 arguments_ref.SetValue(NOT_CONST_INIT); | 225 arguments_ref.SetValue(NOT_CONST_INIT); |
| 247 } | 226 } |
| 248 shadow_ref.SetValue(NOT_CONST_INIT); | 227 shadow_ref.SetValue(NOT_CONST_INIT); |
| 249 } | 228 } |
| 250 frame_->Drop(); // Value is no longer needed. | 229 frame_->Drop(); // Value is no longer needed. |
| 251 } | 230 } |
| 252 | 231 |
| 253 // Generate code to 'execute' declarations and initialize functions | 232 // Generate code to 'execute' declarations and initialize functions |
| 254 // (source elements). In case of an illegal redeclaration we need to | 233 // (source elements). In case of an illegal redeclaration we need to |
| 255 // handle that instead of processing the declarations. | 234 // handle that instead of processing the declarations. |
| 256 if (scope_->HasIllegalRedeclaration()) { | 235 if (scope_->HasIllegalRedeclaration()) { |
| 257 Comment cmnt(masm_, "[ illegal redeclarations"); | 236 Comment cmnt(masm_, "[ illegal redeclarations"); |
| 258 scope_->VisitIllegalRedeclaration(this); | 237 scope_->VisitIllegalRedeclaration(this); |
| 259 } else { | 238 } else { |
| 260 Comment cmnt(masm_, "[ declarations"); | 239 Comment cmnt(masm_, "[ declarations"); |
| 261 ProcessDeclarations(scope_->declarations()); | 240 ProcessDeclarations(scope_->declarations()); |
| 262 // Bail out if a stack-overflow exception occurred when processing | 241 // Bail out if a stack-overflow exception occurred when processing |
| 263 // declarations. | 242 // declarations. |
| 264 if (HasStackOverflow()) return; | 243 if (HasStackOverflow()) return; |
| 265 } | 244 } |
| 266 | 245 |
| 267 if (FLAG_trace) { | 246 if (FLAG_trace) { |
| 268 frame_->CallRuntime(Runtime::kTraceEnter, 0); | 247 frame_->CallRuntime(Runtime::kTraceEnter, 0); |
| 269 // Ignore the return value. | 248 // Ignore the return value. |
| 270 } | 249 } |
| 250 frame_->SpillAll(); |
| 271 CheckStack(); | 251 CheckStack(); |
| 272 | 252 |
| 273 // Compile the body of the function in a vanilla state. Don't | 253 // Compile the body of the function in a vanilla state. Don't |
| 274 // bother compiling all the code if the scope has an illegal | 254 // bother compiling all the code if the scope has an illegal |
| 275 // redeclaration. | 255 // redeclaration. |
| 276 if (!scope_->HasIllegalRedeclaration()) { | 256 if (!scope_->HasIllegalRedeclaration()) { |
| 277 Comment cmnt(masm_, "[ function body"); | 257 Comment cmnt(masm_, "[ function body"); |
| 278 #ifdef DEBUG | 258 #ifdef DEBUG |
| 279 bool is_builtin = Bootstrapper::IsActive(); | 259 bool is_builtin = Bootstrapper::IsActive(); |
| 280 bool should_trace = | 260 bool should_trace = |
| (...skipping 14 matching lines...) Expand all Loading... |
| 295 statement.set_statement_pos(fun->end_position()); | 275 statement.set_statement_pos(fun->end_position()); |
| 296 VisitReturnStatement(&statement); | 276 VisitReturnStatement(&statement); |
| 297 } | 277 } |
| 298 } | 278 } |
| 299 } | 279 } |
| 300 | 280 |
| 301 // Adjust for function-level loop nesting. | 281 // Adjust for function-level loop nesting. |
| 302 loop_nesting_ -= fun->loop_nesting(); | 282 loop_nesting_ -= fun->loop_nesting(); |
| 303 | 283 |
| 304 // Code generation state must be reset. | 284 // Code generation state must be reset. |
| 285 ASSERT(state_ == NULL); |
| 286 ASSERT(loop_nesting() == 0); |
| 305 ASSERT(!function_return_is_shadowed_); | 287 ASSERT(!function_return_is_shadowed_); |
| 306 function_return_.Unuse(); | 288 function_return_.Unuse(); |
| 289 ASSERT(!has_cc()); |
| 290 // There is no need to delete the register allocator, it is a |
| 291 // stack-allocated local. |
| 292 allocator_ = NULL; |
| 293 delete_frame(); |
| 307 scope_ = NULL; | 294 scope_ = NULL; |
| 308 delete_frame(); | |
| 309 ASSERT(!has_cc()); | |
| 310 ASSERT(state_ == NULL); | |
| 311 ASSERT(loop_nesting() == 0); | |
| 312 } | 295 } |
| 313 | 296 |
| 314 | 297 |
| 315 Operand CodeGenerator::SlotOperand(Slot* slot, Register tmp) { | 298 Operand CodeGenerator::SlotOperand(Slot* slot, Register tmp) { |
| 316 // Currently, this assertion will fail if we try to assign to | 299 // Currently, this assertion will fail if we try to assign to |
| 317 // a constant variable that is constant because it is read-only | 300 // a constant variable that is constant because it is read-only |
| 318 // (such as the variable referring to a named function expression). | 301 // (such as the variable referring to a named function expression). |
| 319 // We need to implement assignments to read-only variables. | 302 // We need to implement assignments to read-only variables. |
| 320 // Ideally, we should do this during AST generation (by converting | 303 // Ideally, we should do this during AST generation (by converting |
| 321 // such assignments into expression statements); however, in general | 304 // such assignments into expression statements); however, in general |
| (...skipping 5045 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5367 | 5350 |
| 5368 // Slow-case: Go through the JavaScript implementation. | 5351 // Slow-case: Go through the JavaScript implementation. |
| 5369 __ bind(&slow); | 5352 __ bind(&slow); |
| 5370 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 5353 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 5371 } | 5354 } |
| 5372 | 5355 |
| 5373 | 5356 |
| 5374 #undef __ | 5357 #undef __ |
| 5375 | 5358 |
| 5376 } } // namespace v8::internal | 5359 } } // namespace v8::internal |
| OLD | NEW |