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 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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) { | 119 void FastCodeGenerator::Move(Location destination, Slot* source) { |
120 switch (destination.type()) { | 120 switch (destination.type()) { |
121 case Location::NOWHERE: | 121 case Location::UNINITIALIZED: |
| 122 UNREACHABLE(); |
| 123 case Location::EFFECT: |
122 break; | 124 break; |
123 case Location::TEMP: | 125 case Location::VALUE: |
124 __ push(Operand(rbp, SlotOffset(source))); | 126 __ push(Operand(rbp, SlotOffset(source))); |
125 break; | 127 break; |
126 } | 128 } |
127 } | 129 } |
128 | 130 |
129 | 131 |
130 void FastCodeGenerator::Move(Location destination, Literal* expr) { | 132 void FastCodeGenerator::Move(Location destination, Literal* expr) { |
131 switch (destination.type()) { | 133 switch (destination.type()) { |
132 case Location::NOWHERE: | 134 case Location::UNINITIALIZED: |
| 135 UNREACHABLE(); |
| 136 case Location::EFFECT: |
133 break; | 137 break; |
134 case Location::TEMP: | 138 case Location::VALUE: |
135 __ Push(expr->handle()); | 139 __ Push(expr->handle()); |
136 break; | 140 break; |
137 } | 141 } |
138 } | 142 } |
139 | 143 |
140 | 144 |
141 void FastCodeGenerator::Move(Slot* destination, Location source) { | 145 void FastCodeGenerator::Move(Slot* destination, Location source) { |
142 switch (source.type()) { | 146 switch (source.type()) { |
143 case Location::NOWHERE: | 147 case Location::UNINITIALIZED: // Fall through. |
| 148 case Location::EFFECT: |
144 UNREACHABLE(); | 149 UNREACHABLE(); |
145 case Location::TEMP: | 150 case Location::VALUE: |
146 __ pop(Operand(rbp, SlotOffset(destination))); | 151 __ pop(Operand(rbp, SlotOffset(destination))); |
147 break; | 152 break; |
148 } | 153 } |
149 } | 154 } |
150 | 155 |
151 | 156 |
152 void FastCodeGenerator::DropAndMove(Location destination, Register source) { | 157 void FastCodeGenerator::DropAndMove(Location destination, Register source) { |
153 switch (destination.type()) { | 158 switch (destination.type()) { |
154 case Location::NOWHERE: | 159 case Location::UNINITIALIZED: |
| 160 UNREACHABLE(); |
| 161 case Location::EFFECT: |
155 __ addq(rsp, Immediate(kPointerSize)); | 162 __ addq(rsp, Immediate(kPointerSize)); |
156 break; | 163 break; |
157 case Location::TEMP: | 164 case Location::VALUE: |
158 __ movq(Operand(rsp, 0), source); | 165 __ movq(Operand(rsp, 0), source); |
159 break; | 166 break; |
160 } | 167 } |
161 } | 168 } |
162 | 169 |
163 | 170 |
164 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 171 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
165 // Call the runtime to declare the globals. | 172 // Call the runtime to declare the globals. |
166 __ push(rsi); // The context is the first argument. | 173 __ push(rsi); // The context is the first argument. |
167 __ Push(pairs); | 174 __ Push(pairs); |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
239 // indicate that the inobject property case was inlined. Ensure there | 246 // indicate that the inobject property case was inlined. Ensure there |
240 // is no test rax instruction here. | 247 // is no test rax instruction here. |
241 DropAndMove(expr->location(), rax); | 248 DropAndMove(expr->location(), rax); |
242 } else { | 249 } else { |
243 Comment cmnt(masm_, "Stack slot"); | 250 Comment cmnt(masm_, "Stack slot"); |
244 Move(expr->location(), rewrite->AsSlot()); | 251 Move(expr->location(), rewrite->AsSlot()); |
245 } | 252 } |
246 } | 253 } |
247 | 254 |
248 | 255 |
| 256 void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
| 257 Comment cmnt(masm_, "[ RegExp Literal"); |
| 258 Label done; |
| 259 // Registers will be used as follows: |
| 260 // rdi = JS function. |
| 261 // rbx = literals array. |
| 262 // rax = regexp literal. |
| 263 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
| 264 __ movq(rbx, FieldOperand(rdi, JSFunction::kLiteralsOffset)); |
| 265 int literal_offset = |
| 266 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; |
| 267 __ movq(rax, FieldOperand(rbx, literal_offset)); |
| 268 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
| 269 __ j(not_equal, &done); |
| 270 // Create regexp literal using runtime function |
| 271 // Result will be in rax. |
| 272 __ push(rbx); |
| 273 __ Push(Smi::FromInt(expr->literal_index())); |
| 274 __ Push(expr->pattern()); |
| 275 __ Push(expr->flags()); |
| 276 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); |
| 277 // Label done: |
| 278 __ bind(&done); |
| 279 Move(expr->location(), rax); |
| 280 } |
| 281 |
| 282 |
249 void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { | 283 void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { |
250 Comment cmnt(masm_, "[ ObjectLiteral"); | 284 Comment cmnt(masm_, "[ ObjectLiteral"); |
251 Label boilerplate_exists; | 285 Label boilerplate_exists; |
252 | 286 |
253 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 287 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
254 __ movq(rbx, FieldOperand(rdi, JSFunction::kLiteralsOffset)); | 288 __ movq(rbx, FieldOperand(rdi, JSFunction::kLiteralsOffset)); |
255 int literal_offset = | 289 int literal_offset = |
256 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; | 290 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; |
257 __ movq(rax, FieldOperand(rbx, literal_offset)); | 291 __ movq(rax, FieldOperand(rbx, literal_offset)); |
258 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | 292 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
(...skipping 29 matching lines...) Expand all Loading... |
288 if (!result_saved) { | 322 if (!result_saved) { |
289 __ push(rax); // Save result on the stack | 323 __ push(rax); // Save result on the stack |
290 result_saved = true; | 324 result_saved = true; |
291 } | 325 } |
292 switch (property->kind()) { | 326 switch (property->kind()) { |
293 case ObjectLiteral::Property::MATERIALIZED_LITERAL: // fall through | 327 case ObjectLiteral::Property::MATERIALIZED_LITERAL: // fall through |
294 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); | 328 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); |
295 case ObjectLiteral::Property::COMPUTED: | 329 case ObjectLiteral::Property::COMPUTED: |
296 if (key->handle()->IsSymbol()) { | 330 if (key->handle()->IsSymbol()) { |
297 Visit(value); | 331 Visit(value); |
298 ASSERT(value->location().is_temporary()); | 332 ASSERT(value->location().is_value()); |
299 __ pop(rax); | 333 __ pop(rax); |
300 __ Move(rcx, key->handle()); | 334 __ Move(rcx, key->handle()); |
301 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 335 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
302 __ call(ic, RelocInfo::CODE_TARGET); | 336 __ call(ic, RelocInfo::CODE_TARGET); |
303 // StoreIC leaves the receiver on the stack. | 337 // StoreIC leaves the receiver on the stack. |
304 break; | 338 break; |
305 } | 339 } |
306 // fall through | 340 // fall through |
307 case ObjectLiteral::Property::PROTOTYPE: | 341 case ObjectLiteral::Property::PROTOTYPE: |
308 __ push(rax); | 342 __ push(rax); |
309 Visit(key); | 343 Visit(key); |
310 ASSERT(key->location().is_temporary()); | 344 ASSERT(key->location().is_value()); |
311 Visit(value); | 345 Visit(value); |
312 ASSERT(value->location().is_temporary()); | 346 ASSERT(value->location().is_value()); |
313 __ CallRuntime(Runtime::kSetProperty, 3); | 347 __ CallRuntime(Runtime::kSetProperty, 3); |
314 __ movq(rax, Operand(rsp, 0)); // Restore result into rax. | 348 __ movq(rax, Operand(rsp, 0)); // Restore result into rax. |
315 break; | 349 break; |
316 case ObjectLiteral::Property::SETTER: // fall through | 350 case ObjectLiteral::Property::SETTER: // fall through |
317 case ObjectLiteral::Property::GETTER: | 351 case ObjectLiteral::Property::GETTER: |
318 __ push(rax); | 352 __ push(rax); |
319 Visit(key); | 353 Visit(key); |
320 ASSERT(key->location().is_temporary()); | 354 ASSERT(key->location().is_value()); |
321 __ Push(property->kind() == ObjectLiteral::Property::SETTER ? | 355 __ Push(property->kind() == ObjectLiteral::Property::SETTER ? |
322 Smi::FromInt(1) : | 356 Smi::FromInt(1) : |
323 Smi::FromInt(0)); | 357 Smi::FromInt(0)); |
324 Visit(value); | 358 Visit(value); |
325 ASSERT(value->location().is_temporary()); | 359 ASSERT(value->location().is_value()); |
326 __ CallRuntime(Runtime::kDefineAccessor, 4); | 360 __ CallRuntime(Runtime::kDefineAccessor, 4); |
327 __ movq(rax, Operand(rsp, 0)); // Restore result into rax. | 361 __ movq(rax, Operand(rsp, 0)); // Restore result into rax. |
328 break; | 362 break; |
329 default: UNREACHABLE(); | 363 default: UNREACHABLE(); |
330 } | 364 } |
331 } | 365 } |
332 switch (expr->location().type()) { | 366 switch (expr->location().type()) { |
333 case Location::NOWHERE: | 367 case Location::UNINITIALIZED: |
| 368 UNREACHABLE(); |
| 369 case Location::EFFECT: |
334 if (result_saved) __ addq(rsp, Immediate(kPointerSize)); | 370 if (result_saved) __ addq(rsp, Immediate(kPointerSize)); |
335 break; | 371 break; |
336 case Location::TEMP: | 372 case Location::VALUE: |
337 if (!result_saved) __ push(rax); | 373 if (!result_saved) __ push(rax); |
338 break; | 374 break; |
339 } | 375 } |
340 } | 376 } |
341 | 377 |
342 | 378 |
343 void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { | |
344 Comment cmnt(masm_, "[ RegExp Literal"); | |
345 Label done; | |
346 // Registers will be used as follows: | |
347 // rdi = JS function. | |
348 // rbx = literals array. | |
349 // rax = regexp literal. | |
350 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | |
351 __ movq(rbx, FieldOperand(rdi, JSFunction::kLiteralsOffset)); | |
352 int literal_offset = | |
353 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; | |
354 __ movq(rax, FieldOperand(rbx, literal_offset)); | |
355 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | |
356 __ j(not_equal, &done); | |
357 // Create regexp literal using runtime function | |
358 // Result will be in rax. | |
359 __ push(rbx); | |
360 __ Push(Smi::FromInt(expr->literal_index())); | |
361 __ Push(expr->pattern()); | |
362 __ Push(expr->flags()); | |
363 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); | |
364 // Label done: | |
365 __ bind(&done); | |
366 Move(expr->location(), rax); | |
367 } | |
368 | |
369 | |
370 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { | 379 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
371 Comment cmnt(masm_, "[ ArrayLiteral"); | 380 Comment cmnt(masm_, "[ ArrayLiteral"); |
372 Label make_clone; | 381 Label make_clone; |
373 | 382 |
374 // Fetch the function's literals array. | 383 // Fetch the function's literals array. |
375 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 384 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
376 __ movq(rbx, FieldOperand(rbx, JSFunction::kLiteralsOffset)); | 385 __ movq(rbx, FieldOperand(rbx, JSFunction::kLiteralsOffset)); |
377 // Check if the literal's boilerplate has been instantiated. | 386 // Check if the literal's boilerplate has been instantiated. |
378 int offset = | 387 int offset = |
379 FixedArray::kHeaderSize + (expr->literal_index() * kPointerSize); | 388 FixedArray::kHeaderSize + (expr->literal_index() * kPointerSize); |
(...skipping 28 matching lines...) Expand all Loading... |
408 if (subexpr->AsLiteral() != NULL || | 417 if (subexpr->AsLiteral() != NULL || |
409 CompileTimeValue::IsCompileTimeValue(subexpr)) { | 418 CompileTimeValue::IsCompileTimeValue(subexpr)) { |
410 continue; | 419 continue; |
411 } | 420 } |
412 | 421 |
413 if (!result_saved) { | 422 if (!result_saved) { |
414 __ push(rax); | 423 __ push(rax); |
415 result_saved = true; | 424 result_saved = true; |
416 } | 425 } |
417 Visit(subexpr); | 426 Visit(subexpr); |
418 ASSERT(subexpr->location().is_temporary()); | 427 ASSERT(subexpr->location().is_value()); |
419 | 428 |
420 // Store the subexpression value in the array's elements. | 429 // Store the subexpression value in the array's elements. |
421 __ pop(rax); // Subexpression value. | 430 __ pop(rax); // Subexpression value. |
422 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal. | 431 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal. |
423 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset)); | 432 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset)); |
424 int offset = FixedArray::kHeaderSize + (i * kPointerSize); | 433 int offset = FixedArray::kHeaderSize + (i * kPointerSize); |
425 __ movq(FieldOperand(rbx, offset), rax); | 434 __ movq(FieldOperand(rbx, offset), rax); |
426 | 435 |
427 // Update the write barrier for the array store. | 436 // Update the write barrier for the array store. |
428 __ RecordWrite(rbx, offset, rax, rcx); | 437 __ RecordWrite(rbx, offset, rax, rcx); |
429 } | 438 } |
430 | 439 |
431 switch (expr->location().type()) { | 440 switch (expr->location().type()) { |
432 case Location::NOWHERE: | 441 case Location::UNINITIALIZED: |
| 442 UNREACHABLE(); |
| 443 case Location::EFFECT: |
433 if (result_saved) __ addq(rsp, Immediate(kPointerSize)); | 444 if (result_saved) __ addq(rsp, Immediate(kPointerSize)); |
434 break; | 445 break; |
435 case Location::TEMP: | 446 case Location::VALUE: |
436 if (!result_saved) __ push(rax); | 447 if (!result_saved) __ push(rax); |
437 break; | 448 break; |
438 } | 449 } |
439 } | 450 } |
440 | 451 |
441 | 452 |
442 void FastCodeGenerator::VisitAssignment(Assignment* expr) { | 453 void FastCodeGenerator::VisitAssignment(Assignment* expr) { |
443 Comment cmnt(masm_, "[ Assignment"); | 454 Comment cmnt(masm_, "[ Assignment"); |
444 ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR); | 455 ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR); |
445 | 456 |
446 // Left-hand side can only be a global or a (parameter or local) slot. | 457 // Left-hand side can only be a global or a (parameter or local) slot. |
447 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); | 458 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); |
448 ASSERT(var != NULL); | 459 ASSERT(var != NULL); |
449 ASSERT(var->is_global() || var->slot() != NULL); | 460 ASSERT(var->is_global() || var->slot() != NULL); |
450 | 461 |
451 Expression* rhs = expr->value(); | 462 Expression* rhs = expr->value(); |
452 Location destination = expr->location(); | 463 Location destination = expr->location(); |
453 if (var->is_global()) { | 464 if (var->is_global()) { |
454 // Assignment to a global variable, use inline caching. Right-hand-side | 465 // Assignment to a global variable, use inline caching. Right-hand-side |
455 // value is passed in rax, variable name in rcx, and the global object | 466 // value is passed in rax, variable name in rcx, and the global object |
456 // on the stack. | 467 // on the stack. |
457 | 468 |
458 // Code for the right-hand-side expression depends on its type. | 469 // Code for the right-hand-side expression depends on its type. |
459 if (rhs->AsLiteral() != NULL) { | 470 if (rhs->AsLiteral() != NULL) { |
460 __ Move(rax, rhs->AsLiteral()->handle()); | 471 __ Move(rax, rhs->AsLiteral()->handle()); |
461 } else { | 472 } else { |
462 ASSERT(rhs->location().is_temporary()); | 473 ASSERT(rhs->location().is_value()); |
463 Visit(rhs); | 474 Visit(rhs); |
464 __ pop(rax); | 475 __ pop(rax); |
465 } | 476 } |
466 __ Move(rcx, var->name()); | 477 __ Move(rcx, var->name()); |
467 __ push(CodeGenerator::GlobalObject()); | 478 __ push(CodeGenerator::GlobalObject()); |
468 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 479 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
469 __ Call(ic, RelocInfo::CODE_TARGET); | 480 __ Call(ic, RelocInfo::CODE_TARGET); |
470 // Overwrite the global object on the stack with the result if needed. | 481 // Overwrite the global object on the stack with the result if needed. |
471 DropAndMove(expr->location(), rax); | 482 DropAndMove(expr->location(), rax); |
472 } else { | 483 } else { |
473 // Local or parameter assignment. | 484 // Local or parameter assignment. |
474 | 485 |
475 // Code for the right-hand-side expression depends on its type. | 486 // Code for the right-hand-side expression depends on its type. |
476 if (rhs->AsLiteral() != NULL) { | 487 if (rhs->AsLiteral() != NULL) { |
477 // Two cases: 'temp <- (var = constant)', or 'var = constant' with a | 488 // Two cases: 'temp <- (var = constant)', or 'var = constant' with a |
478 // discarded result. Always perform the assignment. | 489 // discarded result. Always perform the assignment. |
479 __ Move(kScratchRegister, rhs->AsLiteral()->handle()); | 490 __ Move(kScratchRegister, rhs->AsLiteral()->handle()); |
480 __ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister); | 491 __ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister); |
481 Move(expr->location(), kScratchRegister); | 492 Move(expr->location(), kScratchRegister); |
482 } else { | 493 } else { |
483 ASSERT(rhs->location().is_temporary()); | 494 ASSERT(rhs->location().is_value()); |
484 Visit(rhs); | 495 Visit(rhs); |
485 switch (expr->location().type()) { | 496 switch (expr->location().type()) { |
486 case Location::NOWHERE: | 497 case Location::UNINITIALIZED: |
| 498 UNREACHABLE(); |
| 499 case Location::EFFECT: |
487 // Case 'var = temp'. Discard right-hand-side temporary. | 500 // Case 'var = temp'. Discard right-hand-side temporary. |
488 Move(var->slot(), rhs->location()); | 501 Move(var->slot(), rhs->location()); |
489 break; | 502 break; |
490 case Location::TEMP: | 503 case Location::VALUE: |
491 // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side | 504 // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side |
492 // temporary on the stack. | 505 // temporary on the stack. |
493 __ movq(kScratchRegister, Operand(rsp, 0)); | 506 __ movq(kScratchRegister, Operand(rsp, 0)); |
494 __ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister); | 507 __ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister); |
495 break; | 508 break; |
496 } | 509 } |
497 } | 510 } |
498 } | 511 } |
499 } | 512 } |
500 | 513 |
(...skipping 24 matching lines...) Expand all Loading... |
525 Visit(expr->key()); | 538 Visit(expr->key()); |
526 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 539 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
527 __ call(ic, RelocInfo::CODE_TARGET); | 540 __ call(ic, RelocInfo::CODE_TARGET); |
528 // By emitting a nop we make sure that we do not have a "test ..." | 541 // By emitting a nop we make sure that we do not have a "test ..." |
529 // instruction after the call it is treated specially by the LoadIC code. | 542 // instruction after the call it is treated specially by the LoadIC code. |
530 __ nop(); | 543 __ nop(); |
531 // Drop key left on the stack by IC. | 544 // Drop key left on the stack by IC. |
532 __ addq(rsp, Immediate(kPointerSize)); | 545 __ addq(rsp, Immediate(kPointerSize)); |
533 } | 546 } |
534 switch (expr->location().type()) { | 547 switch (expr->location().type()) { |
535 case Location::TEMP: | 548 case Location::UNINITIALIZED: |
| 549 UNREACHABLE(); |
| 550 case Location::VALUE: |
536 __ movq(Operand(rsp, 0), rax); | 551 __ movq(Operand(rsp, 0), rax); |
537 break; | 552 break; |
538 case Location::NOWHERE: | 553 case Location::EFFECT: |
539 __ addq(rsp, Immediate(kPointerSize)); | 554 __ addq(rsp, Immediate(kPointerSize)); |
540 break; | 555 break; |
541 } | 556 } |
542 } | 557 } |
543 | 558 |
544 | 559 |
545 void FastCodeGenerator::VisitCall(Call* expr) { | 560 void FastCodeGenerator::VisitCall(Call* expr) { |
546 Expression* fun = expr->expression(); | 561 Expression* fun = expr->expression(); |
547 ZoneList<Expression*>* args = expr->arguments(); | 562 ZoneList<Expression*>* args = expr->arguments(); |
548 Variable* var = fun->AsVariableProxy()->AsVariable(); | 563 Variable* var = fun->AsVariableProxy()->AsVariable(); |
549 ASSERT(var != NULL && !var->is_this() && var->is_global()); | 564 ASSERT(var != NULL && !var->is_this() && var->is_global()); |
550 ASSERT(!var->is_possibly_eval()); | 565 ASSERT(!var->is_possibly_eval()); |
551 | 566 |
552 __ Push(var->name()); | 567 __ Push(var->name()); |
553 // Push global object (receiver). | 568 // Push global object (receiver). |
554 __ push(CodeGenerator::GlobalObject()); | 569 __ push(CodeGenerator::GlobalObject()); |
555 int arg_count = args->length(); | 570 int arg_count = args->length(); |
556 for (int i = 0; i < arg_count; i++) { | 571 for (int i = 0; i < arg_count; i++) { |
557 Visit(args->at(i)); | 572 Visit(args->at(i)); |
558 ASSERT(args->at(i)->location().is_temporary()); | 573 ASSERT(args->at(i)->location().is_value()); |
559 } | 574 } |
560 // Record source position for debugger | 575 // Record source position for debugger |
561 SetSourcePosition(expr->position()); | 576 SetSourcePosition(expr->position()); |
562 // Call the IC initialization code. | 577 // Call the IC initialization code. |
563 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, | 578 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, |
564 NOT_IN_LOOP); | 579 NOT_IN_LOOP); |
565 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 580 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
566 // Restore context register. | 581 // Restore context register. |
567 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 582 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
568 // Discard the function left on TOS. | 583 // Discard the function left on TOS. |
569 DropAndMove(expr->location(), rax); | 584 DropAndMove(expr->location(), rax); |
570 } | 585 } |
571 | 586 |
572 | 587 |
573 void FastCodeGenerator::VisitCallNew(CallNew* node) { | 588 void FastCodeGenerator::VisitCallNew(CallNew* node) { |
574 Comment cmnt(masm_, "[ CallNew"); | 589 Comment cmnt(masm_, "[ CallNew"); |
575 // According to ECMA-262, section 11.2.2, page 44, the function | 590 // According to ECMA-262, section 11.2.2, page 44, the function |
576 // expression in new calls must be evaluated before the | 591 // expression in new calls must be evaluated before the |
577 // arguments. | 592 // arguments. |
578 // Push function on the stack. | 593 // Push function on the stack. |
579 Visit(node->expression()); | 594 Visit(node->expression()); |
580 ASSERT(node->expression()->location().is_temporary()); | 595 ASSERT(node->expression()->location().is_value()); |
581 // If location is temporary, already on the stack, | 596 // If location is temporary, already on the stack, |
582 | 597 |
583 // Push global object (receiver). | 598 // Push global object (receiver). |
584 __ push(CodeGenerator::GlobalObject()); | 599 __ push(CodeGenerator::GlobalObject()); |
585 | 600 |
586 // Push the arguments ("left-to-right") on the stack. | 601 // Push the arguments ("left-to-right") on the stack. |
587 ZoneList<Expression*>* args = node->arguments(); | 602 ZoneList<Expression*>* args = node->arguments(); |
588 int arg_count = args->length(); | 603 int arg_count = args->length(); |
589 for (int i = 0; i < arg_count; i++) { | 604 for (int i = 0; i < arg_count; i++) { |
590 Visit(args->at(i)); | 605 Visit(args->at(i)); |
591 ASSERT(args->at(i)->location().is_temporary()); | 606 ASSERT(args->at(i)->location().is_value()); |
592 // If location is temporary, it is already on the stack, | 607 // If location is temporary, it is already on the stack, |
593 // so nothing to do here. | 608 // so nothing to do here. |
594 } | 609 } |
595 | 610 |
596 // Call the construct call builtin that handles allocation and | 611 // Call the construct call builtin that handles allocation and |
597 // constructor invocation. | 612 // constructor invocation. |
598 SetSourcePosition(node->position()); | 613 SetSourcePosition(node->position()); |
599 | 614 |
600 // Load function, arg_count into rdi and rax. | 615 // Load function, arg_count into rdi and rax. |
601 __ Set(rax, arg_count); | 616 __ Set(rax, arg_count); |
(...skipping 12 matching lines...) Expand all Loading... |
614 Comment cmnt(masm_, "[ CallRuntime"); | 629 Comment cmnt(masm_, "[ CallRuntime"); |
615 ZoneList<Expression*>* args = expr->arguments(); | 630 ZoneList<Expression*>* args = expr->arguments(); |
616 Runtime::Function* function = expr->function(); | 631 Runtime::Function* function = expr->function(); |
617 | 632 |
618 ASSERT(function != NULL); | 633 ASSERT(function != NULL); |
619 | 634 |
620 // Push the arguments ("left-to-right"). | 635 // Push the arguments ("left-to-right"). |
621 int arg_count = args->length(); | 636 int arg_count = args->length(); |
622 for (int i = 0; i < arg_count; i++) { | 637 for (int i = 0; i < arg_count; i++) { |
623 Visit(args->at(i)); | 638 Visit(args->at(i)); |
624 ASSERT(args->at(i)->location().is_temporary()); | 639 ASSERT(args->at(i)->location().is_value()); |
625 } | 640 } |
626 | 641 |
627 __ CallRuntime(function, arg_count); | 642 __ CallRuntime(function, arg_count); |
628 Move(expr->location(), rax); | 643 Move(expr->location(), rax); |
629 } | 644 } |
630 | 645 |
631 | 646 |
632 void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { | 647 void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { |
633 // Compile a short-circuited boolean or operation in a non-test | 648 // Compile a short-circuited boolean or operation in a non-test |
634 // context. | 649 // context. |
635 ASSERT(expr->op() == Token::OR); | 650 ASSERT(expr->op() == Token::OR); |
636 // Compile (e0 || e1) as if it were | 651 // Compile (e0 || e1) as if it were |
637 // (let (temp = e0) temp ? temp : e1). | 652 // (let (temp = e0) temp ? temp : e1). |
638 | 653 |
639 Label eval_right, done; | 654 Label eval_right, done; |
640 Location destination = expr->location(); | 655 Location destination = expr->location(); |
641 Expression* left = expr->left(); | 656 Expression* left = expr->left(); |
642 Expression* right = expr->right(); | 657 Expression* right = expr->right(); |
643 | 658 |
644 // Use the shared ToBoolean stub to find the boolean value of the | 659 // Use the shared ToBoolean stub to find the boolean value of the |
645 // left-hand subexpression. Load the value into rax to perform some | 660 // left-hand subexpression. Load the value into rax to perform some |
646 // inlined checks assumed by the stub. | 661 // inlined checks assumed by the stub. |
647 | 662 |
648 // Compile the left-hand value into rax. Put it on the stack if we may | 663 // Compile the left-hand value into rax. Put it on the stack if we may |
649 // need it as the value of the whole expression. | 664 // need it as the value of the whole expression. |
650 if (left->AsLiteral() != NULL) { | 665 if (left->AsLiteral() != NULL) { |
651 __ Move(rax, left->AsLiteral()->handle()); | 666 __ Move(rax, left->AsLiteral()->handle()); |
652 if (destination.is_temporary()) __ push(rax); | 667 if (destination.is_value()) __ push(rax); |
653 } else { | 668 } else { |
654 Visit(left); | 669 Visit(left); |
655 ASSERT(left->location().is_temporary()); | 670 ASSERT(left->location().is_value()); |
656 switch (destination.type()) { | 671 switch (destination.type()) { |
657 case Location::NOWHERE: | 672 case Location::UNINITIALIZED: |
| 673 UNREACHABLE(); |
| 674 case Location::EFFECT: |
658 // Pop the left-hand value into rax because we will not need it as the | 675 // Pop the left-hand value into rax because we will not need it as the |
659 // final result. | 676 // final result. |
660 __ pop(rax); | 677 __ pop(rax); |
661 break; | 678 break; |
662 case Location::TEMP: | 679 case Location::VALUE: |
663 // Copy the left-hand value into rax because we may need it as the | 680 // Copy the left-hand value into rax because we may need it as the |
664 // final result. | 681 // final result. |
665 __ movq(rax, Operand(rsp, 0)); | 682 __ movq(rax, Operand(rsp, 0)); |
666 break; | 683 break; |
667 } | 684 } |
668 } | 685 } |
669 // The left-hand value is in rax. It is also on the stack iff the | 686 // The left-hand value is in rax. It is also on the stack iff the |
670 // destination location is temporary. | 687 // destination location is temporary. |
671 | 688 |
672 // Perform fast checks assumed by the stub. | 689 // Perform fast checks assumed by the stub. |
(...skipping 12 matching lines...) Expand all Loading... |
685 | 702 |
686 // Call the stub for all other cases. | 703 // Call the stub for all other cases. |
687 __ push(rax); | 704 __ push(rax); |
688 ToBooleanStub stub; | 705 ToBooleanStub stub; |
689 __ CallStub(&stub); | 706 __ CallStub(&stub); |
690 __ testq(rax, rax); // The stub returns nonzero for true. | 707 __ testq(rax, rax); // The stub returns nonzero for true. |
691 __ j(not_zero, &done); | 708 __ j(not_zero, &done); |
692 | 709 |
693 __ bind(&eval_right); | 710 __ bind(&eval_right); |
694 // Discard the left-hand value if present on the stack. | 711 // Discard the left-hand value if present on the stack. |
695 if (destination.is_temporary()) { | 712 if (destination.is_value()) { |
696 __ addq(rsp, Immediate(kPointerSize)); | 713 __ addq(rsp, Immediate(kPointerSize)); |
697 } | 714 } |
698 // Save or discard the right-hand value as needed. | 715 // Save or discard the right-hand value as needed. |
699 if (right->AsLiteral() != NULL) { | 716 if (right->AsLiteral() != NULL) { |
700 Move(destination, right->AsLiteral()); | 717 Move(destination, right->AsLiteral()); |
701 } else { | 718 } else { |
702 Visit(right); | 719 Visit(right); |
703 Move(destination, right->location()); | 720 Move(destination, right->location()); |
704 } | 721 } |
705 | 722 |
706 __ bind(&done); | 723 __ bind(&done); |
707 } | 724 } |
708 | 725 |
709 | 726 |
710 } } // namespace v8::internal | 727 } } // namespace v8::internal |
OLD | NEW |