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 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
66 __ add(fp, sp, Operand(2 * kPointerSize)); | 66 __ add(fp, sp, Operand(2 * kPointerSize)); |
67 | 67 |
68 { Comment cmnt(masm_, "[ Allocate locals"); | 68 { Comment cmnt(masm_, "[ Allocate locals"); |
69 for (int i = 0; i < locals_count; i++) { | 69 for (int i = 0; i < locals_count; i++) { |
70 __ push(ip); | 70 __ push(ip); |
71 } | 71 } |
72 } | 72 } |
73 | 73 |
74 bool function_in_register = true; | 74 bool function_in_register = true; |
75 | 75 |
| 76 // Possibly allocate a local context. |
| 77 if (fun->scope()->num_heap_slots() > 0) { |
| 78 Comment cmnt(masm_, "[ Allocate local context"); |
| 79 // Argument to NewContext is the function, which is in r1. |
| 80 __ push(r1); |
| 81 __ CallRuntime(Runtime::kNewContext, 1); |
| 82 function_in_register = false; |
| 83 // Context is returned in both r0 and cp. It replaces the context |
| 84 // passed to us. It's saved in the stack and kept live in cp. |
| 85 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 86 // Copy any necessary parameters into the context. |
| 87 int num_parameters = fun->scope()->num_parameters(); |
| 88 for (int i = 0; i < num_parameters; i++) { |
| 89 Slot* slot = fun->scope()->parameter(i)->slot(); |
| 90 if (slot != NULL && slot->type() == Slot::CONTEXT) { |
| 91 int parameter_offset = StandardFrameConstants::kCallerSPOffset + |
| 92 (num_parameters - 1 - i) * kPointerSize; |
| 93 // Load parameter from stack. |
| 94 __ ldr(r0, MemOperand(fp, parameter_offset)); |
| 95 // Store it in the context |
| 96 __ str(r0, MemOperand(cp, Context::SlotOffset(slot->index()))); |
| 97 } |
| 98 } |
| 99 } |
| 100 |
76 Variable* arguments = fun->scope()->arguments()->AsVariable(); | 101 Variable* arguments = fun->scope()->arguments()->AsVariable(); |
77 if (arguments != NULL) { | 102 if (arguments != NULL) { |
78 // Function uses arguments object. | 103 // Function uses arguments object. |
79 Comment cmnt(masm_, "[ Allocate arguments object"); | 104 Comment cmnt(masm_, "[ Allocate arguments object"); |
80 __ mov(r3, r1); | 105 if (!function_in_register) { |
| 106 // Load this again, if it's used by the local context below. |
| 107 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
| 108 } else { |
| 109 __ mov(r3, r1); |
| 110 } |
81 // Receiver is just before the parameters on the caller's stack. | 111 // Receiver is just before the parameters on the caller's stack. |
82 __ add(r2, fp, Operand(StandardFrameConstants::kCallerSPOffset + | 112 __ add(r2, fp, Operand(StandardFrameConstants::kCallerSPOffset + |
83 fun->num_parameters() * kPointerSize)); | 113 fun->num_parameters() * kPointerSize)); |
84 __ mov(r1, Operand(Smi::FromInt(fun->num_parameters()))); | 114 __ mov(r1, Operand(Smi::FromInt(fun->num_parameters()))); |
85 __ stm(db_w, sp, r1.bit() | r2.bit() | r3.bit()); | 115 __ stm(db_w, sp, r3.bit() | r2.bit() | r1.bit()); |
86 | 116 |
87 // Arguments to ArgumentsAccessStub: | 117 // Arguments to ArgumentsAccessStub: |
88 // function, receiver address, parameter count. | 118 // function, receiver address, parameter count. |
89 // The stub will rewrite receiever and parameter count if the previous | 119 // The stub will rewrite receiever and parameter count if the previous |
90 // stack frame was an arguments adapter frame. | 120 // stack frame was an arguments adapter frame. |
91 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); | 121 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); |
92 __ CallStub(&stub); | 122 __ CallStub(&stub); |
93 __ str(r0, MemOperand(fp, SlotOffset(arguments->slot()))); | 123 // Duplicate the value; move-to-slot operation might clobber registers. |
| 124 __ mov(r3, r0); |
| 125 Move(arguments->slot(), r0, r1, r2); |
94 Slot* dot_arguments_slot = | 126 Slot* dot_arguments_slot = |
95 fun->scope()->arguments_shadow()->AsVariable()->slot(); | 127 fun->scope()->arguments_shadow()->AsVariable()->slot(); |
96 __ str(r0, MemOperand(fp, SlotOffset(dot_arguments_slot))); | 128 Move(dot_arguments_slot, r3, r1, r2); |
97 function_in_register = false; | |
98 } | |
99 | |
100 // Possibly allocate a local context. | |
101 if (fun->scope()->num_heap_slots() > 0) { | |
102 Comment cmnt(masm_, "[ Allocate local context"); | |
103 if (!function_in_register) { | |
104 // Load this again, if it's used by the local context below. | |
105 __ ldr(r1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); | |
106 } | |
107 // Argument to NewContext is the function, which is in r1. | |
108 __ push(r1); | |
109 __ CallRuntime(Runtime::kNewContext, 1); | |
110 // Context is returned in both r0 and cp. It replaces the context | |
111 // passed to us. It's saved in the stack and kept live in cp. | |
112 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | |
113 #ifdef DEBUG | |
114 // Assert we do not have to copy any parameters into the context. | |
115 for (int i = 0, len = fun->scope()->num_parameters(); i < len; i++) { | |
116 Slot* slot = fun->scope()->parameter(i)->slot(); | |
117 ASSERT(slot != NULL && slot->type() != Slot::CONTEXT); | |
118 } | |
119 #endif | |
120 } | 129 } |
121 | 130 |
122 // Check the stack for overflow or break request. | 131 // Check the stack for overflow or break request. |
123 // Put the lr setup instruction in the delay slot. The kInstrSize is | 132 // Put the lr setup instruction in the delay slot. The kInstrSize is |
124 // added to the implicit 8 byte offset that always applies to operations | 133 // added to the implicit 8 byte offset that always applies to operations |
125 // with pc and gives a return address 12 bytes down. | 134 // with pc and gives a return address 12 bytes down. |
126 { Comment cmnt(masm_, "[ Stack check"); | 135 { Comment cmnt(masm_, "[ Stack check"); |
127 __ LoadRoot(r2, Heap::kStackLimitRootIndex); | 136 __ LoadRoot(r2, Heap::kStackLimitRootIndex); |
128 __ add(lr, pc, Operand(Assembler::kInstrSize)); | 137 __ add(lr, pc, Operand(Assembler::kInstrSize)); |
129 __ cmp(sp, Operand(r2)); | 138 __ cmp(sp, Operand(r2)); |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
231 __ push(source); | 240 __ push(source); |
232 TestAndBranch(source, &discard, false_label_); | 241 TestAndBranch(source, &discard, false_label_); |
233 __ bind(&discard); | 242 __ bind(&discard); |
234 __ pop(); | 243 __ pop(); |
235 __ jmp(true_label_); | 244 __ jmp(true_label_); |
236 } | 245 } |
237 } | 246 } |
238 } | 247 } |
239 | 248 |
240 | 249 |
241 void FastCodeGenerator::Move(Expression::Context context, Slot* source) { | 250 template <> |
| 251 MemOperand FastCodeGenerator::CreateSlotOperand<MemOperand>( |
| 252 Slot* source, |
| 253 Register scratch) { |
| 254 switch (source->type()) { |
| 255 case Slot::PARAMETER: |
| 256 case Slot::LOCAL: |
| 257 return MemOperand(fp, SlotOffset(source)); |
| 258 case Slot::CONTEXT: { |
| 259 int context_chain_length = |
| 260 function_->scope()->ContextChainLength(source->var()->scope()); |
| 261 __ LoadContext(scratch, context_chain_length); |
| 262 return CodeGenerator::ContextOperand(scratch, source->index()); |
| 263 break; |
| 264 } |
| 265 case Slot::LOOKUP: |
| 266 UNIMPLEMENTED(); |
| 267 // Fall-through. |
| 268 default: |
| 269 UNREACHABLE(); |
| 270 return MemOperand(r0, 0); // Dead code to make the compiler happy. |
| 271 } |
| 272 } |
| 273 |
| 274 |
| 275 void FastCodeGenerator::Move(Register dst, Slot* source) { |
| 276 // Use dst as scratch. |
| 277 MemOperand location = CreateSlotOperand<MemOperand>(source, dst); |
| 278 __ ldr(dst, location); |
| 279 } |
| 280 |
| 281 |
| 282 |
| 283 void FastCodeGenerator::Move(Expression::Context context, |
| 284 Slot* source, |
| 285 Register scratch) { |
242 switch (context) { | 286 switch (context) { |
243 case Expression::kUninitialized: | 287 case Expression::kUninitialized: |
244 UNREACHABLE(); | 288 UNREACHABLE(); |
245 case Expression::kEffect: | 289 case Expression::kEffect: |
246 break; | 290 break; |
247 case Expression::kValue: // Fall through. | 291 case Expression::kValue: // Fall through. |
248 case Expression::kTest: // Fall through. | 292 case Expression::kTest: // Fall through. |
249 case Expression::kValueTest: // Fall through. | 293 case Expression::kValueTest: // Fall through. |
250 case Expression::kTestValue: | 294 case Expression::kTestValue: |
251 __ ldr(ip, MemOperand(fp, SlotOffset(source))); | 295 Move(scratch, source); |
252 Move(context, ip); | 296 Move(context, scratch); |
253 break; | 297 break; |
254 } | 298 } |
255 } | 299 } |
256 | 300 |
257 | 301 |
258 void FastCodeGenerator::Move(Expression::Context context, Literal* expr) { | 302 void FastCodeGenerator::Move(Expression::Context context, Literal* expr) { |
259 switch (context) { | 303 switch (context) { |
260 case Expression::kUninitialized: | 304 case Expression::kUninitialized: |
261 UNREACHABLE(); | 305 UNREACHABLE(); |
262 case Expression::kEffect: | 306 case Expression::kEffect: |
263 break; | 307 break; |
264 case Expression::kValue: // Fall through. | 308 case Expression::kValue: // Fall through. |
265 case Expression::kTest: // Fall through. | 309 case Expression::kTest: // Fall through. |
266 case Expression::kValueTest: // Fall through. | 310 case Expression::kValueTest: // Fall through. |
267 case Expression::kTestValue: | 311 case Expression::kTestValue: |
268 __ mov(ip, Operand(expr->handle())); | 312 __ mov(ip, Operand(expr->handle())); |
269 Move(context, ip); | 313 Move(context, ip); |
270 break; | 314 break; |
271 } | 315 } |
272 } | 316 } |
273 | 317 |
274 | 318 |
| 319 void FastCodeGenerator::Move(Slot* dst, |
| 320 Register src, |
| 321 Register scratch1, |
| 322 Register scratch2) { |
| 323 switch (dst->type()) { |
| 324 case Slot::PARAMETER: |
| 325 case Slot::LOCAL: |
| 326 __ str(src, MemOperand(fp, SlotOffset(dst))); |
| 327 break; |
| 328 case Slot::CONTEXT: { |
| 329 int context_chain_length = |
| 330 function_->scope()->ContextChainLength(dst->var()->scope()); |
| 331 __ LoadContext(scratch1, context_chain_length); |
| 332 int index = Context::SlotOffset(dst->index()); |
| 333 __ mov(scratch2, Operand(index)); |
| 334 __ str(src, MemOperand(scratch1, index)); |
| 335 __ RecordWrite(scratch1, scratch2, src); |
| 336 break; |
| 337 } |
| 338 case Slot::LOOKUP: |
| 339 UNIMPLEMENTED(); |
| 340 default: |
| 341 UNREACHABLE(); |
| 342 } |
| 343 } |
| 344 |
| 345 |
| 346 |
275 void FastCodeGenerator::DropAndMove(Expression::Context context, | 347 void FastCodeGenerator::DropAndMove(Expression::Context context, |
276 Register source) { | 348 Register source, |
| 349 int drop_count) { |
| 350 ASSERT(drop_count > 0); |
277 switch (context) { | 351 switch (context) { |
278 case Expression::kUninitialized: | 352 case Expression::kUninitialized: |
279 UNREACHABLE(); | 353 UNREACHABLE(); |
280 case Expression::kEffect: | 354 case Expression::kEffect: |
281 __ pop(); | 355 __ add(sp, sp, Operand(drop_count * kPointerSize)); |
282 break; | 356 break; |
283 case Expression::kValue: | 357 case Expression::kValue: |
| 358 if (drop_count > 1) { |
| 359 __ add(sp, sp, Operand((drop_count - 1) * kPointerSize)); |
| 360 } |
284 __ str(source, MemOperand(sp)); | 361 __ str(source, MemOperand(sp)); |
285 break; | 362 break; |
286 case Expression::kTest: | 363 case Expression::kTest: |
287 ASSERT(!source.is(sp)); | 364 ASSERT(!source.is(sp)); |
288 __ pop(); | 365 __ add(sp, sp, Operand(drop_count * kPointerSize)); |
289 TestAndBranch(source, true_label_, false_label_); | 366 TestAndBranch(source, true_label_, false_label_); |
290 break; | 367 break; |
291 case Expression::kValueTest: { | 368 case Expression::kValueTest: { |
292 Label discard; | 369 Label discard; |
| 370 if (drop_count > 1) { |
| 371 __ add(sp, sp, Operand((drop_count - 1) * kPointerSize)); |
| 372 } |
293 __ str(source, MemOperand(sp)); | 373 __ str(source, MemOperand(sp)); |
294 TestAndBranch(source, true_label_, &discard); | 374 TestAndBranch(source, true_label_, &discard); |
295 __ bind(&discard); | 375 __ bind(&discard); |
296 __ pop(); | 376 __ pop(); |
297 __ jmp(false_label_); | 377 __ jmp(false_label_); |
298 break; | 378 break; |
299 } | 379 } |
300 case Expression::kTestValue: { | 380 case Expression::kTestValue: { |
301 Label discard; | 381 Label discard; |
| 382 if (drop_count > 1) { |
| 383 __ add(sp, sp, Operand((drop_count - 1) * kPointerSize)); |
| 384 } |
302 __ str(source, MemOperand(sp)); | 385 __ str(source, MemOperand(sp)); |
303 TestAndBranch(source, &discard, false_label_); | 386 TestAndBranch(source, &discard, false_label_); |
304 __ bind(&discard); | 387 __ bind(&discard); |
305 __ pop(); | 388 __ pop(); |
306 __ jmp(true_label_); | 389 __ jmp(true_label_); |
307 break; | 390 break; |
308 } | 391 } |
309 } | 392 } |
310 } | 393 } |
311 | 394 |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
460 // Use inline caching. Variable name is passed in r2 and the global | 543 // Use inline caching. Variable name is passed in r2 and the global |
461 // object on the stack. | 544 // object on the stack. |
462 __ ldr(ip, CodeGenerator::GlobalObject()); | 545 __ ldr(ip, CodeGenerator::GlobalObject()); |
463 __ push(ip); | 546 __ push(ip); |
464 __ mov(r2, Operand(expr->name())); | 547 __ mov(r2, Operand(expr->name())); |
465 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 548 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
466 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 549 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
467 DropAndMove(expr->context(), r0); | 550 DropAndMove(expr->context(), r0); |
468 } else if (rewrite->AsSlot() != NULL) { | 551 } else if (rewrite->AsSlot() != NULL) { |
469 Slot* slot = rewrite->AsSlot(); | 552 Slot* slot = rewrite->AsSlot(); |
470 ASSERT_NE(NULL, slot); | 553 if (FLAG_debug_code) { |
471 switch (slot->type()) { | 554 switch (slot->type()) { |
472 case Slot::LOCAL: | 555 case Slot::LOCAL: |
473 case Slot::PARAMETER: { | 556 case Slot::PARAMETER: { |
474 Comment cmnt(masm_, "Stack slot"); | 557 Comment cmnt(masm_, "Stack slot"); |
475 Move(expr->context(), rewrite->AsSlot()); | 558 break; |
476 break; | 559 } |
| 560 case Slot::CONTEXT: { |
| 561 Comment cmnt(masm_, "Context slot"); |
| 562 break; |
| 563 } |
| 564 case Slot::LOOKUP: |
| 565 UNIMPLEMENTED(); |
| 566 break; |
| 567 default: |
| 568 UNREACHABLE(); |
477 } | 569 } |
478 | |
479 case Slot::CONTEXT: { | |
480 Comment cmnt(masm_, "Context slot"); | |
481 int chain_length = | |
482 function_->scope()->ContextChainLength(slot->var()->scope()); | |
483 if (chain_length > 0) { | |
484 // Move up the chain of contexts to the context containing the slot. | |
485 __ ldr(r0, CodeGenerator::ContextOperand(cp, Context::CLOSURE_INDEX)); | |
486 // Load the function context (which is the incoming, outer context). | |
487 __ ldr(r0, FieldMemOperand(r0, JSFunction::kContextOffset)); | |
488 for (int i = 1; i < chain_length; i++) { | |
489 __ ldr(r0, | |
490 CodeGenerator::ContextOperand(r0, Context::CLOSURE_INDEX)); | |
491 // Load the function context (which is the incoming, outer context). | |
492 __ ldr(r0, FieldMemOperand(r0, JSFunction::kContextOffset)); | |
493 } | |
494 // The context may be an intermediate context, not a function context. | |
495 __ ldr(r0, | |
496 CodeGenerator::ContextOperand(r0, Context::FCONTEXT_INDEX)); | |
497 } else { // Slot is in the current context. | |
498 __ ldr(r0, | |
499 CodeGenerator::ContextOperand(cp, Context::FCONTEXT_INDEX)); | |
500 } | |
501 __ ldr(r0, CodeGenerator::ContextOperand(r0, slot->index())); | |
502 Move(expr->context(), r0); | |
503 break; | |
504 } | |
505 | |
506 case Slot::LOOKUP: | |
507 UNREACHABLE(); | |
508 break; | |
509 } | 570 } |
| 571 Move(expr->context(), slot, r0); |
510 } else { | 572 } else { |
511 // The parameter variable has been rewritten into an explict access to | 573 // A variable has been rewritten into an explicit access to |
512 // the arguments object. | 574 // an object property. |
513 Property* property = rewrite->AsProperty(); | 575 Property* property = rewrite->AsProperty(); |
514 ASSERT_NOT_NULL(property); | 576 ASSERT_NOT_NULL(property); |
515 ASSERT_EQ(expr->context(), property->context()); | 577 |
516 Visit(property); | 578 // Currently the only parameter expressions that can occur are |
| 579 // on the form "slot[literal]". |
| 580 |
| 581 // Check that the object is in a slot. |
| 582 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable(); |
| 583 ASSERT_NOT_NULL(object_var); |
| 584 Slot* object_slot = object_var->slot(); |
| 585 ASSERT_NOT_NULL(object_slot); |
| 586 |
| 587 // Load the object. |
| 588 Move(r2, object_slot); |
| 589 |
| 590 // Check that the key is a smi. |
| 591 Literal* key_literal = property->key()->AsLiteral(); |
| 592 ASSERT_NOT_NULL(key_literal); |
| 593 ASSERT(key_literal->handle()->IsSmi()); |
| 594 |
| 595 // Load the key. |
| 596 __ mov(r1, Operand(key_literal->handle())); |
| 597 |
| 598 // Push both as arguments to ic. |
| 599 __ stm(db_w, sp, r2.bit() | r1.bit()); |
| 600 |
| 601 // Do a KEYED property load. |
| 602 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| 603 __ Call(ic, RelocInfo::CODE_TARGET); |
| 604 |
| 605 // Drop key and object left on the stack by IC, and push the result. |
| 606 DropAndMove(expr->context(), r0, 2); |
517 } | 607 } |
518 } | 608 } |
519 | 609 |
520 | 610 |
521 void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { | 611 void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
522 Comment cmnt(masm_, "[ RegExpLiteral"); | 612 Comment cmnt(masm_, "[ RegExpLiteral"); |
523 Label done; | 613 Label done; |
524 // Registers will be used as follows: | 614 // Registers will be used as follows: |
525 // r4 = JS function, literals array | 615 // r4 = JS function, literals array |
526 // r3 = literal index | 616 // r3 = literal index |
(...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
778 // r2, and the global object on the stack. | 868 // r2, and the global object on the stack. |
779 __ pop(r0); | 869 __ pop(r0); |
780 __ mov(r2, Operand(var->name())); | 870 __ mov(r2, Operand(var->name())); |
781 __ ldr(ip, CodeGenerator::GlobalObject()); | 871 __ ldr(ip, CodeGenerator::GlobalObject()); |
782 __ push(ip); | 872 __ push(ip); |
783 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 873 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
784 __ Call(ic, RelocInfo::CODE_TARGET); | 874 __ Call(ic, RelocInfo::CODE_TARGET); |
785 // Overwrite the global object on the stack with the result if needed. | 875 // Overwrite the global object on the stack with the result if needed. |
786 DropAndMove(expr->context(), r0); | 876 DropAndMove(expr->context(), r0); |
787 | 877 |
788 } else { | 878 } else if (var->slot()) { |
789 Slot* slot = var->slot(); | 879 Slot* slot = var->slot(); |
790 ASSERT_NOT_NULL(slot); // Variables rewritten as properties not handled. | 880 ASSERT_NOT_NULL(slot); // Variables rewritten as properties not handled. |
791 switch (slot->type()) { | 881 switch (slot->type()) { |
792 case Slot::LOCAL: | 882 case Slot::LOCAL: |
793 case Slot::PARAMETER: { | 883 case Slot::PARAMETER: { |
794 switch (expr->context()) { | 884 switch (expr->context()) { |
795 case Expression::kUninitialized: | 885 case Expression::kUninitialized: |
796 UNREACHABLE(); | 886 UNREACHABLE(); |
797 case Expression::kEffect: | 887 case Expression::kEffect: |
798 // Perform assignment and discard value. | 888 // Perform assignment and discard value. |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
877 expr->context() != Expression::kValue) { | 967 expr->context() != Expression::kValue) { |
878 Move(expr->context(), r3); | 968 Move(expr->context(), r3); |
879 } | 969 } |
880 break; | 970 break; |
881 } | 971 } |
882 | 972 |
883 case Slot::LOOKUP: | 973 case Slot::LOOKUP: |
884 UNREACHABLE(); | 974 UNREACHABLE(); |
885 break; | 975 break; |
886 } | 976 } |
| 977 } else { |
| 978 Property* property = var->rewrite()->AsProperty(); |
| 979 ASSERT_NOT_NULL(property); |
| 980 |
| 981 // Load object and key onto the stack. |
| 982 Slot* object_slot = property->obj()->AsSlot(); |
| 983 ASSERT_NOT_NULL(object_slot); |
| 984 Move(Expression::kValue, object_slot, r0); |
| 985 |
| 986 Literal* key_literal = property->key()->AsLiteral(); |
| 987 ASSERT_NOT_NULL(key_literal); |
| 988 Move(Expression::kValue, key_literal); |
| 989 |
| 990 // Value to store was pushed before object and key on the stack. |
| 991 __ ldr(r0, MemOperand(sp, 2 * kPointerSize)); |
| 992 |
| 993 // Arguments to ic is value in r0, object and key on stack. |
| 994 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
| 995 __ Call(ic, RelocInfo::CODE_TARGET); |
| 996 |
| 997 if (expr->context() == Expression::kEffect) { |
| 998 __ add(sp, sp, Operand(3 * kPointerSize)); |
| 999 } else if (expr->context() == Expression::kValue) { |
| 1000 // Value is still on the stack in esp[2 * kPointerSize] |
| 1001 __ add(sp, sp, Operand(2 * kPointerSize)); |
| 1002 } else { |
| 1003 __ ldr(r0, MemOperand(sp, 2 * kPointerSize)); |
| 1004 DropAndMove(expr->context(), r0, 3); |
| 1005 } |
887 } | 1006 } |
888 } | 1007 } |
889 | 1008 |
890 | 1009 |
891 void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { | 1010 void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
892 // Assignment to a property, using a named store IC. | 1011 // Assignment to a property, using a named store IC. |
893 Property* prop = expr->target()->AsProperty(); | 1012 Property* prop = expr->target()->AsProperty(); |
894 ASSERT(prop != NULL); | 1013 ASSERT(prop != NULL); |
895 ASSERT(prop->key()->AsLiteral() != NULL); | 1014 ASSERT(prop->key()->AsLiteral() != NULL); |
896 | 1015 |
(...skipping 668 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1565 true_label_ = saved_true; | 1684 true_label_ = saved_true; |
1566 false_label_ = saved_false; | 1685 false_label_ = saved_false; |
1567 // Convert current context to test context: End post-test code. | 1686 // Convert current context to test context: End post-test code. |
1568 } | 1687 } |
1569 | 1688 |
1570 | 1689 |
1571 #undef __ | 1690 #undef __ |
1572 | 1691 |
1573 | 1692 |
1574 } } // namespace v8::internal | 1693 } } // namespace v8::internal |
OLD | NEW |