OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 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 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
101 __ RecordJSReturn(); | 101 __ RecordJSReturn(); |
102 // Do not use the leave instruction here because it is too short to | 102 // Do not use the leave instruction here because it is too short to |
103 // patch with the code required by the debugger. | 103 // patch with the code required by the debugger. |
104 __ mov(esp, ebp); | 104 __ mov(esp, ebp); |
105 __ pop(ebp); | 105 __ pop(ebp); |
106 __ ret((fun->scope()->num_parameters() + 1) * kPointerSize); | 106 __ ret((fun->scope()->num_parameters() + 1) * kPointerSize); |
107 } | 107 } |
108 } | 108 } |
109 | 109 |
110 | 110 |
| 111 void FastCodeGenerator::Move(Location destination, Slot* source) { |
| 112 switch (destination.type()) { |
| 113 case Location::NOWHERE: |
| 114 break; |
| 115 case Location::TEMP: |
| 116 __ push(Operand(ebp, SlotOffset(source))); |
| 117 break; |
| 118 } |
| 119 } |
| 120 |
| 121 |
| 122 void FastCodeGenerator::Move(Location destination, Literal* expr) { |
| 123 switch (destination.type()) { |
| 124 case Location::NOWHERE: |
| 125 break; |
| 126 case Location::TEMP: |
| 127 __ push(Immediate(expr->handle())); |
| 128 break; |
| 129 } |
| 130 } |
| 131 |
| 132 |
| 133 void FastCodeGenerator::Move(Slot* destination, Location source) { |
| 134 switch (source.type()) { |
| 135 case Location::NOWHERE: |
| 136 UNREACHABLE(); |
| 137 case Location::TEMP: |
| 138 __ pop(Operand(ebp, SlotOffset(destination))); |
| 139 break; |
| 140 } |
| 141 } |
| 142 |
| 143 |
111 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 144 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
112 // Call the runtime to declare the globals. | 145 // Call the runtime to declare the globals. |
113 __ push(esi); // The context is the first argument. | 146 __ push(esi); // The context is the first argument. |
114 __ push(Immediate(pairs)); | 147 __ push(Immediate(pairs)); |
115 __ push(Immediate(Smi::FromInt(is_eval_ ? 1 : 0))); | 148 __ push(Immediate(Smi::FromInt(is_eval_ ? 1 : 0))); |
116 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 149 __ CallRuntime(Runtime::kDeclareGlobals, 3); |
117 // Return value is ignored. | 150 // Return value is ignored. |
118 } | 151 } |
119 | 152 |
120 | 153 |
121 void FastCodeGenerator::VisitBlock(Block* stmt) { | |
122 Comment cmnt(masm_, "[ Block"); | |
123 SetStatementPosition(stmt); | |
124 VisitStatements(stmt->statements()); | |
125 } | |
126 | |
127 | |
128 void FastCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { | |
129 Comment cmnt(masm_, "[ ExpressionStatement"); | |
130 SetStatementPosition(stmt); | |
131 Visit(stmt->expression()); | |
132 } | |
133 | |
134 | |
135 void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { | 154 void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { |
136 Comment cmnt(masm_, "[ ReturnStatement"); | 155 Comment cmnt(masm_, "[ ReturnStatement"); |
137 SetStatementPosition(stmt); | 156 SetStatementPosition(stmt); |
138 Expression* expr = stmt->expression(); | 157 Expression* expr = stmt->expression(); |
139 // Complete the statement based on the type of the subexpression. | 158 // Complete the statement based on the type of the subexpression. |
140 if (expr->AsLiteral() != NULL) { | 159 if (expr->AsLiteral() != NULL) { |
141 __ mov(eax, expr->AsLiteral()->handle()); | 160 __ mov(eax, expr->AsLiteral()->handle()); |
142 } else { | 161 } else { |
143 Visit(expr); | 162 Visit(expr); |
144 ASSERT(expr->location().is_temporary()); | 163 Move(eax, expr->location()); |
145 __ pop(eax); | |
146 } | 164 } |
147 | 165 |
148 if (FLAG_trace) { | 166 if (FLAG_trace) { |
149 __ push(eax); | 167 __ push(eax); |
150 __ CallRuntime(Runtime::kTraceExit, 1); | 168 __ CallRuntime(Runtime::kTraceExit, 1); |
151 } | 169 } |
152 __ RecordJSReturn(); | 170 __ RecordJSReturn(); |
153 | 171 |
154 // Do not use the leave instruction here because it is too short to | 172 // Do not use the leave instruction here because it is too short to |
155 // patch with the code required by the debugger. | 173 // patch with the code required by the debugger. |
156 __ mov(esp, ebp); | 174 __ mov(esp, ebp); |
157 __ pop(ebp); | 175 __ pop(ebp); |
158 __ ret((function_->scope()->num_parameters() + 1) * kPointerSize); | 176 __ ret((function_->scope()->num_parameters() + 1) * kPointerSize); |
159 } | 177 } |
160 | 178 |
161 | 179 |
162 void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { | 180 void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { |
163 Comment cmnt(masm_, "[ FunctionLiteral"); | 181 Comment cmnt(masm_, "[ FunctionLiteral"); |
164 | 182 |
165 // Build the function boilerplate and instantiate it. | 183 // Build the function boilerplate and instantiate it. |
166 Handle<JSFunction> boilerplate = BuildBoilerplate(expr); | 184 Handle<JSFunction> boilerplate = BuildBoilerplate(expr); |
167 if (HasStackOverflow()) return; | 185 if (HasStackOverflow()) return; |
168 | 186 |
169 ASSERT(boilerplate->IsBoilerplate()); | 187 ASSERT(boilerplate->IsBoilerplate()); |
170 | 188 |
171 // Create a new closure. | 189 // Create a new closure. |
172 __ push(esi); | 190 __ push(esi); |
173 __ push(Immediate(boilerplate)); | 191 __ push(Immediate(boilerplate)); |
174 __ CallRuntime(Runtime::kNewClosure, 2); | 192 __ CallRuntime(Runtime::kNewClosure, 2); |
175 | 193 Move(expr->location(), eax); |
176 if (expr->location().is_temporary()) { | |
177 __ push(eax); | |
178 } else { | |
179 ASSERT(expr->location().is_nowhere()); | |
180 } | |
181 } | 194 } |
182 | 195 |
183 | 196 |
184 void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) { | 197 void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) { |
185 Comment cmnt(masm_, "[ VariableProxy"); | 198 Comment cmnt(masm_, "[ VariableProxy"); |
186 Expression* rewrite = expr->var()->rewrite(); | 199 Expression* rewrite = expr->var()->rewrite(); |
187 if (rewrite == NULL) { | 200 if (rewrite == NULL) { |
188 Comment cmnt(masm_, "Global variable"); | 201 Comment cmnt(masm_, "Global variable"); |
189 // Use inline caching. Variable name is passed in ecx and the global | 202 // Use inline caching. Variable name is passed in ecx and the global |
190 // object on the stack. | 203 // object on the stack. |
191 __ push(CodeGenerator::GlobalObject()); | 204 __ push(CodeGenerator::GlobalObject()); |
192 __ mov(ecx, expr->name()); | 205 __ mov(ecx, expr->name()); |
193 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 206 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
194 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 207 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
195 | 208 |
196 // A test eax instruction following the call is used by the IC to | 209 // A test eax instruction following the call is used by the IC to |
197 // indicate that the inobject property case was inlined. Ensure there | 210 // indicate that the inobject property case was inlined. Ensure there |
198 // is no test eax instruction here. Remember that the assembler may | 211 // is no test eax instruction here. Remember that the assembler may |
199 // choose to do peephole optimization (eg, push/pop elimination). | 212 // choose to do peephole optimization (eg, push/pop elimination). |
200 if (expr->location().is_temporary()) { | 213 switch (expr->location().type()) { |
201 // Replace the global object with the result. | 214 case Location::NOWHERE: |
202 __ mov(Operand(esp, 0), eax); | 215 __ add(Operand(esp), Immediate(kPointerSize)); |
203 } else { | 216 break; |
204 ASSERT(expr->location().is_nowhere()); | 217 case Location::TEMP: |
205 __ add(Operand(esp), Immediate(kPointerSize)); | 218 // Replace the global object with the result. |
| 219 __ mov(Operand(esp, 0), eax); |
| 220 break; |
206 } | 221 } |
207 | 222 |
208 } else { | 223 } else { |
209 Comment cmnt(masm_, "Stack slot"); | 224 Comment cmnt(masm_, "Stack slot"); |
210 Slot* slot = rewrite->AsSlot(); | 225 Move(expr->location(), rewrite->AsSlot()); |
211 ASSERT(slot != NULL); | |
212 if (expr->location().is_temporary()) { | |
213 __ push(Operand(ebp, SlotOffset(slot))); | |
214 } else { | |
215 ASSERT(expr->location().is_nowhere()); | |
216 } | |
217 } | |
218 } | |
219 | |
220 | |
221 void FastCodeGenerator::VisitLiteral(Literal* expr) { | |
222 if (expr->location().is_temporary()) { | |
223 __ push(Immediate(expr->handle())); | |
224 } else { | |
225 ASSERT(expr->location().is_nowhere()); | |
226 } | 226 } |
227 } | 227 } |
228 | 228 |
229 | 229 |
230 void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { | 230 void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { |
231 Comment cmnt(masm_, "[ ObjectLiteral"); | 231 Comment cmnt(masm_, "[ ObjectLiteral"); |
232 Label exists; | 232 Label exists; |
233 // Registers will be used as follows: | 233 // Registers will be used as follows: |
234 // edi = JS function. | 234 // edi = JS function. |
235 // ebx = literals array. | 235 // ebx = literals array. |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
276 if (!result_saved) { | 276 if (!result_saved) { |
277 __ push(eax); // Save result on the stack | 277 __ push(eax); // Save result on the stack |
278 result_saved = true; | 278 result_saved = true; |
279 } | 279 } |
280 switch (property->kind()) { | 280 switch (property->kind()) { |
281 case ObjectLiteral::Property::MATERIALIZED_LITERAL: // fall through | 281 case ObjectLiteral::Property::MATERIALIZED_LITERAL: // fall through |
282 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); | 282 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); |
283 case ObjectLiteral::Property::COMPUTED: | 283 case ObjectLiteral::Property::COMPUTED: |
284 if (key->handle()->IsSymbol()) { | 284 if (key->handle()->IsSymbol()) { |
285 Visit(value); | 285 Visit(value); |
286 ASSERT(value->location().is_temporary()); | 286 Move(eax, value->location()); |
287 __ pop(eax); | |
288 __ mov(ecx, Immediate(key->handle())); | 287 __ mov(ecx, Immediate(key->handle())); |
289 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 288 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
290 __ call(ic, RelocInfo::CODE_TARGET); | 289 __ call(ic, RelocInfo::CODE_TARGET); |
291 // StoreIC leaves the receiver on the stack. | 290 // StoreIC leaves the receiver on the stack. |
292 break; | 291 break; |
293 } | 292 } |
294 // fall through | 293 // fall through |
295 case ObjectLiteral::Property::PROTOTYPE: | 294 case ObjectLiteral::Property::PROTOTYPE: |
296 __ push(eax); | 295 __ push(eax); |
297 Visit(key); | 296 Visit(key); |
298 ASSERT(key->location().is_temporary()); | 297 ASSERT(value->location().is_temporary()); |
299 Visit(value); | 298 Visit(value); |
300 ASSERT(value->location().is_temporary()); | 299 ASSERT(value->location().is_temporary()); |
301 __ CallRuntime(Runtime::kSetProperty, 3); | 300 __ CallRuntime(Runtime::kSetProperty, 3); |
302 __ mov(eax, Operand(esp, 0)); // Restore result into eax. | 301 __ mov(eax, Operand(esp, 0)); // Restore result into eax. |
303 break; | 302 break; |
304 case ObjectLiteral::Property::SETTER: // fall through | 303 case ObjectLiteral::Property::SETTER: // fall through |
305 case ObjectLiteral::Property::GETTER: | 304 case ObjectLiteral::Property::GETTER: |
306 __ push(eax); | 305 __ push(eax); |
307 Visit(key); | 306 Visit(key); |
308 ASSERT(key->location().is_temporary()); | 307 ASSERT(key->location().is_temporary()); |
309 __ push(Immediate(property->kind() == ObjectLiteral::Property::SETTER ? | 308 __ push(Immediate(property->kind() == ObjectLiteral::Property::SETTER ? |
310 Smi::FromInt(1) : | 309 Smi::FromInt(1) : |
311 Smi::FromInt(0))); | 310 Smi::FromInt(0))); |
312 Visit(value); | 311 Visit(value); |
313 ASSERT(value->location().is_temporary()); | 312 ASSERT(value->location().is_temporary()); |
314 __ CallRuntime(Runtime::kDefineAccessor, 4); | 313 __ CallRuntime(Runtime::kDefineAccessor, 4); |
315 __ mov(eax, Operand(esp, 0)); // Restore result into eax. | 314 __ mov(eax, Operand(esp, 0)); // Restore result into eax. |
316 break; | 315 break; |
317 default: UNREACHABLE(); | 316 default: UNREACHABLE(); |
318 } | 317 } |
319 } | 318 } |
320 if (expr->location().is_nowhere() && result_saved) { | 319 switch (expr->location().type()) { |
321 __ add(Operand(esp), Immediate(kPointerSize)); | 320 case Location::NOWHERE: |
322 } else if (expr->location().is_temporary() && !result_saved) { | 321 if (result_saved) __ add(Operand(esp), Immediate(kPointerSize)); |
323 __ push(eax); | 322 break; |
| 323 case Location::TEMP: |
| 324 if (!result_saved) __ push(eax); |
| 325 break; |
324 } | 326 } |
325 } | 327 } |
326 | 328 |
327 | 329 |
328 void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { | 330 void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
329 Comment cmnt(masm_, "[ RegExp Literal"); | 331 Comment cmnt(masm_, "[ RegExp Literal"); |
330 Label done; | 332 Label done; |
331 // Registers will be used as follows: | 333 // Registers will be used as follows: |
332 // edi = JS function. | 334 // edi = JS function. |
333 // ebx = literals array. | 335 // ebx = literals array. |
334 // eax = regexp literal. | 336 // eax = regexp literal. |
335 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 337 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
336 __ mov(ebx, FieldOperand(edi, JSFunction::kLiteralsOffset)); | 338 __ mov(ebx, FieldOperand(edi, JSFunction::kLiteralsOffset)); |
337 int literal_offset = | 339 int literal_offset = |
338 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; | 340 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; |
339 __ mov(eax, FieldOperand(ebx, literal_offset)); | 341 __ mov(eax, FieldOperand(ebx, literal_offset)); |
340 __ cmp(eax, Factory::undefined_value()); | 342 __ cmp(eax, Factory::undefined_value()); |
341 __ j(not_equal, &done); | 343 __ j(not_equal, &done); |
342 // Create regexp literal using runtime function | 344 // Create regexp literal using runtime function |
343 // Result will be in eax. | 345 // Result will be in eax. |
344 __ push(ebx); | 346 __ push(ebx); |
345 __ push(Immediate(Smi::FromInt(expr->literal_index()))); | 347 __ push(Immediate(Smi::FromInt(expr->literal_index()))); |
346 __ push(Immediate(expr->pattern())); | 348 __ push(Immediate(expr->pattern())); |
347 __ push(Immediate(expr->flags())); | 349 __ push(Immediate(expr->flags())); |
348 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); | 350 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); |
349 // Label done: | 351 // Label done: |
350 __ bind(&done); | 352 __ bind(&done); |
351 if (expr->location().is_temporary()) { | 353 Move(expr->location(), eax); |
352 __ push(eax); | |
353 } else { | |
354 ASSERT(expr->location().is_nowhere()); | |
355 } | |
356 } | 354 } |
357 | 355 |
358 | 356 |
359 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { | 357 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
360 Comment cmnt(masm_, "[ ArrayLiteral"); | 358 Comment cmnt(masm_, "[ ArrayLiteral"); |
361 Label make_clone; | 359 Label make_clone; |
362 | 360 |
363 // Fetch the function's literals array. | 361 // Fetch the function's literals array. |
364 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 362 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
365 __ mov(ebx, FieldOperand(ebx, JSFunction::kLiteralsOffset)); | 363 __ mov(ebx, FieldOperand(ebx, JSFunction::kLiteralsOffset)); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
410 __ pop(eax); // Subexpression value. | 408 __ pop(eax); // Subexpression value. |
411 __ mov(ebx, Operand(esp, 0)); // Copy of array literal. | 409 __ mov(ebx, Operand(esp, 0)); // Copy of array literal. |
412 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset)); | 410 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset)); |
413 int offset = FixedArray::kHeaderSize + (i * kPointerSize); | 411 int offset = FixedArray::kHeaderSize + (i * kPointerSize); |
414 __ mov(FieldOperand(ebx, offset), eax); | 412 __ mov(FieldOperand(ebx, offset), eax); |
415 | 413 |
416 // Update the write barrier for the array store. | 414 // Update the write barrier for the array store. |
417 __ RecordWrite(ebx, offset, eax, ecx); | 415 __ RecordWrite(ebx, offset, eax, ecx); |
418 } | 416 } |
419 | 417 |
420 Location destination = expr->location(); | 418 switch (expr->location().type()) { |
421 if (destination.is_nowhere() && result_saved) { | 419 case Location::NOWHERE: |
422 __ add(Operand(esp), Immediate(kPointerSize)); | 420 if (result_saved) __ add(Operand(esp), Immediate(kPointerSize)); |
423 } else if (destination.is_temporary() && !result_saved) { | 421 break; |
424 __ push(eax); | 422 case Location::TEMP: |
| 423 if (!result_saved) __ push(eax); |
| 424 break; |
425 } | 425 } |
426 } | 426 } |
427 | 427 |
428 | 428 |
429 void FastCodeGenerator::VisitAssignment(Assignment* expr) { | 429 void FastCodeGenerator::VisitAssignment(Assignment* expr) { |
430 Comment cmnt(masm_, "[ Assignment"); | 430 Comment cmnt(masm_, "[ Assignment"); |
431 ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR); | 431 ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR); |
432 | 432 |
433 // Left-hand side can only be a global or a (parameter or local) slot. | 433 // Left-hand side can only be a global or a (parameter or local) slot. |
434 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); | 434 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); |
435 ASSERT(var != NULL); | 435 ASSERT(var != NULL); |
436 ASSERT(var->is_global() || var->slot() != NULL); | 436 ASSERT(var->is_global() || var->slot() != NULL); |
437 | 437 |
438 Expression* rhs = expr->value(); | 438 Expression* rhs = expr->value(); |
439 Location destination = expr->location(); | |
440 if (var->is_global()) { | 439 if (var->is_global()) { |
441 // Assignment to a global variable, use inline caching. Right-hand-side | 440 // Assignment to a global variable, use inline caching. Right-hand-side |
442 // value is passed in eax, variable name in ecx, and the global object | 441 // value is passed in eax, variable name in ecx, and the global object |
443 // on the stack. | 442 // on the stack. |
444 | 443 |
445 // Code for the right-hand-side expression depends on its type. | 444 // Code for the right-hand-side expression depends on its type. |
446 if (rhs->AsLiteral() != NULL) { | 445 if (rhs->AsLiteral() != NULL) { |
447 __ mov(eax, rhs->AsLiteral()->handle()); | 446 __ mov(eax, rhs->AsLiteral()->handle()); |
448 } else { | 447 } else { |
449 ASSERT(rhs->location().is_temporary()); | 448 ASSERT(rhs->location().is_temporary()); |
450 Visit(rhs); | 449 Visit(rhs); |
451 __ pop(eax); | 450 __ pop(eax); |
452 } | 451 } |
453 __ mov(ecx, var->name()); | 452 __ mov(ecx, var->name()); |
454 __ push(CodeGenerator::GlobalObject()); | 453 __ push(CodeGenerator::GlobalObject()); |
455 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 454 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
456 __ call(ic, RelocInfo::CODE_TARGET); | 455 __ call(ic, RelocInfo::CODE_TARGET); |
457 // Overwrite the global object on the stack with the result if needed. | 456 // Overwrite the global object on the stack with the result if needed. |
458 if (destination.is_temporary()) { | 457 switch (expr->location().type()) { |
459 __ mov(Operand(esp, 0), eax); | 458 case Location::NOWHERE: |
460 } else { | 459 __ add(Operand(esp), Immediate(kPointerSize)); |
461 ASSERT(destination.is_nowhere()); | 460 break; |
462 __ add(Operand(esp), Immediate(kPointerSize)); | 461 case Location::TEMP: |
| 462 __ mov(Operand(esp, 0), eax); |
| 463 break; |
463 } | 464 } |
464 } else { | 465 } else { |
465 // Local or parameter assignment. | 466 // Local or parameter assignment. |
466 | 467 |
467 // Code for the right-hand side expression depends on its type. | 468 // Code for the right-hand side expression depends on its type. |
468 if (rhs->AsLiteral() != NULL) { | 469 if (rhs->AsLiteral() != NULL) { |
469 // Two cases: 'temp <- (var = constant)', or 'var = constant' with a | 470 // Two cases: 'temp <- (var = constant)', or 'var = constant' with a |
470 // discarded result. Always perform the assignment. | 471 // discarded result. Always perform the assignment. |
471 __ mov(eax, rhs->AsLiteral()->handle()); | 472 __ mov(eax, rhs->AsLiteral()->handle()); |
472 __ mov(Operand(ebp, SlotOffset(var->slot())), eax); | 473 __ mov(Operand(ebp, SlotOffset(var->slot())), eax); |
473 if (destination.is_temporary()) { | 474 Move(expr->location(), eax); |
474 // Case 'temp <- (var = constant)'. Save result. | |
475 __ push(eax); | |
476 } | |
477 } else { | 475 } else { |
478 ASSERT(rhs->location().is_temporary()); | 476 ASSERT(rhs->location().is_temporary()); |
479 Visit(rhs); | 477 Visit(rhs); |
480 if (destination.is_temporary()) { | 478 switch (expr->location().type()) { |
481 // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side | 479 case Location::NOWHERE: |
482 // temporary on the stack. | 480 // Case 'var = temp'. Discard right-hand-side temporary. |
483 __ mov(eax, Operand(esp, 0)); | 481 Move(var->slot(), rhs->location()); |
484 __ mov(Operand(ebp, SlotOffset(var->slot())), eax); | 482 break; |
485 } else { | 483 case Location::TEMP: |
486 ASSERT(destination.is_nowhere()); | 484 // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side |
487 // Case 'var = temp'. Discard right-hand-side temporary. | 485 // temporary on the stack. |
488 __ pop(Operand(ebp, SlotOffset(var->slot()))); | 486 __ mov(eax, Operand(esp, 0)); |
| 487 __ mov(Operand(ebp, SlotOffset(var->slot())), eax); |
| 488 break; |
489 } | 489 } |
490 } | 490 } |
491 } | 491 } |
492 } | 492 } |
493 | 493 |
494 | 494 |
495 void FastCodeGenerator::VisitCall(Call* expr) { | 495 void FastCodeGenerator::VisitCall(Call* expr) { |
496 Expression* fun = expr->expression(); | 496 Expression* fun = expr->expression(); |
497 ZoneList<Expression*>* args = expr->arguments(); | 497 ZoneList<Expression*>* args = expr->arguments(); |
498 Variable* var = fun->AsVariableProxy()->AsVariable(); | 498 Variable* var = fun->AsVariableProxy()->AsVariable(); |
(...skipping 10 matching lines...) Expand all Loading... |
509 } | 509 } |
510 // Record source position for debugger | 510 // Record source position for debugger |
511 SetSourcePosition(expr->position()); | 511 SetSourcePosition(expr->position()); |
512 // Call the IC initialization code. | 512 // Call the IC initialization code. |
513 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, | 513 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, |
514 NOT_IN_LOOP); | 514 NOT_IN_LOOP); |
515 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 515 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
516 // Restore context register. | 516 // Restore context register. |
517 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 517 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
518 // Discard the function left on TOS. | 518 // Discard the function left on TOS. |
519 if (expr->location().is_temporary()) { | 519 switch (expr->location().type()) { |
520 __ mov(Operand(esp, 0), eax); | 520 case Location::NOWHERE: |
521 } else { | 521 __ add(Operand(esp), Immediate(kPointerSize)); |
522 ASSERT(expr->location().is_nowhere()); | 522 break; |
523 __ add(Operand(esp), Immediate(kPointerSize)); | 523 case Location::TEMP: |
| 524 __ mov(Operand(esp, 0), eax); |
| 525 break; |
524 } | 526 } |
525 } | 527 } |
526 | 528 |
527 | 529 |
528 void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { | 530 void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { |
529 Comment cmnt(masm_, "[ CallRuntime"); | 531 Comment cmnt(masm_, "[ CallRuntime"); |
530 ZoneList<Expression*>* args = expr->arguments(); | 532 ZoneList<Expression*>* args = expr->arguments(); |
531 Runtime::Function* function = expr->function(); | 533 Runtime::Function* function = expr->function(); |
532 | 534 |
533 ASSERT(function != NULL); | 535 ASSERT(function != NULL); |
534 | 536 |
535 // Push the arguments ("left-to-right"). | 537 // Push the arguments ("left-to-right"). |
536 int arg_count = args->length(); | 538 int arg_count = args->length(); |
537 for (int i = 0; i < arg_count; i++) { | 539 for (int i = 0; i < arg_count; i++) { |
538 Visit(args->at(i)); | 540 Visit(args->at(i)); |
539 ASSERT(args->at(i)->location().is_temporary()); | 541 ASSERT(args->at(i)->location().is_temporary()); |
540 } | 542 } |
541 | 543 |
542 __ CallRuntime(function, arg_count); | 544 __ CallRuntime(function, arg_count); |
543 if (expr->location().is_temporary()) { | 545 Move(expr->location(), eax); |
544 __ push(eax); | |
545 } else { | |
546 ASSERT(expr->location().is_nowhere()); | |
547 } | |
548 } | 546 } |
549 | 547 |
550 | 548 |
551 void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { | 549 void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { |
552 // Compile a short-circuited boolean or operation in a non-test | 550 // Compile a short-circuited boolean or operation in a non-test |
553 // context. | 551 // context. |
554 ASSERT(expr->op() == Token::OR); | 552 ASSERT(expr->op() == Token::OR); |
555 // Compile (e0 || e1) as if it were | 553 // Compile (e0 || e1) as if it were |
556 // (let (temp = e0) temp ? temp : e1). | 554 // (let (temp = e0) temp ? temp : e1). |
557 | 555 |
558 Label eval_right, done; | 556 Label eval_right, done; |
559 Location destination = expr->location(); | 557 Location destination = expr->location(); |
560 Expression* left = expr->left(); | 558 Expression* left = expr->left(); |
561 Expression* right = expr->right(); | 559 Expression* right = expr->right(); |
562 | 560 |
563 // Use the shared ToBoolean stub to find the boolean value of the | 561 // Use the shared ToBoolean stub to find the boolean value of the |
564 // left-hand subexpression. Load the value into eax to perform some | 562 // left-hand subexpression. Load the value into eax to perform some |
565 // inlined checks assumed by the stub. | 563 // inlined checks assumed by the stub. |
566 | 564 |
567 // Compile the left-hand value into eax. Put it on the stack if we may | 565 // Compile the left-hand value into eax. Put it on the stack if we may |
568 // need it as the value of the whole expression. | 566 // need it as the value of the whole expression. |
569 if (left->AsLiteral() != NULL) { | 567 if (left->AsLiteral() != NULL) { |
570 __ mov(eax, left->AsLiteral()->handle()); | 568 __ mov(eax, left->AsLiteral()->handle()); |
571 if (destination.is_temporary()) __ push(eax); | 569 if (destination.is_temporary()) __ push(eax); |
572 } else { | 570 } else { |
573 Visit(left); | 571 Visit(left); |
574 ASSERT(left->location().is_temporary()); | 572 ASSERT(left->location().is_temporary()); |
575 if (destination.is_temporary()) { | 573 switch (destination.type()) { |
576 // Copy the left-hand value into eax because we may need it as the | 574 case Location::NOWHERE: |
577 // final result. | 575 // Pop the left-hand value into eax because we will not need it as the |
578 __ mov(eax, Operand(esp, 0)); | 576 // final result. |
579 } else { | 577 __ pop(eax); |
580 // Pop the left-hand value into eax because we will not need it as the | 578 break; |
581 // final result. | 579 case Location::TEMP: |
582 __ pop(eax); | 580 // Copy the left-hand value into eax because we may need it as the |
| 581 // final result. |
| 582 __ mov(eax, Operand(esp, 0)); |
| 583 break; |
583 } | 584 } |
584 } | 585 } |
585 // The left-hand value is in eax. It is also on the stack iff the | 586 // The left-hand value is in eax. It is also on the stack iff the |
586 // destination location is temporary. | 587 // destination location is temporary. |
587 | 588 |
588 // Perform fast checks assumed by the stub. | 589 // Perform fast checks assumed by the stub. |
589 __ cmp(eax, Factory::undefined_value()); // The undefined value is false. | 590 __ cmp(eax, Factory::undefined_value()); // The undefined value is false. |
590 __ j(equal, &eval_right); | 591 __ j(equal, &eval_right); |
591 __ cmp(eax, Factory::true_value()); // True is true. | 592 __ cmp(eax, Factory::true_value()); // True is true. |
592 __ j(equal, &done); | 593 __ j(equal, &done); |
(...skipping 12 matching lines...) Expand all Loading... |
605 __ test(eax, Operand(eax)); // The stub returns nonzero for true. | 606 __ test(eax, Operand(eax)); // The stub returns nonzero for true. |
606 __ j(not_zero, &done); | 607 __ j(not_zero, &done); |
607 | 608 |
608 __ bind(&eval_right); | 609 __ bind(&eval_right); |
609 // Discard the left-hand value if present on the stack. | 610 // Discard the left-hand value if present on the stack. |
610 if (destination.is_temporary()) { | 611 if (destination.is_temporary()) { |
611 __ add(Operand(esp), Immediate(kPointerSize)); | 612 __ add(Operand(esp), Immediate(kPointerSize)); |
612 } | 613 } |
613 // Save or discard the right-hand value as needed. | 614 // Save or discard the right-hand value as needed. |
614 if (right->AsLiteral() != NULL) { | 615 if (right->AsLiteral() != NULL) { |
615 if (destination.is_temporary()) { | 616 Move(destination, right->AsLiteral()); |
616 __ push(Immediate(right->AsLiteral()->handle())); | |
617 } else { | |
618 ASSERT(destination.is_nowhere()); | |
619 } | |
620 } else { | 617 } else { |
621 Visit(right); | 618 Visit(right); |
622 ASSERT(right->location().is_temporary()); | 619 Move(destination, right->location()); |
623 if (destination.is_nowhere()) { | |
624 __ add(Operand(esp), Immediate(kPointerSize)); | |
625 } else { | |
626 ASSERT(destination.is_temporary()); | |
627 } | |
628 } | 620 } |
629 | 621 |
630 __ bind(&done); | 622 __ bind(&done); |
631 } | 623 } |
632 | 624 |
633 | 625 |
634 } } // namespace v8::internal | 626 } } // namespace v8::internal |
OLD | NEW |