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 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
109 // (3 + 1 + 3). | 109 // (3 + 1 + 3). |
110 const int kPadding = Debug::kX64JSReturnSequenceLength - 7; | 110 const int kPadding = Debug::kX64JSReturnSequenceLength - 7; |
111 for (int i = 0; i < kPadding; ++i) { | 111 for (int i = 0; i < kPadding; ++i) { |
112 masm_->int3(); | 112 masm_->int3(); |
113 } | 113 } |
114 #endif | 114 #endif |
115 } | 115 } |
116 } | 116 } |
117 | 117 |
118 | 118 |
| 119 void FastCodeGenerator::Move(Location destination, Slot* source) { |
| 120 switch (destination.type()) { |
| 121 case Location::NOWHERE: |
| 122 break; |
| 123 case Location::TEMP: |
| 124 __ push(Operand(rbp, SlotOffset(source))); |
| 125 break; |
| 126 } |
| 127 } |
| 128 |
| 129 |
| 130 void FastCodeGenerator::Move(Location destination, Literal* expr) { |
| 131 switch (destination.type()) { |
| 132 case Location::NOWHERE: |
| 133 break; |
| 134 case Location::TEMP: |
| 135 __ Push(expr->handle()); |
| 136 break; |
| 137 } |
| 138 } |
| 139 |
| 140 |
| 141 void FastCodeGenerator::Move(Slot* destination, Location source) { |
| 142 switch (source.type()) { |
| 143 case Location::NOWHERE: |
| 144 UNREACHABLE(); |
| 145 case Location::TEMP: |
| 146 __ pop(Operand(rbp, SlotOffset(destination))); |
| 147 break; |
| 148 } |
| 149 } |
| 150 |
| 151 |
119 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 152 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
120 // Call the runtime to declare the globals. | 153 // Call the runtime to declare the globals. |
121 __ push(rsi); // The context is the first argument. | 154 __ push(rsi); // The context is the first argument. |
122 __ Push(pairs); | 155 __ Push(pairs); |
123 __ Push(Smi::FromInt(is_eval_ ? 1 : 0)); | 156 __ Push(Smi::FromInt(is_eval_ ? 1 : 0)); |
124 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 157 __ CallRuntime(Runtime::kDeclareGlobals, 3); |
125 // Return value is ignored. | 158 // Return value is ignored. |
126 } | 159 } |
127 | 160 |
128 | 161 |
129 void FastCodeGenerator::VisitBlock(Block* stmt) { | |
130 Comment cmnt(masm_, "[ Block"); | |
131 SetStatementPosition(stmt); | |
132 VisitStatements(stmt->statements()); | |
133 } | |
134 | |
135 | |
136 void FastCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { | |
137 Comment cmnt(masm_, "[ ExpressionStatement"); | |
138 SetStatementPosition(stmt); | |
139 Visit(stmt->expression()); | |
140 } | |
141 | |
142 | |
143 void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { | 162 void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { |
144 Comment cmnt(masm_, "[ ReturnStatement"); | 163 Comment cmnt(masm_, "[ ReturnStatement"); |
145 SetStatementPosition(stmt); | 164 SetStatementPosition(stmt); |
146 Expression* expr = stmt->expression(); | 165 Expression* expr = stmt->expression(); |
147 // Complete the statement based on the type of the subexpression. | 166 // Complete the statement based on the type of the subexpression. |
148 if (expr->AsLiteral() != NULL) { | 167 if (expr->AsLiteral() != NULL) { |
149 __ Move(rax, expr->AsLiteral()->handle()); | 168 __ Move(rax, expr->AsLiteral()->handle()); |
150 } else { | 169 } else { |
151 Visit(expr); | 170 Visit(expr); |
152 ASSERT(expr->location().is_temporary()); | 171 ASSERT(expr->location().is_temporary()); |
(...skipping 29 matching lines...) Expand all Loading... |
182 // Build the function boilerplate and instantiate it. | 201 // Build the function boilerplate and instantiate it. |
183 Handle<JSFunction> boilerplate = BuildBoilerplate(expr); | 202 Handle<JSFunction> boilerplate = BuildBoilerplate(expr); |
184 if (HasStackOverflow()) return; | 203 if (HasStackOverflow()) return; |
185 | 204 |
186 ASSERT(boilerplate->IsBoilerplate()); | 205 ASSERT(boilerplate->IsBoilerplate()); |
187 | 206 |
188 // Create a new closure. | 207 // Create a new closure. |
189 __ push(rsi); | 208 __ push(rsi); |
190 __ Push(boilerplate); | 209 __ Push(boilerplate); |
191 __ CallRuntime(Runtime::kNewClosure, 2); | 210 __ CallRuntime(Runtime::kNewClosure, 2); |
192 | 211 Move(expr->location(), rax); |
193 if (expr->location().is_temporary()) { | |
194 __ push(rax); | |
195 } else { | |
196 ASSERT(expr->location().is_nowhere()); | |
197 } | |
198 } | 212 } |
199 | 213 |
200 | 214 |
201 void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) { | 215 void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) { |
202 Comment cmnt(masm_, "[ VariableProxy"); | 216 Comment cmnt(masm_, "[ VariableProxy"); |
203 Expression* rewrite = expr->var()->rewrite(); | 217 Expression* rewrite = expr->var()->rewrite(); |
204 if (rewrite == NULL) { | 218 if (rewrite == NULL) { |
205 Comment cmnt(masm_, "Global variable"); | 219 Comment cmnt(masm_, "Global variable"); |
206 // Use inline caching. Variable name is passed in rcx and the global | 220 // Use inline caching. Variable name is passed in rcx and the global |
207 // object on the stack. | 221 // object on the stack. |
208 __ push(CodeGenerator::GlobalObject()); | 222 __ push(CodeGenerator::GlobalObject()); |
209 __ Move(rcx, expr->name()); | 223 __ Move(rcx, expr->name()); |
210 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 224 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
211 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 225 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
212 | 226 |
213 // A test rax instruction following the call is used by the IC to | 227 // A test rax instruction following the call is used by the IC to |
214 // indicate that the inobject property case was inlined. Ensure there | 228 // indicate that the inobject property case was inlined. Ensure there |
215 // is no test rax instruction here. | 229 // is no test rax instruction here. |
216 if (expr->location().is_temporary()) { | 230 switch (expr->location().type()) { |
217 // Replace the global object with the result. | 231 case Location::NOWHERE: |
218 __ movq(Operand(rsp, 0), rax); | 232 __ addq(rsp, Immediate(kPointerSize)); |
219 } else { | 233 break; |
220 ASSERT(expr->location().is_nowhere()); | 234 case Location::TEMP: |
221 __ addq(rsp, Immediate(kPointerSize)); | 235 // Replace the global object with the result. |
| 236 __ movq(Operand(rsp, 0), rax); |
| 237 break; |
222 } | 238 } |
223 | 239 |
224 } else { | 240 } else { |
225 Comment cmnt(masm_, "Stack slot"); | 241 Comment cmnt(masm_, "Stack slot"); |
226 Slot* slot = rewrite->AsSlot(); | 242 Move(expr->location(), rewrite->AsSlot()); |
227 ASSERT(slot != NULL); | |
228 if (expr->location().is_temporary()) { | |
229 __ push(Operand(rbp, SlotOffset(slot))); | |
230 } else { | |
231 ASSERT(expr->location().is_nowhere()); | |
232 } | |
233 } | |
234 } | |
235 | |
236 | |
237 void FastCodeGenerator::VisitLiteral(Literal* expr) { | |
238 if (expr->location().is_temporary()) { | |
239 __ Push(expr->handle()); | |
240 } else { | |
241 ASSERT(expr->location().is_nowhere()); | |
242 } | 243 } |
243 } | 244 } |
244 | 245 |
245 | 246 |
246 void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { | 247 void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { |
247 Comment cmnt(masm_, "[ ObjectLiteral"); | 248 Comment cmnt(masm_, "[ ObjectLiteral"); |
248 Label boilerplate_exists; | 249 Label boilerplate_exists; |
249 | 250 |
250 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 251 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
251 __ movq(rbx, FieldOperand(rdi, JSFunction::kLiteralsOffset)); | 252 __ movq(rbx, FieldOperand(rdi, JSFunction::kLiteralsOffset)); |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
322 Smi::FromInt(1) : | 323 Smi::FromInt(1) : |
323 Smi::FromInt(0)); | 324 Smi::FromInt(0)); |
324 Visit(value); | 325 Visit(value); |
325 ASSERT(value->location().is_temporary()); | 326 ASSERT(value->location().is_temporary()); |
326 __ CallRuntime(Runtime::kDefineAccessor, 4); | 327 __ CallRuntime(Runtime::kDefineAccessor, 4); |
327 __ movq(rax, Operand(rsp, 0)); // Restore result into rax. | 328 __ movq(rax, Operand(rsp, 0)); // Restore result into rax. |
328 break; | 329 break; |
329 default: UNREACHABLE(); | 330 default: UNREACHABLE(); |
330 } | 331 } |
331 } | 332 } |
332 if (expr->location().is_nowhere() && result_saved) { | 333 switch (expr->location().type()) { |
333 __ addq(rsp, Immediate(kPointerSize)); | 334 case Location::NOWHERE: |
334 } else if (expr->location().is_temporary() && !result_saved) { | 335 if (result_saved) __ addq(rsp, Immediate(kPointerSize)); |
335 __ push(rax); | 336 break; |
| 337 case Location::TEMP: |
| 338 if (!result_saved) __ push(rax); |
| 339 break; |
336 } | 340 } |
337 } | 341 } |
338 | 342 |
339 | 343 |
340 void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { | 344 void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
341 Comment cmnt(masm_, "[ RegExp Literal"); | 345 Comment cmnt(masm_, "[ RegExp Literal"); |
342 Label done; | 346 Label done; |
343 // Registers will be used as follows: | 347 // Registers will be used as follows: |
344 // rdi = JS function. | 348 // rdi = JS function. |
345 // rbx = literals array. | 349 // rbx = literals array. |
346 // rax = regexp literal. | 350 // rax = regexp literal. |
347 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 351 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
348 __ movq(rbx, FieldOperand(rdi, JSFunction::kLiteralsOffset)); | 352 __ movq(rbx, FieldOperand(rdi, JSFunction::kLiteralsOffset)); |
349 int literal_offset = | 353 int literal_offset = |
350 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; | 354 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; |
351 __ movq(rax, FieldOperand(rbx, literal_offset)); | 355 __ movq(rax, FieldOperand(rbx, literal_offset)); |
352 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | 356 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
353 __ j(not_equal, &done); | 357 __ j(not_equal, &done); |
354 // Create regexp literal using runtime function | 358 // Create regexp literal using runtime function |
355 // Result will be in rax. | 359 // Result will be in rax. |
356 __ push(rbx); | 360 __ push(rbx); |
357 __ Push(Smi::FromInt(expr->literal_index())); | 361 __ Push(Smi::FromInt(expr->literal_index())); |
358 __ Push(expr->pattern()); | 362 __ Push(expr->pattern()); |
359 __ Push(expr->flags()); | 363 __ Push(expr->flags()); |
360 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); | 364 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); |
361 // Label done: | 365 // Label done: |
362 __ bind(&done); | 366 __ bind(&done); |
363 if (expr->location().is_temporary()) { | 367 Move(expr->location(), rax); |
364 __ push(rax); | |
365 } else { | |
366 ASSERT(expr->location().is_nowhere()); | |
367 } | |
368 } | 368 } |
369 | 369 |
370 | 370 |
371 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { | 371 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
372 Comment cmnt(masm_, "[ ArrayLiteral"); | 372 Comment cmnt(masm_, "[ ArrayLiteral"); |
373 Label make_clone; | 373 Label make_clone; |
374 | 374 |
375 // Fetch the function's literals array. | 375 // Fetch the function's literals array. |
376 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 376 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
377 __ movq(rbx, FieldOperand(rbx, JSFunction::kLiteralsOffset)); | 377 __ movq(rbx, FieldOperand(rbx, JSFunction::kLiteralsOffset)); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
422 __ pop(rax); // Subexpression value. | 422 __ pop(rax); // Subexpression value. |
423 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal. | 423 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal. |
424 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset)); | 424 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset)); |
425 int offset = FixedArray::kHeaderSize + (i * kPointerSize); | 425 int offset = FixedArray::kHeaderSize + (i * kPointerSize); |
426 __ movq(FieldOperand(rbx, offset), rax); | 426 __ movq(FieldOperand(rbx, offset), rax); |
427 | 427 |
428 // Update the write barrier for the array store. | 428 // Update the write barrier for the array store. |
429 __ RecordWrite(rbx, offset, rax, rcx); | 429 __ RecordWrite(rbx, offset, rax, rcx); |
430 } | 430 } |
431 | 431 |
432 Location destination = expr->location(); | 432 switch (expr->location().type()) { |
433 if (destination.is_nowhere() && result_saved) { | 433 case Location::NOWHERE: |
434 __ addq(rsp, Immediate(kPointerSize)); | 434 if (result_saved) __ addq(rsp, Immediate(kPointerSize)); |
435 } else if (destination.is_temporary() && !result_saved) { | 435 break; |
436 __ push(rax); | 436 case Location::TEMP: |
| 437 if (!result_saved) __ push(rax); |
| 438 break; |
437 } | 439 } |
438 } | 440 } |
439 | 441 |
440 | 442 |
441 void FastCodeGenerator::VisitAssignment(Assignment* expr) { | 443 void FastCodeGenerator::VisitAssignment(Assignment* expr) { |
442 Comment cmnt(masm_, "[ Assignment"); | 444 Comment cmnt(masm_, "[ Assignment"); |
443 ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR); | 445 ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR); |
444 | 446 |
445 // Left-hand side can only be a global or a (parameter or local) slot. | 447 // Left-hand side can only be a global or a (parameter or local) slot. |
446 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); | 448 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); |
(...skipping 13 matching lines...) Expand all Loading... |
460 } else { | 462 } else { |
461 ASSERT(rhs->location().is_temporary()); | 463 ASSERT(rhs->location().is_temporary()); |
462 Visit(rhs); | 464 Visit(rhs); |
463 __ pop(rax); | 465 __ pop(rax); |
464 } | 466 } |
465 __ Move(rcx, var->name()); | 467 __ Move(rcx, var->name()); |
466 __ push(CodeGenerator::GlobalObject()); | 468 __ push(CodeGenerator::GlobalObject()); |
467 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 469 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
468 __ Call(ic, RelocInfo::CODE_TARGET); | 470 __ Call(ic, RelocInfo::CODE_TARGET); |
469 // Overwrite the global object on the stack with the result if needed. | 471 // Overwrite the global object on the stack with the result if needed. |
470 if (destination.is_temporary()) { | 472 switch (expr->location().type()) { |
471 __ movq(Operand(rsp, 0), rax); | 473 case Location::NOWHERE: |
472 } else { | 474 __ addq(rsp, Immediate(kPointerSize)); |
473 __ addq(rsp, Immediate(kPointerSize)); | 475 break; |
| 476 case Location::TEMP: |
| 477 __ movq(Operand(rsp, 0), rax); |
| 478 break; |
474 } | 479 } |
475 } else { | 480 } else { |
476 // Local or parameter assignment. | 481 // Local or parameter assignment. |
477 | 482 |
478 // Code for the right-hand-side expression depends on its type. | 483 // Code for the right-hand-side expression depends on its type. |
479 if (rhs->AsLiteral() != NULL) { | 484 if (rhs->AsLiteral() != NULL) { |
480 // Two cases: 'temp <- (var = constant)', or 'var = constant' with a | 485 // Two cases: 'temp <- (var = constant)', or 'var = constant' with a |
481 // discarded result. Always perform the assignment. | 486 // discarded result. Always perform the assignment. |
482 __ Move(kScratchRegister, rhs->AsLiteral()->handle()); | 487 __ Move(kScratchRegister, rhs->AsLiteral()->handle()); |
483 __ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister); | 488 __ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister); |
484 if (destination.is_temporary()) { | 489 Move(expr->location(), kScratchRegister); |
485 // Case 'temp <- (var = constant)'. Save result. | |
486 __ push(kScratchRegister); | |
487 } | |
488 } else { | 490 } else { |
489 ASSERT(rhs->location().is_temporary()); | 491 ASSERT(rhs->location().is_temporary()); |
490 Visit(rhs); | 492 Visit(rhs); |
491 if (destination.is_temporary()) { | 493 switch (expr->location().type()) { |
492 // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side temporary | 494 case Location::NOWHERE: |
493 // on the stack. | 495 // Case 'var = temp'. Discard right-hand-side temporary. |
494 __ movq(kScratchRegister, Operand(rsp, 0)); | 496 Move(var->slot(), rhs->location()); |
495 __ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister); | 497 break; |
496 } else { | 498 case Location::TEMP: |
497 ASSERT(destination.is_nowhere()); | 499 // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side |
498 // Case 'var = temp'. Discard right-hand-side temporary. | 500 // temporary on the stack. |
499 __ pop(Operand(rbp, SlotOffset(var->slot()))); | 501 __ movq(kScratchRegister, Operand(rsp, 0)); |
| 502 __ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister); |
| 503 break; |
500 } | 504 } |
501 } | 505 } |
502 } | 506 } |
503 } | 507 } |
504 | 508 |
505 | 509 |
506 void FastCodeGenerator::VisitCall(Call* expr) { | 510 void FastCodeGenerator::VisitCall(Call* expr) { |
507 Expression* fun = expr->expression(); | 511 Expression* fun = expr->expression(); |
508 ZoneList<Expression*>* args = expr->arguments(); | 512 ZoneList<Expression*>* args = expr->arguments(); |
509 Variable* var = fun->AsVariableProxy()->AsVariable(); | 513 Variable* var = fun->AsVariableProxy()->AsVariable(); |
(...skipping 10 matching lines...) Expand all Loading... |
520 } | 524 } |
521 // Record source position for debugger | 525 // Record source position for debugger |
522 SetSourcePosition(expr->position()); | 526 SetSourcePosition(expr->position()); |
523 // Call the IC initialization code. | 527 // Call the IC initialization code. |
524 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, | 528 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, |
525 NOT_IN_LOOP); | 529 NOT_IN_LOOP); |
526 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 530 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
527 // Restore context register. | 531 // Restore context register. |
528 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 532 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
529 // Discard the function left on TOS. | 533 // Discard the function left on TOS. |
530 if (expr->location().is_temporary()) { | 534 switch (expr->location().type()) { |
531 __ movq(Operand(rsp, 0), rax); | 535 case Location::NOWHERE: |
532 } else { | 536 __ addq(rsp, Immediate(kPointerSize)); |
533 ASSERT(expr->location().is_nowhere()); | 537 break; |
534 __ addq(rsp, Immediate(kPointerSize)); | 538 case Location::TEMP: |
| 539 __ movq(Operand(rsp, 0), rax); |
| 540 break; |
535 } | 541 } |
536 } | 542 } |
537 | 543 |
538 | 544 |
539 void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { | 545 void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { |
540 Comment cmnt(masm_, "[ CallRuntime"); | 546 Comment cmnt(masm_, "[ CallRuntime"); |
541 ZoneList<Expression*>* args = expr->arguments(); | 547 ZoneList<Expression*>* args = expr->arguments(); |
542 Runtime::Function* function = expr->function(); | 548 Runtime::Function* function = expr->function(); |
543 | 549 |
544 ASSERT(function != NULL); | 550 ASSERT(function != NULL); |
545 | 551 |
546 // Push the arguments ("left-to-right"). | 552 // Push the arguments ("left-to-right"). |
547 int arg_count = args->length(); | 553 int arg_count = args->length(); |
548 for (int i = 0; i < arg_count; i++) { | 554 for (int i = 0; i < arg_count; i++) { |
549 Visit(args->at(i)); | 555 Visit(args->at(i)); |
550 ASSERT(args->at(i)->location().is_temporary()); | 556 ASSERT(args->at(i)->location().is_temporary()); |
551 } | 557 } |
552 | 558 |
553 __ CallRuntime(function, arg_count); | 559 __ CallRuntime(function, arg_count); |
554 if (expr->location().is_temporary()) { | 560 Move(expr->location(), rax); |
555 __ push(rax); | |
556 } else { | |
557 ASSERT(expr->location().is_nowhere()); | |
558 } | |
559 } | 561 } |
560 | 562 |
561 | 563 |
562 void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { | 564 void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { |
563 // Compile a short-circuited boolean or operation in a non-test | 565 // Compile a short-circuited boolean or operation in a non-test |
564 // context. | 566 // context. |
565 ASSERT(expr->op() == Token::OR); | 567 ASSERT(expr->op() == Token::OR); |
566 // Compile (e0 || e1) as if it were | 568 // Compile (e0 || e1) as if it were |
567 // (let (temp = e0) temp ? temp : e1). | 569 // (let (temp = e0) temp ? temp : e1). |
568 | 570 |
569 Label eval_right, done; | 571 Label eval_right, done; |
570 Location destination = expr->location(); | 572 Location destination = expr->location(); |
571 Expression* left = expr->left(); | 573 Expression* left = expr->left(); |
572 Expression* right = expr->right(); | 574 Expression* right = expr->right(); |
573 | 575 |
574 // Use the shared ToBoolean stub to find the boolean value of the | 576 // Use the shared ToBoolean stub to find the boolean value of the |
575 // left-hand subexpression. Load the value into rax to perform some | 577 // left-hand subexpression. Load the value into rax to perform some |
576 // inlined checks assumed by the stub. | 578 // inlined checks assumed by the stub. |
577 | 579 |
578 // Compile the left-hand value into rax. Put it on the stack if we may | 580 // Compile the left-hand value into rax. Put it on the stack if we may |
579 // need it as the value of the whole expression. | 581 // need it as the value of the whole expression. |
580 if (left->AsLiteral() != NULL) { | 582 if (left->AsLiteral() != NULL) { |
581 __ Move(rax, left->AsLiteral()->handle()); | 583 __ Move(rax, left->AsLiteral()->handle()); |
582 if (destination.is_temporary()) __ push(rax); | 584 if (destination.is_temporary()) __ push(rax); |
583 } else { | 585 } else { |
584 Visit(left); | 586 Visit(left); |
585 ASSERT(left->location().is_temporary()); | 587 ASSERT(left->location().is_temporary()); |
586 if (destination.is_temporary()) { | 588 switch (destination.type()) { |
587 // Copy the left-hand value into rax because we may need it as the | 589 case Location::NOWHERE: |
588 // final result. | 590 // Pop the left-hand value into rax because we will not need it as the |
589 __ movq(rax, Operand(rsp, 0)); | 591 // final result. |
590 } else { | 592 __ pop(rax); |
591 // Pop the left-hand value into rax because we will not need it as the | 593 break; |
592 // final result. | 594 case Location::TEMP: |
593 __ pop(rax); | 595 // Copy the left-hand value into rax because we may need it as the |
| 596 // final result. |
| 597 __ movq(rax, Operand(rsp, 0)); |
| 598 break; |
594 } | 599 } |
595 } | 600 } |
596 // The left-hand value is in rax. It is also on the stack iff the | 601 // The left-hand value is in rax. It is also on the stack iff the |
597 // destination location is temporary. | 602 // destination location is temporary. |
598 | 603 |
599 // Perform fast checks assumed by the stub. | 604 // Perform fast checks assumed by the stub. |
600 // The undefined value is false. | 605 // The undefined value is false. |
601 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | 606 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
602 __ j(equal, &eval_right); | 607 __ j(equal, &eval_right); |
603 __ CompareRoot(rax, Heap::kTrueValueRootIndex); // True is true. | 608 __ CompareRoot(rax, Heap::kTrueValueRootIndex); // True is true. |
(...skipping 13 matching lines...) Expand all Loading... |
617 __ testq(rax, rax); // The stub returns nonzero for true. | 622 __ testq(rax, rax); // The stub returns nonzero for true. |
618 __ j(not_zero, &done); | 623 __ j(not_zero, &done); |
619 | 624 |
620 __ bind(&eval_right); | 625 __ bind(&eval_right); |
621 // Discard the left-hand value if present on the stack. | 626 // Discard the left-hand value if present on the stack. |
622 if (destination.is_temporary()) { | 627 if (destination.is_temporary()) { |
623 __ addq(rsp, Immediate(kPointerSize)); | 628 __ addq(rsp, Immediate(kPointerSize)); |
624 } | 629 } |
625 // Save or discard the right-hand value as needed. | 630 // Save or discard the right-hand value as needed. |
626 if (right->AsLiteral() != NULL) { | 631 if (right->AsLiteral() != NULL) { |
627 if (destination.is_temporary()) { | 632 Move(destination, right->AsLiteral()); |
628 __ Push(right->AsLiteral()->handle()); | |
629 } else { | |
630 ASSERT(destination.is_nowhere()); | |
631 } | |
632 } else { | 633 } else { |
633 Visit(right); | 634 Visit(right); |
634 ASSERT(right->location().is_temporary()); | 635 Move(destination, right->location()); |
635 if (destination.is_nowhere()) { | |
636 __ addq(rsp, Immediate(kPointerSize)); | |
637 } else { | |
638 ASSERT(destination.is_temporary()); | |
639 } | |
640 } | 636 } |
641 | 637 |
642 __ bind(&done); | 638 __ bind(&done); |
643 } | 639 } |
644 | 640 |
645 | 641 |
646 } } // namespace v8::internal | 642 } } // namespace v8::internal |
OLD | NEW |