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 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
55 function_ = fun; | 55 function_ = fun; |
56 SetFunctionPosition(fun); | 56 SetFunctionPosition(fun); |
57 | 57 |
58 __ push(rbp); // Caller's frame pointer. | 58 __ push(rbp); // Caller's frame pointer. |
59 __ movq(rbp, rsp); | 59 __ movq(rbp, rsp); |
60 __ push(rsi); // Callee's context. | 60 __ push(rsi); // Callee's context. |
61 __ push(rdi); // Callee's JS Function. | 61 __ push(rdi); // Callee's JS Function. |
62 | 62 |
63 { Comment cmnt(masm_, "[ Allocate locals"); | 63 { Comment cmnt(masm_, "[ Allocate locals"); |
64 int locals_count = fun->scope()->num_stack_slots(); | 64 int locals_count = fun->scope()->num_stack_slots(); |
65 if (locals_count <= 1) { | 65 if (locals_count == 1) { |
66 if (locals_count > 0) { | 66 __ PushRoot(Heap::kUndefinedValueRootIndex); |
67 __ PushRoot(Heap::kUndefinedValueRootIndex); | 67 } else if (locals_count > 1) { |
68 } | |
69 } else { | |
70 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex); | 68 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex); |
71 for (int i = 0; i < locals_count; i++) { | 69 for (int i = 0; i < locals_count; i++) { |
72 __ push(rdx); | 70 __ push(rdx); |
73 } | 71 } |
74 } | 72 } |
75 } | 73 } |
76 | 74 |
77 bool function_in_register = true; | 75 bool function_in_register = true; |
78 | 76 |
79 // Possibly allocate a local context. | 77 // Possibly allocate a local context. |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
195 } | 193 } |
196 // Check that the size of the code used for returning matches what is | 194 // Check that the size of the code used for returning matches what is |
197 // expected by the debugger. | 195 // expected by the debugger. |
198 ASSERT_EQ(Assembler::kJSReturnSequenceLength, | 196 ASSERT_EQ(Assembler::kJSReturnSequenceLength, |
199 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); | 197 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); |
200 #endif | 198 #endif |
201 } | 199 } |
202 } | 200 } |
203 | 201 |
204 | 202 |
205 void FastCodeGenerator::Apply(Expression::Context context, | 203 void FastCodeGenerator::Apply(Expression::Context context, Register reg) { |
206 Slot* slot, | 204 switch (context) { |
207 Register scratch) { | 205 case Expression::kUninitialized: |
| 206 UNREACHABLE(); |
| 207 |
| 208 case Expression::kEffect: |
| 209 // Nothing to do. |
| 210 break; |
| 211 |
| 212 case Expression::kValue: |
| 213 // Move value into place. |
| 214 switch (location_) { |
| 215 case kAccumulator: |
| 216 if (!reg.is(result_register())) __ movq(result_register(), reg); |
| 217 break; |
| 218 case kStack: |
| 219 __ push(reg); |
| 220 break; |
| 221 } |
| 222 break; |
| 223 |
| 224 case Expression::kValueTest: |
| 225 case Expression::kTestValue: |
| 226 // Push an extra copy of the value in case it's needed. |
| 227 __ push(reg); |
| 228 // Fall through. |
| 229 |
| 230 case Expression::kTest: |
| 231 // For simplicity we always test the accumulator register. |
| 232 if (!reg.is(result_register())) __ movq(result_register(), reg); |
| 233 DoTest(context); |
| 234 break; |
| 235 } |
| 236 } |
| 237 |
| 238 |
| 239 void FastCodeGenerator::Apply(Expression::Context context, Slot* slot) { |
208 switch (context) { | 240 switch (context) { |
209 case Expression::kUninitialized: | 241 case Expression::kUninitialized: |
210 UNREACHABLE(); | 242 UNREACHABLE(); |
211 case Expression::kEffect: | 243 case Expression::kEffect: |
| 244 // Nothing to do. |
212 break; | 245 break; |
213 case Expression::kValue: { | 246 case Expression::kValue: { |
214 MemOperand location = EmitSlotSearch(slot, scratch); | 247 MemOperand slot_operand = EmitSlotSearch(slot, result_register()); |
215 __ push(location); | 248 switch (location_) { |
| 249 case kAccumulator: |
| 250 __ movq(result_register(), slot_operand); |
| 251 break; |
| 252 case kStack: |
| 253 // Memory operands can be pushed directly. |
| 254 __ push(slot_operand); |
| 255 break; |
| 256 } |
216 break; | 257 break; |
217 } | 258 } |
| 259 |
218 case Expression::kTest: | 260 case Expression::kTest: |
| 261 Move(result_register(), slot); |
| 262 DoTest(context); |
| 263 break; |
| 264 |
219 case Expression::kValueTest: | 265 case Expression::kValueTest: |
220 case Expression::kTestValue: | 266 case Expression::kTestValue: |
221 Move(scratch, slot); | 267 Move(result_register(), slot); |
222 Apply(context, scratch); | 268 __ push(result_register()); |
| 269 DoTest(context); |
223 break; | 270 break; |
224 } | 271 } |
225 } | 272 } |
226 | 273 |
227 | 274 |
228 void FastCodeGenerator::Apply(Expression::Context context, Literal* lit) { | 275 void FastCodeGenerator::Apply(Expression::Context context, Literal* lit) { |
229 switch (context) { | 276 switch (context) { |
230 case Expression::kUninitialized: | 277 case Expression::kUninitialized: |
231 UNREACHABLE(); | 278 UNREACHABLE(); |
232 case Expression::kEffect: | 279 case Expression::kEffect: |
| 280 // Nothing to do. |
233 break; | 281 break; |
234 case Expression::kValue: | 282 case Expression::kValue: |
235 __ Push(lit->handle()); | 283 switch (location_) { |
| 284 case kAccumulator: |
| 285 __ Move(result_register(), lit->handle()); |
| 286 break; |
| 287 case kStack: |
| 288 __ Push(lit->handle()); |
| 289 break; |
| 290 } |
236 break; | 291 break; |
| 292 |
237 case Expression::kTest: | 293 case Expression::kTest: |
| 294 __ Move(result_register(), lit->handle()); |
| 295 DoTest(context); |
| 296 break; |
| 297 |
238 case Expression::kValueTest: | 298 case Expression::kValueTest: |
239 case Expression::kTestValue: | 299 case Expression::kTestValue: |
240 __ Move(rax, lit->handle()); | 300 __ Move(result_register(), lit->handle()); |
241 Apply(context, rax); | 301 __ push(result_register()); |
| 302 DoTest(context); |
242 break; | 303 break; |
243 } | 304 } |
244 } | 305 } |
245 | 306 |
246 | 307 |
247 void FastCodeGenerator::ApplyTOS(Expression::Context context) { | 308 void FastCodeGenerator::ApplyTOS(Expression::Context context) { |
248 switch (context) { | 309 switch (context) { |
249 case Expression::kUninitialized: | 310 case Expression::kUninitialized: |
250 UNREACHABLE(); | 311 UNREACHABLE(); |
| 312 |
251 case Expression::kEffect: | 313 case Expression::kEffect: |
252 __ Drop(1); | 314 __ Drop(1); |
253 break; | 315 break; |
| 316 |
254 case Expression::kValue: | 317 case Expression::kValue: |
| 318 switch (location_) { |
| 319 case kAccumulator: |
| 320 __ pop(result_register()); |
| 321 break; |
| 322 case kStack: |
| 323 break; |
| 324 } |
255 break; | 325 break; |
| 326 |
256 case Expression::kTest: | 327 case Expression::kTest: |
257 __ pop(rax); | 328 __ pop(result_register()); |
258 TestAndBranch(rax, true_label_, false_label_); | 329 DoTest(context); |
259 break; | 330 break; |
260 case Expression::kValueTest: { | 331 |
261 Label discard; | 332 case Expression::kValueTest: |
262 __ movq(rax, Operand(rsp, 0)); | 333 case Expression::kTestValue: |
263 TestAndBranch(rax, true_label_, &discard); | 334 __ movq(result_register(), Operand(rsp, 0)); |
264 __ bind(&discard); | 335 DoTest(context); |
265 __ Drop(1); | |
266 __ jmp(false_label_); | |
267 break; | 336 break; |
268 } | |
269 case Expression::kTestValue: { | |
270 Label discard; | |
271 __ movq(rax, Operand(rsp, 0)); | |
272 TestAndBranch(rax, &discard, false_label_); | |
273 __ bind(&discard); | |
274 __ Drop(1); | |
275 __ jmp(true_label_); | |
276 } | |
277 } | 337 } |
278 } | 338 } |
279 | 339 |
280 | 340 |
281 void FastCodeGenerator::DropAndApply(int count, | 341 void FastCodeGenerator::DropAndApply(int count, |
282 Expression::Context context, | 342 Expression::Context context, |
283 Register reg) { | 343 Register reg) { |
284 ASSERT(count > 0); | 344 ASSERT(count > 0); |
285 ASSERT(!reg.is(rsp)); | 345 ASSERT(!reg.is(rsp)); |
286 switch (context) { | 346 switch (context) { |
287 case Expression::kUninitialized: | 347 case Expression::kUninitialized: |
288 UNREACHABLE(); | 348 UNREACHABLE(); |
| 349 |
289 case Expression::kEffect: | 350 case Expression::kEffect: |
290 __ Drop(count); | 351 __ Drop(count); |
291 break; | 352 break; |
| 353 |
292 case Expression::kValue: | 354 case Expression::kValue: |
293 if (count > 1) __ Drop(count - 1); | 355 switch (location_) { |
294 __ movq(Operand(rsp, 0), reg); | 356 case kAccumulator: |
| 357 __ Drop(count); |
| 358 if (!reg.is(result_register())) __ movq(result_register(), reg); |
| 359 break; |
| 360 case kStack: |
| 361 if (count > 1) __ Drop(count - 1); |
| 362 __ movq(Operand(rsp, 0), reg); |
| 363 break; |
| 364 } |
295 break; | 365 break; |
| 366 |
296 case Expression::kTest: | 367 case Expression::kTest: |
297 __ Drop(count); | 368 __ Drop(count); |
298 TestAndBranch(reg, true_label_, false_label_); | 369 if (!reg.is(result_register())) __ movq(result_register(), reg); |
| 370 DoTest(context); |
299 break; | 371 break; |
300 case Expression::kValueTest: { | 372 |
301 Label discard; | 373 case Expression::kValueTest: |
| 374 case Expression::kTestValue: |
302 if (count > 1) __ Drop(count - 1); | 375 if (count > 1) __ Drop(count - 1); |
303 __ movq(Operand(rsp, 0), reg); | 376 if (!reg.is(result_register())) __ movq(result_register(), reg); |
304 TestAndBranch(reg, true_label_, &discard); | 377 __ movq(Operand(rsp, 0), result_register()); |
| 378 DoTest(context); |
| 379 break; |
| 380 } |
| 381 } |
| 382 |
| 383 |
| 384 void FastCodeGenerator::Apply(Expression::Context context, |
| 385 Label* materialize_true, |
| 386 Label* materialize_false) { |
| 387 switch (context) { |
| 388 case Expression::kUninitialized: |
| 389 |
| 390 case Expression::kEffect: |
| 391 ASSERT_EQ(materialize_true, materialize_false); |
| 392 __ bind(materialize_true); |
| 393 |
| 394 case Expression::kValue: { |
| 395 Label done; |
| 396 switch (location_) { |
| 397 case kAccumulator: |
| 398 __ bind(materialize_true); |
| 399 __ Move(result_register(), Factory::true_value()); |
| 400 __ jmp(&done); |
| 401 __ bind(materialize_false); |
| 402 __ Move(result_register(), Factory::false_value()); |
| 403 break; |
| 404 case kStack: |
| 405 __ bind(materialize_true); |
| 406 __ Push(Factory::true_value()); |
| 407 __ jmp(&done); |
| 408 __ bind(materialize_false); |
| 409 __ Push(Factory::false_value()); |
| 410 break; |
| 411 } |
| 412 __ bind(&done); |
| 413 break; |
| 414 } |
| 415 |
| 416 case Expression::kTest: |
| 417 break; |
| 418 |
| 419 case Expression::kValueTest: |
| 420 __ bind(materialize_true); |
| 421 switch (location_) { |
| 422 case kAccumulator: |
| 423 __ Move(result_register(), Factory::true_value()); |
| 424 break; |
| 425 case kStack: |
| 426 __ Push(Factory::true_value()); |
| 427 break; |
| 428 } |
| 429 __ jmp(true_label_); |
| 430 break; |
| 431 |
| 432 case Expression::kTestValue: |
| 433 __ bind(materialize_false); |
| 434 switch (location_) { |
| 435 case kAccumulator: |
| 436 __ Move(result_register(), Factory::false_value()); |
| 437 break; |
| 438 case kStack: |
| 439 __ Push(Factory::false_value()); |
| 440 break; |
| 441 } |
| 442 __ jmp(false_label_); |
| 443 break; |
| 444 } |
| 445 } |
| 446 |
| 447 |
| 448 void FastCodeGenerator::DoTest(Expression::Context context) { |
| 449 // The value to test is in the accumulator, and duplicated on the stack if |
| 450 // necessary (for value/test and test/value contexts). |
| 451 ASSERT_NE(NULL, true_label_); |
| 452 ASSERT_NE(NULL, false_label_); |
| 453 |
| 454 // If there is a value on the stack, use a discard label for the |
| 455 // value-is-unneeded branch in the inlined part of the test. |
| 456 Label discard; |
| 457 Label* if_true = |
| 458 (context == Expression::kTestValue) ? &discard : true_label_; |
| 459 Label* if_false = |
| 460 (context == Expression::kValueTest) ? &discard : false_label_; |
| 461 |
| 462 // Emit the inlined tests assumed by the stub. |
| 463 __ CompareRoot(result_register(), Heap::kUndefinedValueRootIndex); |
| 464 __ j(equal, if_false); |
| 465 __ CompareRoot(result_register(), Heap::kTrueValueRootIndex); |
| 466 __ j(equal, if_true); |
| 467 __ CompareRoot(result_register(), Heap::kFalseValueRootIndex); |
| 468 __ j(equal, if_false); |
| 469 ASSERT_EQ(0, kSmiTag); |
| 470 __ SmiCompare(result_register(), Smi::FromInt(0)); |
| 471 __ j(equal, if_false); |
| 472 Condition is_smi = masm_->CheckSmi(result_register()); |
| 473 __ j(is_smi, if_true); |
| 474 |
| 475 // Call the ToBoolean stub for all other cases. |
| 476 ToBooleanStub stub; |
| 477 __ push(result_register()); |
| 478 __ CallStub(&stub); |
| 479 __ testq(rax, rax); |
| 480 |
| 481 // The stub returns nonzero for true. Complete based on the context. |
| 482 switch (context) { |
| 483 case Expression::kUninitialized: |
| 484 case Expression::kEffect: |
| 485 case Expression::kValue: |
| 486 UNREACHABLE(); |
| 487 |
| 488 case Expression::kTest: |
| 489 __ j(not_zero, true_label_); |
| 490 __ jmp(false_label_); |
| 491 break; |
| 492 |
| 493 case Expression::kValueTest: |
| 494 switch (location_) { |
| 495 case kAccumulator: |
| 496 __ j(zero, &discard); |
| 497 __ pop(result_register()); |
| 498 __ jmp(true_label_); |
| 499 break; |
| 500 case kStack: |
| 501 __ j(not_zero, true_label_); |
| 502 break; |
| 503 } |
305 __ bind(&discard); | 504 __ bind(&discard); |
306 __ Drop(1); | 505 __ Drop(1); |
307 __ jmp(false_label_); | 506 __ jmp(false_label_); |
308 break; | 507 break; |
309 } | 508 |
310 case Expression::kTestValue: { | 509 case Expression::kTestValue: |
311 Label discard; | 510 switch (location_) { |
312 if (count > 1) __ Drop(count - 1); | 511 case kAccumulator: |
313 __ movq(Operand(rsp, 0), reg); | 512 __ j(not_zero, &discard); |
314 TestAndBranch(reg, &discard, false_label_); | 513 __ pop(result_register()); |
| 514 __ jmp(false_label_); |
| 515 break; |
| 516 case kStack: |
| 517 __ j(zero, false_label_); |
| 518 break; |
| 519 } |
315 __ bind(&discard); | 520 __ bind(&discard); |
316 __ Drop(1); | 521 __ Drop(1); |
317 __ jmp(true_label_); | 522 __ jmp(true_label_); |
318 break; | 523 break; |
319 } | |
320 } | 524 } |
321 } | 525 } |
322 | 526 |
323 | 527 |
324 MemOperand FastCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) { | 528 MemOperand FastCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) { |
325 switch (slot->type()) { | 529 switch (slot->type()) { |
326 case Slot::PARAMETER: | 530 case Slot::PARAMETER: |
327 case Slot::LOCAL: | 531 case Slot::LOCAL: |
328 return Operand(rbp, SlotOffset(slot)); | 532 return Operand(rbp, SlotOffset(slot)); |
329 case Slot::CONTEXT: { | 533 case Slot::CONTEXT: { |
(...skipping 25 matching lines...) Expand all Loading... |
355 MemOperand location = EmitSlotSearch(dst, scratch1); | 559 MemOperand location = EmitSlotSearch(dst, scratch1); |
356 __ movq(location, src); | 560 __ movq(location, src); |
357 // Emit the write barrier code if the location is in the heap. | 561 // Emit the write barrier code if the location is in the heap. |
358 if (dst->type() == Slot::CONTEXT) { | 562 if (dst->type() == Slot::CONTEXT) { |
359 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize; | 563 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize; |
360 __ RecordWrite(scratch1, offset, src, scratch2); | 564 __ RecordWrite(scratch1, offset, src, scratch2); |
361 } | 565 } |
362 } | 566 } |
363 | 567 |
364 | 568 |
365 void FastCodeGenerator::TestAndBranch(Register source, | |
366 Label* true_label, | |
367 Label* false_label) { | |
368 ASSERT_NE(NULL, true_label); | |
369 ASSERT_NE(NULL, false_label); | |
370 // Use the shared ToBoolean stub to compile the value in the register into | |
371 // control flow to the code generator's true and false labels. Perform | |
372 // the fast checks assumed by the stub. | |
373 | |
374 // The undefined value is false. | |
375 __ CompareRoot(source, Heap::kUndefinedValueRootIndex); | |
376 __ j(equal, false_label); | |
377 __ CompareRoot(source, Heap::kTrueValueRootIndex); // True is true. | |
378 __ j(equal, true_label); | |
379 __ CompareRoot(source, Heap::kFalseValueRootIndex); // False is false. | |
380 __ j(equal, false_label); | |
381 ASSERT_EQ(0, kSmiTag); | |
382 __ SmiCompare(source, Smi::FromInt(0)); // The smi zero is false. | |
383 __ j(equal, false_label); | |
384 Condition is_smi = masm_->CheckSmi(source); // All other smis are true. | |
385 __ j(is_smi, true_label); | |
386 | |
387 // Call the stub for all other cases. | |
388 __ push(source); | |
389 ToBooleanStub stub; | |
390 __ CallStub(&stub); | |
391 __ testq(rax, rax); // The stub returns nonzero for true. | |
392 __ j(not_zero, true_label); | |
393 __ jmp(false_label); | |
394 } | |
395 | |
396 | |
397 void FastCodeGenerator::VisitDeclaration(Declaration* decl) { | 569 void FastCodeGenerator::VisitDeclaration(Declaration* decl) { |
398 Comment cmnt(masm_, "[ Declaration"); | 570 Comment cmnt(masm_, "[ Declaration"); |
399 Variable* var = decl->proxy()->var(); | 571 Variable* var = decl->proxy()->var(); |
400 ASSERT(var != NULL); // Must have been resolved. | 572 ASSERT(var != NULL); // Must have been resolved. |
401 Slot* slot = var->slot(); | 573 Slot* slot = var->slot(); |
402 Property* prop = var->AsProperty(); | 574 Property* prop = var->AsProperty(); |
403 | 575 |
404 if (slot != NULL) { | 576 if (slot != NULL) { |
405 switch (slot->type()) { | 577 switch (slot->type()) { |
406 case Slot::PARAMETER: | 578 case Slot::PARAMETER: |
407 case Slot::LOCAL: | 579 case Slot::LOCAL: |
408 if (decl->mode() == Variable::CONST) { | 580 if (decl->mode() == Variable::CONST) { |
409 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); | 581 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); |
410 __ movq(Operand(rbp, SlotOffset(slot)), kScratchRegister); | 582 __ movq(Operand(rbp, SlotOffset(slot)), kScratchRegister); |
411 } else if (decl->fun() != NULL) { | 583 } else if (decl->fun() != NULL) { |
412 Visit(decl->fun()); | 584 VisitForValue(decl->fun(), kAccumulator); |
413 __ pop(Operand(rbp, SlotOffset(slot))); | 585 __ movq(Operand(rbp, SlotOffset(slot)), result_register()); |
414 } | 586 } |
415 break; | 587 break; |
416 | 588 |
417 case Slot::CONTEXT: | 589 case Slot::CONTEXT: |
418 // We bypass the general EmitSlotSearch because we know more about | 590 // We bypass the general EmitSlotSearch because we know more about |
419 // this specific context. | 591 // this specific context. |
420 | 592 |
421 // The variable in the decl always resides in the current context. | 593 // The variable in the decl always resides in the current context. |
422 ASSERT_EQ(0, function_->scope()->ContextChainLength(var->scope())); | 594 ASSERT_EQ(0, function_->scope()->ContextChainLength(var->scope())); |
423 if (FLAG_debug_code) { | 595 if (FLAG_debug_code) { |
424 // Check if we have the correct context pointer. | 596 // Check if we have the correct context pointer. |
425 __ movq(rbx, | 597 __ movq(rbx, |
426 CodeGenerator::ContextOperand(rsi, Context::FCONTEXT_INDEX)); | 598 CodeGenerator::ContextOperand(rsi, Context::FCONTEXT_INDEX)); |
427 __ cmpq(rbx, rsi); | 599 __ cmpq(rbx, rsi); |
428 __ Check(equal, "Unexpected declaration in current context."); | 600 __ Check(equal, "Unexpected declaration in current context."); |
429 } | 601 } |
430 if (decl->mode() == Variable::CONST) { | 602 if (decl->mode() == Variable::CONST) { |
431 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); | 603 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); |
432 __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), | 604 __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), |
433 kScratchRegister); | 605 kScratchRegister); |
434 // No write barrier since the hole value is in old space. | 606 // No write barrier since the hole value is in old space. |
435 } else if (decl->fun() != NULL) { | 607 } else if (decl->fun() != NULL) { |
436 Visit(decl->fun()); | 608 VisitForValue(decl->fun(), kAccumulator); |
437 __ pop(rax); | 609 __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), |
438 __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), rax); | 610 result_register()); |
439 int offset = Context::SlotOffset(slot->index()); | 611 int offset = Context::SlotOffset(slot->index()); |
440 __ RecordWrite(rsi, offset, rax, rcx); | 612 __ RecordWrite(rsi, offset, result_register(), rcx); |
441 } | 613 } |
442 break; | 614 break; |
443 | 615 |
444 case Slot::LOOKUP: { | 616 case Slot::LOOKUP: { |
445 __ push(rsi); | 617 __ push(rsi); |
446 __ Push(var->name()); | 618 __ Push(var->name()); |
447 // Declaration nodes are always introduced in one of two modes. | 619 // Declaration nodes are always introduced in one of two modes. |
448 ASSERT(decl->mode() == Variable::VAR || | 620 ASSERT(decl->mode() == Variable::VAR || |
449 decl->mode() == Variable::CONST); | 621 decl->mode() == Variable::CONST); |
450 PropertyAttributes attr = | 622 PropertyAttributes attr = |
451 (decl->mode() == Variable::VAR) ? NONE : READ_ONLY; | 623 (decl->mode() == Variable::VAR) ? NONE : READ_ONLY; |
452 __ Push(Smi::FromInt(attr)); | 624 __ Push(Smi::FromInt(attr)); |
453 // Push initial value, if any. | 625 // Push initial value, if any. |
454 // Note: For variables we must not push an initial value (such as | 626 // Note: For variables we must not push an initial value (such as |
455 // 'undefined') because we may have a (legal) redeclaration and we | 627 // 'undefined') because we may have a (legal) redeclaration and we |
456 // must not destroy the current value. | 628 // must not destroy the current value. |
457 if (decl->mode() == Variable::CONST) { | 629 if (decl->mode() == Variable::CONST) { |
458 __ PushRoot(Heap::kTheHoleValueRootIndex); | 630 __ PushRoot(Heap::kTheHoleValueRootIndex); |
459 } else if (decl->fun() != NULL) { | 631 } else if (decl->fun() != NULL) { |
460 Visit(decl->fun()); | 632 VisitForValue(decl->fun(), kStack); |
461 } else { | 633 } else { |
462 __ Push(Smi::FromInt(0)); // no initial value! | 634 __ Push(Smi::FromInt(0)); // no initial value! |
463 } | 635 } |
464 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | 636 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
465 break; | 637 break; |
466 } | 638 } |
467 } | 639 } |
468 | 640 |
469 } else if (prop != NULL) { | 641 } else if (prop != NULL) { |
470 if (decl->fun() != NULL || decl->mode() == Variable::CONST) { | 642 if (decl->fun() != NULL || decl->mode() == Variable::CONST) { |
471 // We are declaring a function or constant that rewrites to a | 643 // We are declaring a function or constant that rewrites to a |
472 // property. Use (keyed) IC to set the initial value. | 644 // property. Use (keyed) IC to set the initial value. |
473 ASSERT_EQ(Expression::kValue, prop->obj()->context()); | 645 VisitForValue(prop->obj(), kStack); |
474 Visit(prop->obj()); | 646 VisitForValue(prop->key(), kStack); |
475 ASSERT_EQ(Expression::kValue, prop->key()->context()); | |
476 Visit(prop->key()); | |
477 | 647 |
478 if (decl->fun() != NULL) { | 648 if (decl->fun() != NULL) { |
479 ASSERT_EQ(Expression::kValue, decl->fun()->context()); | 649 VisitForValue(decl->fun(), kAccumulator); |
480 Visit(decl->fun()); | |
481 __ pop(rax); | |
482 } else { | 650 } else { |
483 __ LoadRoot(rax, Heap::kTheHoleValueRootIndex); | 651 __ LoadRoot(result_register(), Heap::kTheHoleValueRootIndex); |
484 } | 652 } |
485 | 653 |
486 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 654 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
487 __ call(ic, RelocInfo::CODE_TARGET); | 655 __ call(ic, RelocInfo::CODE_TARGET); |
488 | |
489 // Absence of a test rax instruction following the call | 656 // Absence of a test rax instruction following the call |
490 // indicates that none of the load was inlined. | 657 // indicates that none of the load was inlined. |
| 658 __ nop(); |
491 | 659 |
492 // Value in rax is ignored (declarations are statements). Receiver | 660 // Value in rax is ignored (declarations are statements). Receiver |
493 // and key on stack are discarded. | 661 // and key on stack are discarded. |
494 __ Drop(2); | 662 __ Drop(2); |
495 } | 663 } |
496 } | 664 } |
497 } | 665 } |
498 | 666 |
499 | 667 |
500 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 668 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
(...skipping 24 matching lines...) Expand all Loading... |
525 } | 693 } |
526 | 694 |
527 | 695 |
528 void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) { | 696 void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) { |
529 Comment cmnt(masm_, "[ VariableProxy"); | 697 Comment cmnt(masm_, "[ VariableProxy"); |
530 EmitVariableLoad(expr->var(), expr->context()); | 698 EmitVariableLoad(expr->var(), expr->context()); |
531 } | 699 } |
532 | 700 |
533 | 701 |
534 void FastCodeGenerator::EmitVariableLoad(Variable* var, | 702 void FastCodeGenerator::EmitVariableLoad(Variable* var, |
535 Expression::Context context) { | 703 Expression::Context context) { |
536 Expression* rewrite = var->rewrite(); | 704 Expression* rewrite = var->rewrite(); |
537 if (rewrite == NULL) { | 705 if (rewrite == NULL) { |
538 ASSERT(var->is_global()); | 706 ASSERT(var->is_global()); |
539 Comment cmnt(masm_, "Global variable"); | 707 Comment cmnt(masm_, "Global variable"); |
540 // Use inline caching. Variable name is passed in rcx and the global | 708 // Use inline caching. Variable name is passed in rcx and the global |
541 // object on the stack. | 709 // object on the stack. |
542 __ push(CodeGenerator::GlobalObject()); | 710 __ push(CodeGenerator::GlobalObject()); |
543 __ Move(rcx, var->name()); | 711 __ Move(rcx, var->name()); |
544 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 712 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
545 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 713 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
546 // A test rax instruction following the call is used by the IC to | 714 // A test rax instruction following the call is used by the IC to |
547 // indicate that the inobject property case was inlined. Ensure there | 715 // indicate that the inobject property case was inlined. Ensure there |
548 // is no test rax instruction here. | 716 // is no test rax instruction here. |
549 __ nop(); | 717 __ nop(); |
550 | |
551 DropAndApply(1, context, rax); | 718 DropAndApply(1, context, rax); |
552 } else if (rewrite->AsSlot() != NULL) { | 719 } else if (rewrite->AsSlot() != NULL) { |
553 Slot* slot = rewrite->AsSlot(); | 720 Slot* slot = rewrite->AsSlot(); |
554 if (FLAG_debug_code) { | 721 if (FLAG_debug_code) { |
555 switch (slot->type()) { | 722 switch (slot->type()) { |
556 case Slot::LOCAL: | 723 case Slot::PARAMETER: |
557 case Slot::PARAMETER: { | 724 case Slot::LOCAL: { |
558 Comment cmnt(masm_, "Stack slot"); | 725 Comment cmnt(masm_, "Stack slot"); |
559 break; | 726 break; |
560 } | 727 } |
561 case Slot::CONTEXT: { | 728 case Slot::CONTEXT: { |
562 Comment cmnt(masm_, "Context slot"); | 729 Comment cmnt(masm_, "Context slot"); |
563 break; | 730 break; |
564 } | 731 } |
565 case Slot::LOOKUP: | 732 case Slot::LOOKUP: |
566 UNIMPLEMENTED(); | 733 UNIMPLEMENTED(); |
567 break; | 734 break; |
568 } | 735 } |
569 } | 736 } |
570 Apply(context, slot, rax); | 737 Apply(context, slot); |
571 } else { | 738 } else { |
572 Comment cmnt(masm_, "Variable rewritten to property"); | 739 Comment cmnt(masm_, "Variable rewritten to property"); |
573 // A variable has been rewritten into an explicit access to an object | 740 // A variable has been rewritten into an explicit access to an object |
574 // property. | 741 // property. |
575 Property* property = rewrite->AsProperty(); | 742 Property* property = rewrite->AsProperty(); |
576 ASSERT_NOT_NULL(property); | 743 ASSERT_NOT_NULL(property); |
577 | 744 |
578 // The only property expressions that can occur are of the form | 745 // The only property expressions that can occur are of the form |
579 // "slot[literal]". | 746 // "slot[literal]". |
580 | 747 |
581 // Assert that the object is in a slot. | 748 // Assert that the object is in a slot. |
582 Variable* object = property->obj()->AsVariableProxy()->AsVariable(); | 749 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable(); |
583 ASSERT_NOT_NULL(object); | 750 ASSERT_NOT_NULL(object_var); |
584 Slot* object_slot = object->slot(); | 751 Slot* object_slot = object_var->slot(); |
585 ASSERT_NOT_NULL(object_slot); | 752 ASSERT_NOT_NULL(object_slot); |
586 | 753 |
587 // Load the object. | 754 // Load the object. |
588 MemOperand object_loc = EmitSlotSearch(object_slot, rax); | 755 MemOperand object_loc = EmitSlotSearch(object_slot, rax); |
589 __ push(object_loc); | 756 __ push(object_loc); |
590 | 757 |
591 // Assert that the key is a smi. | 758 // Assert that the key is a smi. |
592 Literal* key_literal = property->key()->AsLiteral(); | 759 Literal* key_literal = property->key()->AsLiteral(); |
593 ASSERT_NOT_NULL(key_literal); | 760 ASSERT_NOT_NULL(key_literal); |
594 ASSERT(key_literal->handle()->IsSmi()); | 761 ASSERT(key_literal->handle()->IsSmi()); |
595 | 762 |
596 // Load the key. | 763 // Load the key. |
597 __ Push(key_literal->handle()); | 764 __ Push(key_literal->handle()); |
598 | 765 |
599 // Do a keyed property load. | 766 // Do a keyed property load. |
600 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 767 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
601 __ call(ic, RelocInfo::CODE_TARGET); | 768 __ call(ic, RelocInfo::CODE_TARGET); |
602 // Notice: We must not have a "test rax, ..." instruction after the | 769 // Notice: We must not have a "test rax, ..." instruction after the |
603 // call. It is treated specially by the LoadIC code. | 770 // call. It is treated specially by the LoadIC code. |
604 | 771 __ nop(); |
605 // Drop key and object left on the stack by IC, and push the result. | 772 // Drop key and object left on the stack by IC, and push the result. |
606 DropAndApply(2, context, rax); | 773 DropAndApply(2, context, rax); |
607 } | 774 } |
608 } | 775 } |
609 | 776 |
610 | 777 |
611 void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { | 778 void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
612 Comment cmnt(masm_, "[ RegExpLiteral"); | 779 Comment cmnt(masm_, "[ RegExpLiteral"); |
613 Label done; | 780 Label done; |
614 // Registers will be used as follows: | 781 // Registers will be used as follows: |
615 // rdi = JS function. | 782 // rdi = JS function. |
616 // rbx = literals array. | 783 // rbx = literals array. |
617 // rax = regexp literal. | 784 // rax = regexp literal. |
618 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 785 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
619 __ movq(rbx, FieldOperand(rdi, JSFunction::kLiteralsOffset)); | 786 __ movq(rbx, FieldOperand(rdi, JSFunction::kLiteralsOffset)); |
620 int literal_offset = | 787 int literal_offset = |
621 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; | 788 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; |
622 __ movq(rax, FieldOperand(rbx, literal_offset)); | 789 __ movq(rax, FieldOperand(rbx, literal_offset)); |
623 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | 790 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
624 __ j(not_equal, &done); | 791 __ j(not_equal, &done); |
625 // Create regexp literal using runtime function | 792 // Create regexp literal using runtime function |
626 // Result will be in rax. | 793 // Result will be in rax. |
627 __ push(rbx); | 794 __ push(rbx); |
628 __ Push(Smi::FromInt(expr->literal_index())); | 795 __ Push(Smi::FromInt(expr->literal_index())); |
629 __ Push(expr->pattern()); | 796 __ Push(expr->pattern()); |
630 __ Push(expr->flags()); | 797 __ Push(expr->flags()); |
631 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); | 798 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); |
632 // Label done: | |
633 __ bind(&done); | 799 __ bind(&done); |
634 Apply(expr->context(), rax); | 800 Apply(expr->context(), rax); |
635 } | 801 } |
636 | 802 |
637 | 803 |
638 void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { | 804 void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { |
639 Comment cmnt(masm_, "[ ObjectLiteral"); | 805 Comment cmnt(masm_, "[ ObjectLiteral"); |
640 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 806 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
641 __ push(FieldOperand(rdi, JSFunction::kLiteralsOffset)); | 807 __ push(FieldOperand(rdi, JSFunction::kLiteralsOffset)); |
642 __ Push(Smi::FromInt(expr->literal_index())); | 808 __ Push(Smi::FromInt(expr->literal_index())); |
643 __ Push(expr->constant_properties()); | 809 __ Push(expr->constant_properties()); |
644 if (expr->depth() > 1) { | 810 if (expr->depth() > 1) { |
645 __ CallRuntime(Runtime::kCreateObjectLiteral, 3); | 811 __ CallRuntime(Runtime::kCreateObjectLiteral, 3); |
646 } else { | 812 } else { |
647 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 3); | 813 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 3); |
648 } | 814 } |
649 | 815 |
650 // If result_saved == true: The result is saved on top of the | 816 // If result_saved is true the result is on top of the stack. If |
651 // stack and in rax. | 817 // result_saved is false the result is in rax. |
652 // If result_saved == false: The result not on the stack, just in rax. | |
653 bool result_saved = false; | 818 bool result_saved = false; |
654 | 819 |
655 for (int i = 0; i < expr->properties()->length(); i++) { | 820 for (int i = 0; i < expr->properties()->length(); i++) { |
656 ObjectLiteral::Property* property = expr->properties()->at(i); | 821 ObjectLiteral::Property* property = expr->properties()->at(i); |
657 if (property->IsCompileTimeValue()) continue; | 822 if (property->IsCompileTimeValue()) continue; |
658 | 823 |
659 Literal* key = property->key(); | 824 Literal* key = property->key(); |
660 Expression* value = property->value(); | 825 Expression* value = property->value(); |
661 if (!result_saved) { | 826 if (!result_saved) { |
662 __ push(rax); // Save result on the stack | 827 __ push(rax); // Save result on the stack |
663 result_saved = true; | 828 result_saved = true; |
664 } | 829 } |
665 switch (property->kind()) { | 830 switch (property->kind()) { |
| 831 case ObjectLiteral::Property::CONSTANT: |
| 832 UNREACHABLE(); |
666 case ObjectLiteral::Property::MATERIALIZED_LITERAL: | 833 case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
667 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); | 834 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); |
| 835 // Fall through. |
668 case ObjectLiteral::Property::COMPUTED: | 836 case ObjectLiteral::Property::COMPUTED: |
669 if (key->handle()->IsSymbol()) { | 837 if (key->handle()->IsSymbol()) { |
670 Visit(value); | 838 VisitForValue(value, kAccumulator); |
671 ASSERT_EQ(Expression::kValue, value->context()); | |
672 __ pop(rax); | |
673 __ Move(rcx, key->handle()); | 839 __ Move(rcx, key->handle()); |
674 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 840 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
675 __ call(ic, RelocInfo::CODE_TARGET); | 841 __ call(ic, RelocInfo::CODE_TARGET); |
| 842 __ nop(); |
676 // StoreIC leaves the receiver on the stack. | 843 // StoreIC leaves the receiver on the stack. |
677 __ movq(rax, Operand(rsp, 0)); // Restore result back into rax. | |
678 break; | 844 break; |
679 } | 845 } |
680 // Fall through. | 846 // Fall through. |
681 case ObjectLiteral::Property::PROTOTYPE: | 847 case ObjectLiteral::Property::PROTOTYPE: |
682 __ push(rax); | 848 __ push(Operand(rsp, 0)); // Duplicate receiver. |
683 Visit(key); | 849 VisitForValue(key, kStack); |
684 ASSERT_EQ(Expression::kValue, key->context()); | 850 VisitForValue(value, kStack); |
685 Visit(value); | |
686 ASSERT_EQ(Expression::kValue, value->context()); | |
687 __ CallRuntime(Runtime::kSetProperty, 3); | 851 __ CallRuntime(Runtime::kSetProperty, 3); |
688 __ movq(rax, Operand(rsp, 0)); // Restore result into rax. | |
689 break; | 852 break; |
690 case ObjectLiteral::Property::SETTER: | 853 case ObjectLiteral::Property::SETTER: |
691 case ObjectLiteral::Property::GETTER: | 854 case ObjectLiteral::Property::GETTER: |
692 __ push(rax); | 855 __ push(Operand(rsp, 0)); // Duplicate receiver. |
693 Visit(key); | 856 VisitForValue(key, kStack); |
694 ASSERT_EQ(Expression::kValue, key->context()); | |
695 __ Push(property->kind() == ObjectLiteral::Property::SETTER ? | 857 __ Push(property->kind() == ObjectLiteral::Property::SETTER ? |
696 Smi::FromInt(1) : | 858 Smi::FromInt(1) : |
697 Smi::FromInt(0)); | 859 Smi::FromInt(0)); |
698 Visit(value); | 860 VisitForValue(value, kStack); |
699 ASSERT_EQ(Expression::kValue, value->context()); | |
700 __ CallRuntime(Runtime::kDefineAccessor, 4); | 861 __ CallRuntime(Runtime::kDefineAccessor, 4); |
701 __ movq(rax, Operand(rsp, 0)); // Restore result into rax. | |
702 break; | 862 break; |
703 default: UNREACHABLE(); | |
704 } | 863 } |
705 } | 864 } |
706 switch (expr->context()) { | 865 |
707 case Expression::kUninitialized: | 866 if (result_saved) { |
708 UNREACHABLE(); | 867 ApplyTOS(expr->context()); |
709 case Expression::kEffect: | 868 } else { |
710 if (result_saved) __ Drop(1); | 869 Apply(expr->context(), rax); |
711 break; | |
712 case Expression::kValue: | |
713 if (!result_saved) __ push(rax); | |
714 break; | |
715 case Expression::kTest: | |
716 if (result_saved) __ pop(rax); | |
717 TestAndBranch(rax, true_label_, false_label_); | |
718 break; | |
719 case Expression::kValueTest: { | |
720 Label discard; | |
721 if (!result_saved) __ push(rax); | |
722 TestAndBranch(rax, true_label_, &discard); | |
723 __ bind(&discard); | |
724 __ Drop(1); | |
725 __ jmp(false_label_); | |
726 break; | |
727 } | |
728 case Expression::kTestValue: { | |
729 Label discard; | |
730 if (!result_saved) __ push(rax); | |
731 TestAndBranch(rax, &discard, false_label_); | |
732 __ bind(&discard); | |
733 __ Drop(1); | |
734 __ jmp(true_label_); | |
735 break; | |
736 } | |
737 } | 870 } |
738 } | 871 } |
739 | 872 |
740 | 873 |
741 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { | 874 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
742 Comment cmnt(masm_, "[ ArrayLiteral"); | 875 Comment cmnt(masm_, "[ ArrayLiteral"); |
743 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 876 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
744 __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset)); | 877 __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset)); |
745 __ Push(Smi::FromInt(expr->literal_index())); | 878 __ Push(Smi::FromInt(expr->literal_index())); |
746 __ Push(expr->constant_elements()); | 879 __ Push(expr->constant_elements()); |
(...skipping 14 matching lines...) Expand all Loading... |
761 // is already set in the cloned array. | 894 // is already set in the cloned array. |
762 if (subexpr->AsLiteral() != NULL || | 895 if (subexpr->AsLiteral() != NULL || |
763 CompileTimeValue::IsCompileTimeValue(subexpr)) { | 896 CompileTimeValue::IsCompileTimeValue(subexpr)) { |
764 continue; | 897 continue; |
765 } | 898 } |
766 | 899 |
767 if (!result_saved) { | 900 if (!result_saved) { |
768 __ push(rax); | 901 __ push(rax); |
769 result_saved = true; | 902 result_saved = true; |
770 } | 903 } |
771 Visit(subexpr); | 904 VisitForValue(subexpr, kAccumulator); |
772 ASSERT_EQ(Expression::kValue, subexpr->context()); | |
773 | 905 |
774 // Store the subexpression value in the array's elements. | 906 // Store the subexpression value in the array's elements. |
775 __ pop(rax); // Subexpression value. | |
776 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal. | 907 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal. |
777 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset)); | 908 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset)); |
778 int offset = FixedArray::kHeaderSize + (i * kPointerSize); | 909 int offset = FixedArray::kHeaderSize + (i * kPointerSize); |
779 __ movq(FieldOperand(rbx, offset), rax); | 910 __ movq(FieldOperand(rbx, offset), result_register()); |
780 | 911 |
781 // Update the write barrier for the array store. | 912 // Update the write barrier for the array store. |
782 __ RecordWrite(rbx, offset, rax, rcx); | 913 __ RecordWrite(rbx, offset, result_register(), rcx); |
783 } | 914 } |
784 | 915 |
785 switch (expr->context()) { | 916 if (result_saved) { |
786 case Expression::kUninitialized: | 917 ApplyTOS(expr->context()); |
787 UNREACHABLE(); | 918 } else { |
788 case Expression::kEffect: | 919 Apply(expr->context(), rax); |
789 if (result_saved) __ Drop(1); | |
790 break; | |
791 case Expression::kValue: | |
792 if (!result_saved) __ push(rax); | |
793 break; | |
794 case Expression::kTest: | |
795 if (result_saved) __ pop(rax); | |
796 TestAndBranch(rax, true_label_, false_label_); | |
797 break; | |
798 case Expression::kValueTest: { | |
799 Label discard; | |
800 if (!result_saved) __ push(rax); | |
801 TestAndBranch(rax, true_label_, &discard); | |
802 __ bind(&discard); | |
803 __ Drop(1); | |
804 __ jmp(false_label_); | |
805 break; | |
806 } | |
807 case Expression::kTestValue: { | |
808 Label discard; | |
809 if (!result_saved) __ push(rax); | |
810 TestAndBranch(rax, &discard, false_label_); | |
811 __ bind(&discard); | |
812 __ Drop(1); | |
813 __ jmp(true_label_); | |
814 break; | |
815 } | |
816 } | 920 } |
817 } | 921 } |
818 | 922 |
819 | 923 |
820 void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop) { | 924 void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop) { |
821 SetSourcePosition(prop->position()); | 925 SetSourcePosition(prop->position()); |
822 Literal* key = prop->key()->AsLiteral(); | 926 Literal* key = prop->key()->AsLiteral(); |
823 __ Move(rcx, key->handle()); | 927 __ Move(rcx, key->handle()); |
824 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 928 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
825 __ Call(ic, RelocInfo::CODE_TARGET); | 929 __ Call(ic, RelocInfo::CODE_TARGET); |
826 __ nop(); | 930 __ nop(); |
827 } | 931 } |
828 | 932 |
829 | 933 |
830 void FastCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { | 934 void FastCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { |
831 SetSourcePosition(prop->position()); | 935 SetSourcePosition(prop->position()); |
832 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 936 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
833 __ Call(ic, RelocInfo::CODE_TARGET); | 937 __ Call(ic, RelocInfo::CODE_TARGET); |
834 __ nop(); | 938 __ nop(); |
835 } | 939 } |
836 | 940 |
837 | 941 |
838 void FastCodeGenerator::EmitCompoundAssignmentOp(Token::Value op, | 942 void FastCodeGenerator::EmitBinaryOp(Token::Value op, |
839 Expression::Context context) { | 943 Expression::Context context) { |
| 944 __ push(result_register()); |
840 GenericBinaryOpStub stub(op, | 945 GenericBinaryOpStub stub(op, |
841 NO_OVERWRITE, | 946 NO_OVERWRITE, |
842 NO_GENERIC_BINARY_FLAGS); | 947 NO_GENERIC_BINARY_FLAGS); |
843 __ CallStub(&stub); | 948 __ CallStub(&stub); |
844 Apply(context, rax); | 949 Apply(context, rax); |
845 } | 950 } |
846 | 951 |
847 | 952 |
848 void FastCodeGenerator::EmitVariableAssignment(Variable* var, | 953 void FastCodeGenerator::EmitVariableAssignment(Variable* var, |
849 Expression::Context context) { | 954 Expression::Context context) { |
850 ASSERT(var != NULL); | 955 ASSERT(var != NULL); |
851 ASSERT(var->is_global() || var->slot() != NULL); | 956 ASSERT(var->is_global() || var->slot() != NULL); |
852 if (var->is_global()) { | 957 if (var->is_global()) { |
853 // Assignment to a global variable. Use inline caching for the | 958 // Assignment to a global variable. Use inline caching for the |
854 // assignment. Right-hand-side value is passed in rax, variable name in | 959 // assignment. Right-hand-side value is passed in rax, variable name in |
855 // rcx, and the global object on the stack. | 960 // rcx, and the global object on the stack. |
856 __ pop(rax); | |
857 __ Move(rcx, var->name()); | 961 __ Move(rcx, var->name()); |
858 __ push(CodeGenerator::GlobalObject()); | 962 __ push(CodeGenerator::GlobalObject()); |
859 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 963 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
860 __ Call(ic, RelocInfo::CODE_TARGET); | 964 __ Call(ic, RelocInfo::CODE_TARGET); |
861 // Overwrite the global object on the stack with the result if needed. | 965 // Overwrite the global object on the stack with the result if needed. |
862 DropAndApply(1, context, rax); | 966 DropAndApply(1, context, rax); |
863 | 967 |
864 } else if (var->slot() != NULL) { | 968 } else if (var->slot() != NULL) { |
865 Slot* slot = var->slot(); | 969 Slot* slot = var->slot(); |
866 switch (slot->type()) { | 970 switch (slot->type()) { |
867 case Slot::LOCAL: | 971 case Slot::LOCAL: |
868 case Slot::PARAMETER: { | 972 case Slot::PARAMETER: |
869 Operand target = Operand(rbp, SlotOffset(slot)); | 973 __ movq(Operand(rbp, SlotOffset(slot)), result_register()); |
870 switch (context) { | 974 break; |
871 case Expression::kUninitialized: | 975 |
872 UNREACHABLE(); | 976 case Slot::CONTEXT: { |
873 case Expression::kEffect: | 977 MemOperand target = EmitSlotSearch(slot, rcx); |
874 // Perform assignment and discard value. | 978 __ movq(target, result_register()); |
875 __ pop(target); | 979 |
876 break; | 980 // RecordWrite may destroy all its register arguments. |
877 case Expression::kValue: | 981 __ movq(rdx, result_register()); |
878 // Perform assignment and preserve value. | 982 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
879 __ movq(rax, Operand(rsp, 0)); | 983 __ RecordWrite(rcx, offset, rdx, rbx); |
880 __ movq(target, rax); | |
881 break; | |
882 case Expression::kTest: | |
883 // Perform assignment and test (and discard) value. | |
884 __ pop(rax); | |
885 __ movq(target, rax); | |
886 TestAndBranch(rax, true_label_, false_label_); | |
887 break; | |
888 case Expression::kValueTest: { | |
889 Label discard; | |
890 __ movq(rax, Operand(rsp, 0)); | |
891 __ movq(target, rax); | |
892 TestAndBranch(rax, true_label_, &discard); | |
893 __ bind(&discard); | |
894 __ Drop(1); | |
895 __ jmp(false_label_); | |
896 break; | |
897 } | |
898 case Expression::kTestValue: { | |
899 Label discard; | |
900 __ movq(rax, Operand(rsp, 0)); | |
901 __ movq(target, rax); | |
902 TestAndBranch(rax, &discard, false_label_); | |
903 __ bind(&discard); | |
904 __ Drop(1); | |
905 __ jmp(true_label_); | |
906 break; | |
907 } | |
908 } | |
909 break; | 984 break; |
910 } | 985 } |
911 | 986 |
912 case Slot::CONTEXT: { | |
913 MemOperand target = EmitSlotSearch(slot, rcx); | |
914 __ pop(rax); | |
915 __ movq(target, rax); | |
916 | |
917 // RecordWrite may destroy all its register arguments. | |
918 if (context == Expression::kValue) { | |
919 __ push(rax); | |
920 } else if (context != Expression::kEffect) { | |
921 __ movq(rdx, rax); | |
922 } | |
923 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | |
924 __ RecordWrite(rcx, offset, rax, rbx); | |
925 if (context != Expression::kEffect && context != Expression::kValue) { | |
926 Apply(context, rdx); | |
927 } | |
928 break; | |
929 } | |
930 | |
931 case Slot::LOOKUP: | 987 case Slot::LOOKUP: |
932 UNREACHABLE(); | 988 UNREACHABLE(); |
933 break; | 989 break; |
934 } | 990 } |
| 991 Apply(context, result_register()); |
935 } else { | 992 } else { |
936 // Variables rewritten as properties are not treated as variables in | 993 // Variables rewritten as properties are not treated as variables in |
937 // assignments. | 994 // assignments. |
938 UNREACHABLE(); | 995 UNREACHABLE(); |
939 } | 996 } |
940 } | 997 } |
941 | 998 |
942 | 999 |
943 void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { | 1000 void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
944 // Assignment to a property, using a named store IC. | 1001 // Assignment to a property, using a named store IC. |
945 Property* prop = expr->target()->AsProperty(); | 1002 Property* prop = expr->target()->AsProperty(); |
946 ASSERT(prop != NULL); | 1003 ASSERT(prop != NULL); |
947 ASSERT(prop->key()->AsLiteral() != NULL); | 1004 ASSERT(prop->key()->AsLiteral() != NULL); |
948 | 1005 |
949 // If the assignment starts a block of assignments to the same object, | 1006 // If the assignment starts a block of assignments to the same object, |
950 // change to slow case to avoid the quadratic behavior of repeatedly | 1007 // change to slow case to avoid the quadratic behavior of repeatedly |
951 // adding fast properties. | 1008 // adding fast properties. |
952 if (expr->starts_initialization_block()) { | 1009 if (expr->starts_initialization_block()) { |
953 __ push(Operand(rsp, kPointerSize)); // Receiver is under value. | 1010 __ push(result_register()); |
| 1011 __ push(Operand(rsp, kPointerSize)); // Receiver is now under value. |
954 __ CallRuntime(Runtime::kToSlowProperties, 1); | 1012 __ CallRuntime(Runtime::kToSlowProperties, 1); |
| 1013 __ pop(result_register()); |
955 } | 1014 } |
956 | 1015 |
957 // Record source code position before IC call. | 1016 // Record source code position before IC call. |
958 SetSourcePosition(expr->position()); | 1017 SetSourcePosition(expr->position()); |
959 | |
960 __ pop(rax); | |
961 __ Move(rcx, prop->key()->AsLiteral()->handle()); | 1018 __ Move(rcx, prop->key()->AsLiteral()->handle()); |
962 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 1019 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
963 __ Call(ic, RelocInfo::CODE_TARGET); | 1020 __ Call(ic, RelocInfo::CODE_TARGET); |
| 1021 __ nop(); |
964 | 1022 |
965 // If the assignment ends an initialization block, revert to fast case. | 1023 // If the assignment ends an initialization block, revert to fast case. |
966 if (expr->ends_initialization_block()) { | 1024 if (expr->ends_initialization_block()) { |
967 __ push(rax); // Result of assignment, saved even if not needed. | 1025 __ push(rax); // Result of assignment, saved even if not needed. |
968 __ push(Operand(rsp, kPointerSize)); // Receiver is under value. | 1026 __ push(Operand(rsp, kPointerSize)); // Receiver is under value. |
969 __ CallRuntime(Runtime::kToFastProperties, 1); | 1027 __ CallRuntime(Runtime::kToFastProperties, 1); |
970 __ pop(rax); | 1028 __ pop(rax); |
971 } | 1029 } |
972 | 1030 |
973 DropAndApply(1, expr->context(), rax); | 1031 DropAndApply(1, expr->context(), rax); |
974 } | 1032 } |
975 | 1033 |
976 | 1034 |
977 void FastCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { | 1035 void FastCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { |
978 // Assignment to a property, using a keyed store IC. | 1036 // Assignment to a property, using a keyed store IC. |
979 | 1037 |
980 // If the assignment starts a block of assignments to the same object, | 1038 // If the assignment starts a block of assignments to the same object, |
981 // change to slow case to avoid the quadratic behavior of repeatedly | 1039 // change to slow case to avoid the quadratic behavior of repeatedly |
982 // adding fast properties. | 1040 // adding fast properties. |
983 if (expr->starts_initialization_block()) { | 1041 if (expr->starts_initialization_block()) { |
984 // Reciever is under the key and value. | 1042 __ push(result_register()); |
| 1043 // Receiver is now under the key and value. |
985 __ push(Operand(rsp, 2 * kPointerSize)); | 1044 __ push(Operand(rsp, 2 * kPointerSize)); |
986 __ CallRuntime(Runtime::kToSlowProperties, 1); | 1045 __ CallRuntime(Runtime::kToSlowProperties, 1); |
| 1046 __ pop(result_register()); |
987 } | 1047 } |
988 | 1048 |
989 // Record source code position before IC call. | 1049 // Record source code position before IC call. |
990 SetSourcePosition(expr->position()); | 1050 SetSourcePosition(expr->position()); |
991 | |
992 __ pop(rax); | |
993 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 1051 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
994 __ Call(ic, RelocInfo::CODE_TARGET); | 1052 __ Call(ic, RelocInfo::CODE_TARGET); |
995 // This nop signals to the IC that there is no inlined code at the call | 1053 // This nop signals to the IC that there is no inlined code at the call |
996 // site for it to patch. | 1054 // site for it to patch. |
997 __ nop(); | 1055 __ nop(); |
998 | 1056 |
999 // If the assignment ends an initialization block, revert to fast case. | 1057 // If the assignment ends an initialization block, revert to fast case. |
1000 if (expr->ends_initialization_block()) { | 1058 if (expr->ends_initialization_block()) { |
1001 __ push(rax); // Result of assignment, saved even if not needed. | 1059 __ push(rax); // Result of assignment, saved even if not needed. |
1002 // Reciever is under the key and value. | 1060 // Receiver is under the key and value. |
1003 __ push(Operand(rsp, 2 * kPointerSize)); | 1061 __ push(Operand(rsp, 2 * kPointerSize)); |
1004 __ CallRuntime(Runtime::kToFastProperties, 1); | 1062 __ CallRuntime(Runtime::kToFastProperties, 1); |
1005 __ pop(rax); | 1063 __ pop(rax); |
1006 } | 1064 } |
1007 | 1065 |
1008 // Receiver and key are still on stack. | 1066 // Receiver and key are still on stack. |
1009 DropAndApply(2, expr->context(), rax); | 1067 DropAndApply(2, expr->context(), rax); |
1010 } | 1068 } |
1011 | 1069 |
1012 | 1070 |
1013 void FastCodeGenerator::VisitProperty(Property* expr) { | 1071 void FastCodeGenerator::VisitProperty(Property* expr) { |
1014 Comment cmnt(masm_, "[ Property"); | 1072 Comment cmnt(masm_, "[ Property"); |
1015 Expression* key = expr->key(); | 1073 Expression* key = expr->key(); |
1016 | 1074 |
1017 // Evaluate receiver. | 1075 // Evaluate receiver. |
1018 Visit(expr->obj()); | 1076 VisitForValue(expr->obj(), kStack); |
1019 | 1077 |
1020 if (key->IsPropertyName()) { | 1078 if (key->IsPropertyName()) { |
1021 EmitNamedPropertyLoad(expr); | 1079 EmitNamedPropertyLoad(expr); |
1022 // Drop receiver left on the stack by IC. | 1080 // Drop receiver left on the stack by IC. |
1023 DropAndApply(1, expr->context(), rax); | 1081 DropAndApply(1, expr->context(), rax); |
1024 } else { | 1082 } else { |
1025 Visit(expr->key()); | 1083 VisitForValue(expr->key(), kStack); |
1026 EmitKeyedPropertyLoad(expr); | 1084 EmitKeyedPropertyLoad(expr); |
1027 // Drop key and receiver left on the stack by IC. | 1085 // Drop key and receiver left on the stack by IC. |
1028 DropAndApply(2, expr->context(), rax); | 1086 DropAndApply(2, expr->context(), rax); |
1029 } | 1087 } |
1030 } | 1088 } |
1031 | 1089 |
1032 | 1090 |
1033 void FastCodeGenerator::EmitCallWithIC(Call* expr, | 1091 void FastCodeGenerator::EmitCallWithIC(Call* expr, |
1034 Handle<Object> ignored, | 1092 Handle<Object> ignored, |
1035 RelocInfo::Mode mode) { | 1093 RelocInfo::Mode mode) { |
1036 // Code common for calls using the IC. | 1094 // Code common for calls using the IC. |
1037 ZoneList<Expression*>* args = expr->arguments(); | 1095 ZoneList<Expression*>* args = expr->arguments(); |
1038 int arg_count = args->length(); | 1096 int arg_count = args->length(); |
1039 for (int i = 0; i < arg_count; i++) { | 1097 for (int i = 0; i < arg_count; i++) { |
1040 Visit(args->at(i)); | 1098 VisitForValue(args->at(i), kStack); |
1041 ASSERT_EQ(Expression::kValue, args->at(i)->context()); | |
1042 } | 1099 } |
1043 // Record source position for debugger. | 1100 // Record source position for debugger. |
1044 SetSourcePosition(expr->position()); | 1101 SetSourcePosition(expr->position()); |
1045 // Call the IC initialization code. | 1102 // Call the IC initialization code. |
1046 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 1103 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
1047 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, | 1104 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, |
1048 in_loop); | 1105 in_loop); |
1049 __ Call(ic, mode); | 1106 __ Call(ic, mode); |
1050 // Restore context register. | 1107 // Restore context register. |
1051 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 1108 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
1052 // Discard the function left on TOS. | 1109 // Discard the function left on TOS. |
1053 DropAndApply(1, expr->context(), rax); | 1110 DropAndApply(1, expr->context(), rax); |
1054 } | 1111 } |
1055 | 1112 |
1056 | 1113 |
1057 void FastCodeGenerator::EmitCallWithStub(Call* expr) { | 1114 void FastCodeGenerator::EmitCallWithStub(Call* expr) { |
1058 // Code common for calls using the call stub. | 1115 // Code common for calls using the call stub. |
1059 ZoneList<Expression*>* args = expr->arguments(); | 1116 ZoneList<Expression*>* args = expr->arguments(); |
1060 int arg_count = args->length(); | 1117 int arg_count = args->length(); |
1061 for (int i = 0; i < arg_count; i++) { | 1118 for (int i = 0; i < arg_count; i++) { |
1062 Visit(args->at(i)); | 1119 VisitForValue(args->at(i), kStack); |
1063 } | 1120 } |
1064 // Record source position for debugger. | 1121 // Record source position for debugger. |
1065 SetSourcePosition(expr->position()); | 1122 SetSourcePosition(expr->position()); |
1066 CallFunctionStub stub(arg_count, NOT_IN_LOOP, RECEIVER_MIGHT_BE_VALUE); | 1123 CallFunctionStub stub(arg_count, NOT_IN_LOOP, RECEIVER_MIGHT_BE_VALUE); |
1067 __ CallStub(&stub); | 1124 __ CallStub(&stub); |
1068 // Restore context register. | 1125 // Restore context register. |
1069 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 1126 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
1070 // Discard the function left on TOS. | 1127 // Discard the function left on TOS. |
1071 DropAndApply(1, expr->context(), rax); | 1128 DropAndApply(1, expr->context(), rax); |
1072 } | 1129 } |
(...skipping 17 matching lines...) Expand all Loading... |
1090 var->slot()->type() == Slot::LOOKUP) { | 1147 var->slot()->type() == Slot::LOOKUP) { |
1091 // Call to a lookup slot. | 1148 // Call to a lookup slot. |
1092 UNREACHABLE(); | 1149 UNREACHABLE(); |
1093 } else if (fun->AsProperty() != NULL) { | 1150 } else if (fun->AsProperty() != NULL) { |
1094 // Call to an object property. | 1151 // Call to an object property. |
1095 Property* prop = fun->AsProperty(); | 1152 Property* prop = fun->AsProperty(); |
1096 Literal* key = prop->key()->AsLiteral(); | 1153 Literal* key = prop->key()->AsLiteral(); |
1097 if (key != NULL && key->handle()->IsSymbol()) { | 1154 if (key != NULL && key->handle()->IsSymbol()) { |
1098 // Call to a named property, use call IC. | 1155 // Call to a named property, use call IC. |
1099 __ Push(key->handle()); | 1156 __ Push(key->handle()); |
1100 Visit(prop->obj()); | 1157 VisitForValue(prop->obj(), kStack); |
1101 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); | 1158 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); |
1102 } else { | 1159 } else { |
1103 // Call to a keyed property, use keyed load IC followed by function | 1160 // Call to a keyed property, use keyed load IC followed by function |
1104 // call. | 1161 // call. |
1105 Visit(prop->obj()); | 1162 VisitForValue(prop->obj(), kStack); |
1106 Visit(prop->key()); | 1163 VisitForValue(prop->key(), kStack); |
1107 // Record source code position for IC call. | 1164 // Record source code position for IC call. |
1108 SetSourcePosition(prop->position()); | 1165 SetSourcePosition(prop->position()); |
1109 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 1166 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
1110 __ call(ic, RelocInfo::CODE_TARGET); | 1167 __ call(ic, RelocInfo::CODE_TARGET); |
1111 // By emitting a nop we make sure that we do not have a "test rax,..." | 1168 // By emitting a nop we make sure that we do not have a "test rax,..." |
1112 // instruction after the call it is treated specially by the LoadIC code. | 1169 // instruction after the call it is treated specially by the LoadIC code. |
1113 __ nop(); | 1170 __ nop(); |
1114 // Drop key left on the stack by IC. | 1171 // Drop key left on the stack by IC. |
1115 __ Drop(1); | 1172 __ Drop(1); |
1116 // Pop receiver. | 1173 // Pop receiver. |
(...skipping 12 matching lines...) Expand all Loading... |
1129 } else { | 1186 } else { |
1130 // Call to some other expression. If the expression is an anonymous | 1187 // Call to some other expression. If the expression is an anonymous |
1131 // function literal not called in a loop, mark it as one that should | 1188 // function literal not called in a loop, mark it as one that should |
1132 // also use the fast code generator. | 1189 // also use the fast code generator. |
1133 FunctionLiteral* lit = fun->AsFunctionLiteral(); | 1190 FunctionLiteral* lit = fun->AsFunctionLiteral(); |
1134 if (lit != NULL && | 1191 if (lit != NULL && |
1135 lit->name()->Equals(Heap::empty_string()) && | 1192 lit->name()->Equals(Heap::empty_string()) && |
1136 loop_depth() == 0) { | 1193 loop_depth() == 0) { |
1137 lit->set_try_fast_codegen(true); | 1194 lit->set_try_fast_codegen(true); |
1138 } | 1195 } |
1139 Visit(fun); | 1196 VisitForValue(fun, kStack); |
1140 // Load global receiver object. | 1197 // Load global receiver object. |
1141 __ movq(rbx, CodeGenerator::GlobalObject()); | 1198 __ movq(rbx, CodeGenerator::GlobalObject()); |
1142 __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset)); | 1199 __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset)); |
1143 // Emit function call. | 1200 // Emit function call. |
1144 EmitCallWithStub(expr); | 1201 EmitCallWithStub(expr); |
1145 } | 1202 } |
1146 } | 1203 } |
1147 | 1204 |
1148 | 1205 |
1149 void FastCodeGenerator::VisitCallNew(CallNew* expr) { | 1206 void FastCodeGenerator::VisitCallNew(CallNew* expr) { |
1150 Comment cmnt(masm_, "[ CallNew"); | 1207 Comment cmnt(masm_, "[ CallNew"); |
1151 // According to ECMA-262, section 11.2.2, page 44, the function | 1208 // According to ECMA-262, section 11.2.2, page 44, the function |
1152 // expression in new calls must be evaluated before the | 1209 // expression in new calls must be evaluated before the |
1153 // arguments. | 1210 // arguments. |
1154 // Push function on the stack. | 1211 // Push function on the stack. |
1155 Visit(expr->expression()); | 1212 VisitForValue(expr->expression(), kStack); |
1156 ASSERT_EQ(Expression::kValue, expr->expression()->context()); | |
1157 // If location is value, already on the stack, | |
1158 | 1213 |
1159 // Push global object (receiver). | 1214 // Push global object (receiver). |
1160 __ push(CodeGenerator::GlobalObject()); | 1215 __ push(CodeGenerator::GlobalObject()); |
1161 | 1216 |
1162 // Push the arguments ("left-to-right") on the stack. | 1217 // Push the arguments ("left-to-right") on the stack. |
1163 ZoneList<Expression*>* args = expr->arguments(); | 1218 ZoneList<Expression*>* args = expr->arguments(); |
1164 int arg_count = args->length(); | 1219 int arg_count = args->length(); |
1165 for (int i = 0; i < arg_count; i++) { | 1220 for (int i = 0; i < arg_count; i++) { |
1166 Visit(args->at(i)); | 1221 VisitForValue(args->at(i), kStack); |
1167 ASSERT_EQ(Expression::kValue, args->at(i)->context()); | |
1168 // If location is value, it is already on the stack, | |
1169 // so nothing to do here. | |
1170 } | 1222 } |
1171 | 1223 |
1172 // Call the construct call builtin that handles allocation and | 1224 // Call the construct call builtin that handles allocation and |
1173 // constructor invocation. | 1225 // constructor invocation. |
1174 SetSourcePosition(expr->position()); | 1226 SetSourcePosition(expr->position()); |
1175 | 1227 |
1176 // Load function, arg_count into rdi and rax. | 1228 // Load function, arg_count into rdi and rax. |
1177 __ Set(rax, arg_count); | 1229 __ Set(rax, arg_count); |
1178 // Function is in rsp[arg_count + 1]. | 1230 // Function is in rsp[arg_count + 1]. |
1179 __ movq(rdi, Operand(rsp, rax, times_pointer_size, kPointerSize)); | 1231 __ movq(rdi, Operand(rsp, rax, times_pointer_size, kPointerSize)); |
(...skipping 13 matching lines...) Expand all Loading... |
1193 if (expr->is_jsruntime()) { | 1245 if (expr->is_jsruntime()) { |
1194 // Prepare for calling JS runtime function. | 1246 // Prepare for calling JS runtime function. |
1195 __ Push(expr->name()); | 1247 __ Push(expr->name()); |
1196 __ movq(rax, CodeGenerator::GlobalObject()); | 1248 __ movq(rax, CodeGenerator::GlobalObject()); |
1197 __ push(FieldOperand(rax, GlobalObject::kBuiltinsOffset)); | 1249 __ push(FieldOperand(rax, GlobalObject::kBuiltinsOffset)); |
1198 } | 1250 } |
1199 | 1251 |
1200 // Push the arguments ("left-to-right"). | 1252 // Push the arguments ("left-to-right"). |
1201 int arg_count = args->length(); | 1253 int arg_count = args->length(); |
1202 for (int i = 0; i < arg_count; i++) { | 1254 for (int i = 0; i < arg_count; i++) { |
1203 Visit(args->at(i)); | 1255 VisitForValue(args->at(i), kStack); |
1204 ASSERT_EQ(Expression::kValue, args->at(i)->context()); | |
1205 } | 1256 } |
1206 | 1257 |
1207 if (expr->is_jsruntime()) { | 1258 if (expr->is_jsruntime()) { |
1208 // Call the JS runtime function. | 1259 // Call the JS runtime function. |
1209 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, | 1260 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, |
1210 NOT_IN_LOOP); | 1261 NOT_IN_LOOP); |
1211 __ call(ic, RelocInfo::CODE_TARGET); | 1262 __ call(ic, RelocInfo::CODE_TARGET); |
1212 // Restore context register. | 1263 // Restore context register. |
1213 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 1264 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
1214 // Discard the function left on TOS. | 1265 // Discard the function left on TOS. |
1215 DropAndApply(1, expr->context(), rax); | 1266 DropAndApply(1, expr->context(), rax); |
1216 } else { | 1267 } else { |
1217 __ CallRuntime(expr->function(), arg_count); | 1268 __ CallRuntime(expr->function(), arg_count); |
1218 Apply(expr->context(), rax); | 1269 Apply(expr->context(), rax); |
1219 } | 1270 } |
1220 } | 1271 } |
1221 | 1272 |
1222 | 1273 |
1223 void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | 1274 void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
1224 switch (expr->op()) { | 1275 switch (expr->op()) { |
1225 case Token::VOID: { | 1276 case Token::VOID: { |
1226 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); | 1277 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); |
| 1278 ASSERT_EQ(Expression::kEffect, expr->expression()->context()); |
1227 Visit(expr->expression()); | 1279 Visit(expr->expression()); |
1228 ASSERT_EQ(Expression::kEffect, expr->expression()->context()); | |
1229 switch (expr->context()) { | 1280 switch (expr->context()) { |
1230 case Expression::kUninitialized: | 1281 case Expression::kUninitialized: |
1231 UNREACHABLE(); | 1282 UNREACHABLE(); |
1232 break; | 1283 break; |
1233 case Expression::kEffect: | 1284 case Expression::kEffect: |
1234 break; | 1285 break; |
1235 case Expression::kValue: | 1286 case Expression::kValue: |
1236 __ PushRoot(Heap::kUndefinedValueRootIndex); | 1287 switch (location_) { |
| 1288 case kAccumulator: |
| 1289 __ LoadRoot(result_register(), Heap::kUndefinedValueRootIndex); |
| 1290 break; |
| 1291 case kStack: |
| 1292 __ PushRoot(Heap::kUndefinedValueRootIndex); |
| 1293 break; |
| 1294 } |
1237 break; | 1295 break; |
1238 case Expression::kTestValue: | 1296 case Expression::kTestValue: |
1239 // Value is false so it's needed. | 1297 // Value is false so it's needed. |
1240 __ PushRoot(Heap::kUndefinedValueRootIndex); | 1298 switch (location_) { |
| 1299 case kAccumulator: |
| 1300 __ LoadRoot(result_register(), Heap::kUndefinedValueRootIndex); |
| 1301 break; |
| 1302 case kStack: |
| 1303 __ PushRoot(Heap::kUndefinedValueRootIndex); |
| 1304 break; |
| 1305 } |
1241 // Fall through. | 1306 // Fall through. |
1242 case Expression::kTest: | 1307 case Expression::kTest: |
1243 case Expression::kValueTest: | 1308 case Expression::kValueTest: |
1244 __ jmp(false_label_); | 1309 __ jmp(false_label_); |
1245 break; | 1310 break; |
1246 } | 1311 } |
1247 break; | 1312 break; |
1248 } | 1313 } |
1249 | 1314 |
1250 case Token::NOT: { | 1315 case Token::NOT: { |
1251 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); | 1316 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); |
1252 ASSERT_EQ(Expression::kTest, expr->expression()->context()); | 1317 ASSERT_EQ(Expression::kTest, expr->expression()->context()); |
1253 | 1318 |
1254 Label push_true, push_false, done; | 1319 Label materialize_true, materialize_false, done; |
| 1320 // Initially assume a pure test context. Notice that the labels are |
| 1321 // swapped. |
| 1322 Label* if_true = false_label_; |
| 1323 Label* if_false = true_label_; |
1255 switch (expr->context()) { | 1324 switch (expr->context()) { |
1256 case Expression::kUninitialized: | 1325 case Expression::kUninitialized: |
1257 UNREACHABLE(); | 1326 UNREACHABLE(); |
1258 break; | 1327 break; |
1259 | 1328 case Expression::kEffect: |
| 1329 if_true = &done; |
| 1330 if_false = &done; |
| 1331 break; |
1260 case Expression::kValue: | 1332 case Expression::kValue: |
1261 VisitForControl(expr->expression(), &push_false, &push_true); | 1333 if_true = &materialize_false; |
1262 __ bind(&push_true); | 1334 if_false = &materialize_true; |
1263 __ PushRoot(Heap::kTrueValueRootIndex); | |
1264 __ jmp(&done); | |
1265 __ bind(&push_false); | |
1266 __ PushRoot(Heap::kFalseValueRootIndex); | |
1267 __ bind(&done); | |
1268 break; | 1335 break; |
1269 | 1336 case Expression::kTest: |
1270 case Expression::kEffect: | |
1271 VisitForControl(expr->expression(), &done, &done); | |
1272 __ bind(&done); | |
1273 break; | 1337 break; |
1274 | 1338 case Expression::kValueTest: |
1275 case Expression::kTest: | 1339 if_false = &materialize_true; |
1276 VisitForControl(expr->expression(), false_label_, true_label_); | |
1277 break; | 1340 break; |
1278 | |
1279 case Expression::kValueTest: | |
1280 VisitForControl(expr->expression(), false_label_, &push_true); | |
1281 __ bind(&push_true); | |
1282 __ PushRoot(Heap::kTrueValueRootIndex); | |
1283 __ jmp(true_label_); | |
1284 break; | |
1285 | |
1286 case Expression::kTestValue: | 1341 case Expression::kTestValue: |
1287 VisitForControl(expr->expression(), &push_false, true_label_); | 1342 if_true = &materialize_false; |
1288 __ bind(&push_false); | |
1289 __ PushRoot(Heap::kFalseValueRootIndex); | |
1290 __ jmp(false_label_); | |
1291 break; | 1343 break; |
1292 } | 1344 } |
| 1345 VisitForControl(expr->expression(), if_true, if_false); |
| 1346 Apply(expr->context(), if_false, if_true); // Labels swapped. |
1293 break; | 1347 break; |
1294 } | 1348 } |
1295 | 1349 |
1296 case Token::TYPEOF: { | 1350 case Token::TYPEOF: { |
1297 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); | 1351 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); |
1298 ASSERT_EQ(Expression::kValue, expr->expression()->context()); | 1352 ASSERT_EQ(Expression::kValue, expr->expression()->context()); |
1299 | 1353 |
1300 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | 1354 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
1301 if (proxy != NULL && | 1355 if (proxy != NULL && |
1302 !proxy->var()->is_this() && | 1356 !proxy->var()->is_this() && |
1303 proxy->var()->is_global()) { | 1357 proxy->var()->is_global()) { |
1304 Comment cmnt(masm_, "Global variable"); | 1358 Comment cmnt(masm_, "Global variable"); |
1305 __ push(CodeGenerator::GlobalObject()); | 1359 __ push(CodeGenerator::GlobalObject()); |
1306 __ Move(rcx, proxy->name()); | 1360 __ Move(rcx, proxy->name()); |
1307 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 1361 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
1308 // Use a regular load, not a contextual load, to avoid a reference | 1362 // Use a regular load, not a contextual load, to avoid a reference |
1309 // error. | 1363 // error. |
1310 __ Call(ic, RelocInfo::CODE_TARGET); | 1364 __ Call(ic, RelocInfo::CODE_TARGET); |
1311 __ movq(Operand(rsp, 0), rax); | 1365 __ movq(Operand(rsp, 0), rax); |
1312 } else if (proxy != NULL && | 1366 } else if (proxy != NULL && |
1313 proxy->var()->slot() != NULL && | 1367 proxy->var()->slot() != NULL && |
1314 proxy->var()->slot()->type() == Slot::LOOKUP) { | 1368 proxy->var()->slot()->type() == Slot::LOOKUP) { |
1315 __ push(rsi); | 1369 __ push(rsi); |
1316 __ Push(proxy->name()); | 1370 __ Push(proxy->name()); |
1317 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 1371 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
1318 __ push(rax); | 1372 __ push(rax); |
1319 } else { | 1373 } else { |
1320 // This expression cannot throw a reference error at the top level. | 1374 // This expression cannot throw a reference error at the top level. |
1321 Visit(expr->expression()); | 1375 VisitForValue(expr->expression(), kStack); |
1322 } | 1376 } |
1323 | 1377 |
1324 __ CallRuntime(Runtime::kTypeof, 1); | 1378 __ CallRuntime(Runtime::kTypeof, 1); |
1325 Apply(expr->context(), rax); | 1379 Apply(expr->context(), rax); |
1326 break; | 1380 break; |
1327 } | 1381 } |
1328 | 1382 |
1329 default: | 1383 default: |
1330 UNREACHABLE(); | 1384 UNREACHABLE(); |
1331 } | 1385 } |
(...skipping 12 matching lines...) Expand all Loading... |
1344 // of the key to detect a named property. | 1398 // of the key to detect a named property. |
1345 if (prop != NULL) { | 1399 if (prop != NULL) { |
1346 assign_type = (prop->key()->context() == Expression::kUninitialized) | 1400 assign_type = (prop->key()->context() == Expression::kUninitialized) |
1347 ? NAMED_PROPERTY | 1401 ? NAMED_PROPERTY |
1348 : KEYED_PROPERTY; | 1402 : KEYED_PROPERTY; |
1349 } | 1403 } |
1350 | 1404 |
1351 // Evaluate expression and get value. | 1405 // Evaluate expression and get value. |
1352 if (assign_type == VARIABLE) { | 1406 if (assign_type == VARIABLE) { |
1353 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); | 1407 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); |
| 1408 Location saved_location = location_; |
| 1409 location_ = kStack; |
1354 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(), | 1410 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(), |
1355 Expression::kValue); | 1411 Expression::kValue); |
| 1412 location_ = saved_location; |
1356 } else { | 1413 } else { |
1357 // Reserve space for result of postfix operation. | 1414 // Reserve space for result of postfix operation. |
1358 if (expr->is_postfix() && expr->context() != Expression::kEffect) { | 1415 if (expr->is_postfix() && expr->context() != Expression::kEffect) { |
1359 ASSERT(expr->context() != Expression::kUninitialized); | 1416 ASSERT(expr->context() != Expression::kUninitialized); |
1360 __ Push(Smi::FromInt(0)); | 1417 __ Push(Smi::FromInt(0)); |
1361 } | 1418 } |
1362 Visit(prop->obj()); | 1419 VisitForValue(prop->obj(), kStack); |
1363 ASSERT_EQ(Expression::kValue, prop->obj()->context()); | |
1364 if (assign_type == NAMED_PROPERTY) { | 1420 if (assign_type == NAMED_PROPERTY) { |
1365 EmitNamedPropertyLoad(prop); | 1421 EmitNamedPropertyLoad(prop); |
1366 } else { | 1422 } else { |
1367 Visit(prop->key()); | 1423 VisitForValue(prop->key(), kStack); |
1368 ASSERT_EQ(Expression::kValue, prop->key()->context()); | |
1369 EmitKeyedPropertyLoad(prop); | 1424 EmitKeyedPropertyLoad(prop); |
1370 } | 1425 } |
1371 __ push(rax); | 1426 __ push(rax); |
1372 } | 1427 } |
1373 | 1428 |
1374 // Convert to number. | 1429 // Convert to number. |
1375 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); | 1430 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); |
1376 | 1431 |
1377 // Save result for postfix expressions. | 1432 // Save result for postfix expressions. |
1378 if (expr->is_postfix()) { | 1433 if (expr->is_postfix()) { |
1379 switch (expr->context()) { | 1434 switch (expr->context()) { |
1380 case Expression::kUninitialized: | 1435 case Expression::kUninitialized: |
1381 UNREACHABLE(); | 1436 UNREACHABLE(); |
1382 case Expression::kEffect: | 1437 case Expression::kEffect: |
1383 // Do not save result. | 1438 // Do not save result. |
1384 break; | 1439 break; |
1385 case Expression::kValue: // Fall through | 1440 case Expression::kValue: |
1386 case Expression::kTest: // Fall through | 1441 case Expression::kTest: |
1387 case Expression::kTestValue: // Fall through | |
1388 case Expression::kValueTest: | 1442 case Expression::kValueTest: |
| 1443 case Expression::kTestValue: |
1389 // Save the result on the stack. If we have a named or keyed property | 1444 // Save the result on the stack. If we have a named or keyed property |
1390 // we store the result under the receiver that is currently on top | 1445 // we store the result under the receiver that is currently on top |
1391 // of the stack. | 1446 // of the stack. |
1392 switch (assign_type) { | 1447 switch (assign_type) { |
1393 case VARIABLE: | 1448 case VARIABLE: |
1394 __ push(rax); | 1449 __ push(rax); |
1395 break; | 1450 break; |
1396 case NAMED_PROPERTY: | 1451 case NAMED_PROPERTY: |
1397 __ movq(Operand(rsp, kPointerSize), rax); | 1452 __ movq(Operand(rsp, kPointerSize), rax); |
1398 break; | 1453 break; |
1399 case KEYED_PROPERTY: | 1454 case KEYED_PROPERTY: |
1400 __ movq(Operand(rsp, 2 * kPointerSize), rax); | 1455 __ movq(Operand(rsp, 2 * kPointerSize), rax); |
1401 break; | 1456 break; |
1402 } | 1457 } |
1403 break; | 1458 break; |
1404 } | 1459 } |
1405 } | 1460 } |
1406 | 1461 |
1407 // Call stub for +1/-1. | 1462 // Call stub for +1/-1. |
1408 __ push(rax); | 1463 __ push(rax); |
1409 __ Push(Smi::FromInt(1)); | 1464 __ Push(Smi::FromInt(1)); |
1410 GenericBinaryOpStub stub(expr->binary_op(), | 1465 GenericBinaryOpStub stub(expr->binary_op(), |
1411 NO_OVERWRITE, | 1466 NO_OVERWRITE, |
1412 NO_GENERIC_BINARY_FLAGS); | 1467 NO_GENERIC_BINARY_FLAGS); |
1413 __ CallStub(&stub); | 1468 __ CallStub(&stub); |
1414 | 1469 |
1415 // Store the value returned in rax. | 1470 // Store the value returned in rax. |
1416 switch (assign_type) { | 1471 switch (assign_type) { |
1417 case VARIABLE: | 1472 case VARIABLE: |
1418 __ push(rax); | |
1419 if (expr->is_postfix()) { | 1473 if (expr->is_postfix()) { |
1420 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 1474 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
1421 Expression::kEffect); | 1475 Expression::kEffect); |
1422 // For all contexts except kEffect: We have the result on | 1476 // For all contexts except kEffect: We have the result on |
1423 // top of the stack. | 1477 // top of the stack. |
1424 if (expr->context() != Expression::kEffect) { | 1478 if (expr->context() != Expression::kEffect) { |
1425 ApplyTOS(expr->context()); | 1479 ApplyTOS(expr->context()); |
1426 } | 1480 } |
1427 } else { | 1481 } else { |
1428 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 1482 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1483 case Token::ADD: | 1537 case Token::ADD: |
1484 case Token::SUB: | 1538 case Token::SUB: |
1485 case Token::DIV: | 1539 case Token::DIV: |
1486 case Token::MOD: | 1540 case Token::MOD: |
1487 case Token::MUL: | 1541 case Token::MUL: |
1488 case Token::BIT_OR: | 1542 case Token::BIT_OR: |
1489 case Token::BIT_AND: | 1543 case Token::BIT_AND: |
1490 case Token::BIT_XOR: | 1544 case Token::BIT_XOR: |
1491 case Token::SHL: | 1545 case Token::SHL: |
1492 case Token::SHR: | 1546 case Token::SHR: |
1493 case Token::SAR: { | 1547 case Token::SAR: |
1494 ASSERT_EQ(Expression::kValue, expr->left()->context()); | 1548 VisitForValue(expr->left(), kStack); |
1495 ASSERT_EQ(Expression::kValue, expr->right()->context()); | 1549 VisitForValue(expr->right(), kAccumulator); |
| 1550 EmitBinaryOp(expr->op(), expr->context()); |
| 1551 break; |
1496 | 1552 |
1497 Visit(expr->left()); | |
1498 Visit(expr->right()); | |
1499 GenericBinaryOpStub stub(expr->op(), | |
1500 NO_OVERWRITE, | |
1501 NO_GENERIC_BINARY_FLAGS); | |
1502 __ CallStub(&stub); | |
1503 Apply(expr->context(), rax); | |
1504 | |
1505 break; | |
1506 } | |
1507 default: | 1553 default: |
1508 UNREACHABLE(); | 1554 UNREACHABLE(); |
1509 } | 1555 } |
1510 } | 1556 } |
1511 | 1557 |
1512 | 1558 |
1513 void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) { | 1559 void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) { |
1514 Comment cmnt(masm_, "[ CompareOperation"); | 1560 Comment cmnt(masm_, "[ CompareOperation"); |
1515 ASSERT_EQ(Expression::kValue, expr->left()->context()); | |
1516 ASSERT_EQ(Expression::kValue, expr->right()->context()); | |
1517 Visit(expr->left()); | |
1518 Visit(expr->right()); | |
1519 | 1561 |
1520 // Always perform the comparison for its control flow. Pack the result | 1562 // Always perform the comparison for its control flow. Pack the result |
1521 // into the expression's context after the comparison is performed. | 1563 // into the expression's context after the comparison is performed. |
1522 Label push_true, push_false, done; | 1564 Label materialize_true, materialize_false, done; |
1523 // Initially assume we are in a test context. | 1565 // Initially assume we are in a test context. |
1524 Label* if_true = true_label_; | 1566 Label* if_true = true_label_; |
1525 Label* if_false = false_label_; | 1567 Label* if_false = false_label_; |
1526 switch (expr->context()) { | 1568 switch (expr->context()) { |
1527 case Expression::kUninitialized: | 1569 case Expression::kUninitialized: |
1528 UNREACHABLE(); | 1570 UNREACHABLE(); |
1529 break; | 1571 break; |
1530 case Expression::kValue: | |
1531 if_true = &push_true; | |
1532 if_false = &push_false; | |
1533 break; | |
1534 case Expression::kEffect: | 1572 case Expression::kEffect: |
1535 if_true = &done; | 1573 if_true = &done; |
1536 if_false = &done; | 1574 if_false = &done; |
1537 break; | 1575 break; |
| 1576 case Expression::kValue: |
| 1577 if_true = &materialize_true; |
| 1578 if_false = &materialize_false; |
| 1579 break; |
1538 case Expression::kTest: | 1580 case Expression::kTest: |
1539 break; | 1581 break; |
1540 case Expression::kValueTest: | 1582 case Expression::kValueTest: |
1541 if_true = &push_true; | 1583 if_true = &materialize_true; |
1542 break; | 1584 break; |
1543 case Expression::kTestValue: | 1585 case Expression::kTestValue: |
1544 if_false = &push_false; | 1586 if_false = &materialize_false; |
1545 break; | 1587 break; |
1546 } | 1588 } |
1547 | 1589 |
| 1590 VisitForValue(expr->left(), kStack); |
1548 switch (expr->op()) { | 1591 switch (expr->op()) { |
1549 case Token::IN: { | 1592 case Token::IN: |
| 1593 VisitForValue(expr->right(), kStack); |
1550 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); | 1594 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); |
1551 __ CompareRoot(rax, Heap::kTrueValueRootIndex); | 1595 __ CompareRoot(rax, Heap::kTrueValueRootIndex); |
1552 __ j(equal, if_true); | 1596 __ j(equal, if_true); |
1553 __ jmp(if_false); | 1597 __ jmp(if_false); |
1554 break; | 1598 break; |
1555 } | |
1556 | 1599 |
1557 case Token::INSTANCEOF: { | 1600 case Token::INSTANCEOF: { |
| 1601 VisitForValue(expr->right(), kStack); |
1558 InstanceofStub stub; | 1602 InstanceofStub stub; |
1559 __ CallStub(&stub); | 1603 __ CallStub(&stub); |
1560 __ testq(rax, rax); | 1604 __ testq(rax, rax); |
1561 __ j(zero, if_true); // The stub returns 0 for true. | 1605 __ j(zero, if_true); // The stub returns 0 for true. |
1562 __ jmp(if_false); | 1606 __ jmp(if_false); |
1563 break; | 1607 break; |
1564 } | 1608 } |
1565 | 1609 |
1566 default: { | 1610 default: { |
| 1611 VisitForValue(expr->right(), kAccumulator); |
1567 Condition cc = no_condition; | 1612 Condition cc = no_condition; |
1568 bool strict = false; | 1613 bool strict = false; |
1569 switch (expr->op()) { | 1614 switch (expr->op()) { |
1570 case Token::EQ_STRICT: | 1615 case Token::EQ_STRICT: |
1571 strict = true; | 1616 strict = true; |
1572 // Fall through. | 1617 // Fall through. |
1573 case Token::EQ: | 1618 case Token::EQ: |
1574 cc = equal; | 1619 cc = equal; |
1575 __ pop(rax); | |
1576 __ pop(rdx); | 1620 __ pop(rdx); |
1577 break; | 1621 break; |
1578 case Token::LT: | 1622 case Token::LT: |
1579 cc = less; | 1623 cc = less; |
1580 __ pop(rax); | |
1581 __ pop(rdx); | 1624 __ pop(rdx); |
1582 break; | 1625 break; |
1583 case Token::GT: | 1626 case Token::GT: |
1584 // Reverse left and right sizes to obtain ECMA-262 conversion order. | 1627 // Reverse left and right sizes to obtain ECMA-262 conversion order. |
1585 cc = less; | 1628 cc = less; |
1586 __ pop(rdx); | 1629 __ movq(rdx, result_register()); |
1587 __ pop(rax); | 1630 __ pop(rax); |
1588 break; | 1631 break; |
1589 case Token::LTE: | 1632 case Token::LTE: |
1590 // Reverse left and right sizes to obtain ECMA-262 conversion order. | 1633 // Reverse left and right sizes to obtain ECMA-262 conversion order. |
1591 cc = greater_equal; | 1634 cc = greater_equal; |
1592 __ pop(rdx); | 1635 __ movq(rdx, result_register()); |
1593 __ pop(rax); | 1636 __ pop(rax); |
1594 break; | 1637 break; |
1595 case Token::GTE: | 1638 case Token::GTE: |
1596 cc = greater_equal; | 1639 cc = greater_equal; |
1597 __ pop(rax); | |
1598 __ pop(rdx); | 1640 __ pop(rdx); |
1599 break; | 1641 break; |
1600 case Token::IN: | 1642 case Token::IN: |
1601 case Token::INSTANCEOF: | 1643 case Token::INSTANCEOF: |
1602 default: | 1644 default: |
1603 UNREACHABLE(); | 1645 UNREACHABLE(); |
1604 } | 1646 } |
1605 | 1647 |
1606 // The comparison stub expects the smi vs. smi case to be handled | 1648 // The comparison stub expects the smi vs. smi case to be handled |
1607 // before it is called. | 1649 // before it is called. |
1608 Label slow_case; | 1650 Label slow_case; |
1609 __ JumpIfNotBothSmi(rax, rdx, &slow_case); | 1651 __ JumpIfNotBothSmi(rax, rdx, &slow_case); |
1610 __ SmiCompare(rdx, rax); | 1652 __ SmiCompare(rdx, rax); |
1611 __ j(cc, if_true); | 1653 __ j(cc, if_true); |
1612 __ jmp(if_false); | 1654 __ jmp(if_false); |
1613 | 1655 |
1614 __ bind(&slow_case); | 1656 __ bind(&slow_case); |
1615 CompareStub stub(cc, strict); | 1657 CompareStub stub(cc, strict); |
1616 __ CallStub(&stub); | 1658 __ CallStub(&stub); |
1617 __ testq(rax, rax); | 1659 __ testq(rax, rax); |
1618 __ j(cc, if_true); | 1660 __ j(cc, if_true); |
1619 __ jmp(if_false); | 1661 __ jmp(if_false); |
1620 } | 1662 } |
1621 } | 1663 } |
1622 | 1664 |
1623 // Convert the result of the comparison into one expected for this | 1665 // Convert the result of the comparison into one expected for this |
1624 // expression's context. | 1666 // expression's context. |
1625 switch (expr->context()) { | 1667 Apply(expr->context(), if_true, if_false); |
1626 case Expression::kUninitialized: | |
1627 UNREACHABLE(); | |
1628 break; | |
1629 | |
1630 case Expression::kEffect: | |
1631 __ bind(&done); | |
1632 break; | |
1633 | |
1634 case Expression::kValue: | |
1635 __ bind(&push_true); | |
1636 __ PushRoot(Heap::kTrueValueRootIndex); | |
1637 __ jmp(&done); | |
1638 __ bind(&push_false); | |
1639 __ PushRoot(Heap::kFalseValueRootIndex); | |
1640 __ bind(&done); | |
1641 break; | |
1642 | |
1643 case Expression::kTest: | |
1644 break; | |
1645 | |
1646 case Expression::kValueTest: | |
1647 __ bind(&push_true); | |
1648 __ PushRoot(Heap::kTrueValueRootIndex); | |
1649 __ jmp(true_label_); | |
1650 break; | |
1651 | |
1652 case Expression::kTestValue: | |
1653 __ bind(&push_false); | |
1654 __ PushRoot(Heap::kFalseValueRootIndex); | |
1655 __ jmp(false_label_); | |
1656 break; | |
1657 } | |
1658 } | 1668 } |
1659 | 1669 |
1660 | 1670 |
1661 void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) { | 1671 void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) { |
1662 __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 1672 __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
1663 Apply(expr->context(), rax); | 1673 Apply(expr->context(), rax); |
1664 } | 1674 } |
1665 | 1675 |
1666 | 1676 |
1667 Register FastCodeGenerator::result_register() { return rax; } | 1677 Register FastCodeGenerator::result_register() { return rax; } |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1712 __ movq(Operand(rsp, 0), rdx); | 1722 __ movq(Operand(rsp, 0), rdx); |
1713 // And return. | 1723 // And return. |
1714 __ ret(0); | 1724 __ ret(0); |
1715 } | 1725 } |
1716 | 1726 |
1717 | 1727 |
1718 #undef __ | 1728 #undef __ |
1719 | 1729 |
1720 | 1730 |
1721 } } // namespace v8::internal | 1731 } } // namespace v8::internal |
OLD | NEW |