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 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
69 } else { | 69 } else { |
70 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex); | 70 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex); |
71 for (int i = 0; i < locals_count; i++) { | 71 for (int i = 0; i < locals_count; i++) { |
72 __ push(rdx); | 72 __ push(rdx); |
73 } | 73 } |
74 } | 74 } |
75 } | 75 } |
76 | 76 |
77 bool function_in_register = true; | 77 bool function_in_register = true; |
78 | 78 |
| 79 // Possibly allocate a local context. |
| 80 if (fun->scope()->num_heap_slots() > 0) { |
| 81 Comment cmnt(masm_, "[ Allocate local context"); |
| 82 // Argument to NewContext is the function, which is still in rdi. |
| 83 __ push(rdi); |
| 84 __ CallRuntime(Runtime::kNewContext, 1); |
| 85 function_in_register = false; |
| 86 // Context is returned in both rax and rsi. It replaces the context |
| 87 // passed to us. It's saved in the stack and kept live in rsi. |
| 88 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi); |
| 89 |
| 90 // Copy any necessary parameters into the context. |
| 91 int num_parameters = fun->scope()->num_parameters(); |
| 92 for (int i = 0; i < num_parameters; i++) { |
| 93 Slot* slot = fun->scope()->parameter(i)->slot(); |
| 94 if (slot != NULL && slot->type() == Slot::CONTEXT) { |
| 95 int parameter_offset = StandardFrameConstants::kCallerSPOffset + |
| 96 (num_parameters - 1 - i) * kPointerSize; |
| 97 // Load parameter from stack. |
| 98 __ movq(rax, Operand(rbp, parameter_offset)); |
| 99 // Store it in the context |
| 100 __ movq(Operand(rsi, Context::SlotOffset(slot->index())), rax); |
| 101 } |
| 102 } |
| 103 } |
| 104 |
| 105 // Possibly allocate an arguments object. |
79 Variable* arguments = fun->scope()->arguments()->AsVariable(); | 106 Variable* arguments = fun->scope()->arguments()->AsVariable(); |
80 if (arguments != NULL) { | 107 if (arguments != NULL) { |
81 // Function uses arguments object. | 108 // Arguments object must be allocated after the context object, in |
| 109 // case the "arguments" or ".arguments" variables are in the context. |
82 Comment cmnt(masm_, "[ Allocate arguments object"); | 110 Comment cmnt(masm_, "[ Allocate arguments object"); |
83 __ push(rdi); | 111 if (function_in_register) { |
| 112 __ push(rdi); |
| 113 } else { |
| 114 __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
| 115 } |
84 // The receiver is just before the parameters on the caller's stack. | 116 // The receiver is just before the parameters on the caller's stack. |
85 __ lea(rdx, Operand(rbp, StandardFrameConstants::kCallerSPOffset + | 117 __ lea(rdx, Operand(rbp, StandardFrameConstants::kCallerSPOffset + |
86 fun->num_parameters() * kPointerSize)); | 118 fun->num_parameters() * kPointerSize)); |
87 __ push(rdx); | 119 __ push(rdx); |
88 __ Push(Smi::FromInt(fun->num_parameters())); | 120 __ Push(Smi::FromInt(fun->num_parameters())); |
89 // Arguments to ArgumentsAccessStub: | 121 // Arguments to ArgumentsAccessStub: |
90 // function, receiver address, parameter count. | 122 // function, receiver address, parameter count. |
91 // The stub will rewrite receiver and parameter count if the previous | 123 // The stub will rewrite receiver and parameter count if the previous |
92 // stack frame was an arguments adapter frame. | 124 // stack frame was an arguments adapter frame. |
93 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); | 125 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); |
94 __ CallStub(&stub); | 126 __ CallStub(&stub); |
95 // Store new arguments object in both "arguments" and ".arguments" slots. | 127 // Store new arguments object in both "arguments" and ".arguments" slots. |
96 __ movq(Operand(rbp, SlotOffset(arguments->slot())), rax); | 128 __ movq(rcx, rax); |
| 129 Move(arguments->slot(), rax, rbx, rdx); |
97 Slot* dot_arguments_slot = | 130 Slot* dot_arguments_slot = |
98 fun->scope()->arguments_shadow()->AsVariable()->slot(); | 131 fun->scope()->arguments_shadow()->AsVariable()->slot(); |
99 __ movq(Operand(rbp, SlotOffset(dot_arguments_slot)), rax); | 132 Move(dot_arguments_slot, rcx, rbx, rdx); |
100 function_in_register = false; | |
101 } | |
102 | |
103 // Possibly allocate a local context. | |
104 if (fun->scope()->num_heap_slots() > 0) { | |
105 Comment cmnt(masm_, "[ Allocate local context"); | |
106 if (function_in_register) { | |
107 // Argument to NewContext is the function, still in rdi. | |
108 __ push(rdi); | |
109 } else { | |
110 // Argument to NewContext is the function, no longer in rdi. | |
111 __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | |
112 } | |
113 __ CallRuntime(Runtime::kNewContext, 1); | |
114 // Context is returned in both rax and rsi. It replaces the context | |
115 // passed to us. It's saved in the stack and kept live in rsi. | |
116 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi); | |
117 #ifdef DEBUG | |
118 // Assert we do not have to copy any parameters into the context. | |
119 for (int i = 0, len = fun->scope()->num_parameters(); i < len; i++) { | |
120 Slot* slot = fun->scope()->parameter(i)->slot(); | |
121 ASSERT(slot != NULL && slot->type() != Slot::CONTEXT); | |
122 } | |
123 #endif | |
124 } | 133 } |
125 | 134 |
126 { Comment cmnt(masm_, "[ Stack check"); | 135 { Comment cmnt(masm_, "[ Stack check"); |
127 Label ok; | 136 Label ok; |
128 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); | 137 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); |
129 __ j(above_equal, &ok); | 138 __ j(above_equal, &ok); |
130 StackCheckStub stub; | 139 StackCheckStub stub; |
131 __ CallStub(&stub); | 140 __ CallStub(&stub); |
132 __ bind(&ok); | 141 __ bind(&ok); |
133 } | 142 } |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
220 TestAndBranch(source, &discard, false_label_); | 229 TestAndBranch(source, &discard, false_label_); |
221 __ bind(&discard); | 230 __ bind(&discard); |
222 __ addq(rsp, Immediate(kPointerSize)); | 231 __ addq(rsp, Immediate(kPointerSize)); |
223 __ jmp(true_label_); | 232 __ jmp(true_label_); |
224 break; | 233 break; |
225 } | 234 } |
226 } | 235 } |
227 } | 236 } |
228 | 237 |
229 | 238 |
230 void FastCodeGenerator::Move(Expression::Context context, Slot* source) { | 239 template <> |
| 240 Operand FastCodeGenerator::CreateSlotOperand<Operand>(Slot* source, |
| 241 Register scratch) { |
| 242 switch (source->type()) { |
| 243 case Slot::PARAMETER: |
| 244 case Slot::LOCAL: |
| 245 return Operand(rbp, SlotOffset(source)); |
| 246 case Slot::CONTEXT: { |
| 247 int context_chain_length = |
| 248 function_->scope()->ContextChainLength(source->var()->scope()); |
| 249 __ LoadContext(scratch, context_chain_length); |
| 250 return CodeGenerator::ContextOperand(scratch, source->index()); |
| 251 break; |
| 252 } |
| 253 case Slot::LOOKUP: |
| 254 UNIMPLEMENTED(); |
| 255 // Fall-through. |
| 256 default: |
| 257 UNREACHABLE(); |
| 258 return Operand(rax, 0); // Dead code to make the compiler happy. |
| 259 } |
| 260 } |
| 261 |
| 262 |
| 263 void FastCodeGenerator::Move(Register dst, Slot* source) { |
| 264 Operand location = CreateSlotOperand<Operand>(source, dst); |
| 265 __ movq(dst, location); |
| 266 } |
| 267 |
| 268 |
| 269 void FastCodeGenerator::Move(Expression::Context context, |
| 270 Slot* source, |
| 271 Register scratch) { |
231 switch (context) { | 272 switch (context) { |
232 case Expression::kUninitialized: | 273 case Expression::kUninitialized: |
233 UNREACHABLE(); | 274 UNREACHABLE(); |
234 case Expression::kEffect: | 275 case Expression::kEffect: |
235 break; | 276 break; |
236 case Expression::kValue: | 277 case Expression::kValue: { |
237 __ push(Operand(rbp, SlotOffset(source))); | 278 Operand location = CreateSlotOperand<Operand>(source, scratch); |
| 279 __ push(location); |
238 break; | 280 break; |
| 281 } |
239 case Expression::kTest: // Fall through. | 282 case Expression::kTest: // Fall through. |
240 case Expression::kValueTest: // Fall through. | 283 case Expression::kValueTest: // Fall through. |
241 case Expression::kTestValue: | 284 case Expression::kTestValue: |
242 __ movq(rax, Operand(rbp, SlotOffset(source))); | 285 Move(scratch, source); |
243 Move(context, rax); | 286 Move(context, scratch); |
244 break; | 287 break; |
245 } | 288 } |
246 } | 289 } |
247 | 290 |
248 | 291 |
249 void FastCodeGenerator::Move(Expression::Context context, Literal* expr) { | 292 void FastCodeGenerator::Move(Expression::Context context, Literal* expr) { |
250 switch (context) { | 293 switch (context) { |
251 case Expression::kUninitialized: | 294 case Expression::kUninitialized: |
252 UNREACHABLE(); | 295 UNREACHABLE(); |
253 case Expression::kEffect: | 296 case Expression::kEffect: |
254 break; | 297 break; |
255 case Expression::kValue: | 298 case Expression::kValue: |
256 __ Push(expr->handle()); | 299 __ Push(expr->handle()); |
257 break; | 300 break; |
258 case Expression::kTest: // Fall through. | 301 case Expression::kTest: // Fall through. |
259 case Expression::kValueTest: // Fall through. | 302 case Expression::kValueTest: // Fall through. |
260 case Expression::kTestValue: | 303 case Expression::kTestValue: |
261 __ Move(rax, expr->handle()); | 304 __ Move(rax, expr->handle()); |
262 Move(context, rax); | 305 Move(context, rax); |
263 break; | 306 break; |
264 } | 307 } |
265 } | 308 } |
266 | 309 |
267 | 310 |
| 311 void FastCodeGenerator::Move(Slot* dst, |
| 312 Register src, |
| 313 Register scratch1, |
| 314 Register scratch2) { |
| 315 switch (dst->type()) { |
| 316 case Slot::PARAMETER: |
| 317 case Slot::LOCAL: |
| 318 __ movq(Operand(rbp, SlotOffset(dst)), src); |
| 319 break; |
| 320 case Slot::CONTEXT: { |
| 321 ASSERT(!src.is(scratch1)); |
| 322 ASSERT(!src.is(scratch2)); |
| 323 ASSERT(!scratch1.is(scratch2)); |
| 324 int context_chain_length = |
| 325 function_->scope()->ContextChainLength(dst->var()->scope()); |
| 326 __ LoadContext(scratch1, context_chain_length); |
| 327 __ movq(Operand(scratch1, Context::SlotOffset(dst->index())), src); |
| 328 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize; |
| 329 __ RecordWrite(scratch1, offset, src, scratch2); |
| 330 break; |
| 331 } |
| 332 case Slot::LOOKUP: |
| 333 UNIMPLEMENTED(); |
| 334 default: |
| 335 UNREACHABLE(); |
| 336 } |
| 337 } |
| 338 |
| 339 |
268 void FastCodeGenerator::DropAndMove(Expression::Context context, | 340 void FastCodeGenerator::DropAndMove(Expression::Context context, |
269 Register source) { | 341 Register source, |
| 342 int drop_count) { |
| 343 ASSERT(drop_count > 0); |
270 switch (context) { | 344 switch (context) { |
271 case Expression::kUninitialized: | 345 case Expression::kUninitialized: |
272 UNREACHABLE(); | 346 UNREACHABLE(); |
273 case Expression::kEffect: | 347 case Expression::kEffect: |
274 __ addq(rsp, Immediate(kPointerSize)); | 348 __ addq(rsp, Immediate(drop_count * kPointerSize)); |
275 break; | 349 break; |
276 case Expression::kValue: | 350 case Expression::kValue: |
| 351 if (drop_count > 1) { |
| 352 __ addq(rsp, Immediate((drop_count - 1) * kPointerSize)); |
| 353 } |
277 __ movq(Operand(rsp, 0), source); | 354 __ movq(Operand(rsp, 0), source); |
278 break; | 355 break; |
279 case Expression::kTest: | 356 case Expression::kTest: |
280 ASSERT(!source.is(rsp)); | 357 ASSERT(!source.is(rsp)); |
281 __ addq(rsp, Immediate(kPointerSize)); | 358 __ addq(rsp, Immediate(drop_count * kPointerSize)); |
282 TestAndBranch(source, true_label_, false_label_); | 359 TestAndBranch(source, true_label_, false_label_); |
283 break; | 360 break; |
284 case Expression::kValueTest: { | 361 case Expression::kValueTest: { |
285 Label discard; | 362 Label discard; |
| 363 if (drop_count > 1) { |
| 364 __ addq(rsp, Immediate((drop_count - 1) * kPointerSize)); |
| 365 } |
286 __ movq(Operand(rsp, 0), source); | 366 __ movq(Operand(rsp, 0), source); |
287 TestAndBranch(source, true_label_, &discard); | 367 TestAndBranch(source, true_label_, &discard); |
288 __ bind(&discard); | 368 __ bind(&discard); |
289 __ addq(rsp, Immediate(kPointerSize)); | 369 __ addq(rsp, Immediate(kPointerSize)); |
290 __ jmp(false_label_); | 370 __ jmp(false_label_); |
291 break; | 371 break; |
292 } | 372 } |
293 case Expression::kTestValue: { | 373 case Expression::kTestValue: { |
294 Label discard; | 374 Label discard; |
295 __ movq(Operand(rsp, 0), source); | 375 __ movq(Operand(rsp, 0), source); |
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
466 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 546 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
467 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 547 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
468 // A test rax instruction following the call is used by the IC to | 548 // A test rax instruction following the call is used by the IC to |
469 // indicate that the inobject property case was inlined. Ensure there | 549 // indicate that the inobject property case was inlined. Ensure there |
470 // is no test rax instruction here. | 550 // is no test rax instruction here. |
471 __ nop(); | 551 __ nop(); |
472 | 552 |
473 DropAndMove(expr->context(), rax); | 553 DropAndMove(expr->context(), rax); |
474 } else if (rewrite->AsSlot() != NULL) { | 554 } else if (rewrite->AsSlot() != NULL) { |
475 Slot* slot = rewrite->AsSlot(); | 555 Slot* slot = rewrite->AsSlot(); |
476 switch (slot->type()) { | 556 if (FLAG_debug_code) { |
477 case Slot::LOCAL: | 557 switch (slot->type()) { |
478 case Slot::PARAMETER: { | 558 case Slot::LOCAL: |
479 Comment cmnt(masm_, "Stack slot"); | 559 case Slot::PARAMETER: { |
480 Move(expr->context(), slot); | 560 Comment cmnt(masm_, "Stack slot"); |
481 break; | 561 break; |
| 562 } |
| 563 case Slot::CONTEXT: { |
| 564 Comment cmnt(masm_, "Context slot"); |
| 565 break; |
| 566 } |
| 567 case Slot::LOOKUP: |
| 568 UNIMPLEMENTED(); |
| 569 break; |
| 570 default: |
| 571 UNREACHABLE(); |
482 } | 572 } |
483 | |
484 case Slot::CONTEXT: { | |
485 Comment cmnt(masm_, "Context slot"); | |
486 int chain_length = | |
487 function_->scope()->ContextChainLength(slot->var()->scope()); | |
488 if (chain_length > 0) { | |
489 // Move up the chain of contexts to the context containing the slot. | |
490 __ movq(rax, | |
491 Operand(rsi, Context::SlotOffset(Context::CLOSURE_INDEX))); | |
492 // Load the function context (which is the incoming, outer context). | |
493 __ movq(rax, FieldOperand(rax, JSFunction::kContextOffset)); | |
494 for (int i = 1; i < chain_length; i++) { | |
495 __ movq(rax, | |
496 Operand(rax, Context::SlotOffset(Context::CLOSURE_INDEX))); | |
497 __ movq(rax, FieldOperand(rax, JSFunction::kContextOffset)); | |
498 } | |
499 // The context may be an intermediate context, not a function context. | |
500 __ movq(rax, | |
501 Operand(rax, Context::SlotOffset(Context::FCONTEXT_INDEX))); | |
502 } else { // Slot is in the current function context. | |
503 // The context may be an intermediate context, not a function context. | |
504 __ movq(rax, | |
505 Operand(rsi, Context::SlotOffset(Context::FCONTEXT_INDEX))); | |
506 } | |
507 __ movq(rax, Operand(rax, Context::SlotOffset(slot->index()))); | |
508 Move(expr->context(), rax); | |
509 break; | |
510 } | |
511 | |
512 case Slot::LOOKUP: | |
513 UNREACHABLE(); | |
514 break; | |
515 } | 573 } |
| 574 Move(expr->context(), slot, rax); |
516 } else { | 575 } else { |
517 // The parameter variable has been rewritten into an explict access to | 576 // A variable has been rewritten into an explicit access to |
518 // the arguments object. | 577 // an object property. |
519 Property* property = rewrite->AsProperty(); | 578 Property* property = rewrite->AsProperty(); |
520 ASSERT_NOT_NULL(property); | 579 ASSERT_NOT_NULL(property); |
521 ASSERT_EQ(expr->context(), property->context()); | 580 |
522 Visit(property); | 581 // Currently the only parameter expressions that can occur are |
| 582 // on the form "slot[literal]". |
| 583 |
| 584 // Check that the object is in a slot. |
| 585 Variable* object = property->obj()->AsVariableProxy()->AsVariable(); |
| 586 ASSERT_NOT_NULL(object); |
| 587 Slot* object_slot = object->slot(); |
| 588 ASSERT_NOT_NULL(object_slot); |
| 589 |
| 590 // Load the object. |
| 591 Move(Expression::kValue, object_slot, rax); |
| 592 |
| 593 // Check that the key is a smi. |
| 594 Literal* key_literal = property->key()->AsLiteral(); |
| 595 ASSERT_NOT_NULL(key_literal); |
| 596 ASSERT(key_literal->handle()->IsSmi()); |
| 597 |
| 598 // Load the key. |
| 599 Move(Expression::kValue, key_literal); |
| 600 |
| 601 // Do a KEYED property load. |
| 602 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| 603 __ call(ic, RelocInfo::CODE_TARGET); |
| 604 // Notice: We must not have a "test rax, ..." instruction after |
| 605 // the call. It is treated specially by the LoadIC code. |
| 606 |
| 607 // Drop key and object left on the stack by IC, and push the result. |
| 608 DropAndMove(expr->context(), rax, 2); |
523 } | 609 } |
524 } | 610 } |
525 | 611 |
526 | 612 |
527 void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { | 613 void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
528 Comment cmnt(masm_, "[ RegExpLiteral"); | 614 Comment cmnt(masm_, "[ RegExpLiteral"); |
529 Label done; | 615 Label done; |
530 // Registers will be used as follows: | 616 // Registers will be used as follows: |
531 // rdi = JS function. | 617 // rdi = JS function. |
532 // rbx = literals array. | 618 // rbx = literals array. |
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
774 // assignment. Right-hand-side value is passed in rax, variable name in | 860 // assignment. Right-hand-side value is passed in rax, variable name in |
775 // rcx, and the global object on the stack. | 861 // rcx, and the global object on the stack. |
776 __ pop(rax); | 862 __ pop(rax); |
777 __ Move(rcx, var->name()); | 863 __ Move(rcx, var->name()); |
778 __ push(CodeGenerator::GlobalObject()); | 864 __ push(CodeGenerator::GlobalObject()); |
779 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 865 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
780 __ Call(ic, RelocInfo::CODE_TARGET); | 866 __ Call(ic, RelocInfo::CODE_TARGET); |
781 // Overwrite the global object on the stack with the result if needed. | 867 // Overwrite the global object on the stack with the result if needed. |
782 DropAndMove(expr->context(), rax); | 868 DropAndMove(expr->context(), rax); |
783 | 869 |
784 } else { | 870 } else if (var->slot()) { |
785 Slot* slot = var->slot(); | 871 Slot* slot = var->slot(); |
786 ASSERT_NOT_NULL(slot); // Variables rewritten as properties not handled. | 872 ASSERT_NOT_NULL(slot); // Variables rewritten as properties not handled. |
787 switch (slot->type()) { | 873 switch (slot->type()) { |
788 case Slot::LOCAL: | 874 case Slot::LOCAL: |
789 case Slot::PARAMETER: { | 875 case Slot::PARAMETER: { |
790 switch (expr->context()) { | 876 switch (expr->context()) { |
791 case Expression::kUninitialized: | 877 case Expression::kUninitialized: |
792 UNREACHABLE(); | 878 UNREACHABLE(); |
793 case Expression::kEffect: | 879 case Expression::kEffect: |
794 // Perform assignment and discard value. | 880 // Perform assignment and discard value. |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
866 expr->context() != Expression::kValue) { | 952 expr->context() != Expression::kValue) { |
867 Move(expr->context(), rdx); | 953 Move(expr->context(), rdx); |
868 } | 954 } |
869 break; | 955 break; |
870 } | 956 } |
871 | 957 |
872 case Slot::LOOKUP: | 958 case Slot::LOOKUP: |
873 UNREACHABLE(); | 959 UNREACHABLE(); |
874 break; | 960 break; |
875 } | 961 } |
| 962 } else { |
| 963 Property* property = var->AsProperty(); |
| 964 ASSERT_NOT_NULL(property); |
| 965 // A variable has been rewritten into a property on an object. |
| 966 |
| 967 // Load object and key onto the stack. |
| 968 Slot* object_slot = property->obj()->AsSlot(); |
| 969 ASSERT_NOT_NULL(object_slot); |
| 970 Move(Expression::kValue, object_slot, rax); |
| 971 |
| 972 Literal* key_literal = property->key()->AsLiteral(); |
| 973 ASSERT_NOT_NULL(key_literal); |
| 974 Move(Expression::kValue, key_literal); |
| 975 |
| 976 // Value to store was pushed before object and key on the stack. |
| 977 __ movq(rax, Operand(rsp, 2 * kPointerSize)); |
| 978 |
| 979 // Arguments to ic is value in rax, object and key on stack. |
| 980 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
| 981 __ call(ic, RelocInfo::CODE_TARGET); |
| 982 |
| 983 if (expr->context() == Expression::kEffect) { |
| 984 __ addq(rsp, Immediate(3 * kPointerSize)); |
| 985 } else if (expr->context() == Expression::kValue) { |
| 986 // Value is still on the stack in rsp[2 * kPointerSize] |
| 987 __ addq(rsp, Immediate(2 * kPointerSize)); |
| 988 } else { |
| 989 __ movq(rax, Operand(rsp, 2 * kPointerSize)); |
| 990 DropAndMove(expr->context(), rax, 3); |
| 991 } |
876 } | 992 } |
877 } | 993 } |
878 | 994 |
879 | 995 |
880 void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { | 996 void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
881 // Assignment to a property, using a named store IC. | 997 // Assignment to a property, using a named store IC. |
882 Property* prop = expr->target()->AsProperty(); | 998 Property* prop = expr->target()->AsProperty(); |
883 ASSERT(prop != NULL); | 999 ASSERT(prop != NULL); |
884 ASSERT(prop->key()->AsLiteral() != NULL); | 1000 ASSERT(prop->key()->AsLiteral() != NULL); |
885 | 1001 |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
962 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 1078 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
963 __ call(ic, RelocInfo::CODE_TARGET); | 1079 __ call(ic, RelocInfo::CODE_TARGET); |
964 // By emitting a nop we make sure that we do not have a "test rax,..." | 1080 // By emitting a nop we make sure that we do not have a "test rax,..." |
965 // instruction after the call it is treated specially by the LoadIC code. | 1081 // instruction after the call it is treated specially by the LoadIC code. |
966 __ nop(); | 1082 __ nop(); |
967 } else { | 1083 } else { |
968 // Do a KEYED property load. | 1084 // Do a KEYED property load. |
969 Visit(expr->key()); | 1085 Visit(expr->key()); |
970 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 1086 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
971 __ call(ic, RelocInfo::CODE_TARGET); | 1087 __ call(ic, RelocInfo::CODE_TARGET); |
972 // By emitting a nop we make sure that we do not have a "test rax,..." | 1088 // Notice: We must not have a "test rax, ..." instruction after |
973 // instruction after the call it is treated specially by the LoadIC code. | 1089 // the call. It is treated specially by the LoadIC code. |
974 __ nop(); | 1090 |
975 // Drop key left on the stack by IC. | 1091 // Drop key left on the stack by IC. |
976 __ addq(rsp, Immediate(kPointerSize)); | 1092 __ addq(rsp, Immediate(kPointerSize)); |
977 } | 1093 } |
978 DropAndMove(expr->context(), rax); | 1094 DropAndMove(expr->context(), rax); |
979 } | 1095 } |
980 | 1096 |
981 | 1097 |
982 void FastCodeGenerator::EmitCallWithIC(Call* expr, RelocInfo::Mode reloc_info) { | 1098 void FastCodeGenerator::EmitCallWithIC(Call* expr, RelocInfo::Mode reloc_info) { |
983 // Code common for calls using the IC. | 1099 // Code common for calls using the IC. |
984 ZoneList<Expression*>* args = expr->arguments(); | 1100 ZoneList<Expression*>* args = expr->arguments(); |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1047 EmitCallWithIC(expr, RelocInfo::CODE_TARGET); | 1163 EmitCallWithIC(expr, RelocInfo::CODE_TARGET); |
1048 } else { | 1164 } else { |
1049 // Call to a keyed property, use keyed load IC followed by function | 1165 // Call to a keyed property, use keyed load IC followed by function |
1050 // call. | 1166 // call. |
1051 Visit(prop->obj()); | 1167 Visit(prop->obj()); |
1052 Visit(prop->key()); | 1168 Visit(prop->key()); |
1053 // Record source code position for IC call. | 1169 // Record source code position for IC call. |
1054 SetSourcePosition(prop->position()); | 1170 SetSourcePosition(prop->position()); |
1055 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 1171 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
1056 __ call(ic, RelocInfo::CODE_TARGET); | 1172 __ call(ic, RelocInfo::CODE_TARGET); |
1057 // By emitting a nop we make sure that we do not have a "test eax,..." | 1173 // By emitting a nop we make sure that we do not have a "test rax,..." |
1058 // instruction after the call it is treated specially by the LoadIC code. | 1174 // instruction after the call it is treated specially by the LoadIC code. |
1059 __ nop(); | 1175 __ nop(); |
1060 // Drop key left on the stack by IC. | 1176 // Drop key left on the stack by IC. |
1061 __ addq(rsp, Immediate(kPointerSize)); | 1177 __ addq(rsp, Immediate(kPointerSize)); |
1062 // Pop receiver. | 1178 // Pop receiver. |
1063 __ pop(rbx); | 1179 __ pop(rbx); |
1064 // Push result (function). | 1180 // Push result (function). |
1065 __ push(rax); | 1181 __ push(rax); |
1066 // Push receiver object on stack. | 1182 // Push receiver object on stack. |
1067 if (prop->is_synthetic()) { | 1183 if (prop->is_synthetic()) { |
(...skipping 480 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1548 true_label_ = saved_true; | 1664 true_label_ = saved_true; |
1549 false_label_ = saved_false; | 1665 false_label_ = saved_false; |
1550 // Convert current context to test context: End post-test code. | 1666 // Convert current context to test context: End post-test code. |
1551 } | 1667 } |
1552 | 1668 |
1553 | 1669 |
1554 #undef __ | 1670 #undef __ |
1555 | 1671 |
1556 | 1672 |
1557 } } // namespace v8::internal | 1673 } } // namespace v8::internal |
OLD | NEW |