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 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
195 } | 195 } |
196 // Check that the size of the code used for returning matches what is | 196 // Check that the size of the code used for returning matches what is |
197 // expected by the debugger. | 197 // expected by the debugger. |
198 ASSERT_EQ(Assembler::kJSReturnSequenceLength, | 198 ASSERT_EQ(Assembler::kJSReturnSequenceLength, |
199 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); | 199 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); |
200 #endif | 200 #endif |
201 } | 201 } |
202 } | 202 } |
203 | 203 |
204 | 204 |
205 void FastCodeGenerator::Move(Expression::Context context, Register source) { | 205 void FastCodeGenerator::Apply(Expression::Context context, |
| 206 Slot* slot, |
| 207 Register scratch) { |
| 208 switch (context) { |
| 209 case Expression::kUninitialized: |
| 210 UNREACHABLE(); |
| 211 case Expression::kEffect: |
| 212 break; |
| 213 case Expression::kValue: { |
| 214 MemOperand location = EmitSlotSearch(slot, scratch); |
| 215 __ push(location); |
| 216 break; |
| 217 } |
| 218 case Expression::kTest: |
| 219 case Expression::kValueTest: |
| 220 case Expression::kTestValue: |
| 221 Move(scratch, slot); |
| 222 Apply(context, scratch); |
| 223 break; |
| 224 } |
| 225 } |
| 226 |
| 227 |
| 228 void FastCodeGenerator::Apply(Expression::Context context, Literal* lit) { |
206 switch (context) { | 229 switch (context) { |
207 case Expression::kUninitialized: | 230 case Expression::kUninitialized: |
208 UNREACHABLE(); | 231 UNREACHABLE(); |
209 case Expression::kEffect: | 232 case Expression::kEffect: |
210 break; | 233 break; |
211 case Expression::kValue: | 234 case Expression::kValue: |
212 __ push(source); | 235 __ Push(lit->handle()); |
213 break; | 236 break; |
214 case Expression::kTest: | 237 case Expression::kTest: |
215 TestAndBranch(source, true_label_, false_label_); | 238 case Expression::kValueTest: |
| 239 case Expression::kTestValue: |
| 240 __ Move(rax, lit->handle()); |
| 241 Apply(context, rax); |
216 break; | 242 break; |
217 case Expression::kValueTest: { | |
218 Label discard; | |
219 __ push(source); | |
220 TestAndBranch(source, true_label_, &discard); | |
221 __ bind(&discard); | |
222 __ addq(rsp, Immediate(kPointerSize)); | |
223 __ jmp(false_label_); | |
224 break; | |
225 } | |
226 case Expression::kTestValue: { | |
227 Label discard; | |
228 __ push(source); | |
229 TestAndBranch(source, &discard, false_label_); | |
230 __ bind(&discard); | |
231 __ addq(rsp, Immediate(kPointerSize)); | |
232 __ jmp(true_label_); | |
233 break; | |
234 } | |
235 } | 243 } |
236 } | 244 } |
237 | 245 |
238 | 246 |
239 void FastCodeGenerator::MoveTOS(Expression::Context context) { | 247 void FastCodeGenerator::ApplyTOS(Expression::Context context) { |
240 switch (context) { | 248 switch (context) { |
241 case Expression::kUninitialized: | 249 case Expression::kUninitialized: |
242 UNREACHABLE(); | 250 UNREACHABLE(); |
243 case Expression::kEffect: | 251 case Expression::kEffect: |
244 __ Drop(1); | 252 __ Drop(1); |
245 break; | 253 break; |
246 case Expression::kValue: | 254 case Expression::kValue: |
247 break; | 255 break; |
248 case Expression::kTest: | 256 case Expression::kTest: |
249 __ pop(rax); | 257 __ pop(rax); |
250 TestAndBranch(rax, true_label_, false_label_); | 258 TestAndBranch(rax, true_label_, false_label_); |
251 break; | 259 break; |
252 case Expression::kValueTest: { | 260 case Expression::kValueTest: { |
253 Label discard; | 261 Label discard; |
254 __ movq(rax, Operand(rsp, 0)); | 262 __ movq(rax, Operand(rsp, 0)); |
255 TestAndBranch(rax, true_label_, &discard); | 263 TestAndBranch(rax, true_label_, &discard); |
256 __ bind(&discard); | 264 __ bind(&discard); |
257 __ Drop(1); | 265 __ Drop(1); |
258 __ jmp(false_label_); | 266 __ jmp(false_label_); |
| 267 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 } |
| 278 } |
| 279 |
| 280 |
| 281 void FastCodeGenerator::DropAndApply(int count, |
| 282 Expression::Context context, |
| 283 Register reg) { |
| 284 ASSERT(count > 0); |
| 285 ASSERT(!reg.is(rsp)); |
| 286 switch (context) { |
| 287 case Expression::kUninitialized: |
| 288 UNREACHABLE(); |
| 289 case Expression::kEffect: |
| 290 __ Drop(count); |
| 291 break; |
| 292 case Expression::kValue: |
| 293 if (count > 1) __ Drop(count - 1); |
| 294 __ movq(Operand(rsp, 0), reg); |
| 295 break; |
| 296 case Expression::kTest: |
| 297 __ Drop(count); |
| 298 TestAndBranch(reg, true_label_, false_label_); |
| 299 break; |
| 300 case Expression::kValueTest: { |
| 301 Label discard; |
| 302 if (count > 1) __ Drop(count - 1); |
| 303 __ movq(Operand(rsp, 0), reg); |
| 304 TestAndBranch(reg, true_label_, &discard); |
| 305 __ bind(&discard); |
| 306 __ Drop(1); |
| 307 __ jmp(false_label_); |
259 break; | 308 break; |
260 } | 309 } |
261 case Expression::kTestValue: { | 310 case Expression::kTestValue: { |
262 Label discard; | 311 Label discard; |
263 __ movq(rax, Operand(rsp, 0)); | 312 if (count > 1) __ Drop(count - 1); |
264 TestAndBranch(rax, &discard, false_label_); | 313 __ movq(Operand(rsp, 0), reg); |
| 314 TestAndBranch(reg, &discard, false_label_); |
265 __ bind(&discard); | 315 __ bind(&discard); |
266 __ Drop(1); | 316 __ Drop(1); |
267 __ jmp(true_label_); | 317 __ jmp(true_label_); |
| 318 break; |
268 } | 319 } |
269 } | 320 } |
270 } | 321 } |
271 | 322 |
272 | 323 |
273 MemOperand FastCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) { | 324 MemOperand FastCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) { |
274 switch (slot->type()) { | 325 switch (slot->type()) { |
275 case Slot::PARAMETER: | 326 case Slot::PARAMETER: |
276 case Slot::LOCAL: | 327 case Slot::LOCAL: |
277 return Operand(rbp, SlotOffset(slot)); | 328 return Operand(rbp, SlotOffset(slot)); |
(...skipping 10 matching lines...) Expand all Loading... |
288 return Operand(rax, 0); | 339 return Operand(rax, 0); |
289 } | 340 } |
290 | 341 |
291 | 342 |
292 void FastCodeGenerator::Move(Register destination, Slot* source) { | 343 void FastCodeGenerator::Move(Register destination, Slot* source) { |
293 MemOperand location = EmitSlotSearch(source, destination); | 344 MemOperand location = EmitSlotSearch(source, destination); |
294 __ movq(destination, location); | 345 __ movq(destination, location); |
295 } | 346 } |
296 | 347 |
297 | 348 |
298 void FastCodeGenerator::Move(Expression::Context context, | |
299 Slot* source, | |
300 Register scratch) { | |
301 switch (context) { | |
302 case Expression::kUninitialized: | |
303 UNREACHABLE(); | |
304 case Expression::kEffect: | |
305 break; | |
306 case Expression::kValue: { | |
307 MemOperand location = EmitSlotSearch(source, scratch); | |
308 __ push(location); | |
309 break; | |
310 } | |
311 case Expression::kTest: | |
312 case Expression::kValueTest: | |
313 case Expression::kTestValue: | |
314 Move(scratch, source); | |
315 Move(context, scratch); | |
316 break; | |
317 } | |
318 } | |
319 | |
320 | |
321 void FastCodeGenerator::Move(Expression::Context context, Literal* expr) { | |
322 switch (context) { | |
323 case Expression::kUninitialized: | |
324 UNREACHABLE(); | |
325 case Expression::kEffect: | |
326 break; | |
327 case Expression::kValue: | |
328 __ Push(expr->handle()); | |
329 break; | |
330 case Expression::kTest: | |
331 case Expression::kValueTest: | |
332 case Expression::kTestValue: | |
333 __ Move(rax, expr->handle()); | |
334 Move(context, rax); | |
335 break; | |
336 } | |
337 } | |
338 | |
339 | |
340 void FastCodeGenerator::Move(Slot* dst, | 349 void FastCodeGenerator::Move(Slot* dst, |
341 Register src, | 350 Register src, |
342 Register scratch1, | 351 Register scratch1, |
343 Register scratch2) { | 352 Register scratch2) { |
344 ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented. | 353 ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented. |
345 ASSERT(!scratch1.is(src) && !scratch2.is(src)); | 354 ASSERT(!scratch1.is(src) && !scratch2.is(src)); |
346 MemOperand location = EmitSlotSearch(dst, scratch1); | 355 MemOperand location = EmitSlotSearch(dst, scratch1); |
347 __ movq(location, src); | 356 __ movq(location, src); |
348 // Emit the write barrier code if the location is in the heap. | 357 // Emit the write barrier code if the location is in the heap. |
349 if (dst->type() == Slot::CONTEXT) { | 358 if (dst->type() == Slot::CONTEXT) { |
350 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize; | 359 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize; |
351 __ RecordWrite(scratch1, offset, src, scratch2); | 360 __ RecordWrite(scratch1, offset, src, scratch2); |
352 } | 361 } |
353 } | 362 } |
354 | 363 |
355 | 364 |
356 void FastCodeGenerator::DropAndMove(Expression::Context context, | |
357 Register source, | |
358 int drop_count) { | |
359 ASSERT(drop_count > 0); | |
360 switch (context) { | |
361 case Expression::kUninitialized: | |
362 UNREACHABLE(); | |
363 case Expression::kEffect: | |
364 __ addq(rsp, Immediate(drop_count * kPointerSize)); | |
365 break; | |
366 case Expression::kValue: | |
367 if (drop_count > 1) { | |
368 __ addq(rsp, Immediate((drop_count - 1) * kPointerSize)); | |
369 } | |
370 __ movq(Operand(rsp, 0), source); | |
371 break; | |
372 case Expression::kTest: | |
373 ASSERT(!source.is(rsp)); | |
374 __ addq(rsp, Immediate(drop_count * kPointerSize)); | |
375 TestAndBranch(source, true_label_, false_label_); | |
376 break; | |
377 case Expression::kValueTest: { | |
378 Label discard; | |
379 if (drop_count > 1) { | |
380 __ addq(rsp, Immediate((drop_count - 1) * kPointerSize)); | |
381 } | |
382 __ movq(Operand(rsp, 0), source); | |
383 TestAndBranch(source, true_label_, &discard); | |
384 __ bind(&discard); | |
385 __ addq(rsp, Immediate(kPointerSize)); | |
386 __ jmp(false_label_); | |
387 break; | |
388 } | |
389 case Expression::kTestValue: { | |
390 Label discard; | |
391 __ movq(Operand(rsp, 0), source); | |
392 TestAndBranch(source, &discard, false_label_); | |
393 __ bind(&discard); | |
394 __ addq(rsp, Immediate(kPointerSize)); | |
395 __ jmp(true_label_); | |
396 break; | |
397 } | |
398 } | |
399 } | |
400 | |
401 | |
402 void FastCodeGenerator::TestAndBranch(Register source, | 365 void FastCodeGenerator::TestAndBranch(Register source, |
403 Label* true_label, | 366 Label* true_label, |
404 Label* false_label) { | 367 Label* false_label) { |
405 ASSERT_NE(NULL, true_label); | 368 ASSERT_NE(NULL, true_label); |
406 ASSERT_NE(NULL, false_label); | 369 ASSERT_NE(NULL, false_label); |
407 // Use the shared ToBoolean stub to compile the value in the register into | 370 // Use the shared ToBoolean stub to compile the value in the register into |
408 // control flow to the code generator's true and false labels. Perform | 371 // control flow to the code generator's true and false labels. Perform |
409 // the fast checks assumed by the stub. | 372 // the fast checks assumed by the stub. |
410 | 373 |
411 // The undefined value is false. | 374 // The undefined value is false. |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
521 } | 484 } |
522 | 485 |
523 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 486 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
524 __ call(ic, RelocInfo::CODE_TARGET); | 487 __ call(ic, RelocInfo::CODE_TARGET); |
525 | 488 |
526 // Absence of a test rax instruction following the call | 489 // Absence of a test rax instruction following the call |
527 // indicates that none of the load was inlined. | 490 // indicates that none of the load was inlined. |
528 | 491 |
529 // Value in rax is ignored (declarations are statements). Receiver | 492 // Value in rax is ignored (declarations are statements). Receiver |
530 // and key on stack are discarded. | 493 // and key on stack are discarded. |
531 __ addq(rsp, Immediate(2 * kPointerSize)); | 494 __ Drop(2); |
532 } | 495 } |
533 } | 496 } |
534 } | 497 } |
535 | 498 |
536 | 499 |
537 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 500 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
538 // Call the runtime to declare the globals. | 501 // Call the runtime to declare the globals. |
539 __ push(rsi); // The context is the first argument. | 502 __ push(rsi); // The context is the first argument. |
540 __ Push(pairs); | 503 __ Push(pairs); |
541 __ Push(Smi::FromInt(is_eval_ ? 1 : 0)); | 504 __ Push(Smi::FromInt(is_eval_ ? 1 : 0)); |
542 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 505 __ CallRuntime(Runtime::kDeclareGlobals, 3); |
543 // Return value is ignored. | 506 // Return value is ignored. |
544 } | 507 } |
545 | 508 |
546 | 509 |
547 void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { | 510 void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { |
548 Comment cmnt(masm_, "[ FunctionLiteral"); | 511 Comment cmnt(masm_, "[ FunctionLiteral"); |
549 | 512 |
550 // Build the function boilerplate and instantiate it. | 513 // Build the function boilerplate and instantiate it. |
551 Handle<JSFunction> boilerplate = | 514 Handle<JSFunction> boilerplate = |
552 Compiler::BuildBoilerplate(expr, script_, this); | 515 Compiler::BuildBoilerplate(expr, script_, this); |
553 if (HasStackOverflow()) return; | 516 if (HasStackOverflow()) return; |
554 | 517 |
555 ASSERT(boilerplate->IsBoilerplate()); | 518 ASSERT(boilerplate->IsBoilerplate()); |
556 | 519 |
557 // Create a new closure. | 520 // Create a new closure. |
558 __ push(rsi); | 521 __ push(rsi); |
559 __ Push(boilerplate); | 522 __ Push(boilerplate); |
560 __ CallRuntime(Runtime::kNewClosure, 2); | 523 __ CallRuntime(Runtime::kNewClosure, 2); |
561 Move(expr->context(), rax); | 524 Apply(expr->context(), rax); |
562 } | 525 } |
563 | 526 |
564 | 527 |
565 void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) { | 528 void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) { |
566 Comment cmnt(masm_, "[ VariableProxy"); | 529 Comment cmnt(masm_, "[ VariableProxy"); |
567 EmitVariableLoad(expr->var(), expr->context()); | 530 EmitVariableLoad(expr->var(), expr->context()); |
568 } | 531 } |
569 | 532 |
570 | 533 |
571 void FastCodeGenerator::EmitVariableLoad(Variable* var, | 534 void FastCodeGenerator::EmitVariableLoad(Variable* var, |
572 Expression::Context context) { | 535 Expression::Context context) { |
573 Expression* rewrite = var->rewrite(); | 536 Expression* rewrite = var->rewrite(); |
574 if (rewrite == NULL) { | 537 if (rewrite == NULL) { |
575 ASSERT(var->is_global()); | 538 ASSERT(var->is_global()); |
576 Comment cmnt(masm_, "Global variable"); | 539 Comment cmnt(masm_, "Global variable"); |
577 // Use inline caching. Variable name is passed in rcx and the global | 540 // Use inline caching. Variable name is passed in rcx and the global |
578 // object on the stack. | 541 // object on the stack. |
579 __ push(CodeGenerator::GlobalObject()); | 542 __ push(CodeGenerator::GlobalObject()); |
580 __ Move(rcx, var->name()); | 543 __ Move(rcx, var->name()); |
581 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 544 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
582 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 545 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
583 // A test rax instruction following the call is used by the IC to | 546 // A test rax instruction following the call is used by the IC to |
584 // indicate that the inobject property case was inlined. Ensure there | 547 // indicate that the inobject property case was inlined. Ensure there |
585 // is no test rax instruction here. | 548 // is no test rax instruction here. |
586 __ nop(); | 549 __ nop(); |
587 | 550 |
588 DropAndMove(context, rax); | 551 DropAndApply(1, context, rax); |
589 } else if (rewrite->AsSlot() != NULL) { | 552 } else if (rewrite->AsSlot() != NULL) { |
590 Slot* slot = rewrite->AsSlot(); | 553 Slot* slot = rewrite->AsSlot(); |
591 if (FLAG_debug_code) { | 554 if (FLAG_debug_code) { |
592 switch (slot->type()) { | 555 switch (slot->type()) { |
593 case Slot::LOCAL: | 556 case Slot::LOCAL: |
594 case Slot::PARAMETER: { | 557 case Slot::PARAMETER: { |
595 Comment cmnt(masm_, "Stack slot"); | 558 Comment cmnt(masm_, "Stack slot"); |
596 break; | 559 break; |
597 } | 560 } |
598 case Slot::CONTEXT: { | 561 case Slot::CONTEXT: { |
599 Comment cmnt(masm_, "Context slot"); | 562 Comment cmnt(masm_, "Context slot"); |
600 break; | 563 break; |
601 } | 564 } |
602 case Slot::LOOKUP: | 565 case Slot::LOOKUP: |
603 UNIMPLEMENTED(); | 566 UNIMPLEMENTED(); |
604 break; | 567 break; |
605 } | 568 } |
606 } | 569 } |
607 Move(context, slot, rax); | 570 Apply(context, slot, rax); |
608 } else { | 571 } else { |
609 // A variable has been rewritten into an explicit access to | 572 Comment cmnt(masm_, "Variable rewritten to property"); |
610 // an object property. | 573 // A variable has been rewritten into an explicit access to an object |
| 574 // property. |
611 Property* property = rewrite->AsProperty(); | 575 Property* property = rewrite->AsProperty(); |
612 ASSERT_NOT_NULL(property); | 576 ASSERT_NOT_NULL(property); |
613 | 577 |
614 // Currently the only parameter expressions that can occur are | 578 // The only property expressions that can occur are of the form |
615 // on the form "slot[literal]". | 579 // "slot[literal]". |
616 | 580 |
617 // Check that the object is in a slot. | 581 // Assert that the object is in a slot. |
618 Variable* object = property->obj()->AsVariableProxy()->AsVariable(); | 582 Variable* object = property->obj()->AsVariableProxy()->AsVariable(); |
619 ASSERT_NOT_NULL(object); | 583 ASSERT_NOT_NULL(object); |
620 Slot* object_slot = object->slot(); | 584 Slot* object_slot = object->slot(); |
621 ASSERT_NOT_NULL(object_slot); | 585 ASSERT_NOT_NULL(object_slot); |
622 | 586 |
623 // Load the object. | 587 // Load the object. |
624 Move(Expression::kValue, object_slot, rax); | 588 MemOperand object_loc = EmitSlotSearch(object_slot, rax); |
| 589 __ push(object_loc); |
625 | 590 |
626 // Check that the key is a smi. | 591 // Assert that the key is a smi. |
627 Literal* key_literal = property->key()->AsLiteral(); | 592 Literal* key_literal = property->key()->AsLiteral(); |
628 ASSERT_NOT_NULL(key_literal); | 593 ASSERT_NOT_NULL(key_literal); |
629 ASSERT(key_literal->handle()->IsSmi()); | 594 ASSERT(key_literal->handle()->IsSmi()); |
630 | 595 |
631 // Load the key. | 596 // Load the key. |
632 Move(Expression::kValue, key_literal); | 597 __ Push(key_literal->handle()); |
633 | 598 |
634 // Do a KEYED property load. | 599 // Do a keyed property load. |
635 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 600 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
636 __ call(ic, RelocInfo::CODE_TARGET); | 601 __ call(ic, RelocInfo::CODE_TARGET); |
637 // Notice: We must not have a "test rax, ..." instruction after | 602 // Notice: We must not have a "test rax, ..." instruction after the |
638 // the call. It is treated specially by the LoadIC code. | 603 // call. It is treated specially by the LoadIC code. |
639 | 604 |
640 // Drop key and object left on the stack by IC, and push the result. | 605 // Drop key and object left on the stack by IC, and push the result. |
641 DropAndMove(context, rax, 2); | 606 DropAndApply(2, context, rax); |
642 } | 607 } |
643 } | 608 } |
644 | 609 |
645 | 610 |
646 void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { | 611 void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
647 Comment cmnt(masm_, "[ RegExpLiteral"); | 612 Comment cmnt(masm_, "[ RegExpLiteral"); |
648 Label done; | 613 Label done; |
649 // Registers will be used as follows: | 614 // Registers will be used as follows: |
650 // rdi = JS function. | 615 // rdi = JS function. |
651 // rbx = literals array. | 616 // rbx = literals array. |
652 // rax = regexp literal. | 617 // rax = regexp literal. |
653 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 618 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
654 __ movq(rbx, FieldOperand(rdi, JSFunction::kLiteralsOffset)); | 619 __ movq(rbx, FieldOperand(rdi, JSFunction::kLiteralsOffset)); |
655 int literal_offset = | 620 int literal_offset = |
656 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; | 621 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; |
657 __ movq(rax, FieldOperand(rbx, literal_offset)); | 622 __ movq(rax, FieldOperand(rbx, literal_offset)); |
658 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | 623 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
659 __ j(not_equal, &done); | 624 __ j(not_equal, &done); |
660 // Create regexp literal using runtime function | 625 // Create regexp literal using runtime function |
661 // Result will be in rax. | 626 // Result will be in rax. |
662 __ push(rbx); | 627 __ push(rbx); |
663 __ Push(Smi::FromInt(expr->literal_index())); | 628 __ Push(Smi::FromInt(expr->literal_index())); |
664 __ Push(expr->pattern()); | 629 __ Push(expr->pattern()); |
665 __ Push(expr->flags()); | 630 __ Push(expr->flags()); |
666 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); | 631 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); |
667 // Label done: | 632 // Label done: |
668 __ bind(&done); | 633 __ bind(&done); |
669 Move(expr->context(), rax); | 634 Apply(expr->context(), rax); |
670 } | 635 } |
671 | 636 |
672 | 637 |
673 void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { | 638 void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { |
674 Comment cmnt(masm_, "[ ObjectLiteral"); | 639 Comment cmnt(masm_, "[ ObjectLiteral"); |
675 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 640 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
676 __ push(FieldOperand(rdi, JSFunction::kLiteralsOffset)); | 641 __ push(FieldOperand(rdi, JSFunction::kLiteralsOffset)); |
677 __ Push(Smi::FromInt(expr->literal_index())); | 642 __ Push(Smi::FromInt(expr->literal_index())); |
678 __ Push(expr->constant_properties()); | 643 __ Push(expr->constant_properties()); |
679 if (expr->depth() > 1) { | 644 if (expr->depth() > 1) { |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
735 __ CallRuntime(Runtime::kDefineAccessor, 4); | 700 __ CallRuntime(Runtime::kDefineAccessor, 4); |
736 __ movq(rax, Operand(rsp, 0)); // Restore result into rax. | 701 __ movq(rax, Operand(rsp, 0)); // Restore result into rax. |
737 break; | 702 break; |
738 default: UNREACHABLE(); | 703 default: UNREACHABLE(); |
739 } | 704 } |
740 } | 705 } |
741 switch (expr->context()) { | 706 switch (expr->context()) { |
742 case Expression::kUninitialized: | 707 case Expression::kUninitialized: |
743 UNREACHABLE(); | 708 UNREACHABLE(); |
744 case Expression::kEffect: | 709 case Expression::kEffect: |
745 if (result_saved) __ addq(rsp, Immediate(kPointerSize)); | 710 if (result_saved) __ Drop(1); |
746 break; | 711 break; |
747 case Expression::kValue: | 712 case Expression::kValue: |
748 if (!result_saved) __ push(rax); | 713 if (!result_saved) __ push(rax); |
749 break; | 714 break; |
750 case Expression::kTest: | 715 case Expression::kTest: |
751 if (result_saved) __ pop(rax); | 716 if (result_saved) __ pop(rax); |
752 TestAndBranch(rax, true_label_, false_label_); | 717 TestAndBranch(rax, true_label_, false_label_); |
753 break; | 718 break; |
754 case Expression::kValueTest: { | 719 case Expression::kValueTest: { |
755 Label discard; | 720 Label discard; |
756 if (!result_saved) __ push(rax); | 721 if (!result_saved) __ push(rax); |
757 TestAndBranch(rax, true_label_, &discard); | 722 TestAndBranch(rax, true_label_, &discard); |
758 __ bind(&discard); | 723 __ bind(&discard); |
759 __ addq(rsp, Immediate(kPointerSize)); | 724 __ Drop(1); |
760 __ jmp(false_label_); | 725 __ jmp(false_label_); |
761 break; | 726 break; |
762 } | 727 } |
763 case Expression::kTestValue: { | 728 case Expression::kTestValue: { |
764 Label discard; | 729 Label discard; |
765 if (!result_saved) __ push(rax); | 730 if (!result_saved) __ push(rax); |
766 TestAndBranch(rax, &discard, false_label_); | 731 TestAndBranch(rax, &discard, false_label_); |
767 __ bind(&discard); | 732 __ bind(&discard); |
768 __ addq(rsp, Immediate(kPointerSize)); | 733 __ Drop(1); |
769 __ jmp(true_label_); | 734 __ jmp(true_label_); |
770 break; | 735 break; |
771 } | 736 } |
772 } | 737 } |
773 } | 738 } |
774 | 739 |
775 | 740 |
776 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { | 741 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
777 Comment cmnt(masm_, "[ ArrayLiteral"); | 742 Comment cmnt(masm_, "[ ArrayLiteral"); |
778 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 743 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
814 __ movq(FieldOperand(rbx, offset), rax); | 779 __ movq(FieldOperand(rbx, offset), rax); |
815 | 780 |
816 // Update the write barrier for the array store. | 781 // Update the write barrier for the array store. |
817 __ RecordWrite(rbx, offset, rax, rcx); | 782 __ RecordWrite(rbx, offset, rax, rcx); |
818 } | 783 } |
819 | 784 |
820 switch (expr->context()) { | 785 switch (expr->context()) { |
821 case Expression::kUninitialized: | 786 case Expression::kUninitialized: |
822 UNREACHABLE(); | 787 UNREACHABLE(); |
823 case Expression::kEffect: | 788 case Expression::kEffect: |
824 if (result_saved) __ addq(rsp, Immediate(kPointerSize)); | 789 if (result_saved) __ Drop(1); |
825 break; | 790 break; |
826 case Expression::kValue: | 791 case Expression::kValue: |
827 if (!result_saved) __ push(rax); | 792 if (!result_saved) __ push(rax); |
828 break; | 793 break; |
829 case Expression::kTest: | 794 case Expression::kTest: |
830 if (result_saved) __ pop(rax); | 795 if (result_saved) __ pop(rax); |
831 TestAndBranch(rax, true_label_, false_label_); | 796 TestAndBranch(rax, true_label_, false_label_); |
832 break; | 797 break; |
833 case Expression::kValueTest: { | 798 case Expression::kValueTest: { |
834 Label discard; | 799 Label discard; |
835 if (!result_saved) __ push(rax); | 800 if (!result_saved) __ push(rax); |
836 TestAndBranch(rax, true_label_, &discard); | 801 TestAndBranch(rax, true_label_, &discard); |
837 __ bind(&discard); | 802 __ bind(&discard); |
838 __ addq(rsp, Immediate(kPointerSize)); | 803 __ Drop(1); |
839 __ jmp(false_label_); | 804 __ jmp(false_label_); |
840 break; | 805 break; |
841 } | 806 } |
842 case Expression::kTestValue: { | 807 case Expression::kTestValue: { |
843 Label discard; | 808 Label discard; |
844 if (!result_saved) __ push(rax); | 809 if (!result_saved) __ push(rax); |
845 TestAndBranch(rax, &discard, false_label_); | 810 TestAndBranch(rax, &discard, false_label_); |
846 __ bind(&discard); | 811 __ bind(&discard); |
847 __ addq(rsp, Immediate(kPointerSize)); | 812 __ Drop(1); |
848 __ jmp(true_label_); | 813 __ jmp(true_label_); |
849 break; | 814 break; |
850 } | 815 } |
851 } | 816 } |
852 } | 817 } |
853 | 818 |
854 | 819 |
855 void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop, | 820 void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop, |
856 Expression::Context context) { | 821 Expression::Context context) { |
857 SetSourcePosition(prop->position()); | 822 SetSourcePosition(prop->position()); |
858 Literal* key = prop->key()->AsLiteral(); | 823 Literal* key = prop->key()->AsLiteral(); |
859 __ Move(rcx, key->handle()); | 824 __ Move(rcx, key->handle()); |
860 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 825 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
861 __ Call(ic, RelocInfo::CODE_TARGET); | 826 __ Call(ic, RelocInfo::CODE_TARGET); |
862 Move(context, rax); | 827 Apply(context, rax); |
863 } | 828 } |
864 | 829 |
865 | 830 |
866 void FastCodeGenerator::EmitKeyedPropertyLoad(Property* prop, | 831 void FastCodeGenerator::EmitKeyedPropertyLoad(Property* prop, |
867 Expression::Context context) { | 832 Expression::Context context) { |
868 SetSourcePosition(prop->position()); | 833 SetSourcePosition(prop->position()); |
869 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 834 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
870 __ Call(ic, RelocInfo::CODE_TARGET); | 835 __ Call(ic, RelocInfo::CODE_TARGET); |
871 Move(context, rax); | 836 Apply(context, rax); |
872 } | 837 } |
873 | 838 |
874 | 839 |
875 void FastCodeGenerator::EmitCompoundAssignmentOp(Token::Value op, | 840 void FastCodeGenerator::EmitCompoundAssignmentOp(Token::Value op, |
876 Expression::Context context) { | 841 Expression::Context context) { |
877 GenericBinaryOpStub stub(op, | 842 GenericBinaryOpStub stub(op, |
878 NO_OVERWRITE, | 843 NO_OVERWRITE, |
879 NO_GENERIC_BINARY_FLAGS); | 844 NO_GENERIC_BINARY_FLAGS); |
880 __ CallStub(&stub); | 845 __ CallStub(&stub); |
881 Move(context, rax); | 846 Apply(context, rax); |
882 } | 847 } |
883 | 848 |
884 | 849 |
885 void FastCodeGenerator::EmitVariableAssignment(Variable* var, | 850 void FastCodeGenerator::EmitVariableAssignment(Variable* var, |
886 Expression::Context context) { | 851 Expression::Context context) { |
887 ASSERT(var != NULL); | 852 ASSERT(var != NULL); |
888 ASSERT(var->is_global() || var->slot() != NULL); | 853 ASSERT(var->is_global() || var->slot() != NULL); |
889 if (var->is_global()) { | 854 if (var->is_global()) { |
890 // Assignment to a global variable. Use inline caching for the | 855 // Assignment to a global variable. Use inline caching for the |
891 // assignment. Right-hand-side value is passed in rax, variable name in | 856 // assignment. Right-hand-side value is passed in rax, variable name in |
892 // rcx, and the global object on the stack. | 857 // rcx, and the global object on the stack. |
893 __ pop(rax); | 858 __ pop(rax); |
894 __ Move(rcx, var->name()); | 859 __ Move(rcx, var->name()); |
895 __ push(CodeGenerator::GlobalObject()); | 860 __ push(CodeGenerator::GlobalObject()); |
896 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 861 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
897 __ Call(ic, RelocInfo::CODE_TARGET); | 862 __ Call(ic, RelocInfo::CODE_TARGET); |
898 // Overwrite the global object on the stack with the result if needed. | 863 // Overwrite the global object on the stack with the result if needed. |
899 DropAndMove(context, rax); | 864 DropAndApply(1, context, rax); |
900 | 865 |
901 } else if (var->slot() != NULL) { | 866 } else if (var->slot() != NULL) { |
902 Slot* slot = var->slot(); | 867 Slot* slot = var->slot(); |
903 switch (slot->type()) { | 868 switch (slot->type()) { |
904 case Slot::LOCAL: | 869 case Slot::LOCAL: |
905 case Slot::PARAMETER: { | 870 case Slot::PARAMETER: { |
906 Operand target = Operand(rbp, SlotOffset(slot)); | 871 Operand target = Operand(rbp, SlotOffset(slot)); |
907 switch (context) { | 872 switch (context) { |
908 case Expression::kUninitialized: | 873 case Expression::kUninitialized: |
909 UNREACHABLE(); | 874 UNREACHABLE(); |
(...skipping 11 matching lines...) Expand all Loading... |
921 __ pop(rax); | 886 __ pop(rax); |
922 __ movq(target, rax); | 887 __ movq(target, rax); |
923 TestAndBranch(rax, true_label_, false_label_); | 888 TestAndBranch(rax, true_label_, false_label_); |
924 break; | 889 break; |
925 case Expression::kValueTest: { | 890 case Expression::kValueTest: { |
926 Label discard; | 891 Label discard; |
927 __ movq(rax, Operand(rsp, 0)); | 892 __ movq(rax, Operand(rsp, 0)); |
928 __ movq(target, rax); | 893 __ movq(target, rax); |
929 TestAndBranch(rax, true_label_, &discard); | 894 TestAndBranch(rax, true_label_, &discard); |
930 __ bind(&discard); | 895 __ bind(&discard); |
931 __ addq(rsp, Immediate(kPointerSize)); | 896 __ Drop(1); |
932 __ jmp(false_label_); | 897 __ jmp(false_label_); |
933 break; | 898 break; |
934 } | 899 } |
935 case Expression::kTestValue: { | 900 case Expression::kTestValue: { |
936 Label discard; | 901 Label discard; |
937 __ movq(rax, Operand(rsp, 0)); | 902 __ movq(rax, Operand(rsp, 0)); |
938 __ movq(target, rax); | 903 __ movq(target, rax); |
939 TestAndBranch(rax, &discard, false_label_); | 904 TestAndBranch(rax, &discard, false_label_); |
940 __ bind(&discard); | 905 __ bind(&discard); |
941 __ addq(rsp, Immediate(kPointerSize)); | 906 __ Drop(1); |
942 __ jmp(true_label_); | 907 __ jmp(true_label_); |
943 break; | 908 break; |
944 } | 909 } |
945 } | 910 } |
946 break; | 911 break; |
947 } | 912 } |
948 | 913 |
949 case Slot::CONTEXT: { | 914 case Slot::CONTEXT: { |
950 MemOperand target = EmitSlotSearch(slot, rcx); | 915 MemOperand target = EmitSlotSearch(slot, rcx); |
951 __ pop(rax); | 916 __ pop(rax); |
952 __ movq(target, rax); | 917 __ movq(target, rax); |
953 | 918 |
954 // RecordWrite may destroy all its register arguments. | 919 // RecordWrite may destroy all its register arguments. |
955 if (context == Expression::kValue) { | 920 if (context == Expression::kValue) { |
956 __ push(rax); | 921 __ push(rax); |
957 } else if (context != Expression::kEffect) { | 922 } else if (context != Expression::kEffect) { |
958 __ movq(rdx, rax); | 923 __ movq(rdx, rax); |
959 } | 924 } |
960 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | 925 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
961 __ RecordWrite(rcx, offset, rax, rbx); | 926 __ RecordWrite(rcx, offset, rax, rbx); |
962 if (context != Expression::kEffect && | 927 if (context != Expression::kEffect && context != Expression::kValue) { |
963 context != Expression::kValue) { | 928 Apply(context, rdx); |
964 Move(context, rdx); | |
965 } | 929 } |
966 break; | 930 break; |
967 } | 931 } |
968 | 932 |
969 case Slot::LOOKUP: | 933 case Slot::LOOKUP: |
970 UNREACHABLE(); | 934 UNREACHABLE(); |
971 break; | 935 break; |
972 } | 936 } |
973 } else { | 937 } else { |
974 // Variables rewritten as properties are not treated as variables in | 938 // Variables rewritten as properties are not treated as variables in |
(...skipping 23 matching lines...) Expand all Loading... |
998 __ Call(ic, RelocInfo::CODE_TARGET); | 962 __ Call(ic, RelocInfo::CODE_TARGET); |
999 | 963 |
1000 // If the assignment ends an initialization block, revert to fast case. | 964 // If the assignment ends an initialization block, revert to fast case. |
1001 if (expr->ends_initialization_block()) { | 965 if (expr->ends_initialization_block()) { |
1002 __ push(rax); // Result of assignment, saved even if not needed. | 966 __ push(rax); // Result of assignment, saved even if not needed. |
1003 __ push(Operand(rsp, kPointerSize)); // Receiver is under value. | 967 __ push(Operand(rsp, kPointerSize)); // Receiver is under value. |
1004 __ CallRuntime(Runtime::kToFastProperties, 1); | 968 __ CallRuntime(Runtime::kToFastProperties, 1); |
1005 __ pop(rax); | 969 __ pop(rax); |
1006 } | 970 } |
1007 | 971 |
1008 DropAndMove(expr->context(), rax); | 972 DropAndApply(1, expr->context(), rax); |
1009 } | 973 } |
1010 | 974 |
1011 | 975 |
1012 void FastCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { | 976 void FastCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { |
1013 // Assignment to a property, using a keyed store IC. | 977 // Assignment to a property, using a keyed store IC. |
1014 | 978 |
1015 // If the assignment starts a block of assignments to the same object, | 979 // If the assignment starts a block of assignments to the same object, |
1016 // change to slow case to avoid the quadratic behavior of repeatedly | 980 // change to slow case to avoid the quadratic behavior of repeatedly |
1017 // adding fast properties. | 981 // adding fast properties. |
1018 if (expr->starts_initialization_block()) { | 982 if (expr->starts_initialization_block()) { |
(...skipping 12 matching lines...) Expand all Loading... |
1031 // If the assignment ends an initialization block, revert to fast case. | 995 // If the assignment ends an initialization block, revert to fast case. |
1032 if (expr->ends_initialization_block()) { | 996 if (expr->ends_initialization_block()) { |
1033 __ push(rax); // Result of assignment, saved even if not needed. | 997 __ push(rax); // Result of assignment, saved even if not needed. |
1034 // Reciever is under the key and value. | 998 // Reciever is under the key and value. |
1035 __ push(Operand(rsp, 2 * kPointerSize)); | 999 __ push(Operand(rsp, 2 * kPointerSize)); |
1036 __ CallRuntime(Runtime::kToFastProperties, 1); | 1000 __ CallRuntime(Runtime::kToFastProperties, 1); |
1037 __ pop(rax); | 1001 __ pop(rax); |
1038 } | 1002 } |
1039 | 1003 |
1040 // Receiver and key are still on stack. | 1004 // Receiver and key are still on stack. |
1041 __ addq(rsp, Immediate(2 * kPointerSize)); | 1005 DropAndApply(2, expr->context(), rax); |
1042 Move(expr->context(), rax); | |
1043 } | 1006 } |
1044 | 1007 |
1045 | 1008 |
1046 void FastCodeGenerator::VisitProperty(Property* expr) { | 1009 void FastCodeGenerator::VisitProperty(Property* expr) { |
1047 Comment cmnt(masm_, "[ Property"); | 1010 Comment cmnt(masm_, "[ Property"); |
1048 Expression* key = expr->key(); | 1011 Expression* key = expr->key(); |
1049 uint32_t dummy; | |
1050 | 1012 |
1051 // Record the source position for the property load. | 1013 // Record the source position for the property load. |
1052 SetSourcePosition(expr->position()); | 1014 SetSourcePosition(expr->position()); |
1053 | 1015 |
1054 // Evaluate receiver. | 1016 // Evaluate receiver. |
1055 Visit(expr->obj()); | 1017 Visit(expr->obj()); |
1056 | 1018 |
1057 | 1019 if (key->IsPropertyName()) { |
1058 if (key->AsLiteral() != NULL && key->AsLiteral()->handle()->IsSymbol() && | 1020 // Do a named property load. The IC expects the property name in rcx |
1059 !String::cast(*(key->AsLiteral()->handle()))->AsArrayIndex(&dummy)) { | 1021 // and the receiver on the stack. |
1060 // Do a NAMED property load. | |
1061 // The IC expects the property name in rcx and the receiver on the stack. | |
1062 __ Move(rcx, key->AsLiteral()->handle()); | 1022 __ Move(rcx, key->AsLiteral()->handle()); |
1063 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 1023 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
1064 __ call(ic, RelocInfo::CODE_TARGET); | 1024 __ call(ic, RelocInfo::CODE_TARGET); |
1065 // By emitting a nop we make sure that we do not have a "test rax,..." | 1025 // By emitting a nop we make sure that we do not have a "test rax,..." |
1066 // instruction after the call it is treated specially by the LoadIC code. | 1026 // instruction after the call it is treated specially by the LoadIC code. |
1067 __ nop(); | 1027 __ nop(); |
| 1028 DropAndApply(1, expr->context(), rax); |
1068 } else { | 1029 } else { |
1069 // Do a KEYED property load. | 1030 // Do a keyed property load. |
1070 Visit(expr->key()); | 1031 Visit(expr->key()); |
1071 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 1032 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
1072 __ call(ic, RelocInfo::CODE_TARGET); | 1033 __ call(ic, RelocInfo::CODE_TARGET); |
1073 // Notice: We must not have a "test rax, ..." instruction after | 1034 // Notice: We must not have a "test rax, ..." instruction after the |
1074 // the call. It is treated specially by the LoadIC code. | 1035 // call. It is treated specially by the LoadIC code. |
1075 | 1036 __ nop(); |
1076 // Drop key left on the stack by IC. | 1037 // Drop key and receiver left on the stack by IC. |
1077 __ addq(rsp, Immediate(kPointerSize)); | 1038 DropAndApply(2, expr->context(), rax); |
1078 } | 1039 } |
1079 DropAndMove(expr->context(), rax); | |
1080 } | 1040 } |
1081 | 1041 |
1082 | 1042 |
1083 void FastCodeGenerator::EmitCallWithIC(Call* expr, | 1043 void FastCodeGenerator::EmitCallWithIC(Call* expr, |
1084 Handle<Object> ignored, | 1044 Handle<Object> ignored, |
1085 RelocInfo::Mode mode) { | 1045 RelocInfo::Mode mode) { |
1086 // Code common for calls using the IC. | 1046 // Code common for calls using the IC. |
1087 ZoneList<Expression*>* args = expr->arguments(); | 1047 ZoneList<Expression*>* args = expr->arguments(); |
1088 int arg_count = args->length(); | 1048 int arg_count = args->length(); |
1089 for (int i = 0; i < arg_count; i++) { | 1049 for (int i = 0; i < arg_count; i++) { |
1090 Visit(args->at(i)); | 1050 Visit(args->at(i)); |
1091 ASSERT_EQ(Expression::kValue, args->at(i)->context()); | 1051 ASSERT_EQ(Expression::kValue, args->at(i)->context()); |
1092 } | 1052 } |
1093 // Record source position for debugger. | 1053 // Record source position for debugger. |
1094 SetSourcePosition(expr->position()); | 1054 SetSourcePosition(expr->position()); |
1095 // Call the IC initialization code. | 1055 // Call the IC initialization code. |
1096 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, | 1056 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, |
1097 NOT_IN_LOOP); | 1057 NOT_IN_LOOP); |
1098 __ call(ic, mode); | 1058 __ call(ic, mode); |
1099 // Restore context register. | 1059 // Restore context register. |
1100 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 1060 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
1101 // Discard the function left on TOS. | 1061 // Discard the function left on TOS. |
1102 DropAndMove(expr->context(), rax); | 1062 DropAndApply(1, expr->context(), rax); |
1103 } | 1063 } |
1104 | 1064 |
1105 | 1065 |
1106 void FastCodeGenerator::EmitCallWithStub(Call* expr) { | 1066 void FastCodeGenerator::EmitCallWithStub(Call* expr) { |
1107 // Code common for calls using the call stub. | 1067 // Code common for calls using the call stub. |
1108 ZoneList<Expression*>* args = expr->arguments(); | 1068 ZoneList<Expression*>* args = expr->arguments(); |
1109 int arg_count = args->length(); | 1069 int arg_count = args->length(); |
1110 for (int i = 0; i < arg_count; i++) { | 1070 for (int i = 0; i < arg_count; i++) { |
1111 Visit(args->at(i)); | 1071 Visit(args->at(i)); |
1112 } | 1072 } |
1113 // Record source position for debugger. | 1073 // Record source position for debugger. |
1114 SetSourcePosition(expr->position()); | 1074 SetSourcePosition(expr->position()); |
1115 CallFunctionStub stub(arg_count, NOT_IN_LOOP); | 1075 CallFunctionStub stub(arg_count, NOT_IN_LOOP); |
1116 __ CallStub(&stub); | 1076 __ CallStub(&stub); |
1117 // Restore context register. | 1077 // Restore context register. |
1118 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 1078 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
1119 // Discard the function left on TOS. | 1079 // Discard the function left on TOS. |
1120 DropAndMove(expr->context(), rax); | 1080 DropAndApply(1, expr->context(), rax); |
1121 } | 1081 } |
1122 | 1082 |
1123 | 1083 |
1124 void FastCodeGenerator::VisitCall(Call* expr) { | 1084 void FastCodeGenerator::VisitCall(Call* expr) { |
1125 Comment cmnt(masm_, "[ Call"); | 1085 Comment cmnt(masm_, "[ Call"); |
1126 Expression* fun = expr->expression(); | 1086 Expression* fun = expr->expression(); |
1127 Variable* var = fun->AsVariableProxy()->AsVariable(); | 1087 Variable* var = fun->AsVariableProxy()->AsVariable(); |
1128 | 1088 |
1129 if (var != NULL && var->is_possibly_eval()) { | 1089 if (var != NULL && var->is_possibly_eval()) { |
1130 // Call to the identifier 'eval'. | 1090 // Call to the identifier 'eval'. |
(...skipping 23 matching lines...) Expand all Loading... |
1154 Visit(prop->obj()); | 1114 Visit(prop->obj()); |
1155 Visit(prop->key()); | 1115 Visit(prop->key()); |
1156 // Record source code position for IC call. | 1116 // Record source code position for IC call. |
1157 SetSourcePosition(prop->position()); | 1117 SetSourcePosition(prop->position()); |
1158 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 1118 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
1159 __ call(ic, RelocInfo::CODE_TARGET); | 1119 __ call(ic, RelocInfo::CODE_TARGET); |
1160 // By emitting a nop we make sure that we do not have a "test rax,..." | 1120 // By emitting a nop we make sure that we do not have a "test rax,..." |
1161 // instruction after the call it is treated specially by the LoadIC code. | 1121 // instruction after the call it is treated specially by the LoadIC code. |
1162 __ nop(); | 1122 __ nop(); |
1163 // Drop key left on the stack by IC. | 1123 // Drop key left on the stack by IC. |
1164 __ addq(rsp, Immediate(kPointerSize)); | 1124 __ Drop(1); |
1165 // Pop receiver. | 1125 // Pop receiver. |
1166 __ pop(rbx); | 1126 __ pop(rbx); |
1167 // Push result (function). | 1127 // Push result (function). |
1168 __ push(rax); | 1128 __ push(rax); |
1169 // Push receiver object on stack. | 1129 // Push receiver object on stack. |
1170 if (prop->is_synthetic()) { | 1130 if (prop->is_synthetic()) { |
1171 __ push(CodeGenerator::GlobalObject()); | 1131 __ push(CodeGenerator::GlobalObject()); |
1172 } else { | 1132 } else { |
1173 __ push(rbx); | 1133 __ push(rbx); |
1174 } | 1134 } |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1223 | 1183 |
1224 // Load function, arg_count into rdi and rax. | 1184 // Load function, arg_count into rdi and rax. |
1225 __ Set(rax, arg_count); | 1185 __ Set(rax, arg_count); |
1226 // Function is in rsp[arg_count + 1]. | 1186 // Function is in rsp[arg_count + 1]. |
1227 __ movq(rdi, Operand(rsp, rax, times_pointer_size, kPointerSize)); | 1187 __ movq(rdi, Operand(rsp, rax, times_pointer_size, kPointerSize)); |
1228 | 1188 |
1229 Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall)); | 1189 Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall)); |
1230 __ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL); | 1190 __ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL); |
1231 | 1191 |
1232 // Replace function on TOS with result in rax, or pop it. | 1192 // Replace function on TOS with result in rax, or pop it. |
1233 DropAndMove(expr->context(), rax); | 1193 DropAndApply(1, expr->context(), rax); |
1234 } | 1194 } |
1235 | 1195 |
1236 | 1196 |
1237 void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { | 1197 void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { |
1238 Comment cmnt(masm_, "[ CallRuntime"); | 1198 Comment cmnt(masm_, "[ CallRuntime"); |
1239 ZoneList<Expression*>* args = expr->arguments(); | 1199 ZoneList<Expression*>* args = expr->arguments(); |
1240 | 1200 |
1241 if (expr->is_jsruntime()) { | 1201 if (expr->is_jsruntime()) { |
1242 // Prepare for calling JS runtime function. | 1202 // Prepare for calling JS runtime function. |
1243 __ Push(expr->name()); | 1203 __ Push(expr->name()); |
1244 __ movq(rax, CodeGenerator::GlobalObject()); | 1204 __ movq(rax, CodeGenerator::GlobalObject()); |
1245 __ push(FieldOperand(rax, GlobalObject::kBuiltinsOffset)); | 1205 __ push(FieldOperand(rax, GlobalObject::kBuiltinsOffset)); |
1246 } | 1206 } |
1247 | 1207 |
1248 // Push the arguments ("left-to-right"). | 1208 // Push the arguments ("left-to-right"). |
1249 int arg_count = args->length(); | 1209 int arg_count = args->length(); |
1250 for (int i = 0; i < arg_count; i++) { | 1210 for (int i = 0; i < arg_count; i++) { |
1251 Visit(args->at(i)); | 1211 Visit(args->at(i)); |
1252 ASSERT_EQ(Expression::kValue, args->at(i)->context()); | 1212 ASSERT_EQ(Expression::kValue, args->at(i)->context()); |
1253 } | 1213 } |
1254 | 1214 |
1255 if (expr->is_jsruntime()) { | 1215 if (expr->is_jsruntime()) { |
1256 // Call the JS runtime function. | 1216 // Call the JS runtime function. |
1257 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, | 1217 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, |
1258 NOT_IN_LOOP); | 1218 NOT_IN_LOOP); |
1259 __ call(ic, RelocInfo::CODE_TARGET); | 1219 __ call(ic, RelocInfo::CODE_TARGET); |
1260 // Restore context register. | 1220 // Restore context register. |
1261 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 1221 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
1262 // Discard the function left on TOS. | 1222 // Discard the function left on TOS. |
1263 DropAndMove(expr->context(), rax); | 1223 DropAndApply(1, expr->context(), rax); |
1264 } else { | 1224 } else { |
1265 __ CallRuntime(expr->function(), arg_count); | 1225 __ CallRuntime(expr->function(), arg_count); |
1266 Move(expr->context(), rax); | 1226 Apply(expr->context(), rax); |
1267 } | 1227 } |
1268 } | 1228 } |
1269 | 1229 |
1270 | 1230 |
1271 void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | 1231 void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
1272 switch (expr->op()) { | 1232 switch (expr->op()) { |
1273 case Token::VOID: { | 1233 case Token::VOID: { |
1274 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); | 1234 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); |
1275 Visit(expr->expression()); | 1235 Visit(expr->expression()); |
1276 ASSERT_EQ(Expression::kEffect, expr->expression()->context()); | 1236 ASSERT_EQ(Expression::kEffect, expr->expression()->context()); |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1379 __ push(rsi); | 1339 __ push(rsi); |
1380 __ Push(proxy->name()); | 1340 __ Push(proxy->name()); |
1381 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 1341 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
1382 __ push(rax); | 1342 __ push(rax); |
1383 } else { | 1343 } else { |
1384 // This expression cannot throw a reference error at the top level. | 1344 // This expression cannot throw a reference error at the top level. |
1385 Visit(expr->expression()); | 1345 Visit(expr->expression()); |
1386 } | 1346 } |
1387 | 1347 |
1388 __ CallRuntime(Runtime::kTypeof, 1); | 1348 __ CallRuntime(Runtime::kTypeof, 1); |
1389 Move(expr->context(), rax); | 1349 Apply(expr->context(), rax); |
1390 break; | 1350 break; |
1391 } | 1351 } |
1392 | 1352 |
1393 default: | 1353 default: |
1394 UNREACHABLE(); | 1354 UNREACHABLE(); |
1395 } | 1355 } |
1396 } | 1356 } |
1397 | 1357 |
1398 | 1358 |
1399 void FastCodeGenerator::VisitCountOperation(CountOperation* expr) { | 1359 void FastCodeGenerator::VisitCountOperation(CountOperation* expr) { |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1479 // Store the value returned in rax. | 1439 // Store the value returned in rax. |
1480 switch (assign_type) { | 1440 switch (assign_type) { |
1481 case VARIABLE: | 1441 case VARIABLE: |
1482 __ push(rax); | 1442 __ push(rax); |
1483 if (expr->is_postfix()) { | 1443 if (expr->is_postfix()) { |
1484 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 1444 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
1485 Expression::kEffect); | 1445 Expression::kEffect); |
1486 // For all contexts except kEffect: We have the result on | 1446 // For all contexts except kEffect: We have the result on |
1487 // top of the stack. | 1447 // top of the stack. |
1488 if (expr->context() != Expression::kEffect) { | 1448 if (expr->context() != Expression::kEffect) { |
1489 MoveTOS(expr->context()); | 1449 ApplyTOS(expr->context()); |
1490 } | 1450 } |
1491 } else { | 1451 } else { |
1492 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 1452 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
1493 expr->context()); | 1453 expr->context()); |
1494 } | 1454 } |
1495 break; | 1455 break; |
1496 case NAMED_PROPERTY: { | 1456 case NAMED_PROPERTY: { |
1497 __ Move(rcx, prop->key()->AsLiteral()->handle()); | 1457 __ Move(rcx, prop->key()->AsLiteral()->handle()); |
1498 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 1458 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
1499 __ call(ic, RelocInfo::CODE_TARGET); | 1459 __ call(ic, RelocInfo::CODE_TARGET); |
1500 // This nop signals to the IC that there is no inlined code at the call | 1460 // This nop signals to the IC that there is no inlined code at the call |
1501 // site for it to patch. | 1461 // site for it to patch. |
1502 __ nop(); | 1462 __ nop(); |
1503 if (expr->is_postfix()) { | 1463 if (expr->is_postfix()) { |
1504 __ Drop(1); // Result is on the stack under the receiver. | 1464 __ Drop(1); // Result is on the stack under the receiver. |
1505 if (expr->context() != Expression::kEffect) { | 1465 if (expr->context() != Expression::kEffect) { |
1506 MoveTOS(expr->context()); | 1466 ApplyTOS(expr->context()); |
1507 } | 1467 } |
1508 } else { | 1468 } else { |
1509 DropAndMove(expr->context(), rax); | 1469 DropAndApply(1, expr->context(), rax); |
1510 } | 1470 } |
1511 break; | 1471 break; |
1512 } | 1472 } |
1513 case KEYED_PROPERTY: { | 1473 case KEYED_PROPERTY: { |
1514 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 1474 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
1515 __ call(ic, RelocInfo::CODE_TARGET); | 1475 __ call(ic, RelocInfo::CODE_TARGET); |
1516 // This nop signals to the IC that there is no inlined code at the call | 1476 // This nop signals to the IC that there is no inlined code at the call |
1517 // site for it to patch. | 1477 // site for it to patch. |
1518 __ nop(); | 1478 __ nop(); |
1519 if (expr->is_postfix()) { | 1479 if (expr->is_postfix()) { |
1520 __ Drop(2); // Result is on the stack under the key and the receiver. | 1480 __ Drop(2); // Result is on the stack under the key and the receiver. |
1521 if (expr->context() != Expression::kEffect) { | 1481 if (expr->context() != Expression::kEffect) { |
1522 MoveTOS(expr->context()); | 1482 ApplyTOS(expr->context()); |
1523 } | 1483 } |
1524 } else { | 1484 } else { |
1525 DropAndMove(expr->context(), rax, 2); | 1485 DropAndApply(2, expr->context(), rax); |
1526 } | 1486 } |
1527 break; | 1487 break; |
1528 } | 1488 } |
1529 } | 1489 } |
1530 } | 1490 } |
1531 | 1491 |
1532 void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { | 1492 void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { |
1533 Comment cmnt(masm_, "[ BinaryOperation"); | 1493 Comment cmnt(masm_, "[ BinaryOperation"); |
1534 switch (expr->op()) { | 1494 switch (expr->op()) { |
1535 case Token::COMMA: | 1495 case Token::COMMA: |
(...skipping 21 matching lines...) Expand all Loading... |
1557 case Token::SAR: { | 1517 case Token::SAR: { |
1558 ASSERT_EQ(Expression::kValue, expr->left()->context()); | 1518 ASSERT_EQ(Expression::kValue, expr->left()->context()); |
1559 ASSERT_EQ(Expression::kValue, expr->right()->context()); | 1519 ASSERT_EQ(Expression::kValue, expr->right()->context()); |
1560 | 1520 |
1561 Visit(expr->left()); | 1521 Visit(expr->left()); |
1562 Visit(expr->right()); | 1522 Visit(expr->right()); |
1563 GenericBinaryOpStub stub(expr->op(), | 1523 GenericBinaryOpStub stub(expr->op(), |
1564 NO_OVERWRITE, | 1524 NO_OVERWRITE, |
1565 NO_GENERIC_BINARY_FLAGS); | 1525 NO_GENERIC_BINARY_FLAGS); |
1566 __ CallStub(&stub); | 1526 __ CallStub(&stub); |
1567 Move(expr->context(), rax); | 1527 Apply(expr->context(), rax); |
1568 | 1528 |
1569 break; | 1529 break; |
1570 } | 1530 } |
1571 default: | 1531 default: |
1572 UNREACHABLE(); | 1532 UNREACHABLE(); |
1573 } | 1533 } |
1574 } | 1534 } |
1575 | 1535 |
1576 | 1536 |
1577 void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) { | 1537 void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) { |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1725 break; | 1685 break; |
1726 } | 1686 } |
1727 true_label_ = saved_true; | 1687 true_label_ = saved_true; |
1728 false_label_ = saved_false; | 1688 false_label_ = saved_false; |
1729 // Convert current context to test context: End post-test code. | 1689 // Convert current context to test context: End post-test code. |
1730 } | 1690 } |
1731 | 1691 |
1732 | 1692 |
1733 void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) { | 1693 void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) { |
1734 __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 1694 __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
1735 Move(expr->context(), rax); | 1695 Apply(expr->context(), rax); |
1736 } | 1696 } |
1737 | 1697 |
1738 | 1698 |
1739 Register FastCodeGenerator::result_register() { return rax; } | 1699 Register FastCodeGenerator::result_register() { return rax; } |
1740 | 1700 |
1741 | 1701 |
1742 Register FastCodeGenerator::context_register() { return rsi; } | 1702 Register FastCodeGenerator::context_register() { return rsi; } |
1743 | 1703 |
1744 | 1704 |
1745 void FastCodeGenerator::StoreToFrameField(int frame_offset, Register value) { | 1705 void FastCodeGenerator::StoreToFrameField(int frame_offset, Register value) { |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1784 __ movq(Operand(rsp, 0), rdx); | 1744 __ movq(Operand(rsp, 0), rdx); |
1785 // And return. | 1745 // And return. |
1786 __ ret(0); | 1746 __ ret(0); |
1787 } | 1747 } |
1788 | 1748 |
1789 | 1749 |
1790 #undef __ | 1750 #undef __ |
1791 | 1751 |
1792 | 1752 |
1793 } } // namespace v8::internal | 1753 } } // namespace v8::internal |
OLD | NEW |