| 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 |