| 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 |