1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include "v8.h" 29 30 #if defined(V8_TARGET_ARCH_ARM) 31 32 #include "code-stubs.h" 33 #include "codegen.h" 34 #include "compiler.h" 35 #include "debug.h" 36 #include "full-codegen.h" 37 #include "isolate-inl.h" 38 #include "parser.h" 39 #include "scopes.h" 40 #include "stub-cache.h" 41 42 #include "arm/code-stubs-arm.h" 43 #include "arm/macro-assembler-arm.h" 44 45 namespace v8 { 46 namespace internal { 47 48 #define __ ACCESS_MASM(masm_) 49 50 51 // A patch site is a location in the code which it is possible to patch. This 52 // class has a number of methods to emit the code which is patchable and the 53 // method EmitPatchInfo to record a marker back to the patchable code. This 54 // marker is a cmp rx, #yyy instruction, and x * 0x00000fff + yyy (raw 12 bit 55 // immediate value is used) is the delta from the pc to the first instruction of 56 // the patchable code. 57 class JumpPatchSite BASE_EMBEDDED { 58 public: 59 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) { 60 #ifdef DEBUG 61 info_emitted_ = false; 62 #endif 63 } 64 65 ~JumpPatchSite() { 66 ASSERT(patch_site_.is_bound() == info_emitted_); 67 } 68 69 // When initially emitting this ensure that a jump is always generated to skip 70 // the inlined smi code. 71 void EmitJumpIfNotSmi(Register reg, Label* target) { 72 ASSERT(!patch_site_.is_bound() && !info_emitted_); 73 Assembler::BlockConstPoolScope block_const_pool(masm_); 74 __ bind(&patch_site_); 75 __ cmp(reg, Operand(reg)); 76 // Don't use b(al, ...) as that might emit the constant pool right after the 77 // branch. After patching when the branch is no longer unconditional 78 // execution can continue into the constant pool. 79 __ b(eq, target); // Always taken before patched. 80 } 81 82 // When initially emitting this ensure that a jump is never generated to skip 83 // the inlined smi code. 84 void EmitJumpIfSmi(Register reg, Label* target) { 85 ASSERT(!patch_site_.is_bound() && !info_emitted_); 86 Assembler::BlockConstPoolScope block_const_pool(masm_); 87 __ bind(&patch_site_); 88 __ cmp(reg, Operand(reg)); 89 __ b(ne, target); // Never taken before patched. 90 } 91 92 void EmitPatchInfo() { 93 if (patch_site_.is_bound()) { 94 int delta_to_patch_site = masm_->InstructionsGeneratedSince(&patch_site_); 95 Register reg; 96 reg.set_code(delta_to_patch_site / kOff12Mask); 97 __ cmp_raw_immediate(reg, delta_to_patch_site % kOff12Mask); 98 #ifdef DEBUG 99 info_emitted_ = true; 100 #endif 101 } else { 102 __ nop(); // Signals no inlined code. 103 } 104 } 105 106 private: 107 MacroAssembler* masm_; 108 Label patch_site_; 109 #ifdef DEBUG 110 bool info_emitted_; 111 #endif 112 }; 113 114 115 // TODO(jkummerow): Obsolete as soon as x64 is updated. Remove. 116 int FullCodeGenerator::self_optimization_header_size() { 117 UNREACHABLE(); 118 return 24; 119 } 120 121 122 // Generate code for a JS function. On entry to the function the receiver 123 // and arguments have been pushed on the stack left to right. The actual 124 // argument count matches the formal parameter count expected by the 125 // function. 126 // 127 // The live registers are: 128 // o r1: the JS function object being called (i.e., ourselves) 129 // o cp: our context 130 // o fp: our caller's frame pointer 131 // o sp: stack pointer 132 // o lr: return address 133 // 134 // The function builds a JS frame. Please see JavaScriptFrameConstants in 135 // frames-arm.h for its layout. 136 void FullCodeGenerator::Generate() { 137 CompilationInfo* info = info_; 138 handler_table_ = 139 isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED); 140 profiling_counter_ = isolate()->factory()->NewJSGlobalPropertyCell( 141 Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget))); 142 SetFunctionPosition(function()); 143 Comment cmnt(masm_, "[ function compiled by full code generator"); 144 145 #ifdef DEBUG 146 if (strlen(FLAG_stop_at) > 0 && 147 info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { 148 __ stop("stop-at"); 149 } 150 #endif 151 152 // Strict mode functions and builtins need to replace the receiver 153 // with undefined when called as functions (without an explicit 154 // receiver object). r5 is zero for method calls and non-zero for 155 // function calls. 156 if (!info->is_classic_mode() || info->is_native()) { 157 Label ok; 158 __ cmp(r5, Operand(0)); 159 __ b(eq, &ok); 160 int receiver_offset = info->scope()->num_parameters() * kPointerSize; 161 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); 162 __ str(r2, MemOperand(sp, receiver_offset)); 163 __ bind(&ok); 164 } 165 166 // Open a frame scope to indicate that there is a frame on the stack. The 167 // MANUAL indicates that the scope shouldn't actually generate code to set up 168 // the frame (that is done below). 169 FrameScope frame_scope(masm_, StackFrame::MANUAL); 170 171 int locals_count = info->scope()->num_stack_slots(); 172 173 __ Push(lr, fp, cp, r1); 174 if (locals_count > 0) { 175 // Load undefined value here, so the value is ready for the loop 176 // below. 177 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); 178 } 179 // Adjust fp to point to caller's fp. 180 __ add(fp, sp, Operand(2 * kPointerSize)); 181 182 { Comment cmnt(masm_, "[ Allocate locals"); 183 for (int i = 0; i < locals_count; i++) { 184 __ push(ip); 185 } 186 } 187 188 bool function_in_register = true; 189 190 // Possibly allocate a local context. 191 int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; 192 if (heap_slots > 0) { 193 Comment cmnt(masm_, "[ Allocate local context"); 194 // Argument to NewContext is the function, which is in r1. 195 __ push(r1); 196 if (heap_slots <= FastNewContextStub::kMaximumSlots) { 197 FastNewContextStub stub(heap_slots); 198 __ CallStub(&stub); 199 } else { 200 __ CallRuntime(Runtime::kNewFunctionContext, 1); 201 } 202 function_in_register = false; 203 // Context is returned in both r0 and cp. It replaces the context 204 // passed to us. It's saved in the stack and kept live in cp. 205 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); 206 // Copy any necessary parameters into the context. 207 int num_parameters = info->scope()->num_parameters(); 208 for (int i = 0; i < num_parameters; i++) { 209 Variable* var = scope()->parameter(i); 210 if (var->IsContextSlot()) { 211 int parameter_offset = StandardFrameConstants::kCallerSPOffset + 212 (num_parameters - 1 - i) * kPointerSize; 213 // Load parameter from stack. 214 __ ldr(r0, MemOperand(fp, parameter_offset)); 215 // Store it in the context. 216 MemOperand target = ContextOperand(cp, var->index()); 217 __ str(r0, target); 218 219 // Update the write barrier. 220 __ RecordWriteContextSlot( 221 cp, target.offset(), r0, r3, kLRHasBeenSaved, kDontSaveFPRegs); 222 } 223 } 224 } 225 226 Variable* arguments = scope()->arguments(); 227 if (arguments != NULL) { 228 // Function uses arguments object. 229 Comment cmnt(masm_, "[ Allocate arguments object"); 230 if (!function_in_register) { 231 // Load this again, if it's used by the local context below. 232 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 233 } else { 234 __ mov(r3, r1); 235 } 236 // Receiver is just before the parameters on the caller's stack. 237 int num_parameters = info->scope()->num_parameters(); 238 int offset = num_parameters * kPointerSize; 239 __ add(r2, fp, 240 Operand(StandardFrameConstants::kCallerSPOffset + offset)); 241 __ mov(r1, Operand(Smi::FromInt(num_parameters))); 242 __ Push(r3, r2, r1); 243 244 // Arguments to ArgumentsAccessStub: 245 // function, receiver address, parameter count. 246 // The stub will rewrite receiever and parameter count if the previous 247 // stack frame was an arguments adapter frame. 248 ArgumentsAccessStub::Type type; 249 if (!is_classic_mode()) { 250 type = ArgumentsAccessStub::NEW_STRICT; 251 } else if (function()->has_duplicate_parameters()) { 252 type = ArgumentsAccessStub::NEW_NON_STRICT_SLOW; 253 } else { 254 type = ArgumentsAccessStub::NEW_NON_STRICT_FAST; 255 } 256 ArgumentsAccessStub stub(type); 257 __ CallStub(&stub); 258 259 SetVar(arguments, r0, r1, r2); 260 } 261 262 if (FLAG_trace) { 263 __ CallRuntime(Runtime::kTraceEnter, 0); 264 } 265 266 // Visit the declarations and body unless there is an illegal 267 // redeclaration. 268 if (scope()->HasIllegalRedeclaration()) { 269 Comment cmnt(masm_, "[ Declarations"); 270 scope()->VisitIllegalRedeclaration(this); 271 272 } else { 273 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); 274 { Comment cmnt(masm_, "[ Declarations"); 275 // For named function expressions, declare the function name as a 276 // constant. 277 if (scope()->is_function_scope() && scope()->function() != NULL) { 278 VariableProxy* proxy = scope()->function(); 279 ASSERT(proxy->var()->mode() == CONST || 280 proxy->var()->mode() == CONST_HARMONY); 281 ASSERT(proxy->var()->location() != Variable::UNALLOCATED); 282 EmitDeclaration(proxy, proxy->var()->mode(), NULL); 283 } 284 VisitDeclarations(scope()->declarations()); 285 } 286 287 { Comment cmnt(masm_, "[ Stack check"); 288 PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS); 289 Label ok; 290 __ LoadRoot(ip, Heap::kStackLimitRootIndex); 291 __ cmp(sp, Operand(ip)); 292 __ b(hs, &ok); 293 StackCheckStub stub; 294 __ CallStub(&stub); 295 __ bind(&ok); 296 } 297 298 { Comment cmnt(masm_, "[ Body"); 299 ASSERT(loop_depth() == 0); 300 VisitStatements(function()->body()); 301 ASSERT(loop_depth() == 0); 302 } 303 } 304 305 // Always emit a 'return undefined' in case control fell off the end of 306 // the body. 307 { Comment cmnt(masm_, "[ return <undefined>;"); 308 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); 309 } 310 EmitReturnSequence(); 311 312 // Force emit the constant pool, so it doesn't get emitted in the middle 313 // of the stack check table. 314 masm()->CheckConstPool(true, false); 315 } 316 317 318 void FullCodeGenerator::ClearAccumulator() { 319 __ mov(r0, Operand(Smi::FromInt(0))); 320 } 321 322 323 void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) { 324 __ mov(r2, Operand(profiling_counter_)); 325 __ ldr(r3, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset)); 326 __ sub(r3, r3, Operand(Smi::FromInt(delta)), SetCC); 327 __ str(r3, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset)); 328 } 329 330 331 void FullCodeGenerator::EmitProfilingCounterReset() { 332 int reset_value = FLAG_interrupt_budget; 333 if (info_->ShouldSelfOptimize() && !FLAG_retry_self_opt) { 334 // Self-optimization is a one-off thing: if it fails, don't try again. 335 reset_value = Smi::kMaxValue; 336 } 337 if (isolate()->IsDebuggerActive()) { 338 // Detect debug break requests as soon as possible. 339 reset_value = 10; 340 } 341 __ mov(r2, Operand(profiling_counter_)); 342 __ mov(r3, Operand(Smi::FromInt(reset_value))); 343 __ str(r3, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset)); 344 } 345 346 347 static const int kMaxBackEdgeWeight = 127; 348 static const int kBackEdgeDistanceDivisor = 142; 349 350 351 void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt, 352 Label* back_edge_target) { 353 Comment cmnt(masm_, "[ Stack check"); 354 Label ok; 355 356 if (FLAG_count_based_interrupts) { 357 int weight = 1; 358 if (FLAG_weighted_back_edges) { 359 ASSERT(back_edge_target->is_bound()); 360 int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target); 361 weight = Min(kMaxBackEdgeWeight, 362 Max(1, distance / kBackEdgeDistanceDivisor)); 363 } 364 EmitProfilingCounterDecrement(weight); 365 __ b(pl, &ok); 366 InterruptStub stub; 367 __ CallStub(&stub); 368 } else { 369 __ LoadRoot(ip, Heap::kStackLimitRootIndex); 370 __ cmp(sp, Operand(ip)); 371 __ b(hs, &ok); 372 StackCheckStub stub; 373 __ CallStub(&stub); 374 } 375 376 // Record a mapping of this PC offset to the OSR id. This is used to find 377 // the AST id from the unoptimized code in order to use it as a key into 378 // the deoptimization input data found in the optimized code. 379 RecordStackCheck(stmt->OsrEntryId()); 380 381 if (FLAG_count_based_interrupts) { 382 EmitProfilingCounterReset(); 383 } 384 385 __ bind(&ok); 386 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); 387 // Record a mapping of the OSR id to this PC. This is used if the OSR 388 // entry becomes the target of a bailout. We don't expect it to be, but 389 // we want it to work if it is. 390 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS); 391 } 392 393 394 void FullCodeGenerator::EmitReturnSequence() { 395 Comment cmnt(masm_, "[ Return sequence"); 396 if (return_label_.is_bound()) { 397 __ b(&return_label_); 398 } else { 399 __ bind(&return_label_); 400 if (FLAG_trace) { 401 // Push the return value on the stack as the parameter. 402 // Runtime::TraceExit returns its parameter in r0. 403 __ push(r0); 404 __ CallRuntime(Runtime::kTraceExit, 1); 405 } 406 if (FLAG_interrupt_at_exit || FLAG_self_optimization) { 407 // Pretend that the exit is a backwards jump to the entry. 408 int weight = 1; 409 if (info_->ShouldSelfOptimize()) { 410 weight = FLAG_interrupt_budget / FLAG_self_opt_count; 411 } else if (FLAG_weighted_back_edges) { 412 int distance = masm_->pc_offset(); 413 weight = Min(kMaxBackEdgeWeight, 414 Max(1, distance / kBackEdgeDistanceDivisor)); 415 } 416 EmitProfilingCounterDecrement(weight); 417 Label ok; 418 __ b(pl, &ok); 419 __ push(r0); 420 if (info_->ShouldSelfOptimize() && FLAG_direct_self_opt) { 421 __ ldr(r2, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 422 __ push(r2); 423 __ CallRuntime(Runtime::kOptimizeFunctionOnNextCall, 1); 424 } else { 425 InterruptStub stub; 426 __ CallStub(&stub); 427 } 428 __ pop(r0); 429 EmitProfilingCounterReset(); 430 __ bind(&ok); 431 } 432 433 #ifdef DEBUG 434 // Add a label for checking the size of the code used for returning. 435 Label check_exit_codesize; 436 masm_->bind(&check_exit_codesize); 437 #endif 438 // Make sure that the constant pool is not emitted inside of the return 439 // sequence. 440 { Assembler::BlockConstPoolScope block_const_pool(masm_); 441 // Here we use masm_-> instead of the __ macro to avoid the code coverage 442 // tool from instrumenting as we rely on the code size here. 443 int32_t sp_delta = (info_->scope()->num_parameters() + 1) * kPointerSize; 444 CodeGenerator::RecordPositions(masm_, function()->end_position() - 1); 445 __ RecordJSReturn(); 446 masm_->mov(sp, fp); 447 masm_->ldm(ia_w, sp, fp.bit() | lr.bit()); 448 masm_->add(sp, sp, Operand(sp_delta)); 449 masm_->Jump(lr); 450 } 451 452 #ifdef DEBUG 453 // Check that the size of the code used for returning is large enough 454 // for the debugger's requirements. 455 ASSERT(Assembler::kJSReturnSequenceInstructions <= 456 masm_->InstructionsGeneratedSince(&check_exit_codesize)); 457 #endif 458 } 459 } 460 461 462 void FullCodeGenerator::EffectContext::Plug(Variable* var) const { 463 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); 464 } 465 466 467 void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const { 468 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); 469 codegen()->GetVar(result_register(), var); 470 } 471 472 473 void FullCodeGenerator::StackValueContext::Plug(Variable* var) const { 474 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); 475 codegen()->GetVar(result_register(), var); 476 __ push(result_register()); 477 } 478 479 480 void FullCodeGenerator::TestContext::Plug(Variable* var) const { 481 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); 482 // For simplicity we always test the accumulator register. 483 codegen()->GetVar(result_register(), var); 484 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL); 485 codegen()->DoTest(this); 486 } 487 488 489 void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const { 490 } 491 492 493 void FullCodeGenerator::AccumulatorValueContext::Plug( 494 Heap::RootListIndex index) const { 495 __ LoadRoot(result_register(), index); 496 } 497 498 499 void FullCodeGenerator::StackValueContext::Plug( 500 Heap::RootListIndex index) const { 501 __ LoadRoot(result_register(), index); 502 __ push(result_register()); 503 } 504 505 506 void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const { 507 codegen()->PrepareForBailoutBeforeSplit(condition(), 508 true, 509 true_label_, 510 false_label_); 511 if (index == Heap::kUndefinedValueRootIndex || 512 index == Heap::kNullValueRootIndex || 513 index == Heap::kFalseValueRootIndex) { 514 if (false_label_ != fall_through_) __ b(false_label_); 515 } else if (index == Heap::kTrueValueRootIndex) { 516 if (true_label_ != fall_through_) __ b(true_label_); 517 } else { 518 __ LoadRoot(result_register(), index); 519 codegen()->DoTest(this); 520 } 521 } 522 523 524 void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const { 525 } 526 527 528 void FullCodeGenerator::AccumulatorValueContext::Plug( 529 Handle<Object> lit) const { 530 __ mov(result_register(), Operand(lit)); 531 } 532 533 534 void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const { 535 // Immediates cannot be pushed directly. 536 __ mov(result_register(), Operand(lit)); 537 __ push(result_register()); 538 } 539 540 541 void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const { 542 codegen()->PrepareForBailoutBeforeSplit(condition(), 543 true, 544 true_label_, 545 false_label_); 546 ASSERT(!lit->IsUndetectableObject()); // There are no undetectable literals. 547 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) { 548 if (false_label_ != fall_through_) __ b(false_label_); 549 } else if (lit->IsTrue() || lit->IsJSObject()) { 550 if (true_label_ != fall_through_) __ b(true_label_); 551 } else if (lit->IsString()) { 552 if (String::cast(*lit)->length() == 0) { 553 if (false_label_ != fall_through_) __ b(false_label_); 554 } else { 555 if (true_label_ != fall_through_) __ b(true_label_); 556 } 557 } else if (lit->IsSmi()) { 558 if (Smi::cast(*lit)->value() == 0) { 559 if (false_label_ != fall_through_) __ b(false_label_); 560 } else { 561 if (true_label_ != fall_through_) __ b(true_label_); 562 } 563 } else { 564 // For simplicity we always test the accumulator register. 565 __ mov(result_register(), Operand(lit)); 566 codegen()->DoTest(this); 567 } 568 } 569 570 571 void FullCodeGenerator::EffectContext::DropAndPlug(int count, 572 Register reg) const { 573 ASSERT(count > 0); 574 __ Drop(count); 575 } 576 577 578 void FullCodeGenerator::AccumulatorValueContext::DropAndPlug( 579 int count, 580 Register reg) const { 581 ASSERT(count > 0); 582 __ Drop(count); 583 __ Move(result_register(), reg); 584 } 585 586 587 void FullCodeGenerator::StackValueContext::DropAndPlug(int count, 588 Register reg) const { 589 ASSERT(count > 0); 590 if (count > 1) __ Drop(count - 1); 591 __ str(reg, MemOperand(sp, 0)); 592 } 593 594 595 void FullCodeGenerator::TestContext::DropAndPlug(int count, 596 Register reg) const { 597 ASSERT(count > 0); 598 // For simplicity we always test the accumulator register. 599 __ Drop(count); 600 __ Move(result_register(), reg); 601 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL); 602 codegen()->DoTest(this); 603 } 604 605 606 void FullCodeGenerator::EffectContext::Plug(Label* materialize_true, 607 Label* materialize_false) const { 608 ASSERT(materialize_true == materialize_false); 609 __ bind(materialize_true); 610 } 611 612 613 void FullCodeGenerator::AccumulatorValueContext::Plug( 614 Label* materialize_true, 615 Label* materialize_false) const { 616 Label done; 617 __ bind(materialize_true); 618 __ LoadRoot(result_register(), Heap::kTrueValueRootIndex); 619 __ jmp(&done); 620 __ bind(materialize_false); 621 __ LoadRoot(result_register(), Heap::kFalseValueRootIndex); 622 __ bind(&done); 623 } 624 625 626 void FullCodeGenerator::StackValueContext::Plug( 627 Label* materialize_true, 628 Label* materialize_false) const { 629 Label done; 630 __ bind(materialize_true); 631 __ LoadRoot(ip, Heap::kTrueValueRootIndex); 632 __ push(ip); 633 __ jmp(&done); 634 __ bind(materialize_false); 635 __ LoadRoot(ip, Heap::kFalseValueRootIndex); 636 __ push(ip); 637 __ bind(&done); 638 } 639 640 641 void FullCodeGenerator::TestContext::Plug(Label* materialize_true, 642 Label* materialize_false) const { 643 ASSERT(materialize_true == true_label_); 644 ASSERT(materialize_false == false_label_); 645 } 646 647 648 void FullCodeGenerator::EffectContext::Plug(bool flag) const { 649 } 650 651 652 void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const { 653 Heap::RootListIndex value_root_index = 654 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex; 655 __ LoadRoot(result_register(), value_root_index); 656 } 657 658 659 void FullCodeGenerator::StackValueContext::Plug(bool flag) const { 660 Heap::RootListIndex value_root_index = 661 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex; 662 __ LoadRoot(ip, value_root_index); 663 __ push(ip); 664 } 665 666 667 void FullCodeGenerator::TestContext::Plug(bool flag) const { 668 codegen()->PrepareForBailoutBeforeSplit(condition(), 669 true, 670 true_label_, 671 false_label_); 672 if (flag) { 673 if (true_label_ != fall_through_) __ b(true_label_); 674 } else { 675 if (false_label_ != fall_through_) __ b(false_label_); 676 } 677 } 678 679 680 void FullCodeGenerator::DoTest(Expression* condition, 681 Label* if_true, 682 Label* if_false, 683 Label* fall_through) { 684 if (CpuFeatures::IsSupported(VFP3)) { 685 ToBooleanStub stub(result_register()); 686 __ CallStub(&stub); 687 __ tst(result_register(), result_register()); 688 } else { 689 // Call the runtime to find the boolean value of the source and then 690 // translate it into control flow to the pair of labels. 691 __ push(result_register()); 692 __ CallRuntime(Runtime::kToBool, 1); 693 __ LoadRoot(ip, Heap::kFalseValueRootIndex); 694 __ cmp(r0, ip); 695 } 696 Split(ne, if_true, if_false, fall_through); 697 } 698 699 700 void FullCodeGenerator::Split(Condition cond, 701 Label* if_true, 702 Label* if_false, 703 Label* fall_through) { 704 if (if_false == fall_through) { 705 __ b(cond, if_true); 706 } else if (if_true == fall_through) { 707 __ b(NegateCondition(cond), if_false); 708 } else { 709 __ b(cond, if_true); 710 __ b(if_false); 711 } 712 } 713 714 715 MemOperand FullCodeGenerator::StackOperand(Variable* var) { 716 ASSERT(var->IsStackAllocated()); 717 // Offset is negative because higher indexes are at lower addresses. 718 int offset = -var->index() * kPointerSize; 719 // Adjust by a (parameter or local) base offset. 720 if (var->IsParameter()) { 721 offset += (info_->scope()->num_parameters() + 1) * kPointerSize; 722 } else { 723 offset += JavaScriptFrameConstants::kLocal0Offset; 724 } 725 return MemOperand(fp, offset); 726 } 727 728 729 MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) { 730 ASSERT(var->IsContextSlot() || var->IsStackAllocated()); 731 if (var->IsContextSlot()) { 732 int context_chain_length = scope()->ContextChainLength(var->scope()); 733 __ LoadContext(scratch, context_chain_length); 734 return ContextOperand(scratch, var->index()); 735 } else { 736 return StackOperand(var); 737 } 738 } 739 740 741 void FullCodeGenerator::GetVar(Register dest, Variable* var) { 742 // Use destination as scratch. 743 MemOperand location = VarOperand(var, dest); 744 __ ldr(dest, location); 745 } 746 747 748 void FullCodeGenerator::SetVar(Variable* var, 749 Register src, 750 Register scratch0, 751 Register scratch1) { 752 ASSERT(var->IsContextSlot() || var->IsStackAllocated()); 753 ASSERT(!scratch0.is(src)); 754 ASSERT(!scratch0.is(scratch1)); 755 ASSERT(!scratch1.is(src)); 756 MemOperand location = VarOperand(var, scratch0); 757 __ str(src, location); 758 759 // Emit the write barrier code if the location is in the heap. 760 if (var->IsContextSlot()) { 761 __ RecordWriteContextSlot(scratch0, 762 location.offset(), 763 src, 764 scratch1, 765 kLRHasBeenSaved, 766 kDontSaveFPRegs); 767 } 768 } 769 770 771 void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr, 772 bool should_normalize, 773 Label* if_true, 774 Label* if_false) { 775 // Only prepare for bailouts before splits if we're in a test 776 // context. Otherwise, we let the Visit function deal with the 777 // preparation to avoid preparing with the same AST id twice. 778 if (!context()->IsTest() || !info_->IsOptimizable()) return; 779 780 Label skip; 781 if (should_normalize) __ b(&skip); 782 PrepareForBailout(expr, TOS_REG); 783 if (should_normalize) { 784 __ LoadRoot(ip, Heap::kTrueValueRootIndex); 785 __ cmp(r0, ip); 786 Split(eq, if_true, if_false, NULL); 787 __ bind(&skip); 788 } 789 } 790 791 792 void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, 793 VariableMode mode, 794 FunctionLiteral* function) { 795 // If it was not possible to allocate the variable at compile time, we 796 // need to "declare" it at runtime to make sure it actually exists in the 797 // local context. 798 Variable* variable = proxy->var(); 799 bool binding_needs_init = (function == NULL) && 800 (mode == CONST || mode == CONST_HARMONY || mode == LET); 801 switch (variable->location()) { 802 case Variable::UNALLOCATED: 803 ++global_count_; 804 break; 805 806 case Variable::PARAMETER: 807 case Variable::LOCAL: 808 if (function != NULL) { 809 Comment cmnt(masm_, "[ Declaration"); 810 VisitForAccumulatorValue(function); 811 __ str(result_register(), StackOperand(variable)); 812 } else if (binding_needs_init) { 813 Comment cmnt(masm_, "[ Declaration"); 814 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); 815 __ str(ip, StackOperand(variable)); 816 } 817 break; 818 819 case Variable::CONTEXT: 820 // The variable in the decl always resides in the current function 821 // context. 822 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); 823 if (FLAG_debug_code) { 824 // Check that we're not inside a with or catch context. 825 __ ldr(r1, FieldMemOperand(cp, HeapObject::kMapOffset)); 826 __ CompareRoot(r1, Heap::kWithContextMapRootIndex); 827 __ Check(ne, "Declaration in with context."); 828 __ CompareRoot(r1, Heap::kCatchContextMapRootIndex); 829 __ Check(ne, "Declaration in catch context."); 830 } 831 if (function != NULL) { 832 Comment cmnt(masm_, "[ Declaration"); 833 VisitForAccumulatorValue(function); 834 __ str(result_register(), ContextOperand(cp, variable->index())); 835 int offset = Context::SlotOffset(variable->index()); 836 // We know that we have written a function, which is not a smi. 837 __ RecordWriteContextSlot(cp, 838 offset, 839 result_register(), 840 r2, 841 kLRHasBeenSaved, 842 kDontSaveFPRegs, 843 EMIT_REMEMBERED_SET, 844 OMIT_SMI_CHECK); 845 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); 846 } else if (binding_needs_init) { 847 Comment cmnt(masm_, "[ Declaration"); 848 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); 849 __ str(ip, ContextOperand(cp, variable->index())); 850 // No write barrier since the_hole_value is in old space. 851 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); 852 } 853 break; 854 855 case Variable::LOOKUP: { 856 Comment cmnt(masm_, "[ Declaration"); 857 __ mov(r2, Operand(variable->name())); 858 // Declaration nodes are always introduced in one of four modes. 859 ASSERT(mode == VAR || 860 mode == CONST || 861 mode == CONST_HARMONY || 862 mode == LET); 863 PropertyAttributes attr = (mode == CONST || mode == CONST_HARMONY) 864 ? READ_ONLY : NONE; 865 __ mov(r1, Operand(Smi::FromInt(attr))); 866 // Push initial value, if any. 867 // Note: For variables we must not push an initial value (such as 868 // 'undefined') because we may have a (legal) redeclaration and we 869 // must not destroy the current value. 870 if (function != NULL) { 871 __ Push(cp, r2, r1); 872 // Push initial value for function declaration. 873 VisitForStackValue(function); 874 } else if (binding_needs_init) { 875 __ LoadRoot(r0, Heap::kTheHoleValueRootIndex); 876 __ Push(cp, r2, r1, r0); 877 } else { 878 __ mov(r0, Operand(Smi::FromInt(0))); // Indicates no initial value. 879 __ Push(cp, r2, r1, r0); 880 } 881 __ CallRuntime(Runtime::kDeclareContextSlot, 4); 882 break; 883 } 884 } 885 } 886 887 888 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { 889 // Call the runtime to declare the globals. 890 // The context is the first argument. 891 __ mov(r1, Operand(pairs)); 892 __ mov(r0, Operand(Smi::FromInt(DeclareGlobalsFlags()))); 893 __ Push(cp, r1, r0); 894 __ CallRuntime(Runtime::kDeclareGlobals, 3); 895 // Return value is ignored. 896 } 897 898 899 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { 900 Comment cmnt(masm_, "[ SwitchStatement"); 901 Breakable nested_statement(this, stmt); 902 SetStatementPosition(stmt); 903 904 // Keep the switch value on the stack until a case matches. 905 VisitForStackValue(stmt->tag()); 906 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); 907 908 ZoneList<CaseClause*>* clauses = stmt->cases(); 909 CaseClause* default_clause = NULL; // Can occur anywhere in the list. 910 911 Label next_test; // Recycled for each test. 912 // Compile all the tests with branches to their bodies. 913 for (int i = 0; i < clauses->length(); i++) { 914 CaseClause* clause = clauses->at(i); 915 clause->body_target()->Unuse(); 916 917 // The default is not a test, but remember it as final fall through. 918 if (clause->is_default()) { 919 default_clause = clause; 920 continue; 921 } 922 923 Comment cmnt(masm_, "[ Case comparison"); 924 __ bind(&next_test); 925 next_test.Unuse(); 926 927 // Compile the label expression. 928 VisitForAccumulatorValue(clause->label()); 929 930 // Perform the comparison as if via '==='. 931 __ ldr(r1, MemOperand(sp, 0)); // Switch value. 932 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT); 933 JumpPatchSite patch_site(masm_); 934 if (inline_smi_code) { 935 Label slow_case; 936 __ orr(r2, r1, r0); 937 patch_site.EmitJumpIfNotSmi(r2, &slow_case); 938 939 __ cmp(r1, r0); 940 __ b(ne, &next_test); 941 __ Drop(1); // Switch value is no longer needed. 942 __ b(clause->body_target()); 943 __ bind(&slow_case); 944 } 945 946 // Record position before stub call for type feedback. 947 SetSourcePosition(clause->position()); 948 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT); 949 CallIC(ic, RelocInfo::CODE_TARGET, clause->CompareId()); 950 patch_site.EmitPatchInfo(); 951 952 __ cmp(r0, Operand(0)); 953 __ b(ne, &next_test); 954 __ Drop(1); // Switch value is no longer needed. 955 __ b(clause->body_target()); 956 } 957 958 // Discard the test value and jump to the default if present, otherwise to 959 // the end of the statement. 960 __ bind(&next_test); 961 __ Drop(1); // Switch value is no longer needed. 962 if (default_clause == NULL) { 963 __ b(nested_statement.break_label()); 964 } else { 965 __ b(default_clause->body_target()); 966 } 967 968 // Compile all the case bodies. 969 for (int i = 0; i < clauses->length(); i++) { 970 Comment cmnt(masm_, "[ Case body"); 971 CaseClause* clause = clauses->at(i); 972 __ bind(clause->body_target()); 973 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS); 974 VisitStatements(clause->statements()); 975 } 976 977 __ bind(nested_statement.break_label()); 978 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); 979 } 980 981 982 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { 983 Comment cmnt(masm_, "[ ForInStatement"); 984 SetStatementPosition(stmt); 985 986 Label loop, exit; 987 ForIn loop_statement(this, stmt); 988 increment_loop_depth(); 989 990 // Get the object to enumerate over. Both SpiderMonkey and JSC 991 // ignore null and undefined in contrast to the specification; see 992 // ECMA-262 section 12.6.4. 993 VisitForAccumulatorValue(stmt->enumerable()); 994 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); 995 __ cmp(r0, ip); 996 __ b(eq, &exit); 997 Register null_value = r5; 998 __ LoadRoot(null_value, Heap::kNullValueRootIndex); 999 __ cmp(r0, null_value); 1000 __ b(eq, &exit); 1001 1002 PrepareForBailoutForId(stmt->PrepareId(), TOS_REG); 1003 1004 // Convert the object to a JS object. 1005 Label convert, done_convert; 1006 __ JumpIfSmi(r0, &convert); 1007 __ CompareObjectType(r0, r1, r1, FIRST_SPEC_OBJECT_TYPE); 1008 __ b(ge, &done_convert); 1009 __ bind(&convert); 1010 __ push(r0); 1011 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); 1012 __ bind(&done_convert); 1013 __ push(r0); 1014 1015 // Check for proxies. 1016 Label call_runtime; 1017 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); 1018 __ CompareObjectType(r0, r1, r1, LAST_JS_PROXY_TYPE); 1019 __ b(le, &call_runtime); 1020 1021 // Check cache validity in generated code. This is a fast case for 1022 // the JSObject::IsSimpleEnum cache validity checks. If we cannot 1023 // guarantee cache validity, call the runtime system to check cache 1024 // validity or get the property names in a fixed array. 1025 __ CheckEnumCache(null_value, &call_runtime); 1026 1027 // The enum cache is valid. Load the map of the object being 1028 // iterated over and use the cache for the iteration. 1029 Label use_cache; 1030 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset)); 1031 __ b(&use_cache); 1032 1033 // Get the set of properties to enumerate. 1034 __ bind(&call_runtime); 1035 __ push(r0); // Duplicate the enumerable object on the stack. 1036 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1); 1037 1038 // If we got a map from the runtime call, we can do a fast 1039 // modification check. Otherwise, we got a fixed array, and we have 1040 // to do a slow check. 1041 Label fixed_array; 1042 __ mov(r2, r0); 1043 __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset)); 1044 __ LoadRoot(ip, Heap::kMetaMapRootIndex); 1045 __ cmp(r1, ip); 1046 __ b(ne, &fixed_array); 1047 1048 // We got a map in register r0. Get the enumeration cache from it. 1049 __ bind(&use_cache); 1050 __ LoadInstanceDescriptors(r0, r1); 1051 __ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumerationIndexOffset)); 1052 __ ldr(r2, FieldMemOperand(r1, DescriptorArray::kEnumCacheBridgeCacheOffset)); 1053 1054 // Set up the four remaining stack slots. 1055 __ push(r0); // Map. 1056 __ ldr(r1, FieldMemOperand(r2, FixedArray::kLengthOffset)); 1057 __ mov(r0, Operand(Smi::FromInt(0))); 1058 // Push enumeration cache, enumeration cache length (as smi) and zero. 1059 __ Push(r2, r1, r0); 1060 __ jmp(&loop); 1061 1062 // We got a fixed array in register r0. Iterate through that. 1063 Label non_proxy; 1064 __ bind(&fixed_array); 1065 1066 Handle<JSGlobalPropertyCell> cell = 1067 isolate()->factory()->NewJSGlobalPropertyCell( 1068 Handle<Object>( 1069 Smi::FromInt(TypeFeedbackCells::kForInFastCaseMarker))); 1070 RecordTypeFeedbackCell(stmt->PrepareId(), cell); 1071 __ LoadHeapObject(r1, cell); 1072 __ mov(r2, Operand(Smi::FromInt(TypeFeedbackCells::kForInSlowCaseMarker))); 1073 __ str(r2, FieldMemOperand(r1, JSGlobalPropertyCell::kValueOffset)); 1074 1075 __ mov(r1, Operand(Smi::FromInt(1))); // Smi indicates slow check 1076 __ ldr(r2, MemOperand(sp, 0 * kPointerSize)); // Get enumerated object 1077 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); 1078 __ CompareObjectType(r2, r3, r3, LAST_JS_PROXY_TYPE); 1079 __ b(gt, &non_proxy); 1080 __ mov(r1, Operand(Smi::FromInt(0))); // Zero indicates proxy 1081 __ bind(&non_proxy); 1082 __ Push(r1, r0); // Smi and array 1083 __ ldr(r1, FieldMemOperand(r0, FixedArray::kLengthOffset)); 1084 __ mov(r0, Operand(Smi::FromInt(0))); 1085 __ Push(r1, r0); // Fixed array length (as smi) and initial index. 1086 1087 // Generate code for doing the condition check. 1088 PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS); 1089 __ bind(&loop); 1090 // Load the current count to r0, load the length to r1. 1091 __ Ldrd(r0, r1, MemOperand(sp, 0 * kPointerSize)); 1092 __ cmp(r0, r1); // Compare to the array length. 1093 __ b(hs, loop_statement.break_label()); 1094 1095 // Get the current entry of the array into register r3. 1096 __ ldr(r2, MemOperand(sp, 2 * kPointerSize)); 1097 __ add(r2, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); 1098 __ ldr(r3, MemOperand(r2, r0, LSL, kPointerSizeLog2 - kSmiTagSize)); 1099 1100 // Get the expected map from the stack or a smi in the 1101 // permanent slow case into register r2. 1102 __ ldr(r2, MemOperand(sp, 3 * kPointerSize)); 1103 1104 // Check if the expected map still matches that of the enumerable. 1105 // If not, we may have to filter the key. 1106 Label update_each; 1107 __ ldr(r1, MemOperand(sp, 4 * kPointerSize)); 1108 __ ldr(r4, FieldMemOperand(r1, HeapObject::kMapOffset)); 1109 __ cmp(r4, Operand(r2)); 1110 __ b(eq, &update_each); 1111 1112 // For proxies, no filtering is done. 1113 // TODO(rossberg): What if only a prototype is a proxy? Not specified yet. 1114 __ cmp(r2, Operand(Smi::FromInt(0))); 1115 __ b(eq, &update_each); 1116 1117 // Convert the entry to a string or (smi) 0 if it isn't a property 1118 // any more. If the property has been removed while iterating, we 1119 // just skip it. 1120 __ push(r1); // Enumerable. 1121 __ push(r3); // Current entry. 1122 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION); 1123 __ mov(r3, Operand(r0), SetCC); 1124 __ b(eq, loop_statement.continue_label()); 1125 1126 // Update the 'each' property or variable from the possibly filtered 1127 // entry in register r3. 1128 __ bind(&update_each); 1129 __ mov(result_register(), r3); 1130 // Perform the assignment as if via '='. 1131 { EffectContext context(this); 1132 EmitAssignment(stmt->each()); 1133 } 1134 1135 // Generate code for the body of the loop. 1136 Visit(stmt->body()); 1137 1138 // Generate code for the going to the next element by incrementing 1139 // the index (smi) stored on top of the stack. 1140 __ bind(loop_statement.continue_label()); 1141 __ pop(r0); 1142 __ add(r0, r0, Operand(Smi::FromInt(1))); 1143 __ push(r0); 1144 1145 EmitStackCheck(stmt, &loop); 1146 __ b(&loop); 1147 1148 // Remove the pointers stored on the stack. 1149 __ bind(loop_statement.break_label()); 1150 __ Drop(5); 1151 1152 // Exit and decrement the loop depth. 1153 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); 1154 __ bind(&exit); 1155 decrement_loop_depth(); 1156 } 1157 1158 1159 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info, 1160 bool pretenure) { 1161 // Use the fast case closure allocation code that allocates in new 1162 // space for nested functions that don't need literals cloning. If 1163 // we're running with the --always-opt or the --prepare-always-opt 1164 // flag, we need to use the runtime function so that the new function 1165 // we are creating here gets a chance to have its code optimized and 1166 // doesn't just get a copy of the existing unoptimized code. 1167 if (!FLAG_always_opt && 1168 !FLAG_prepare_always_opt && 1169 !pretenure && 1170 scope()->is_function_scope() && 1171 info->num_literals() == 0) { 1172 FastNewClosureStub stub(info->language_mode()); 1173 __ mov(r0, Operand(info)); 1174 __ push(r0); 1175 __ CallStub(&stub); 1176 } else { 1177 __ mov(r0, Operand(info)); 1178 __ LoadRoot(r1, pretenure ? Heap::kTrueValueRootIndex 1179 : Heap::kFalseValueRootIndex); 1180 __ Push(cp, r0, r1); 1181 __ CallRuntime(Runtime::kNewClosure, 3); 1182 } 1183 context()->Plug(r0); 1184 } 1185 1186 1187 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { 1188 Comment cmnt(masm_, "[ VariableProxy"); 1189 EmitVariableLoad(expr); 1190 } 1191 1192 1193 void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var, 1194 TypeofState typeof_state, 1195 Label* slow) { 1196 Register current = cp; 1197 Register next = r1; 1198 Register temp = r2; 1199 1200 Scope* s = scope(); 1201 while (s != NULL) { 1202 if (s->num_heap_slots() > 0) { 1203 if (s->calls_non_strict_eval()) { 1204 // Check that extension is NULL. 1205 __ ldr(temp, ContextOperand(current, Context::EXTENSION_INDEX)); 1206 __ tst(temp, temp); 1207 __ b(ne, slow); 1208 } 1209 // Load next context in chain. 1210 __ ldr(next, ContextOperand(current, Context::PREVIOUS_INDEX)); 1211 // Walk the rest of the chain without clobbering cp. 1212 current = next; 1213 } 1214 // If no outer scope calls eval, we do not need to check more 1215 // context extensions. 1216 if (!s->outer_scope_calls_non_strict_eval() || s->is_eval_scope()) break; 1217 s = s->outer_scope(); 1218 } 1219 1220 if (s->is_eval_scope()) { 1221 Label loop, fast; 1222 if (!current.is(next)) { 1223 __ Move(next, current); 1224 } 1225 __ bind(&loop); 1226 // Terminate at global context. 1227 __ ldr(temp, FieldMemOperand(next, HeapObject::kMapOffset)); 1228 __ LoadRoot(ip, Heap::kGlobalContextMapRootIndex); 1229 __ cmp(temp, ip); 1230 __ b(eq, &fast); 1231 // Check that extension is NULL. 1232 __ ldr(temp, ContextOperand(next, Context::EXTENSION_INDEX)); 1233 __ tst(temp, temp); 1234 __ b(ne, slow); 1235 // Load next context in chain. 1236 __ ldr(next, ContextOperand(next, Context::PREVIOUS_INDEX)); 1237 __ b(&loop); 1238 __ bind(&fast); 1239 } 1240 1241 __ ldr(r0, GlobalObjectOperand()); 1242 __ mov(r2, Operand(var->name())); 1243 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) 1244 ? RelocInfo::CODE_TARGET 1245 : RelocInfo::CODE_TARGET_CONTEXT; 1246 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); 1247 CallIC(ic, mode); 1248 } 1249 1250 1251 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var, 1252 Label* slow) { 1253 ASSERT(var->IsContextSlot()); 1254 Register context = cp; 1255 Register next = r3; 1256 Register temp = r4; 1257 1258 for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) { 1259 if (s->num_heap_slots() > 0) { 1260 if (s->calls_non_strict_eval()) { 1261 // Check that extension is NULL. 1262 __ ldr(temp, ContextOperand(context, Context::EXTENSION_INDEX)); 1263 __ tst(temp, temp); 1264 __ b(ne, slow); 1265 } 1266 __ ldr(next, ContextOperand(context, Context::PREVIOUS_INDEX)); 1267 // Walk the rest of the chain without clobbering cp. 1268 context = next; 1269 } 1270 } 1271 // Check that last extension is NULL. 1272 __ ldr(temp, ContextOperand(context, Context::EXTENSION_INDEX)); 1273 __ tst(temp, temp); 1274 __ b(ne, slow); 1275 1276 // This function is used only for loads, not stores, so it's safe to 1277 // return an cp-based operand (the write barrier cannot be allowed to 1278 // destroy the cp register). 1279 return ContextOperand(context, var->index()); 1280 } 1281 1282 1283 void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var, 1284 TypeofState typeof_state, 1285 Label* slow, 1286 Label* done) { 1287 // Generate fast-case code for variables that might be shadowed by 1288 // eval-introduced variables. Eval is used a lot without 1289 // introducing variables. In those cases, we do not want to 1290 // perform a runtime call for all variables in the scope 1291 // containing the eval. 1292 if (var->mode() == DYNAMIC_GLOBAL) { 1293 EmitLoadGlobalCheckExtensions(var, typeof_state, slow); 1294 __ jmp(done); 1295 } else if (var->mode() == DYNAMIC_LOCAL) { 1296 Variable* local = var->local_if_not_shadowed(); 1297 __ ldr(r0, ContextSlotOperandCheckExtensions(local, slow)); 1298 if (local->mode() == CONST || 1299 local->mode() == CONST_HARMONY || 1300 local->mode() == LET) { 1301 __ CompareRoot(r0, Heap::kTheHoleValueRootIndex); 1302 if (local->mode() == CONST) { 1303 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); 1304 } else { // LET || CONST_HARMONY 1305 __ b(ne, done); 1306 __ mov(r0, Operand(var->name())); 1307 __ push(r0); 1308 __ CallRuntime(Runtime::kThrowReferenceError, 1); 1309 } 1310 } 1311 __ jmp(done); 1312 } 1313 } 1314 1315 1316 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { 1317 // Record position before possible IC call. 1318 SetSourcePosition(proxy->position()); 1319 Variable* var = proxy->var(); 1320 1321 // Three cases: global variables, lookup variables, and all other types of 1322 // variables. 1323 switch (var->location()) { 1324 case Variable::UNALLOCATED: { 1325 Comment cmnt(masm_, "Global variable"); 1326 // Use inline caching. Variable name is passed in r2 and the global 1327 // object (receiver) in r0. 1328 __ ldr(r0, GlobalObjectOperand()); 1329 __ mov(r2, Operand(var->name())); 1330 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); 1331 CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); 1332 context()->Plug(r0); 1333 break; 1334 } 1335 1336 case Variable::PARAMETER: 1337 case Variable::LOCAL: 1338 case Variable::CONTEXT: { 1339 Comment cmnt(masm_, var->IsContextSlot() 1340 ? "Context variable" 1341 : "Stack variable"); 1342 if (var->binding_needs_init()) { 1343 // var->scope() may be NULL when the proxy is located in eval code and 1344 // refers to a potential outside binding. Currently those bindings are 1345 // always looked up dynamically, i.e. in that case 1346 // var->location() == LOOKUP. 1347 // always holds. 1348 ASSERT(var->scope() != NULL); 1349 1350 // Check if the binding really needs an initialization check. The check 1351 // can be skipped in the following situation: we have a LET or CONST 1352 // binding in harmony mode, both the Variable and the VariableProxy have 1353 // the same declaration scope (i.e. they are both in global code, in the 1354 // same function or in the same eval code) and the VariableProxy is in 1355 // the source physically located after the initializer of the variable. 1356 // 1357 // We cannot skip any initialization checks for CONST in non-harmony 1358 // mode because const variables may be declared but never initialized: 1359 // if (false) { const x; }; var y = x; 1360 // 1361 // The condition on the declaration scopes is a conservative check for 1362 // nested functions that access a binding and are called before the 1363 // binding is initialized: 1364 // function() { f(); let x = 1; function f() { x = 2; } } 1365 // 1366 bool skip_init_check; 1367 if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) { 1368 skip_init_check = false; 1369 } else { 1370 // Check that we always have valid source position. 1371 ASSERT(var->initializer_position() != RelocInfo::kNoPosition); 1372 ASSERT(proxy->position() != RelocInfo::kNoPosition); 1373 skip_init_check = var->mode() != CONST && 1374 var->initializer_position() < proxy->position(); 1375 } 1376 1377 if (!skip_init_check) { 1378 // Let and const need a read barrier. 1379 GetVar(r0, var); 1380 __ CompareRoot(r0, Heap::kTheHoleValueRootIndex); 1381 if (var->mode() == LET || var->mode() == CONST_HARMONY) { 1382 // Throw a reference error when using an uninitialized let/const 1383 // binding in harmony mode. 1384 Label done; 1385 __ b(ne, &done); 1386 __ mov(r0, Operand(var->name())); 1387 __ push(r0); 1388 __ CallRuntime(Runtime::kThrowReferenceError, 1); 1389 __ bind(&done); 1390 } else { 1391 // Uninitalized const bindings outside of harmony mode are unholed. 1392 ASSERT(var->mode() == CONST); 1393 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); 1394 } 1395 context()->Plug(r0); 1396 break; 1397 } 1398 } 1399 context()->Plug(var); 1400 break; 1401 } 1402 1403 case Variable::LOOKUP: { 1404 Label done, slow; 1405 // Generate code for loading from variables potentially shadowed 1406 // by eval-introduced variables. 1407 EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done); 1408 __ bind(&slow); 1409 Comment cmnt(masm_, "Lookup variable"); 1410 __ mov(r1, Operand(var->name())); 1411 __ Push(cp, r1); // Context and name. 1412 __ CallRuntime(Runtime::kLoadContextSlot, 2); 1413 __ bind(&done); 1414 context()->Plug(r0); 1415 } 1416 } 1417 } 1418 1419 1420 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { 1421 Comment cmnt(masm_, "[ RegExpLiteral"); 1422 Label materialized; 1423 // Registers will be used as follows: 1424 // r5 = materialized value (RegExp literal) 1425 // r4 = JS function, literals array 1426 // r3 = literal index 1427 // r2 = RegExp pattern 1428 // r1 = RegExp flags 1429 // r0 = RegExp literal clone 1430 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 1431 __ ldr(r4, FieldMemOperand(r0, JSFunction::kLiteralsOffset)); 1432 int literal_offset = 1433 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; 1434 __ ldr(r5, FieldMemOperand(r4, literal_offset)); 1435 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); 1436 __ cmp(r5, ip); 1437 __ b(ne, &materialized); 1438 1439 // Create regexp literal using runtime function. 1440 // Result will be in r0. 1441 __ mov(r3, Operand(Smi::FromInt(expr->literal_index()))); 1442 __ mov(r2, Operand(expr->pattern())); 1443 __ mov(r1, Operand(expr->flags())); 1444 __ Push(r4, r3, r2, r1); 1445 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); 1446 __ mov(r5, r0); 1447 1448 __ bind(&materialized); 1449 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize; 1450 Label allocated, runtime_allocate; 1451 __ AllocateInNewSpace(size, r0, r2, r3, &runtime_allocate, TAG_OBJECT); 1452 __ jmp(&allocated); 1453 1454 __ bind(&runtime_allocate); 1455 __ push(r5); 1456 __ mov(r0, Operand(Smi::FromInt(size))); 1457 __ push(r0); 1458 __ CallRuntime(Runtime::kAllocateInNewSpace, 1); 1459 __ pop(r5); 1460 1461 __ bind(&allocated); 1462 // After this, registers are used as follows: 1463 // r0: Newly allocated regexp. 1464 // r5: Materialized regexp. 1465 // r2: temp. 1466 __ CopyFields(r0, r5, r2.bit(), size / kPointerSize); 1467 context()->Plug(r0); 1468 } 1469 1470 1471 void FullCodeGenerator::EmitAccessor(Expression* expression) { 1472 if (expression == NULL) { 1473 __ LoadRoot(r1, Heap::kNullValueRootIndex); 1474 __ push(r1); 1475 } else { 1476 VisitForStackValue(expression); 1477 } 1478 } 1479 1480 1481 void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { 1482 Comment cmnt(masm_, "[ ObjectLiteral"); 1483 Handle<FixedArray> constant_properties = expr->constant_properties(); 1484 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 1485 __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset)); 1486 __ mov(r2, Operand(Smi::FromInt(expr->literal_index()))); 1487 __ mov(r1, Operand(constant_properties)); 1488 int flags = expr->fast_elements() 1489 ? ObjectLiteral::kFastElements 1490 : ObjectLiteral::kNoFlags; 1491 flags |= expr->has_function() 1492 ? ObjectLiteral::kHasFunction 1493 : ObjectLiteral::kNoFlags; 1494 __ mov(r0, Operand(Smi::FromInt(flags))); 1495 __ Push(r3, r2, r1, r0); 1496 int properties_count = constant_properties->length() / 2; 1497 if (expr->depth() > 1) { 1498 __ CallRuntime(Runtime::kCreateObjectLiteral, 4); 1499 } else if (flags != ObjectLiteral::kFastElements || 1500 properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) { 1501 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 4); 1502 } else { 1503 FastCloneShallowObjectStub stub(properties_count); 1504 __ CallStub(&stub); 1505 } 1506 1507 // If result_saved is true the result is on top of the stack. If 1508 // result_saved is false the result is in r0. 1509 bool result_saved = false; 1510 1511 // Mark all computed expressions that are bound to a key that 1512 // is shadowed by a later occurrence of the same key. For the 1513 // marked expressions, no store code is emitted. 1514 expr->CalculateEmitStore(); 1515 1516 AccessorTable accessor_table(isolate()->zone()); 1517 for (int i = 0; i < expr->properties()->length(); i++) { 1518 ObjectLiteral::Property* property = expr->properties()->at(i); 1519 if (property->IsCompileTimeValue()) continue; 1520 1521 Literal* key = property->key(); 1522 Expression* value = property->value(); 1523 if (!result_saved) { 1524 __ push(r0); // Save result on stack 1525 result_saved = true; 1526 } 1527 switch (property->kind()) { 1528 case ObjectLiteral::Property::CONSTANT: 1529 UNREACHABLE(); 1530 case ObjectLiteral::Property::MATERIALIZED_LITERAL: 1531 ASSERT(!CompileTimeValue::IsCompileTimeValue(property->value())); 1532 // Fall through. 1533 case ObjectLiteral::Property::COMPUTED: 1534 if (key->handle()->IsSymbol()) { 1535 if (property->emit_store()) { 1536 VisitForAccumulatorValue(value); 1537 __ mov(r2, Operand(key->handle())); 1538 __ ldr(r1, MemOperand(sp)); 1539 Handle<Code> ic = is_classic_mode() 1540 ? isolate()->builtins()->StoreIC_Initialize() 1541 : isolate()->builtins()->StoreIC_Initialize_Strict(); 1542 CallIC(ic, RelocInfo::CODE_TARGET, key->id()); 1543 PrepareForBailoutForId(key->id(), NO_REGISTERS); 1544 } else { 1545 VisitForEffect(value); 1546 } 1547 break; 1548 } 1549 // Fall through. 1550 case ObjectLiteral::Property::PROTOTYPE: 1551 // Duplicate receiver on stack. 1552 __ ldr(r0, MemOperand(sp)); 1553 __ push(r0); 1554 VisitForStackValue(key); 1555 VisitForStackValue(value); 1556 if (property->emit_store()) { 1557 __ mov(r0, Operand(Smi::FromInt(NONE))); // PropertyAttributes 1558 __ push(r0); 1559 __ CallRuntime(Runtime::kSetProperty, 4); 1560 } else { 1561 __ Drop(3); 1562 } 1563 break; 1564 case ObjectLiteral::Property::GETTER: 1565 accessor_table.lookup(key)->second->getter = value; 1566 break; 1567 case ObjectLiteral::Property::SETTER: 1568 accessor_table.lookup(key)->second->setter = value; 1569 break; 1570 } 1571 } 1572 1573 // Emit code to define accessors, using only a single call to the runtime for 1574 // each pair of corresponding getters and setters. 1575 for (AccessorTable::Iterator it = accessor_table.begin(); 1576 it != accessor_table.end(); 1577 ++it) { 1578 __ ldr(r0, MemOperand(sp)); // Duplicate receiver. 1579 __ push(r0); 1580 VisitForStackValue(it->first); 1581 EmitAccessor(it->second->getter); 1582 EmitAccessor(it->second->setter); 1583 __ mov(r0, Operand(Smi::FromInt(NONE))); 1584 __ push(r0); 1585 __ CallRuntime(Runtime::kDefineOrRedefineAccessorProperty, 5); 1586 } 1587 1588 if (expr->has_function()) { 1589 ASSERT(result_saved); 1590 __ ldr(r0, MemOperand(sp)); 1591 __ push(r0); 1592 __ CallRuntime(Runtime::kToFastProperties, 1); 1593 } 1594 1595 if (result_saved) { 1596 context()->PlugTOS(); 1597 } else { 1598 context()->Plug(r0); 1599 } 1600 } 1601 1602 1603 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { 1604 Comment cmnt(masm_, "[ ArrayLiteral"); 1605 1606 ZoneList<Expression*>* subexprs = expr->values(); 1607 int length = subexprs->length(); 1608 Handle<FixedArray> constant_elements = expr->constant_elements(); 1609 ASSERT_EQ(2, constant_elements->length()); 1610 ElementsKind constant_elements_kind = 1611 static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value()); 1612 bool has_fast_elements = constant_elements_kind == FAST_ELEMENTS; 1613 Handle<FixedArrayBase> constant_elements_values( 1614 FixedArrayBase::cast(constant_elements->get(1))); 1615 1616 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 1617 __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset)); 1618 __ mov(r2, Operand(Smi::FromInt(expr->literal_index()))); 1619 __ mov(r1, Operand(constant_elements)); 1620 __ Push(r3, r2, r1); 1621 if (has_fast_elements && constant_elements_values->map() == 1622 isolate()->heap()->fixed_cow_array_map()) { 1623 FastCloneShallowArrayStub stub( 1624 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length); 1625 __ CallStub(&stub); 1626 __ IncrementCounter( 1627 isolate()->counters()->cow_arrays_created_stub(), 1, r1, r2); 1628 } else if (expr->depth() > 1) { 1629 __ CallRuntime(Runtime::kCreateArrayLiteral, 3); 1630 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) { 1631 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3); 1632 } else { 1633 ASSERT(constant_elements_kind == FAST_ELEMENTS || 1634 constant_elements_kind == FAST_SMI_ONLY_ELEMENTS || 1635 FLAG_smi_only_arrays); 1636 FastCloneShallowArrayStub::Mode mode = has_fast_elements 1637 ? FastCloneShallowArrayStub::CLONE_ELEMENTS 1638 : FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS; 1639 FastCloneShallowArrayStub stub(mode, length); 1640 __ CallStub(&stub); 1641 } 1642 1643 bool result_saved = false; // Is the result saved to the stack? 1644 1645 // Emit code to evaluate all the non-constant subexpressions and to store 1646 // them into the newly cloned array. 1647 for (int i = 0; i < length; i++) { 1648 Expression* subexpr = subexprs->at(i); 1649 // If the subexpression is a literal or a simple materialized literal it 1650 // is already set in the cloned array. 1651 if (subexpr->AsLiteral() != NULL || 1652 CompileTimeValue::IsCompileTimeValue(subexpr)) { 1653 continue; 1654 } 1655 1656 if (!result_saved) { 1657 __ push(r0); 1658 result_saved = true; 1659 } 1660 VisitForAccumulatorValue(subexpr); 1661 1662 if (constant_elements_kind == FAST_ELEMENTS) { 1663 int offset = FixedArray::kHeaderSize + (i * kPointerSize); 1664 __ ldr(r6, MemOperand(sp)); // Copy of array literal. 1665 __ ldr(r1, FieldMemOperand(r6, JSObject::kElementsOffset)); 1666 __ str(result_register(), FieldMemOperand(r1, offset)); 1667 // Update the write barrier for the array store. 1668 __ RecordWriteField(r1, offset, result_register(), r2, 1669 kLRHasBeenSaved, kDontSaveFPRegs, 1670 EMIT_REMEMBERED_SET, INLINE_SMI_CHECK); 1671 } else { 1672 __ ldr(r1, MemOperand(sp)); // Copy of array literal. 1673 __ ldr(r2, FieldMemOperand(r1, JSObject::kMapOffset)); 1674 __ mov(r3, Operand(Smi::FromInt(i))); 1675 __ mov(r4, Operand(Smi::FromInt(expr->literal_index()))); 1676 StoreArrayLiteralElementStub stub; 1677 __ CallStub(&stub); 1678 } 1679 1680 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); 1681 } 1682 1683 if (result_saved) { 1684 context()->PlugTOS(); 1685 } else { 1686 context()->Plug(r0); 1687 } 1688 } 1689 1690 1691 void FullCodeGenerator::VisitAssignment(Assignment* expr) { 1692 Comment cmnt(masm_, "[ Assignment"); 1693 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' 1694 // on the left-hand side. 1695 if (!expr->target()->IsValidLeftHandSide()) { 1696 VisitForEffect(expr->target()); 1697 return; 1698 } 1699 1700 // Left-hand side can only be a property, a global or a (parameter or local) 1701 // slot. 1702 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; 1703 LhsKind assign_type = VARIABLE; 1704 Property* property = expr->target()->AsProperty(); 1705 if (property != NULL) { 1706 assign_type = (property->key()->IsPropertyName()) 1707 ? NAMED_PROPERTY 1708 : KEYED_PROPERTY; 1709 } 1710 1711 // Evaluate LHS expression. 1712 switch (assign_type) { 1713 case VARIABLE: 1714 // Nothing to do here. 1715 break; 1716 case NAMED_PROPERTY: 1717 if (expr->is_compound()) { 1718 // We need the receiver both on the stack and in the accumulator. 1719 VisitForAccumulatorValue(property->obj()); 1720 __ push(result_register()); 1721 } else { 1722 VisitForStackValue(property->obj()); 1723 } 1724 break; 1725 case KEYED_PROPERTY: 1726 if (expr->is_compound()) { 1727 VisitForStackValue(property->obj()); 1728 VisitForAccumulatorValue(property->key()); 1729 __ ldr(r1, MemOperand(sp, 0)); 1730 __ push(r0); 1731 } else { 1732 VisitForStackValue(property->obj()); 1733 VisitForStackValue(property->key()); 1734 } 1735 break; 1736 } 1737 1738 // For compound assignments we need another deoptimization point after the 1739 // variable/property load. 1740 if (expr->is_compound()) { 1741 { AccumulatorValueContext context(this); 1742 switch (assign_type) { 1743 case VARIABLE: 1744 EmitVariableLoad(expr->target()->AsVariableProxy()); 1745 PrepareForBailout(expr->target(), TOS_REG); 1746 break; 1747 case NAMED_PROPERTY: 1748 EmitNamedPropertyLoad(property); 1749 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG); 1750 break; 1751 case KEYED_PROPERTY: 1752 EmitKeyedPropertyLoad(property); 1753 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG); 1754 break; 1755 } 1756 } 1757 1758 Token::Value op = expr->binary_op(); 1759 __ push(r0); // Left operand goes on the stack. 1760 VisitForAccumulatorValue(expr->value()); 1761 1762 OverwriteMode mode = expr->value()->ResultOverwriteAllowed() 1763 ? OVERWRITE_RIGHT 1764 : NO_OVERWRITE; 1765 SetSourcePosition(expr->position() + 1); 1766 AccumulatorValueContext context(this); 1767 if (ShouldInlineSmiCase(op)) { 1768 EmitInlineSmiBinaryOp(expr->binary_operation(), 1769 op, 1770 mode, 1771 expr->target(), 1772 expr->value()); 1773 } else { 1774 EmitBinaryOp(expr->binary_operation(), op, mode); 1775 } 1776 1777 // Deoptimization point in case the binary operation may have side effects. 1778 PrepareForBailout(expr->binary_operation(), TOS_REG); 1779 } else { 1780 VisitForAccumulatorValue(expr->value()); 1781 } 1782 1783 // Record source position before possible IC call. 1784 SetSourcePosition(expr->position()); 1785 1786 // Store the value. 1787 switch (assign_type) { 1788 case VARIABLE: 1789 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), 1790 expr->op()); 1791 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); 1792 context()->Plug(r0); 1793 break; 1794 case NAMED_PROPERTY: 1795 EmitNamedPropertyAssignment(expr); 1796 break; 1797 case KEYED_PROPERTY: 1798 EmitKeyedPropertyAssignment(expr); 1799 break; 1800 } 1801 } 1802 1803 1804 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { 1805 SetSourcePosition(prop->position()); 1806 Literal* key = prop->key()->AsLiteral(); 1807 __ mov(r2, Operand(key->handle())); 1808 // Call load IC. It has arguments receiver and property name r0 and r2. 1809 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); 1810 CallIC(ic, RelocInfo::CODE_TARGET, prop->id()); 1811 } 1812 1813 1814 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { 1815 SetSourcePosition(prop->position()); 1816 // Call keyed load IC. It has arguments key and receiver in r0 and r1. 1817 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); 1818 CallIC(ic, RelocInfo::CODE_TARGET, prop->id()); 1819 } 1820 1821 1822 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, 1823 Token::Value op, 1824 OverwriteMode mode, 1825 Expression* left_expr, 1826 Expression* right_expr) { 1827 Label done, smi_case, stub_call; 1828 1829 Register scratch1 = r2; 1830 Register scratch2 = r3; 1831 1832 // Get the arguments. 1833 Register left = r1; 1834 Register right = r0; 1835 __ pop(left); 1836 1837 // Perform combined smi check on both operands. 1838 __ orr(scratch1, left, Operand(right)); 1839 STATIC_ASSERT(kSmiTag == 0); 1840 JumpPatchSite patch_site(masm_); 1841 patch_site.EmitJumpIfSmi(scratch1, &smi_case); 1842 1843 __ bind(&stub_call); 1844 BinaryOpStub stub(op, mode); 1845 CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); 1846 patch_site.EmitPatchInfo(); 1847 __ jmp(&done); 1848 1849 __ bind(&smi_case); 1850 // Smi case. This code works the same way as the smi-smi case in the type 1851 // recording binary operation stub, see 1852 // BinaryOpStub::GenerateSmiSmiOperation for comments. 1853 switch (op) { 1854 case Token::SAR: 1855 __ b(&stub_call); 1856 __ GetLeastBitsFromSmi(scratch1, right, 5); 1857 __ mov(right, Operand(left, ASR, scratch1)); 1858 __ bic(right, right, Operand(kSmiTagMask)); 1859 break; 1860 case Token::SHL: { 1861 __ b(&stub_call); 1862 __ SmiUntag(scratch1, left); 1863 __ GetLeastBitsFromSmi(scratch2, right, 5); 1864 __ mov(scratch1, Operand(scratch1, LSL, scratch2)); 1865 __ add(scratch2, scratch1, Operand(0x40000000), SetCC); 1866 __ b(mi, &stub_call); 1867 __ SmiTag(right, scratch1); 1868 break; 1869 } 1870 case Token::SHR: { 1871 __ b(&stub_call); 1872 __ SmiUntag(scratch1, left); 1873 __ GetLeastBitsFromSmi(scratch2, right, 5); 1874 __ mov(scratch1, Operand(scratch1, LSR, scratch2)); 1875 __ tst(scratch1, Operand(0xc0000000)); 1876 __ b(ne, &stub_call); 1877 __ SmiTag(right, scratch1); 1878 break; 1879 } 1880 case Token::ADD: 1881 __ add(scratch1, left, Operand(right), SetCC); 1882 __ b(vs, &stub_call); 1883 __ mov(right, scratch1); 1884 break; 1885 case Token::SUB: 1886 __ sub(scratch1, left, Operand(right), SetCC); 1887 __ b(vs, &stub_call); 1888 __ mov(right, scratch1); 1889 break; 1890 case Token::MUL: { 1891 __ SmiUntag(ip, right); 1892 __ smull(scratch1, scratch2, left, ip); 1893 __ mov(ip, Operand(scratch1, ASR, 31)); 1894 __ cmp(ip, Operand(scratch2)); 1895 __ b(ne, &stub_call); 1896 __ cmp(scratch1, Operand(0)); 1897 __ mov(right, Operand(scratch1), LeaveCC, ne); 1898 __ b(ne, &done); 1899 __ add(scratch2, right, Operand(left), SetCC); 1900 __ mov(right, Operand(Smi::FromInt(0)), LeaveCC, pl); 1901 __ b(mi, &stub_call); 1902 break; 1903 } 1904 case Token::BIT_OR: 1905 __ orr(right, left, Operand(right)); 1906 break; 1907 case Token::BIT_AND: 1908 __ and_(right, left, Operand(right)); 1909 break; 1910 case Token::BIT_XOR: 1911 __ eor(right, left, Operand(right)); 1912 break; 1913 default: 1914 UNREACHABLE(); 1915 } 1916 1917 __ bind(&done); 1918 context()->Plug(r0); 1919 } 1920 1921 1922 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, 1923 Token::Value op, 1924 OverwriteMode mode) { 1925 __ pop(r1); 1926 BinaryOpStub stub(op, mode); 1927 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code. 1928 CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); 1929 patch_site.EmitPatchInfo(); 1930 context()->Plug(r0); 1931 } 1932 1933 1934 void FullCodeGenerator::EmitAssignment(Expression* expr) { 1935 // Invalid left-hand sides are rewritten to have a 'throw 1936 // ReferenceError' on the left-hand side. 1937 if (!expr->IsValidLeftHandSide()) { 1938 VisitForEffect(expr); 1939 return; 1940 } 1941 1942 // Left-hand side can only be a property, a global or a (parameter or local) 1943 // slot. 1944 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; 1945 LhsKind assign_type = VARIABLE; 1946 Property* prop = expr->AsProperty(); 1947 if (prop != NULL) { 1948 assign_type = (prop->key()->IsPropertyName()) 1949 ? NAMED_PROPERTY 1950 : KEYED_PROPERTY; 1951 } 1952 1953 switch (assign_type) { 1954 case VARIABLE: { 1955 Variable* var = expr->AsVariableProxy()->var(); 1956 EffectContext context(this); 1957 EmitVariableAssignment(var, Token::ASSIGN); 1958 break; 1959 } 1960 case NAMED_PROPERTY: { 1961 __ push(r0); // Preserve value. 1962 VisitForAccumulatorValue(prop->obj()); 1963 __ mov(r1, r0); 1964 __ pop(r0); // Restore value. 1965 __ mov(r2, Operand(prop->key()->AsLiteral()->handle())); 1966 Handle<Code> ic = is_classic_mode() 1967 ? isolate()->builtins()->StoreIC_Initialize() 1968 : isolate()->builtins()->StoreIC_Initialize_Strict(); 1969 CallIC(ic); 1970 break; 1971 } 1972 case KEYED_PROPERTY: { 1973 __ push(r0); // Preserve value. 1974 VisitForStackValue(prop->obj()); 1975 VisitForAccumulatorValue(prop->key()); 1976 __ mov(r1, r0); 1977 __ pop(r2); 1978 __ pop(r0); // Restore value. 1979 Handle<Code> ic = is_classic_mode() 1980 ? isolate()->builtins()->KeyedStoreIC_Initialize() 1981 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); 1982 CallIC(ic); 1983 break; 1984 } 1985 } 1986 context()->Plug(r0); 1987 } 1988 1989 1990 void FullCodeGenerator::EmitVariableAssignment(Variable* var, 1991 Token::Value op) { 1992 if (var->IsUnallocated()) { 1993 // Global var, const, or let. 1994 __ mov(r2, Operand(var->name())); 1995 __ ldr(r1, GlobalObjectOperand()); 1996 Handle<Code> ic = is_classic_mode() 1997 ? isolate()->builtins()->StoreIC_Initialize() 1998 : isolate()->builtins()->StoreIC_Initialize_Strict(); 1999 CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); 2000 2001 } else if (op == Token::INIT_CONST) { 2002 // Const initializers need a write barrier. 2003 ASSERT(!var->IsParameter()); // No const parameters. 2004 if (var->IsStackLocal()) { 2005 Label skip; 2006 __ ldr(r1, StackOperand(var)); 2007 __ CompareRoot(r1, Heap::kTheHoleValueRootIndex); 2008 __ b(ne, &skip); 2009 __ str(result_register(), StackOperand(var)); 2010 __ bind(&skip); 2011 } else { 2012 ASSERT(var->IsContextSlot() || var->IsLookupSlot()); 2013 // Like var declarations, const declarations are hoisted to function 2014 // scope. However, unlike var initializers, const initializers are 2015 // able to drill a hole to that function context, even from inside a 2016 // 'with' context. We thus bypass the normal static scope lookup for 2017 // var->IsContextSlot(). 2018 __ push(r0); 2019 __ mov(r0, Operand(var->name())); 2020 __ Push(cp, r0); // Context and name. 2021 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); 2022 } 2023 2024 } else if (var->mode() == LET && op != Token::INIT_LET) { 2025 // Non-initializing assignment to let variable needs a write barrier. 2026 if (var->IsLookupSlot()) { 2027 __ push(r0); // Value. 2028 __ mov(r1, Operand(var->name())); 2029 __ mov(r0, Operand(Smi::FromInt(language_mode()))); 2030 __ Push(cp, r1, r0); // Context, name, strict mode. 2031 __ CallRuntime(Runtime::kStoreContextSlot, 4); 2032 } else { 2033 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); 2034 Label assign; 2035 MemOperand location = VarOperand(var, r1); 2036 __ ldr(r3, location); 2037 __ CompareRoot(r3, Heap::kTheHoleValueRootIndex); 2038 __ b(ne, &assign); 2039 __ mov(r3, Operand(var->name())); 2040 __ push(r3); 2041 __ CallRuntime(Runtime::kThrowReferenceError, 1); 2042 // Perform the assignment. 2043 __ bind(&assign); 2044 __ str(result_register(), location); 2045 if (var->IsContextSlot()) { 2046 // RecordWrite may destroy all its register arguments. 2047 __ mov(r3, result_register()); 2048 int offset = Context::SlotOffset(var->index()); 2049 __ RecordWriteContextSlot( 2050 r1, offset, r3, r2, kLRHasBeenSaved, kDontSaveFPRegs); 2051 } 2052 } 2053 2054 } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) { 2055 // Assignment to var or initializing assignment to let/const 2056 // in harmony mode. 2057 if (var->IsStackAllocated() || var->IsContextSlot()) { 2058 MemOperand location = VarOperand(var, r1); 2059 if (FLAG_debug_code && op == Token::INIT_LET) { 2060 // Check for an uninitialized let binding. 2061 __ ldr(r2, location); 2062 __ CompareRoot(r2, Heap::kTheHoleValueRootIndex); 2063 __ Check(eq, "Let binding re-initialization."); 2064 } 2065 // Perform the assignment. 2066 __ str(r0, location); 2067 if (var->IsContextSlot()) { 2068 __ mov(r3, r0); 2069 int offset = Context::SlotOffset(var->index()); 2070 __ RecordWriteContextSlot( 2071 r1, offset, r3, r2, kLRHasBeenSaved, kDontSaveFPRegs); 2072 } 2073 } else { 2074 ASSERT(var->IsLookupSlot()); 2075 __ push(r0); // Value. 2076 __ mov(r1, Operand(var->name())); 2077 __ mov(r0, Operand(Smi::FromInt(language_mode()))); 2078 __ Push(cp, r1, r0); // Context, name, strict mode. 2079 __ CallRuntime(Runtime::kStoreContextSlot, 4); 2080 } 2081 } 2082 // Non-initializing assignments to consts are ignored. 2083 } 2084 2085 2086 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { 2087 // Assignment to a property, using a named store IC. 2088 Property* prop = expr->target()->AsProperty(); 2089 ASSERT(prop != NULL); 2090 ASSERT(prop->key()->AsLiteral() != NULL); 2091 2092 // If the assignment starts a block of assignments to the same object, 2093 // change to slow case to avoid the quadratic behavior of repeatedly 2094 // adding fast properties. 2095 if (expr->starts_initialization_block()) { 2096 __ push(result_register()); 2097 __ ldr(ip, MemOperand(sp, kPointerSize)); // Receiver is now under value. 2098 __ push(ip); 2099 __ CallRuntime(Runtime::kToSlowProperties, 1); 2100 __ pop(result_register()); 2101 } 2102 2103 // Record source code position before IC call. 2104 SetSourcePosition(expr->position()); 2105 __ mov(r2, Operand(prop->key()->AsLiteral()->handle())); 2106 // Load receiver to r1. Leave a copy in the stack if needed for turning the 2107 // receiver into fast case. 2108 if (expr->ends_initialization_block()) { 2109 __ ldr(r1, MemOperand(sp)); 2110 } else { 2111 __ pop(r1); 2112 } 2113 2114 Handle<Code> ic = is_classic_mode() 2115 ? isolate()->builtins()->StoreIC_Initialize() 2116 : isolate()->builtins()->StoreIC_Initialize_Strict(); 2117 CallIC(ic, RelocInfo::CODE_TARGET, expr->id()); 2118 2119 // If the assignment ends an initialization block, revert to fast case. 2120 if (expr->ends_initialization_block()) { 2121 __ push(r0); // Result of assignment, saved even if not needed. 2122 // Receiver is under the result value. 2123 __ ldr(ip, MemOperand(sp, kPointerSize)); 2124 __ push(ip); 2125 __ CallRuntime(Runtime::kToFastProperties, 1); 2126 __ pop(r0); 2127 __ Drop(1); 2128 } 2129 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); 2130 context()->Plug(r0); 2131 } 2132 2133 2134 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { 2135 // Assignment to a property, using a keyed store IC. 2136 2137 // If the assignment starts a block of assignments to the same object, 2138 // change to slow case to avoid the quadratic behavior of repeatedly 2139 // adding fast properties. 2140 if (expr->starts_initialization_block()) { 2141 __ push(result_register()); 2142 // Receiver is now under the key and value. 2143 __ ldr(ip, MemOperand(sp, 2 * kPointerSize)); 2144 __ push(ip); 2145 __ CallRuntime(Runtime::kToSlowProperties, 1); 2146 __ pop(result_register()); 2147 } 2148 2149 // Record source code position before IC call. 2150 SetSourcePosition(expr->position()); 2151 __ pop(r1); // Key. 2152 // Load receiver to r2. Leave a copy in the stack if needed for turning the 2153 // receiver into fast case. 2154 if (expr->ends_initialization_block()) { 2155 __ ldr(r2, MemOperand(sp)); 2156 } else { 2157 __ pop(r2); 2158 } 2159 2160 Handle<Code> ic = is_classic_mode() 2161 ? isolate()->builtins()->KeyedStoreIC_Initialize() 2162 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); 2163 CallIC(ic, RelocInfo::CODE_TARGET, expr->id()); 2164 2165 // If the assignment ends an initialization block, revert to fast case. 2166 if (expr->ends_initialization_block()) { 2167 __ push(r0); // Result of assignment, saved even if not needed. 2168 // Receiver is under the result value. 2169 __ ldr(ip, MemOperand(sp, kPointerSize)); 2170 __ push(ip); 2171 __ CallRuntime(Runtime::kToFastProperties, 1); 2172 __ pop(r0); 2173 __ Drop(1); 2174 } 2175 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); 2176 context()->Plug(r0); 2177 } 2178 2179 2180 void FullCodeGenerator::VisitProperty(Property* expr) { 2181 Comment cmnt(masm_, "[ Property"); 2182 Expression* key = expr->key(); 2183 2184 if (key->IsPropertyName()) { 2185 VisitForAccumulatorValue(expr->obj()); 2186 EmitNamedPropertyLoad(expr); 2187 context()->Plug(r0); 2188 } else { 2189 VisitForStackValue(expr->obj()); 2190 VisitForAccumulatorValue(expr->key()); 2191 __ pop(r1); 2192 EmitKeyedPropertyLoad(expr); 2193 context()->Plug(r0); 2194 } 2195 } 2196 2197 2198 void FullCodeGenerator::CallIC(Handle<Code> code, 2199 RelocInfo::Mode rmode, 2200 unsigned ast_id) { 2201 ic_total_count_++; 2202 __ Call(code, rmode, ast_id); 2203 } 2204 2205 void FullCodeGenerator::EmitCallWithIC(Call* expr, 2206 Handle<Object> name, 2207 RelocInfo::Mode mode) { 2208 // Code common for calls using the IC. 2209 ZoneList<Expression*>* args = expr->arguments(); 2210 int arg_count = args->length(); 2211 { PreservePositionScope scope(masm()->positions_recorder()); 2212 for (int i = 0; i < arg_count; i++) { 2213 VisitForStackValue(args->at(i)); 2214 } 2215 __ mov(r2, Operand(name)); 2216 } 2217 // Record source position for debugger. 2218 SetSourcePosition(expr->position()); 2219 // Call the IC initialization code. 2220 Handle<Code> ic = 2221 isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode); 2222 CallIC(ic, mode, expr->id()); 2223 RecordJSReturnSite(expr); 2224 // Restore context register. 2225 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); 2226 context()->Plug(r0); 2227 } 2228 2229 2230 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, 2231 Expression* key) { 2232 // Load the key. 2233 VisitForAccumulatorValue(key); 2234 2235 // Swap the name of the function and the receiver on the stack to follow 2236 // the calling convention for call ICs. 2237 __ pop(r1); 2238 __ push(r0); 2239 __ push(r1); 2240 2241 // Code common for calls using the IC. 2242 ZoneList<Expression*>* args = expr->arguments(); 2243 int arg_count = args->length(); 2244 { PreservePositionScope scope(masm()->positions_recorder()); 2245 for (int i = 0; i < arg_count; i++) { 2246 VisitForStackValue(args->at(i)); 2247 } 2248 } 2249 // Record source position for debugger. 2250 SetSourcePosition(expr->position()); 2251 // Call the IC initialization code. 2252 Handle<Code> ic = 2253 isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count); 2254 __ ldr(r2, MemOperand(sp, (arg_count + 1) * kPointerSize)); // Key. 2255 CallIC(ic, RelocInfo::CODE_TARGET, expr->id()); 2256 RecordJSReturnSite(expr); 2257 // Restore context register. 2258 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); 2259 context()->DropAndPlug(1, r0); // Drop the key still on the stack. 2260 } 2261 2262 2263 void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) { 2264 // Code common for calls using the call stub. 2265 ZoneList<Expression*>* args = expr->arguments(); 2266 int arg_count = args->length(); 2267 { PreservePositionScope scope(masm()->positions_recorder()); 2268 for (int i = 0; i < arg_count; i++) { 2269 VisitForStackValue(args->at(i)); 2270 } 2271 } 2272 // Record source position for debugger. 2273 SetSourcePosition(expr->position()); 2274 CallFunctionStub stub(arg_count, flags); 2275 __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize)); 2276 __ CallStub(&stub); 2277 RecordJSReturnSite(expr); 2278 // Restore context register. 2279 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); 2280 context()->DropAndPlug(1, r0); 2281 } 2282 2283 2284 void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { 2285 // Push copy of the first argument or undefined if it doesn't exist. 2286 if (arg_count > 0) { 2287 __ ldr(r1, MemOperand(sp, arg_count * kPointerSize)); 2288 } else { 2289 __ LoadRoot(r1, Heap::kUndefinedValueRootIndex); 2290 } 2291 __ push(r1); 2292 2293 // Push the receiver of the enclosing function. 2294 int receiver_offset = 2 + info_->scope()->num_parameters(); 2295 __ ldr(r1, MemOperand(fp, receiver_offset * kPointerSize)); 2296 __ push(r1); 2297 // Push the language mode. 2298 __ mov(r1, Operand(Smi::FromInt(language_mode()))); 2299 __ push(r1); 2300 2301 // Push the start position of the scope the calls resides in. 2302 __ mov(r1, Operand(Smi::FromInt(scope()->start_position()))); 2303 __ push(r1); 2304 2305 // Do the runtime call. 2306 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5); 2307 } 2308 2309 2310 void FullCodeGenerator::VisitCall(Call* expr) { 2311 #ifdef DEBUG 2312 // We want to verify that RecordJSReturnSite gets called on all paths 2313 // through this function. Avoid early returns. 2314 expr->return_is_recorded_ = false; 2315 #endif 2316 2317 Comment cmnt(masm_, "[ Call"); 2318 Expression* callee = expr->expression(); 2319 VariableProxy* proxy = callee->AsVariableProxy(); 2320 Property* property = callee->AsProperty(); 2321 2322 if (proxy != NULL && proxy->var()->is_possibly_eval()) { 2323 // In a call to eval, we first call %ResolvePossiblyDirectEval to 2324 // resolve the function we need to call and the receiver of the 2325 // call. Then we call the resolved function using the given 2326 // arguments. 2327 ZoneList<Expression*>* args = expr->arguments(); 2328 int arg_count = args->length(); 2329 2330 { PreservePositionScope pos_scope(masm()->positions_recorder()); 2331 VisitForStackValue(callee); 2332 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); 2333 __ push(r2); // Reserved receiver slot. 2334 2335 // Push the arguments. 2336 for (int i = 0; i < arg_count; i++) { 2337 VisitForStackValue(args->at(i)); 2338 } 2339 2340 // Push a copy of the function (found below the arguments) and 2341 // resolve eval. 2342 __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize)); 2343 __ push(r1); 2344 EmitResolvePossiblyDirectEval(arg_count); 2345 2346 // The runtime call returns a pair of values in r0 (function) and 2347 // r1 (receiver). Touch up the stack with the right values. 2348 __ str(r0, MemOperand(sp, (arg_count + 1) * kPointerSize)); 2349 __ str(r1, MemOperand(sp, arg_count * kPointerSize)); 2350 } 2351 2352 // Record source position for debugger. 2353 SetSourcePosition(expr->position()); 2354 CallFunctionStub stub(arg_count, RECEIVER_MIGHT_BE_IMPLICIT); 2355 __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize)); 2356 __ CallStub(&stub); 2357 RecordJSReturnSite(expr); 2358 // Restore context register. 2359 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); 2360 context()->DropAndPlug(1, r0); 2361 } else if (proxy != NULL && proxy->var()->IsUnallocated()) { 2362 // Push global object as receiver for the call IC. 2363 __ ldr(r0, GlobalObjectOperand()); 2364 __ push(r0); 2365 EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT); 2366 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { 2367 // Call to a lookup slot (dynamically introduced variable). 2368 Label slow, done; 2369 2370 { PreservePositionScope scope(masm()->positions_recorder()); 2371 // Generate code for loading from variables potentially shadowed 2372 // by eval-introduced variables. 2373 EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done); 2374 } 2375 2376 __ bind(&slow); 2377 // Call the runtime to find the function to call (returned in r0) 2378 // and the object holding it (returned in edx). 2379 __ push(context_register()); 2380 __ mov(r2, Operand(proxy->name())); 2381 __ push(r2); 2382 __ CallRuntime(Runtime::kLoadContextSlot, 2); 2383 __ Push(r0, r1); // Function, receiver. 2384 2385 // If fast case code has been generated, emit code to push the 2386 // function and receiver and have the slow path jump around this 2387 // code. 2388 if (done.is_linked()) { 2389 Label call; 2390 __ b(&call); 2391 __ bind(&done); 2392 // Push function. 2393 __ push(r0); 2394 // The receiver is implicitly the global receiver. Indicate this 2395 // by passing the hole to the call function stub. 2396 __ LoadRoot(r1, Heap::kTheHoleValueRootIndex); 2397 __ push(r1); 2398 __ bind(&call); 2399 } 2400 2401 // The receiver is either the global receiver or an object found 2402 // by LoadContextSlot. That object could be the hole if the 2403 // receiver is implicitly the global object. 2404 EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT); 2405 } else if (property != NULL) { 2406 { PreservePositionScope scope(masm()->positions_recorder()); 2407 VisitForStackValue(property->obj()); 2408 } 2409 if (property->key()->IsPropertyName()) { 2410 EmitCallWithIC(expr, 2411 property->key()->AsLiteral()->handle(), 2412 RelocInfo::CODE_TARGET); 2413 } else { 2414 EmitKeyedCallWithIC(expr, property->key()); 2415 } 2416 } else { 2417 // Call to an arbitrary expression not handled specially above. 2418 { PreservePositionScope scope(masm()->positions_recorder()); 2419 VisitForStackValue(callee); 2420 } 2421 // Load global receiver object. 2422 __ ldr(r1, GlobalObjectOperand()); 2423 __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset)); 2424 __ push(r1); 2425 // Emit function call. 2426 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS); 2427 } 2428 2429 #ifdef DEBUG 2430 // RecordJSReturnSite should have been called. 2431 ASSERT(expr->return_is_recorded_); 2432 #endif 2433 } 2434 2435 2436 void FullCodeGenerator::VisitCallNew(CallNew* expr) { 2437 Comment cmnt(masm_, "[ CallNew"); 2438 // According to ECMA-262, section 11.2.2, page 44, the function 2439 // expression in new calls must be evaluated before the 2440 // arguments. 2441 2442 // Push constructor on the stack. If it's not a function it's used as 2443 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is 2444 // ignored. 2445 VisitForStackValue(expr->expression()); 2446 2447 // Push the arguments ("left-to-right") on the stack. 2448 ZoneList<Expression*>* args = expr->arguments(); 2449 int arg_count = args->length(); 2450 for (int i = 0; i < arg_count; i++) { 2451 VisitForStackValue(args->at(i)); 2452 } 2453 2454 // Call the construct call builtin that handles allocation and 2455 // constructor invocation. 2456 SetSourcePosition(expr->position()); 2457 2458 // Load function and argument count into r1 and r0. 2459 __ mov(r0, Operand(arg_count)); 2460 __ ldr(r1, MemOperand(sp, arg_count * kPointerSize)); 2461 2462 // Record call targets in unoptimized code, but not in the snapshot. 2463 CallFunctionFlags flags; 2464 if (!Serializer::enabled()) { 2465 flags = RECORD_CALL_TARGET; 2466 Handle<Object> uninitialized = 2467 TypeFeedbackCells::UninitializedSentinel(isolate()); 2468 Handle<JSGlobalPropertyCell> cell = 2469 isolate()->factory()->NewJSGlobalPropertyCell(uninitialized); 2470 RecordTypeFeedbackCell(expr->id(), cell); 2471 __ mov(r2, Operand(cell)); 2472 } else { 2473 flags = NO_CALL_FUNCTION_FLAGS; 2474 } 2475 2476 CallConstructStub stub(flags); 2477 __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL); 2478 PrepareForBailoutForId(expr->ReturnId(), TOS_REG); 2479 context()->Plug(r0); 2480 } 2481 2482 2483 void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) { 2484 ZoneList<Expression*>* args = expr->arguments(); 2485 ASSERT(args->length() == 1); 2486 2487 VisitForAccumulatorValue(args->at(0)); 2488 2489 Label materialize_true, materialize_false; 2490 Label* if_true = NULL; 2491 Label* if_false = NULL; 2492 Label* fall_through = NULL; 2493 context()->PrepareTest(&materialize_true, &materialize_false, 2494 &if_true, &if_false, &fall_through); 2495 2496 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); 2497 __ tst(r0, Operand(kSmiTagMask)); 2498 Split(eq, if_true, if_false, fall_through); 2499 2500 context()->Plug(if_true, if_false); 2501 } 2502 2503 2504 void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) { 2505 ZoneList<Expression*>* args = expr->arguments(); 2506 ASSERT(args->length() == 1); 2507 2508 VisitForAccumulatorValue(args->at(0)); 2509 2510 Label materialize_true, materialize_false; 2511 Label* if_true = NULL; 2512 Label* if_false = NULL; 2513 Label* fall_through = NULL; 2514 context()->PrepareTest(&materialize_true, &materialize_false, 2515 &if_true, &if_false, &fall_through); 2516 2517 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); 2518 __ tst(r0, Operand(kSmiTagMask | 0x80000000)); 2519 Split(eq, if_true, if_false, fall_through); 2520 2521 context()->Plug(if_true, if_false); 2522 } 2523 2524 2525 void FullCodeGenerator::EmitIsObject(CallRuntime* expr) { 2526 ZoneList<Expression*>* args = expr->arguments(); 2527 ASSERT(args->length() == 1); 2528 2529 VisitForAccumulatorValue(args->at(0)); 2530 2531 Label materialize_true, materialize_false; 2532 Label* if_true = NULL; 2533 Label* if_false = NULL; 2534 Label* fall_through = NULL; 2535 context()->PrepareTest(&materialize_true, &materialize_false, 2536 &if_true, &if_false, &fall_through); 2537 2538 __ JumpIfSmi(r0, if_false); 2539 __ LoadRoot(ip, Heap::kNullValueRootIndex); 2540 __ cmp(r0, ip); 2541 __ b(eq, if_true); 2542 __ ldr(r2, FieldMemOperand(r0, HeapObject::kMapOffset)); 2543 // Undetectable objects behave like undefined when tested with typeof. 2544 __ ldrb(r1, FieldMemOperand(r2, Map::kBitFieldOffset)); 2545 __ tst(r1, Operand(1 << Map::kIsUndetectable)); 2546 __ b(ne, if_false); 2547 __ ldrb(r1, FieldMemOperand(r2, Map::kInstanceTypeOffset)); 2548 __ cmp(r1, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); 2549 __ b(lt, if_false); 2550 __ cmp(r1, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE)); 2551 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); 2552 Split(le, if_true, if_false, fall_through); 2553 2554 context()->Plug(if_true, if_false); 2555 } 2556 2557 2558 void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) { 2559 ZoneList<Expression*>* args = expr->arguments(); 2560 ASSERT(args->length() == 1); 2561 2562 VisitForAccumulatorValue(args->at(0)); 2563 2564 Label materialize_true, materialize_false; 2565 Label* if_true = NULL; 2566 Label* if_false = NULL; 2567 Label* fall_through = NULL; 2568 context()->PrepareTest(&materialize_true, &materialize_false, 2569 &if_true, &if_false, &fall_through); 2570 2571 __ JumpIfSmi(r0, if_false); 2572 __ CompareObjectType(r0, r1, r1, FIRST_SPEC_OBJECT_TYPE); 2573 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); 2574 Split(ge, if_true, if_false, fall_through); 2575 2576 context()->Plug(if_true, if_false); 2577 } 2578 2579 2580 void FullCodeGenerator::EmitIsUndetectableObject(CallRuntime* expr) { 2581 ZoneList<Expression*>* args = expr->arguments(); 2582 ASSERT(args->length() == 1); 2583 2584 VisitForAccumulatorValue(args->at(0)); 2585 2586 Label materialize_true, materialize_false; 2587 Label* if_true = NULL; 2588 Label* if_false = NULL; 2589 Label* fall_through = NULL; 2590 context()->PrepareTest(&materialize_true, &materialize_false, 2591 &if_true, &if_false, &fall_through); 2592 2593 __ JumpIfSmi(r0, if_false); 2594 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); 2595 __ ldrb(r1, FieldMemOperand(r1, Map::kBitFieldOffset)); 2596 __ tst(r1, Operand(1 << Map::kIsUndetectable)); 2597 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); 2598 Split(ne, if_true, if_false, fall_through); 2599 2600 context()->Plug(if_true, if_false); 2601 } 2602 2603 2604 void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( 2605 CallRuntime* expr) { 2606 ZoneList<Expression*>* args = expr->arguments(); 2607 ASSERT(args->length() == 1); 2608 2609 VisitForAccumulatorValue(args->at(0)); 2610 2611 Label materialize_true, materialize_false; 2612 Label* if_true = NULL; 2613 Label* if_false = NULL; 2614 Label* fall_through = NULL; 2615 context()->PrepareTest(&materialize_true, &materialize_false, 2616 &if_true, &if_false, &fall_through); 2617 2618 if (FLAG_debug_code) __ AbortIfSmi(r0); 2619 2620 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); 2621 __ ldrb(ip, FieldMemOperand(r1, Map::kBitField2Offset)); 2622 __ tst(ip, Operand(1 << Map::kStringWrapperSafeForDefaultValueOf)); 2623 __ b(ne, if_true); 2624 2625 // Check for fast case object. Generate false result for slow case object. 2626 __ ldr(r2, FieldMemOperand(r0, JSObject::kPropertiesOffset)); 2627 __ ldr(r2, FieldMemOperand(r2, HeapObject::kMapOffset)); 2628 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); 2629 __ cmp(r2, ip); 2630 __ b(eq, if_false); 2631 2632 // Look for valueOf symbol in the descriptor array, and indicate false if 2633 // found. The type is not checked, so if it is a transition it is a false 2634 // negative. 2635 __ LoadInstanceDescriptors(r1, r4); 2636 __ ldr(r3, FieldMemOperand(r4, FixedArray::kLengthOffset)); 2637 // r4: descriptor array 2638 // r3: length of descriptor array 2639 // Calculate the end of the descriptor array. 2640 STATIC_ASSERT(kSmiTag == 0); 2641 STATIC_ASSERT(kSmiTagSize == 1); 2642 STATIC_ASSERT(kPointerSize == 4); 2643 __ add(r2, r4, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); 2644 __ add(r2, r2, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize)); 2645 2646 // Calculate location of the first key name. 2647 __ add(r4, 2648 r4, 2649 Operand(FixedArray::kHeaderSize - kHeapObjectTag + 2650 DescriptorArray::kFirstIndex * kPointerSize)); 2651 // Loop through all the keys in the descriptor array. If one of these is the 2652 // symbol valueOf the result is false. 2653 Label entry, loop; 2654 // The use of ip to store the valueOf symbol asumes that it is not otherwise 2655 // used in the loop below. 2656 __ mov(ip, Operand(FACTORY->value_of_symbol())); 2657 __ jmp(&entry); 2658 __ bind(&loop); 2659 __ ldr(r3, MemOperand(r4, 0)); 2660 __ cmp(r3, ip); 2661 __ b(eq, if_false); 2662 __ add(r4, r4, Operand(kPointerSize)); 2663 __ bind(&entry); 2664 __ cmp(r4, Operand(r2)); 2665 __ b(ne, &loop); 2666 2667 // If a valueOf property is not found on the object check that it's 2668 // prototype is the un-modified String prototype. If not result is false. 2669 __ ldr(r2, FieldMemOperand(r1, Map::kPrototypeOffset)); 2670 __ JumpIfSmi(r2, if_false); 2671 __ ldr(r2, FieldMemOperand(r2, HeapObject::kMapOffset)); 2672 __ ldr(r3, ContextOperand(cp, Context::GLOBAL_INDEX)); 2673 __ ldr(r3, FieldMemOperand(r3, GlobalObject::kGlobalContextOffset)); 2674 __ ldr(r3, ContextOperand(r3, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX)); 2675 __ cmp(r2, r3); 2676 __ b(ne, if_false); 2677 2678 // Set the bit in the map to indicate that it has been checked safe for 2679 // default valueOf and set true result. 2680 __ ldrb(r2, FieldMemOperand(r1, Map::kBitField2Offset)); 2681 __ orr(r2, r2, Operand(1 << Map::kStringWrapperSafeForDefaultValueOf)); 2682 __ strb(r2, FieldMemOperand(r1, Map::kBitField2Offset)); 2683 __ jmp(if_true); 2684 2685 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); 2686 context()->Plug(if_true, if_false); 2687 } 2688 2689 2690 void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) { 2691 ZoneList<Expression*>* args = expr->arguments(); 2692 ASSERT(args->length() == 1); 2693 2694 VisitForAccumulatorValue(args->at(0)); 2695 2696 Label materialize_true, materialize_false; 2697 Label* if_true = NULL; 2698 Label* if_false = NULL; 2699 Label* fall_through = NULL; 2700 context()->PrepareTest(&materialize_true, &materialize_false, 2701 &if_true, &if_false, &fall_through); 2702 2703 __ JumpIfSmi(r0, if_false); 2704 __ CompareObjectType(r0, r1, r2, JS_FUNCTION_TYPE); 2705 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); 2706 Split(eq, if_true, if_false, fall_through); 2707 2708 context()->Plug(if_true, if_false); 2709 } 2710 2711 2712 void FullCodeGenerator::EmitIsArray(CallRuntime* expr) { 2713 ZoneList<Expression*>* args = expr->arguments(); 2714 ASSERT(args->length() == 1); 2715 2716 VisitForAccumulatorValue(args->at(0)); 2717 2718 Label materialize_true, materialize_false; 2719 Label* if_true = NULL; 2720 Label* if_false = NULL; 2721 Label* fall_through = NULL; 2722 context()->PrepareTest(&materialize_true, &materialize_false, 2723 &if_true, &if_false, &fall_through); 2724 2725 __ JumpIfSmi(r0, if_false); 2726 __ CompareObjectType(r0, r1, r1, JS_ARRAY_TYPE); 2727 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); 2728 Split(eq, if_true, if_false, fall_through); 2729 2730 context()->Plug(if_true, if_false); 2731 } 2732 2733 2734 void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) { 2735 ZoneList<Expression*>* args = expr->arguments(); 2736 ASSERT(args->length() == 1); 2737 2738 VisitForAccumulatorValue(args->at(0)); 2739 2740 Label materialize_true, materialize_false; 2741 Label* if_true = NULL; 2742 Label* if_false = NULL; 2743 Label* fall_through = NULL; 2744 context()->PrepareTest(&materialize_true, &materialize_false, 2745 &if_true, &if_false, &fall_through); 2746 2747 __ JumpIfSmi(r0, if_false); 2748 __ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE); 2749 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); 2750 Split(eq, if_true, if_false, fall_through); 2751 2752 context()->Plug(if_true, if_false); 2753 } 2754 2755 2756 2757 void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) { 2758 ASSERT(expr->arguments()->length() == 0); 2759 2760 Label materialize_true, materialize_false; 2761 Label* if_true = NULL; 2762 Label* if_false = NULL; 2763 Label* fall_through = NULL; 2764 context()->PrepareTest(&materialize_true, &materialize_false, 2765 &if_true, &if_false, &fall_through); 2766 2767 // Get the frame pointer for the calling frame. 2768 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); 2769 2770 // Skip the arguments adaptor frame if it exists. 2771 Label check_frame_marker; 2772 __ ldr(r1, MemOperand(r2, StandardFrameConstants::kContextOffset)); 2773 __ cmp(r1, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 2774 __ b(ne, &check_frame_marker); 2775 __ ldr(r2, MemOperand(r2, StandardFrameConstants::kCallerFPOffset)); 2776 2777 // Check the marker in the calling frame. 2778 __ bind(&check_frame_marker); 2779 __ ldr(r1, MemOperand(r2, StandardFrameConstants::kMarkerOffset)); 2780 __ cmp(r1, Operand(Smi::FromInt(StackFrame::CONSTRUCT))); 2781 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); 2782 Split(eq, if_true, if_false, fall_through); 2783 2784 context()->Plug(if_true, if_false); 2785 } 2786 2787 2788 void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) { 2789 ZoneList<Expression*>* args = expr->arguments(); 2790 ASSERT(args->length() == 2); 2791 2792 // Load the two objects into registers and perform the comparison. 2793 VisitForStackValue(args->at(0)); 2794 VisitForAccumulatorValue(args->at(1)); 2795 2796 Label materialize_true, materialize_false; 2797 Label* if_true = NULL; 2798 Label* if_false = NULL; 2799 Label* fall_through = NULL; 2800 context()->PrepareTest(&materialize_true, &materialize_false, 2801 &if_true, &if_false, &fall_through); 2802 2803 __ pop(r1); 2804 __ cmp(r0, r1); 2805 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); 2806 Split(eq, if_true, if_false, fall_through); 2807 2808 context()->Plug(if_true, if_false); 2809 } 2810 2811 2812 void FullCodeGenerator::EmitArguments(CallRuntime* expr) { 2813 ZoneList<Expression*>* args = expr->arguments(); 2814 ASSERT(args->length() == 1); 2815 2816 // ArgumentsAccessStub expects the key in edx and the formal 2817 // parameter count in r0. 2818 VisitForAccumulatorValue(args->at(0)); 2819 __ mov(r1, r0); 2820 __ mov(r0, Operand(Smi::FromInt(info_->scope()->num_parameters()))); 2821 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); 2822 __ CallStub(&stub); 2823 context()->Plug(r0); 2824 } 2825 2826 2827 void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) { 2828 ASSERT(expr->arguments()->length() == 0); 2829 Label exit; 2830 // Get the number of formal parameters. 2831 __ mov(r0, Operand(Smi::FromInt(info_->scope()->num_parameters()))); 2832 2833 // Check if the calling frame is an arguments adaptor frame. 2834 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); 2835 __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset)); 2836 __ cmp(r3, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 2837 __ b(ne, &exit); 2838 2839 // Arguments adaptor case: Read the arguments length from the 2840 // adaptor frame. 2841 __ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset)); 2842 2843 __ bind(&exit); 2844 context()->Plug(r0); 2845 } 2846 2847 2848 void FullCodeGenerator::EmitClassOf(CallRuntime* expr) { 2849 ZoneList<Expression*>* args = expr->arguments(); 2850 ASSERT(args->length() == 1); 2851 Label done, null, function, non_function_constructor; 2852 2853 VisitForAccumulatorValue(args->at(0)); 2854 2855 // If the object is a smi, we return null. 2856 __ JumpIfSmi(r0, &null); 2857 2858 // Check that the object is a JS object but take special care of JS 2859 // functions to make sure they have 'Function' as their class. 2860 // Assume that there are only two callable types, and one of them is at 2861 // either end of the type range for JS object types. Saves extra comparisons. 2862 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); 2863 __ CompareObjectType(r0, r0, r1, FIRST_SPEC_OBJECT_TYPE); 2864 // Map is now in r0. 2865 __ b(lt, &null); 2866 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE == 2867 FIRST_SPEC_OBJECT_TYPE + 1); 2868 __ b(eq, &function); 2869 2870 __ cmp(r1, Operand(LAST_SPEC_OBJECT_TYPE)); 2871 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == 2872 LAST_SPEC_OBJECT_TYPE - 1); 2873 __ b(eq, &function); 2874 // Assume that there is no larger type. 2875 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1); 2876 2877 // Check if the constructor in the map is a JS function. 2878 __ ldr(r0, FieldMemOperand(r0, Map::kConstructorOffset)); 2879 __ CompareObjectType(r0, r1, r1, JS_FUNCTION_TYPE); 2880 __ b(ne, &non_function_constructor); 2881 2882 // r0 now contains the constructor function. Grab the 2883 // instance class name from there. 2884 __ ldr(r0, FieldMemOperand(r0, JSFunction::kSharedFunctionInfoOffset)); 2885 __ ldr(r0, FieldMemOperand(r0, SharedFunctionInfo::kInstanceClassNameOffset)); 2886 __ b(&done); 2887 2888 // Functions have class 'Function'. 2889 __ bind(&function); 2890 __ LoadRoot(r0, Heap::kfunction_class_symbolRootIndex); 2891 __ jmp(&done); 2892 2893 // Objects with a non-function constructor have class 'Object'. 2894 __ bind(&non_function_constructor); 2895 __ LoadRoot(r0, Heap::kObject_symbolRootIndex); 2896 __ jmp(&done); 2897 2898 // Non-JS objects have class null. 2899 __ bind(&null); 2900 __ LoadRoot(r0, Heap::kNullValueRootIndex); 2901 2902 // All done. 2903 __ bind(&done); 2904 2905 context()->Plug(r0); 2906 } 2907 2908 2909 void FullCodeGenerator::EmitLog(CallRuntime* expr) { 2910 // Conditionally generate a log call. 2911 // Args: 2912 // 0 (literal string): The type of logging (corresponds to the flags). 2913 // This is used to determine whether or not to generate the log call. 2914 // 1 (string): Format string. Access the string at argument index 2 2915 // with '%2s' (see Logger::LogRuntime for all the formats). 2916 // 2 (array): Arguments to the format string. 2917 ZoneList<Expression*>* args = expr->arguments(); 2918 ASSERT_EQ(args->length(), 3); 2919 if (CodeGenerator::ShouldGenerateLog(args->at(0))) { 2920 VisitForStackValue(args->at(1)); 2921 VisitForStackValue(args->at(2)); 2922 __ CallRuntime(Runtime::kLog, 2); 2923 } 2924 2925 // Finally, we're expected to leave a value on the top of the stack. 2926 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); 2927 context()->Plug(r0); 2928 } 2929 2930 2931 void FullCodeGenerator::EmitRandomHeapNumber(CallRuntime* expr) { 2932 ASSERT(expr->arguments()->length() == 0); 2933 Label slow_allocate_heapnumber; 2934 Label heapnumber_allocated; 2935 2936 __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex); 2937 __ AllocateHeapNumber(r4, r1, r2, r6, &slow_allocate_heapnumber); 2938 __ jmp(&heapnumber_allocated); 2939 2940 __ bind(&slow_allocate_heapnumber); 2941 // Allocate a heap number. 2942 __ CallRuntime(Runtime::kNumberAlloc, 0); 2943 __ mov(r4, Operand(r0)); 2944 2945 __ bind(&heapnumber_allocated); 2946 2947 // Convert 32 random bits in r0 to 0.(32 random bits) in a double 2948 // by computing: 2949 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)). 2950 if (CpuFeatures::IsSupported(VFP3)) { 2951 __ PrepareCallCFunction(1, r0); 2952 __ ldr(r0, ContextOperand(context_register(), Context::GLOBAL_INDEX)); 2953 __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalContextOffset)); 2954 __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1); 2955 2956 CpuFeatures::Scope scope(VFP3); 2957 // 0x41300000 is the top half of 1.0 x 2^20 as a double. 2958 // Create this constant using mov/orr to avoid PC relative load. 2959 __ mov(r1, Operand(0x41000000)); 2960 __ orr(r1, r1, Operand(0x300000)); 2961 // Move 0x41300000xxxxxxxx (x = random bits) to VFP. 2962 __ vmov(d7, r0, r1); 2963 // Move 0x4130000000000000 to VFP. 2964 __ mov(r0, Operand(0, RelocInfo::NONE)); 2965 __ vmov(d8, r0, r1); 2966 // Subtract and store the result in the heap number. 2967 __ vsub(d7, d7, d8); 2968 __ sub(r0, r4, Operand(kHeapObjectTag)); 2969 __ vstr(d7, r0, HeapNumber::kValueOffset); 2970 __ mov(r0, r4); 2971 } else { 2972 __ PrepareCallCFunction(2, r0); 2973 __ ldr(r1, ContextOperand(context_register(), Context::GLOBAL_INDEX)); 2974 __ mov(r0, Operand(r4)); 2975 __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalContextOffset)); 2976 __ CallCFunction( 2977 ExternalReference::fill_heap_number_with_random_function(isolate()), 2); 2978 } 2979 2980 context()->Plug(r0); 2981 } 2982 2983 2984 void FullCodeGenerator::EmitSubString(CallRuntime* expr) { 2985 // Load the arguments on the stack and call the stub. 2986 SubStringStub stub; 2987 ZoneList<Expression*>* args = expr->arguments(); 2988 ASSERT(args->length() == 3); 2989 VisitForStackValue(args->at(0)); 2990 VisitForStackValue(args->at(1)); 2991 VisitForStackValue(args->at(2)); 2992 __ CallStub(&stub); 2993 context()->Plug(r0); 2994 } 2995 2996 2997 void FullCodeGenerator::EmitRegExpExec(CallRuntime* expr) { 2998 // Load the arguments on the stack and call the stub. 2999 RegExpExecStub stub; 3000 ZoneList<Expression*>* args = expr->arguments(); 3001 ASSERT(args->length() == 4); 3002 VisitForStackValue(args->at(0)); 3003 VisitForStackValue(args->at(1)); 3004 VisitForStackValue(args->at(2)); 3005 VisitForStackValue(args->at(3)); 3006 __ CallStub(&stub); 3007 context()->Plug(r0); 3008 } 3009 3010 3011 void FullCodeGenerator::EmitValueOf(CallRuntime* expr) { 3012 ZoneList<Expression*>* args = expr->arguments(); 3013 ASSERT(args->length() == 1); 3014 VisitForAccumulatorValue(args->at(0)); // Load the object. 3015 3016 Label done; 3017 // If the object is a smi return the object. 3018 __ JumpIfSmi(r0, &done); 3019 // If the object is not a value type, return the object. 3020 __ CompareObjectType(r0, r1, r1, JS_VALUE_TYPE); 3021 __ b(ne, &done); 3022 __ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset)); 3023 3024 __ bind(&done); 3025 context()->Plug(r0); 3026 } 3027 3028 3029 void FullCodeGenerator::EmitDateField(CallRuntime* expr) { 3030 ZoneList<Expression*>* args = expr->arguments(); 3031 ASSERT(args->length() == 2); 3032 ASSERT_NE(NULL, args->at(1)->AsLiteral()); 3033 Smi* index = Smi::cast(*(args->at(1)->AsLiteral()->handle())); 3034 3035 VisitForAccumulatorValue(args->at(0)); // Load the object. 3036 3037 Label runtime, done; 3038 Register object = r0; 3039 Register result = r0; 3040 Register scratch0 = r9; 3041 Register scratch1 = r1; 3042 3043 #ifdef DEBUG 3044 __ AbortIfSmi(object); 3045 __ CompareObjectType(object, scratch1, scratch1, JS_DATE_TYPE); 3046 __ Assert(eq, "Trying to get date field from non-date."); 3047 #endif 3048 3049 if (index->value() == 0) { 3050 __ ldr(result, FieldMemOperand(object, JSDate::kValueOffset)); 3051 } else { 3052 if (index->value() < JSDate::kFirstUncachedField) { 3053 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate()); 3054 __ mov(scratch1, Operand(stamp)); 3055 __ ldr(scratch1, MemOperand(scratch1)); 3056 __ ldr(scratch0, FieldMemOperand(object, JSDate::kCacheStampOffset)); 3057 __ cmp(scratch1, scratch0); 3058 __ b(ne, &runtime); 3059 __ ldr(result, FieldMemOperand(object, JSDate::kValueOffset + 3060 kPointerSize * index->value())); 3061 __ jmp(&done); 3062 } 3063 __ bind(&runtime); 3064 __ PrepareCallCFunction(2, scratch1); 3065 __ mov(r1, Operand(index)); 3066 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2); 3067 __ bind(&done); 3068 } 3069 context()->Plug(r0); 3070 } 3071 3072 3073 void FullCodeGenerator::EmitMathPow(CallRuntime* expr) { 3074 // Load the arguments on the stack and call the runtime function. 3075 ZoneList<Expression*>* args = expr->arguments(); 3076 ASSERT(args->length() == 2); 3077 VisitForStackValue(args->at(0)); 3078 VisitForStackValue(args->at(1)); 3079 if (CpuFeatures::IsSupported(VFP3)) { 3080 MathPowStub stub(MathPowStub::ON_STACK); 3081 __ CallStub(&stub); 3082 } else { 3083 __ CallRuntime(Runtime::kMath_pow, 2); 3084 } 3085 context()->Plug(r0); 3086 } 3087 3088 3089 void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) { 3090 ZoneList<Expression*>* args = expr->arguments(); 3091 ASSERT(args->length() == 2); 3092 VisitForStackValue(args->at(0)); // Load the object. 3093 VisitForAccumulatorValue(args->at(1)); // Load the value. 3094 __ pop(r1); // r0 = value. r1 = object. 3095 3096 Label done; 3097 // If the object is a smi, return the value. 3098 __ JumpIfSmi(r1, &done); 3099 3100 // If the object is not a value type, return the value. 3101 __ CompareObjectType(r1, r2, r2, JS_VALUE_TYPE); 3102 __ b(ne, &done); 3103 3104 // Store the value. 3105 __ str(r0, FieldMemOperand(r1, JSValue::kValueOffset)); 3106 // Update the write barrier. Save the value as it will be 3107 // overwritten by the write barrier code and is needed afterward. 3108 __ mov(r2, r0); 3109 __ RecordWriteField( 3110 r1, JSValue::kValueOffset, r2, r3, kLRHasBeenSaved, kDontSaveFPRegs); 3111 3112 __ bind(&done); 3113 context()->Plug(r0); 3114 } 3115 3116 3117 void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) { 3118 ZoneList<Expression*>* args = expr->arguments(); 3119 ASSERT_EQ(args->length(), 1); 3120 // Load the argument on the stack and call the stub. 3121 VisitForStackValue(args->at(0)); 3122 3123 NumberToStringStub stub; 3124 __ CallStub(&stub); 3125 context()->Plug(r0); 3126 } 3127 3128 3129 void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) { 3130 ZoneList<Expression*>* args = expr->arguments(); 3131 ASSERT(args->length() == 1); 3132 VisitForAccumulatorValue(args->at(0)); 3133 3134 Label done; 3135 StringCharFromCodeGenerator generator(r0, r1); 3136 generator.GenerateFast(masm_); 3137 __ jmp(&done); 3138 3139 NopRuntimeCallHelper call_helper; 3140 generator.GenerateSlow(masm_, call_helper); 3141 3142 __ bind(&done); 3143 context()->Plug(r1); 3144 } 3145 3146 3147 void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) { 3148 ZoneList<Expression*>* args = expr->arguments(); 3149 ASSERT(args->length() == 2); 3150 VisitForStackValue(args->at(0)); 3151 VisitForAccumulatorValue(args->at(1)); 3152 3153 Register object = r1; 3154 Register index = r0; 3155 Register result = r3; 3156 3157 __ pop(object); 3158 3159 Label need_conversion; 3160 Label index_out_of_range; 3161 Label done; 3162 StringCharCodeAtGenerator generator(object, 3163 index, 3164 result, 3165 &need_conversion, 3166 &need_conversion, 3167 &index_out_of_range, 3168 STRING_INDEX_IS_NUMBER); 3169 generator.GenerateFast(masm_); 3170 __ jmp(&done); 3171 3172 __ bind(&index_out_of_range); 3173 // When the index is out of range, the spec requires us to return 3174 // NaN. 3175 __ LoadRoot(result, Heap::kNanValueRootIndex); 3176 __ jmp(&done); 3177 3178 __ bind(&need_conversion); 3179 // Load the undefined value into the result register, which will 3180 // trigger conversion. 3181 __ LoadRoot(result, Heap::kUndefinedValueRootIndex); 3182 __ jmp(&done); 3183 3184 NopRuntimeCallHelper call_helper; 3185 generator.GenerateSlow(masm_, call_helper); 3186 3187 __ bind(&done); 3188 context()->Plug(result); 3189 } 3190 3191 3192 void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) { 3193 ZoneList<Expression*>* args = expr->arguments(); 3194 ASSERT(args->length() == 2); 3195 VisitForStackValue(args->at(0)); 3196 VisitForAccumulatorValue(args->at(1)); 3197 3198 Register object = r1; 3199 Register index = r0; 3200 Register scratch = r3; 3201 Register result = r0; 3202 3203 __ pop(object); 3204 3205 Label need_conversion; 3206 Label index_out_of_range; 3207 Label done; 3208 StringCharAtGenerator generator(object, 3209 index, 3210 scratch, 3211 result, 3212 &need_conversion, 3213 &need_conversion, 3214 &index_out_of_range, 3215 STRING_INDEX_IS_NUMBER); 3216 generator.GenerateFast(masm_); 3217 __ jmp(&done); 3218 3219 __ bind(&index_out_of_range); 3220 // When the index is out of range, the spec requires us to return 3221 // the empty string. 3222 __ LoadRoot(result, Heap::kEmptyStringRootIndex); 3223 __ jmp(&done); 3224 3225 __ bind(&need_conversion); 3226 // Move smi zero into the result register, which will trigger 3227 // conversion. 3228 __ mov(result, Operand(Smi::FromInt(0))); 3229 __ jmp(&done); 3230 3231 NopRuntimeCallHelper call_helper; 3232 generator.GenerateSlow(masm_, call_helper); 3233 3234 __ bind(&done); 3235 context()->Plug(result); 3236 } 3237 3238 3239 void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) { 3240 ZoneList<Expression*>* args = expr->arguments(); 3241 ASSERT_EQ(2, args->length()); 3242 VisitForStackValue(args->at(0)); 3243 VisitForStackValue(args->at(1)); 3244 3245 StringAddStub stub(NO_STRING_ADD_FLAGS); 3246 __ CallStub(&stub); 3247 context()->Plug(r0); 3248 } 3249 3250 3251 void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) { 3252 ZoneList<Expression*>* args = expr->arguments(); 3253 ASSERT_EQ(2, args->length()); 3254 VisitForStackValue(args->at(0)); 3255 VisitForStackValue(args->at(1)); 3256 3257 StringCompareStub stub; 3258 __ CallStub(&stub); 3259 context()->Plug(r0); 3260 } 3261 3262 3263 void FullCodeGenerator::EmitMathSin(CallRuntime* expr) { 3264 // Load the argument on the stack and call the stub. 3265 TranscendentalCacheStub stub(TranscendentalCache::SIN, 3266 TranscendentalCacheStub::TAGGED); 3267 ZoneList<Expression*>* args = expr->arguments(); 3268 ASSERT(args->length() == 1); 3269 VisitForStackValue(args->at(0)); 3270 __ CallStub(&stub); 3271 context()->Plug(r0); 3272 } 3273 3274 3275 void FullCodeGenerator::EmitMathCos(CallRuntime* expr) { 3276 // Load the argument on the stack and call the stub. 3277 TranscendentalCacheStub stub(TranscendentalCache::COS, 3278 TranscendentalCacheStub::TAGGED); 3279 ZoneList<Expression*>* args = expr->arguments(); 3280 ASSERT(args->length() == 1); 3281 VisitForStackValue(args->at(0)); 3282 __ CallStub(&stub); 3283 context()->Plug(r0); 3284 } 3285 3286 3287 void FullCodeGenerator::EmitMathTan(CallRuntime* expr) { 3288 // Load the argument on the stack and call the stub. 3289 TranscendentalCacheStub stub(TranscendentalCache::TAN, 3290 TranscendentalCacheStub::TAGGED); 3291 ZoneList<Expression*>* args = expr->arguments(); 3292 ASSERT(args->length() == 1); 3293 VisitForStackValue(args->at(0)); 3294 __ CallStub(&stub); 3295 context()->Plug(r0); 3296 } 3297 3298 3299 void FullCodeGenerator::EmitMathLog(CallRuntime* expr) { 3300 // Load the argument on the stack and call the stub. 3301 TranscendentalCacheStub stub(TranscendentalCache::LOG, 3302 TranscendentalCacheStub::TAGGED); 3303 ZoneList<Expression*>* args = expr->arguments(); 3304 ASSERT(args->length() == 1); 3305 VisitForStackValue(args->at(0)); 3306 __ CallStub(&stub); 3307 context()->Plug(r0); 3308 } 3309 3310 3311 void FullCodeGenerator::EmitMathSqrt(CallRuntime* expr) { 3312 // Load the argument on the stack and call the runtime function. 3313 ZoneList<Expression*>* args = expr->arguments(); 3314 ASSERT(args->length() == 1); 3315 VisitForStackValue(args->at(0)); 3316 __ CallRuntime(Runtime::kMath_sqrt, 1); 3317 context()->Plug(r0); 3318 } 3319 3320 3321 void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) { 3322 ZoneList<Expression*>* args = expr->arguments(); 3323 ASSERT(args->length() >= 2); 3324 3325 int arg_count = args->length() - 2; // 2 ~ receiver and function. 3326 for (int i = 0; i < arg_count + 1; i++) { 3327 VisitForStackValue(args->at(i)); 3328 } 3329 VisitForAccumulatorValue(args->last()); // Function. 3330 3331 // Check for proxy. 3332 Label proxy, done; 3333 __ CompareObjectType(r0, r1, r1, JS_FUNCTION_PROXY_TYPE); 3334 __ b(eq, &proxy); 3335 3336 // InvokeFunction requires the function in r1. Move it in there. 3337 __ mov(r1, result_register()); 3338 ParameterCount count(arg_count); 3339 __ InvokeFunction(r1, count, CALL_FUNCTION, 3340 NullCallWrapper(), CALL_AS_METHOD); 3341 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); 3342 __ jmp(&done); 3343 3344 __ bind(&proxy); 3345 __ push(r0); 3346 __ CallRuntime(Runtime::kCall, args->length()); 3347 __ bind(&done); 3348 3349 context()->Plug(r0); 3350 } 3351 3352 3353 void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) { 3354 RegExpConstructResultStub stub; 3355 ZoneList<Expression*>* args = expr->arguments(); 3356 ASSERT(args->length() == 3); 3357 VisitForStackValue(args->at(0)); 3358 VisitForStackValue(args->at(1)); 3359 VisitForStackValue(args->at(2)); 3360 __ CallStub(&stub); 3361 context()->Plug(r0); 3362 } 3363 3364 3365 void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) { 3366 ZoneList<Expression*>* args = expr->arguments(); 3367 ASSERT_EQ(2, args->length()); 3368 ASSERT_NE(NULL, args->at(0)->AsLiteral()); 3369 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value(); 3370 3371 Handle<FixedArray> jsfunction_result_caches( 3372 isolate()->global_context()->jsfunction_result_caches()); 3373 if (jsfunction_result_caches->length() <= cache_id) { 3374 __ Abort("Attempt to use undefined cache."); 3375 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); 3376 context()->Plug(r0); 3377 return; 3378 } 3379 3380 VisitForAccumulatorValue(args->at(1)); 3381 3382 Register key = r0; 3383 Register cache = r1; 3384 __ ldr(cache, ContextOperand(cp, Context::GLOBAL_INDEX)); 3385 __ ldr(cache, FieldMemOperand(cache, GlobalObject::kGlobalContextOffset)); 3386 __ ldr(cache, ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX)); 3387 __ ldr(cache, 3388 FieldMemOperand(cache, FixedArray::OffsetOfElementAt(cache_id))); 3389 3390 3391 Label done, not_found; 3392 // tmp now holds finger offset as a smi. 3393 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); 3394 __ ldr(r2, FieldMemOperand(cache, JSFunctionResultCache::kFingerOffset)); 3395 // r2 now holds finger offset as a smi. 3396 __ add(r3, cache, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); 3397 // r3 now points to the start of fixed array elements. 3398 __ ldr(r2, MemOperand(r3, r2, LSL, kPointerSizeLog2 - kSmiTagSize, PreIndex)); 3399 // Note side effect of PreIndex: r3 now points to the key of the pair. 3400 __ cmp(key, r2); 3401 __ b(ne, ¬_found); 3402 3403 __ ldr(r0, MemOperand(r3, kPointerSize)); 3404 __ b(&done); 3405 3406 __ bind(¬_found); 3407 // Call runtime to perform the lookup. 3408 __ Push(cache, key); 3409 __ CallRuntime(Runtime::kGetFromCache, 2); 3410 3411 __ bind(&done); 3412 context()->Plug(r0); 3413 } 3414 3415 3416 void FullCodeGenerator::EmitIsRegExpEquivalent(CallRuntime* expr) { 3417 ZoneList<Expression*>* args = expr->arguments(); 3418 ASSERT_EQ(2, args->length()); 3419 3420 Register right = r0; 3421 Register left = r1; 3422 Register tmp = r2; 3423 Register tmp2 = r3; 3424 3425 VisitForStackValue(args->at(0)); 3426 VisitForAccumulatorValue(args->at(1)); 3427 __ pop(left); 3428 3429 Label done, fail, ok; 3430 __ cmp(left, Operand(right)); 3431 __ b(eq, &ok); 3432 // Fail if either is a non-HeapObject. 3433 __ and_(tmp, left, Operand(right)); 3434 __ JumpIfSmi(tmp, &fail); 3435 __ ldr(tmp, FieldMemOperand(left, HeapObject::kMapOffset)); 3436 __ ldrb(tmp2, FieldMemOperand(tmp, Map::kInstanceTypeOffset)); 3437 __ cmp(tmp2, Operand(JS_REGEXP_TYPE)); 3438 __ b(ne, &fail); 3439 __ ldr(tmp2, FieldMemOperand(right, HeapObject::kMapOffset)); 3440 __ cmp(tmp, Operand(tmp2)); 3441 __ b(ne, &fail); 3442 __ ldr(tmp, FieldMemOperand(left, JSRegExp::kDataOffset)); 3443 __ ldr(tmp2, FieldMemOperand(right, JSRegExp::kDataOffset)); 3444 __ cmp(tmp, tmp2); 3445 __ b(eq, &ok); 3446 __ bind(&fail); 3447 __ LoadRoot(r0, Heap::kFalseValueRootIndex); 3448 __ jmp(&done); 3449 __ bind(&ok); 3450 __ LoadRoot(r0, Heap::kTrueValueRootIndex); 3451 __ bind(&done); 3452 3453 context()->Plug(r0); 3454 } 3455 3456 3457 void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) { 3458 ZoneList<Expression*>* args = expr->arguments(); 3459 VisitForAccumulatorValue(args->at(0)); 3460 3461 Label materialize_true, materialize_false; 3462 Label* if_true = NULL; 3463 Label* if_false = NULL; 3464 Label* fall_through = NULL; 3465 context()->PrepareTest(&materialize_true, &materialize_false, 3466 &if_true, &if_false, &fall_through); 3467 3468 __ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset)); 3469 __ tst(r0, Operand(String::kContainsCachedArrayIndexMask)); 3470 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); 3471 Split(eq, if_true, if_false, fall_through); 3472 3473 context()->Plug(if_true, if_false); 3474 } 3475 3476 3477 void FullCodeGenerator::EmitGetCachedArrayIndex(CallRuntime* expr) { 3478 ZoneList<Expression*>* args = expr->arguments(); 3479 ASSERT(args->length() == 1); 3480 VisitForAccumulatorValue(args->at(0)); 3481 3482 if (FLAG_debug_code) { 3483 __ AbortIfNotString(r0); 3484 } 3485 3486 __ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset)); 3487 __ IndexFromHash(r0, r0); 3488 3489 context()->Plug(r0); 3490 } 3491 3492 3493 void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { 3494 Label bailout, done, one_char_separator, long_separator, 3495 non_trivial_array, not_size_one_array, loop, 3496 empty_separator_loop, one_char_separator_loop, 3497 one_char_separator_loop_entry, long_separator_loop; 3498 ZoneList<Expression*>* args = expr->arguments(); 3499 ASSERT(args->length() == 2); 3500 VisitForStackValue(args->at(1)); 3501 VisitForAccumulatorValue(args->at(0)); 3502 3503 // All aliases of the same register have disjoint lifetimes. 3504 Register array = r0; 3505 Register elements = no_reg; // Will be r0. 3506 Register result = no_reg; // Will be r0. 3507 Register separator = r1; 3508 Register array_length = r2; 3509 Register result_pos = no_reg; // Will be r2 3510 Register string_length = r3; 3511 Register string = r4; 3512 Register element = r5; 3513 Register elements_end = r6; 3514 Register scratch1 = r7; 3515 Register scratch2 = r9; 3516 3517 // Separator operand is on the stack. 3518 __ pop(separator); 3519 3520 // Check that the array is a JSArray. 3521 __ JumpIfSmi(array, &bailout); 3522 __ CompareObjectType(array, scratch1, scratch2, JS_ARRAY_TYPE); 3523 __ b(ne, &bailout); 3524 3525 // Check that the array has fast elements. 3526 __ CheckFastElements(scratch1, scratch2, &bailout); 3527 3528 // If the array has length zero, return the empty string. 3529 __ ldr(array_length, FieldMemOperand(array, JSArray::kLengthOffset)); 3530 __ SmiUntag(array_length, SetCC); 3531 __ b(ne, &non_trivial_array); 3532 __ LoadRoot(r0, Heap::kEmptyStringRootIndex); 3533 __ b(&done); 3534 3535 __ bind(&non_trivial_array); 3536 3537 // Get the FixedArray containing array's elements. 3538 elements = array; 3539 __ ldr(elements, FieldMemOperand(array, JSArray::kElementsOffset)); 3540 array = no_reg; // End of array's live range. 3541 3542 // Check that all array elements are sequential ASCII strings, and 3543 // accumulate the sum of their lengths, as a smi-encoded value. 3544 __ mov(string_length, Operand(0)); 3545 __ add(element, 3546 elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); 3547 __ add(elements_end, element, Operand(array_length, LSL, kPointerSizeLog2)); 3548 // Loop condition: while (element < elements_end). 3549 // Live values in registers: 3550 // elements: Fixed array of strings. 3551 // array_length: Length of the fixed array of strings (not smi) 3552 // separator: Separator string 3553 // string_length: Accumulated sum of string lengths (smi). 3554 // element: Current array element. 3555 // elements_end: Array end. 3556 if (FLAG_debug_code) { 3557 __ cmp(array_length, Operand(0)); 3558 __ Assert(gt, "No empty arrays here in EmitFastAsciiArrayJoin"); 3559 } 3560 __ bind(&loop); 3561 __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); 3562 __ JumpIfSmi(string, &bailout); 3563 __ ldr(scratch1, FieldMemOperand(string, HeapObject::kMapOffset)); 3564 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); 3565 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch1, scratch2, &bailout); 3566 __ ldr(scratch1, FieldMemOperand(string, SeqAsciiString::kLengthOffset)); 3567 __ add(string_length, string_length, Operand(scratch1)); 3568 __ b(vs, &bailout); 3569 __ cmp(element, elements_end); 3570 __ b(lt, &loop); 3571 3572 // If array_length is 1, return elements[0], a string. 3573 __ cmp(array_length, Operand(1)); 3574 __ b(ne, ¬_size_one_array); 3575 __ ldr(r0, FieldMemOperand(elements, FixedArray::kHeaderSize)); 3576 __ b(&done); 3577 3578 __ bind(¬_size_one_array); 3579 3580 // Live values in registers: 3581 // separator: Separator string 3582 // array_length: Length of the array. 3583 // string_length: Sum of string lengths (smi). 3584 // elements: FixedArray of strings. 3585 3586 // Check that the separator is a flat ASCII string. 3587 __ JumpIfSmi(separator, &bailout); 3588 __ ldr(scratch1, FieldMemOperand(separator, HeapObject::kMapOffset)); 3589 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); 3590 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch1, scratch2, &bailout); 3591 3592 // Add (separator length times array_length) - separator length to the 3593 // string_length to get the length of the result string. array_length is not 3594 // smi but the other values are, so the result is a smi 3595 __ ldr(scratch1, FieldMemOperand(separator, SeqAsciiString::kLengthOffset)); 3596 __ sub(string_length, string_length, Operand(scratch1)); 3597 __ smull(scratch2, ip, array_length, scratch1); 3598 // Check for smi overflow. No overflow if higher 33 bits of 64-bit result are 3599 // zero. 3600 __ cmp(ip, Operand(0)); 3601 __ b(ne, &bailout); 3602 __ tst(scratch2, Operand(0x80000000)); 3603 __ b(ne, &bailout); 3604 __ add(string_length, string_length, Operand(scratch2)); 3605 __ b(vs, &bailout); 3606 __ SmiUntag(string_length); 3607 3608 // Get first element in the array to free up the elements register to be used 3609 // for the result. 3610 __ add(element, 3611 elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); 3612 result = elements; // End of live range for elements. 3613 elements = no_reg; 3614 // Live values in registers: 3615 // element: First array element 3616 // separator: Separator string 3617 // string_length: Length of result string (not smi) 3618 // array_length: Length of the array. 3619 __ AllocateAsciiString(result, 3620 string_length, 3621 scratch1, 3622 scratch2, 3623 elements_end, 3624 &bailout); 3625 // Prepare for looping. Set up elements_end to end of the array. Set 3626 // result_pos to the position of the result where to write the first 3627 // character. 3628 __ add(elements_end, element, Operand(array_length, LSL, kPointerSizeLog2)); 3629 result_pos = array_length; // End of live range for array_length. 3630 array_length = no_reg; 3631 __ add(result_pos, 3632 result, 3633 Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 3634 3635 // Check the length of the separator. 3636 __ ldr(scratch1, FieldMemOperand(separator, SeqAsciiString::kLengthOffset)); 3637 __ cmp(scratch1, Operand(Smi::FromInt(1))); 3638 __ b(eq, &one_char_separator); 3639 __ b(gt, &long_separator); 3640 3641 // Empty separator case 3642 __ bind(&empty_separator_loop); 3643 // Live values in registers: 3644 // result_pos: the position to which we are currently copying characters. 3645 // element: Current array element. 3646 // elements_end: Array end. 3647 3648 // Copy next array element to the result. 3649 __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); 3650 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset)); 3651 __ SmiUntag(string_length); 3652 __ add(string, string, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 3653 __ CopyBytes(string, result_pos, string_length, scratch1); 3654 __ cmp(element, elements_end); 3655 __ b(lt, &empty_separator_loop); // End while (element < elements_end). 3656 ASSERT(result.is(r0)); 3657 __ b(&done); 3658 3659 // One-character separator case 3660 __ bind(&one_char_separator); 3661 // Replace separator with its ASCII character value. 3662 __ ldrb(separator, FieldMemOperand(separator, SeqAsciiString::kHeaderSize)); 3663 // Jump into the loop after the code that copies the separator, so the first 3664 // element is not preceded by a separator 3665 __ jmp(&one_char_separator_loop_entry); 3666 3667 __ bind(&one_char_separator_loop); 3668 // Live values in registers: 3669 // result_pos: the position to which we are currently copying characters. 3670 // element: Current array element. 3671 // elements_end: Array end. 3672 // separator: Single separator ASCII char (in lower byte). 3673 3674 // Copy the separator character to the result. 3675 __ strb(separator, MemOperand(result_pos, 1, PostIndex)); 3676 3677 // Copy next array element to the result. 3678 __ bind(&one_char_separator_loop_entry); 3679 __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); 3680 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset)); 3681 __ SmiUntag(string_length); 3682 __ add(string, string, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 3683 __ CopyBytes(string, result_pos, string_length, scratch1); 3684 __ cmp(element, elements_end); 3685 __ b(lt, &one_char_separator_loop); // End while (element < elements_end). 3686 ASSERT(result.is(r0)); 3687 __ b(&done); 3688 3689 // Long separator case (separator is more than one character). Entry is at the 3690 // label long_separator below. 3691 __ bind(&long_separator_loop); 3692 // Live values in registers: 3693 // result_pos: the position to which we are currently copying characters. 3694 // element: Current array element. 3695 // elements_end: Array end. 3696 // separator: Separator string. 3697 3698 // Copy the separator to the result. 3699 __ ldr(string_length, FieldMemOperand(separator, String::kLengthOffset)); 3700 __ SmiUntag(string_length); 3701 __ add(string, 3702 separator, 3703 Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 3704 __ CopyBytes(string, result_pos, string_length, scratch1); 3705 3706 __ bind(&long_separator); 3707 __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); 3708 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset)); 3709 __ SmiUntag(string_length); 3710 __ add(string, string, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 3711 __ CopyBytes(string, result_pos, string_length, scratch1); 3712 __ cmp(element, elements_end); 3713 __ b(lt, &long_separator_loop); // End while (element < elements_end). 3714 ASSERT(result.is(r0)); 3715 __ b(&done); 3716 3717 __ bind(&bailout); 3718 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); 3719 __ bind(&done); 3720 context()->Plug(r0); 3721 } 3722 3723 3724 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { 3725 Handle<String> name = expr->name(); 3726 if (name->length() > 0 && name->Get(0) == '_') { 3727 Comment cmnt(masm_, "[ InlineRuntimeCall"); 3728 EmitInlineRuntimeCall(expr); 3729 return; 3730 } 3731 3732 Comment cmnt(masm_, "[ CallRuntime"); 3733 ZoneList<Expression*>* args = expr->arguments(); 3734 3735 if (expr->is_jsruntime()) { 3736 // Prepare for calling JS runtime function. 3737 __ ldr(r0, GlobalObjectOperand()); 3738 __ ldr(r0, FieldMemOperand(r0, GlobalObject::kBuiltinsOffset)); 3739 __ push(r0); 3740 } 3741 3742 // Push the arguments ("left-to-right"). 3743 int arg_count = args->length(); 3744 for (int i = 0; i < arg_count; i++) { 3745 VisitForStackValue(args->at(i)); 3746 } 3747 3748 if (expr->is_jsruntime()) { 3749 // Call the JS runtime function. 3750 __ mov(r2, Operand(expr->name())); 3751 RelocInfo::Mode mode = RelocInfo::CODE_TARGET; 3752 Handle<Code> ic = 3753 isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode); 3754 CallIC(ic, mode, expr->id()); 3755 // Restore context register. 3756 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); 3757 } else { 3758 // Call the C runtime function. 3759 __ CallRuntime(expr->function(), arg_count); 3760 } 3761 context()->Plug(r0); 3762 } 3763 3764 3765 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { 3766 switch (expr->op()) { 3767 case Token::DELETE: { 3768 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); 3769 Property* property = expr->expression()->AsProperty(); 3770 VariableProxy* proxy = expr->expression()->AsVariableProxy(); 3771 3772 if (property != NULL) { 3773 VisitForStackValue(property->obj()); 3774 VisitForStackValue(property->key()); 3775 StrictModeFlag strict_mode_flag = (language_mode() == CLASSIC_MODE) 3776 ? kNonStrictMode : kStrictMode; 3777 __ mov(r1, Operand(Smi::FromInt(strict_mode_flag))); 3778 __ push(r1); 3779 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); 3780 context()->Plug(r0); 3781 } else if (proxy != NULL) { 3782 Variable* var = proxy->var(); 3783 // Delete of an unqualified identifier is disallowed in strict mode 3784 // but "delete this" is allowed. 3785 ASSERT(language_mode() == CLASSIC_MODE || var->is_this()); 3786 if (var->IsUnallocated()) { 3787 __ ldr(r2, GlobalObjectOperand()); 3788 __ mov(r1, Operand(var->name())); 3789 __ mov(r0, Operand(Smi::FromInt(kNonStrictMode))); 3790 __ Push(r2, r1, r0); 3791 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); 3792 context()->Plug(r0); 3793 } else if (var->IsStackAllocated() || var->IsContextSlot()) { 3794 // Result of deleting non-global, non-dynamic variables is false. 3795 // The subexpression does not have side effects. 3796 context()->Plug(var->is_this()); 3797 } else { 3798 // Non-global variable. Call the runtime to try to delete from the 3799 // context where the variable was introduced. 3800 __ push(context_register()); 3801 __ mov(r2, Operand(var->name())); 3802 __ push(r2); 3803 __ CallRuntime(Runtime::kDeleteContextSlot, 2); 3804 context()->Plug(r0); 3805 } 3806 } else { 3807 // Result of deleting non-property, non-variable reference is true. 3808 // The subexpression may have side effects. 3809 VisitForEffect(expr->expression()); 3810 context()->Plug(true); 3811 } 3812 break; 3813 } 3814 3815 case Token::VOID: { 3816 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); 3817 VisitForEffect(expr->expression()); 3818 context()->Plug(Heap::kUndefinedValueRootIndex); 3819 break; 3820 } 3821 3822 case Token::NOT: { 3823 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); 3824 if (context()->IsEffect()) { 3825 // Unary NOT has no side effects so it's only necessary to visit the 3826 // subexpression. Match the optimizing compiler by not branching. 3827 VisitForEffect(expr->expression()); 3828 } else if (context()->IsTest()) { 3829 const TestContext* test = TestContext::cast(context()); 3830 // The labels are swapped for the recursive call. 3831 VisitForControl(expr->expression(), 3832 test->false_label(), 3833 test->true_label(), 3834 test->fall_through()); 3835 context()->Plug(test->true_label(), test->false_label()); 3836 } else { 3837 // We handle value contexts explicitly rather than simply visiting 3838 // for control and plugging the control flow into the context, 3839 // because we need to prepare a pair of extra administrative AST ids 3840 // for the optimizing compiler. 3841 ASSERT(context()->IsAccumulatorValue() || context()->IsStackValue()); 3842 Label materialize_true, materialize_false, done; 3843 VisitForControl(expr->expression(), 3844 &materialize_false, 3845 &materialize_true, 3846 &materialize_true); 3847 __ bind(&materialize_true); 3848 PrepareForBailoutForId(expr->MaterializeTrueId(), NO_REGISTERS); 3849 __ LoadRoot(r0, Heap::kTrueValueRootIndex); 3850 if (context()->IsStackValue()) __ push(r0); 3851 __ jmp(&done); 3852 __ bind(&materialize_false); 3853 PrepareForBailoutForId(expr->MaterializeFalseId(), NO_REGISTERS); 3854 __ LoadRoot(r0, Heap::kFalseValueRootIndex); 3855 if (context()->IsStackValue()) __ push(r0); 3856 __ bind(&done); 3857 } 3858 break; 3859 } 3860 3861 case Token::TYPEOF: { 3862 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); 3863 { StackValueContext context(this); 3864 VisitForTypeofValue(expr->expression()); 3865 } 3866 __ CallRuntime(Runtime::kTypeof, 1); 3867 context()->Plug(r0); 3868 break; 3869 } 3870 3871 case Token::ADD: { 3872 Comment cmt(masm_, "[ UnaryOperation (ADD)"); 3873 VisitForAccumulatorValue(expr->expression()); 3874 Label no_conversion; 3875 __ JumpIfSmi(result_register(), &no_conversion); 3876 ToNumberStub convert_stub; 3877 __ CallStub(&convert_stub); 3878 __ bind(&no_conversion); 3879 context()->Plug(result_register()); 3880 break; 3881 } 3882 3883 case Token::SUB: 3884 EmitUnaryOperation(expr, "[ UnaryOperation (SUB)"); 3885 break; 3886 3887 case Token::BIT_NOT: 3888 EmitUnaryOperation(expr, "[ UnaryOperation (BIT_NOT)"); 3889 break; 3890 3891 default: 3892 UNREACHABLE(); 3893 } 3894 } 3895 3896 3897 void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr, 3898 const char* comment) { 3899 // TODO(svenpanne): Allowing format strings in Comment would be nice here... 3900 Comment cmt(masm_, comment); 3901 bool can_overwrite = expr->expression()->ResultOverwriteAllowed(); 3902 UnaryOverwriteMode overwrite = 3903 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE; 3904 UnaryOpStub stub(expr->op(), overwrite); 3905 // UnaryOpStub expects the argument to be in the 3906 // accumulator register r0. 3907 VisitForAccumulatorValue(expr->expression()); 3908 SetSourcePosition(expr->position()); 3909 CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); 3910 context()->Plug(r0); 3911 } 3912 3913 3914 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { 3915 Comment cmnt(masm_, "[ CountOperation"); 3916 SetSourcePosition(expr->position()); 3917 3918 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' 3919 // as the left-hand side. 3920 if (!expr->expression()->IsValidLeftHandSide()) { 3921 VisitForEffect(expr->expression()); 3922 return; 3923 } 3924 3925 // Expression can only be a property, a global or a (parameter or local) 3926 // slot. 3927 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; 3928 LhsKind assign_type = VARIABLE; 3929 Property* prop = expr->expression()->AsProperty(); 3930 // In case of a property we use the uninitialized expression context 3931 // of the key to detect a named property. 3932 if (prop != NULL) { 3933 assign_type = 3934 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; 3935 } 3936 3937 // Evaluate expression and get value. 3938 if (assign_type == VARIABLE) { 3939 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); 3940 AccumulatorValueContext context(this); 3941 EmitVariableLoad(expr->expression()->AsVariableProxy()); 3942 } else { 3943 // Reserve space for result of postfix operation. 3944 if (expr->is_postfix() && !context()->IsEffect()) { 3945 __ mov(ip, Operand(Smi::FromInt(0))); 3946 __ push(ip); 3947 } 3948 if (assign_type == NAMED_PROPERTY) { 3949 // Put the object both on the stack and in the accumulator. 3950 VisitForAccumulatorValue(prop->obj()); 3951 __ push(r0); 3952 EmitNamedPropertyLoad(prop); 3953 } else { 3954 VisitForStackValue(prop->obj()); 3955 VisitForAccumulatorValue(prop->key()); 3956 __ ldr(r1, MemOperand(sp, 0)); 3957 __ push(r0); 3958 EmitKeyedPropertyLoad(prop); 3959 } 3960 } 3961 3962 // We need a second deoptimization point after loading the value 3963 // in case evaluating the property load my have a side effect. 3964 if (assign_type == VARIABLE) { 3965 PrepareForBailout(expr->expression(), TOS_REG); 3966 } else { 3967 PrepareForBailoutForId(expr->CountId(), TOS_REG); 3968 } 3969 3970 // Call ToNumber only if operand is not a smi. 3971 Label no_conversion; 3972 __ JumpIfSmi(r0, &no_conversion); 3973 ToNumberStub convert_stub; 3974 __ CallStub(&convert_stub); 3975 __ bind(&no_conversion); 3976 3977 // Save result for postfix expressions. 3978 if (expr->is_postfix()) { 3979 if (!context()->IsEffect()) { 3980 // Save the result on the stack. If we have a named or keyed property 3981 // we store the result under the receiver that is currently on top 3982 // of the stack. 3983 switch (assign_type) { 3984 case VARIABLE: 3985 __ push(r0); 3986 break; 3987 case NAMED_PROPERTY: 3988 __ str(r0, MemOperand(sp, kPointerSize)); 3989 break; 3990 case KEYED_PROPERTY: 3991 __ str(r0, MemOperand(sp, 2 * kPointerSize)); 3992 break; 3993 } 3994 } 3995 } 3996 3997 3998 // Inline smi case if we are in a loop. 3999 Label stub_call, done; 4000 JumpPatchSite patch_site(masm_); 4001 4002 int count_value = expr->op() == Token::INC ? 1 : -1; 4003 if (ShouldInlineSmiCase(expr->op())) { 4004 __ add(r0, r0, Operand(Smi::FromInt(count_value)), SetCC); 4005 __ b(vs, &stub_call); 4006 // We could eliminate this smi check if we split the code at 4007 // the first smi check before calling ToNumber. 4008 patch_site.EmitJumpIfSmi(r0, &done); 4009 4010 __ bind(&stub_call); 4011 // Call stub. Undo operation first. 4012 __ sub(r0, r0, Operand(Smi::FromInt(count_value))); 4013 } 4014 __ mov(r1, Operand(Smi::FromInt(count_value))); 4015 4016 // Record position before stub call. 4017 SetSourcePosition(expr->position()); 4018 4019 BinaryOpStub stub(Token::ADD, NO_OVERWRITE); 4020 CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->CountId()); 4021 patch_site.EmitPatchInfo(); 4022 __ bind(&done); 4023 4024 // Store the value returned in r0. 4025 switch (assign_type) { 4026 case VARIABLE: 4027 if (expr->is_postfix()) { 4028 { EffectContext context(this); 4029 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), 4030 Token::ASSIGN); 4031 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); 4032 context.Plug(r0); 4033 } 4034 // For all contexts except EffectConstant We have the result on 4035 // top of the stack. 4036 if (!context()->IsEffect()) { 4037 context()->PlugTOS(); 4038 } 4039 } else { 4040 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), 4041 Token::ASSIGN); 4042 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); 4043 context()->Plug(r0); 4044 } 4045 break; 4046 case NAMED_PROPERTY: { 4047 __ mov(r2, Operand(prop->key()->AsLiteral()->handle())); 4048 __ pop(r1); 4049 Handle<Code> ic = is_classic_mode() 4050 ? isolate()->builtins()->StoreIC_Initialize() 4051 : isolate()->builtins()->StoreIC_Initialize_Strict(); 4052 CallIC(ic, RelocInfo::CODE_TARGET, expr->id()); 4053 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); 4054 if (expr->is_postfix()) { 4055 if (!context()->IsEffect()) { 4056 context()->PlugTOS(); 4057 } 4058 } else { 4059 context()->Plug(r0); 4060 } 4061 break; 4062 } 4063 case KEYED_PROPERTY: { 4064 __ pop(r1); // Key. 4065 __ pop(r2); // Receiver. 4066 Handle<Code> ic = is_classic_mode() 4067 ? isolate()->builtins()->KeyedStoreIC_Initialize() 4068 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); 4069 CallIC(ic, RelocInfo::CODE_TARGET, expr->id()); 4070 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); 4071 if (expr->is_postfix()) { 4072 if (!context()->IsEffect()) { 4073 context()->PlugTOS(); 4074 } 4075 } else { 4076 context()->Plug(r0); 4077 } 4078 break; 4079 } 4080 } 4081 } 4082 4083 4084 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { 4085 ASSERT(!context()->IsEffect()); 4086 ASSERT(!context()->IsTest()); 4087 VariableProxy* proxy = expr->AsVariableProxy(); 4088 if (proxy != NULL && proxy->var()->IsUnallocated()) { 4089 Comment cmnt(masm_, "Global variable"); 4090 __ ldr(r0, GlobalObjectOperand()); 4091 __ mov(r2, Operand(proxy->name())); 4092 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); 4093 // Use a regular load, not a contextual load, to avoid a reference 4094 // error. 4095 CallIC(ic); 4096 PrepareForBailout(expr, TOS_REG); 4097 context()->Plug(r0); 4098 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { 4099 Label done, slow; 4100 4101 // Generate code for loading from variables potentially shadowed 4102 // by eval-introduced variables. 4103 EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done); 4104 4105 __ bind(&slow); 4106 __ mov(r0, Operand(proxy->name())); 4107 __ Push(cp, r0); 4108 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); 4109 PrepareForBailout(expr, TOS_REG); 4110 __ bind(&done); 4111 4112 context()->Plug(r0); 4113 } else { 4114 // This expression cannot throw a reference error at the top level. 4115 VisitInDuplicateContext(expr); 4116 } 4117 } 4118 4119 4120 void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, 4121 Expression* sub_expr, 4122 Handle<String> check) { 4123 Label materialize_true, materialize_false; 4124 Label* if_true = NULL; 4125 Label* if_false = NULL; 4126 Label* fall_through = NULL; 4127 context()->PrepareTest(&materialize_true, &materialize_false, 4128 &if_true, &if_false, &fall_through); 4129 4130 { AccumulatorValueContext context(this); 4131 VisitForTypeofValue(sub_expr); 4132 } 4133 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); 4134 4135 if (check->Equals(isolate()->heap()->number_symbol())) { 4136 __ JumpIfSmi(r0, if_true); 4137 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset)); 4138 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); 4139 __ cmp(r0, ip); 4140 Split(eq, if_true, if_false, fall_through); 4141 } else if (check->Equals(isolate()->heap()->string_symbol())) { 4142 __ JumpIfSmi(r0, if_false); 4143 // Check for undetectable objects => false. 4144 __ CompareObjectType(r0, r0, r1, FIRST_NONSTRING_TYPE); 4145 __ b(ge, if_false); 4146 __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset)); 4147 __ tst(r1, Operand(1 << Map::kIsUndetectable)); 4148 Split(eq, if_true, if_false, fall_through); 4149 } else if (check->Equals(isolate()->heap()->boolean_symbol())) { 4150 __ CompareRoot(r0, Heap::kTrueValueRootIndex); 4151 __ b(eq, if_true); 4152 __ CompareRoot(r0, Heap::kFalseValueRootIndex); 4153 Split(eq, if_true, if_false, fall_through); 4154 } else if (FLAG_harmony_typeof && 4155 check->Equals(isolate()->heap()->null_symbol())) { 4156 __ CompareRoot(r0, Heap::kNullValueRootIndex); 4157 Split(eq, if_true, if_false, fall_through); 4158 } else if (check->Equals(isolate()->heap()->undefined_symbol())) { 4159 __ CompareRoot(r0, Heap::kUndefinedValueRootIndex); 4160 __ b(eq, if_true); 4161 __ JumpIfSmi(r0, if_false); 4162 // Check for undetectable objects => true. 4163 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset)); 4164 __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset)); 4165 __ tst(r1, Operand(1 << Map::kIsUndetectable)); 4166 Split(ne, if_true, if_false, fall_through); 4167 4168 } else if (check->Equals(isolate()->heap()->function_symbol())) { 4169 __ JumpIfSmi(r0, if_false); 4170 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); 4171 __ CompareObjectType(r0, r0, r1, JS_FUNCTION_TYPE); 4172 __ b(eq, if_true); 4173 __ cmp(r1, Operand(JS_FUNCTION_PROXY_TYPE)); 4174 Split(eq, if_true, if_false, fall_through); 4175 } else if (check->Equals(isolate()->heap()->object_symbol())) { 4176 __ JumpIfSmi(r0, if_false); 4177 if (!FLAG_harmony_typeof) { 4178 __ CompareRoot(r0, Heap::kNullValueRootIndex); 4179 __ b(eq, if_true); 4180 } 4181 // Check for JS objects => true. 4182 __ CompareObjectType(r0, r0, r1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE); 4183 __ b(lt, if_false); 4184 __ CompareInstanceType(r0, r1, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); 4185 __ b(gt, if_false); 4186 // Check for undetectable objects => false. 4187 __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset)); 4188 __ tst(r1, Operand(1 << Map::kIsUndetectable)); 4189 Split(eq, if_true, if_false, fall_through); 4190 } else { 4191 if (if_false != fall_through) __ jmp(if_false); 4192 } 4193 context()->Plug(if_true, if_false); 4194 } 4195 4196 4197 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { 4198 Comment cmnt(masm_, "[ CompareOperation"); 4199 SetSourcePosition(expr->position()); 4200 4201 // First we try a fast inlined version of the compare when one of 4202 // the operands is a literal. 4203 if (TryLiteralCompare(expr)) return; 4204 4205 // Always perform the comparison for its control flow. Pack the result 4206 // into the expression's context after the comparison is performed. 4207 Label materialize_true, materialize_false; 4208 Label* if_true = NULL; 4209 Label* if_false = NULL; 4210 Label* fall_through = NULL; 4211 context()->PrepareTest(&materialize_true, &materialize_false, 4212 &if_true, &if_false, &fall_through); 4213 4214 Token::Value op = expr->op(); 4215 VisitForStackValue(expr->left()); 4216 switch (op) { 4217 case Token::IN: 4218 VisitForStackValue(expr->right()); 4219 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); 4220 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL); 4221 __ LoadRoot(ip, Heap::kTrueValueRootIndex); 4222 __ cmp(r0, ip); 4223 Split(eq, if_true, if_false, fall_through); 4224 break; 4225 4226 case Token::INSTANCEOF: { 4227 VisitForStackValue(expr->right()); 4228 InstanceofStub stub(InstanceofStub::kNoFlags); 4229 __ CallStub(&stub); 4230 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); 4231 // The stub returns 0 for true. 4232 __ tst(r0, r0); 4233 Split(eq, if_true, if_false, fall_through); 4234 break; 4235 } 4236 4237 default: { 4238 VisitForAccumulatorValue(expr->right()); 4239 Condition cond = eq; 4240 switch (op) { 4241 case Token::EQ_STRICT: 4242 case Token::EQ: 4243 cond = eq; 4244 break; 4245 case Token::LT: 4246 cond = lt; 4247 break; 4248 case Token::GT: 4249 cond = gt; 4250 break; 4251 case Token::LTE: 4252 cond = le; 4253 break; 4254 case Token::GTE: 4255 cond = ge; 4256 break; 4257 case Token::IN: 4258 case Token::INSTANCEOF: 4259 default: 4260 UNREACHABLE(); 4261 } 4262 __ pop(r1); 4263 4264 bool inline_smi_code = ShouldInlineSmiCase(op); 4265 JumpPatchSite patch_site(masm_); 4266 if (inline_smi_code) { 4267 Label slow_case; 4268 __ orr(r2, r0, Operand(r1)); 4269 patch_site.EmitJumpIfNotSmi(r2, &slow_case); 4270 __ cmp(r1, r0); 4271 Split(cond, if_true, if_false, NULL); 4272 __ bind(&slow_case); 4273 } 4274 4275 // Record position and call the compare IC. 4276 SetSourcePosition(expr->position()); 4277 Handle<Code> ic = CompareIC::GetUninitialized(op); 4278 CallIC(ic, RelocInfo::CODE_TARGET, expr->id()); 4279 patch_site.EmitPatchInfo(); 4280 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); 4281 __ cmp(r0, Operand(0)); 4282 Split(cond, if_true, if_false, fall_through); 4283 } 4284 } 4285 4286 // Convert the result of the comparison into one expected for this 4287 // expression's context. 4288 context()->Plug(if_true, if_false); 4289 } 4290 4291 4292 void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr, 4293 Expression* sub_expr, 4294 NilValue nil) { 4295 Label materialize_true, materialize_false; 4296 Label* if_true = NULL; 4297 Label* if_false = NULL; 4298 Label* fall_through = NULL; 4299 context()->PrepareTest(&materialize_true, &materialize_false, 4300 &if_true, &if_false, &fall_through); 4301 4302 VisitForAccumulatorValue(sub_expr); 4303 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); 4304 Heap::RootListIndex nil_value = nil == kNullValue ? 4305 Heap::kNullValueRootIndex : 4306 Heap::kUndefinedValueRootIndex; 4307 __ LoadRoot(r1, nil_value); 4308 __ cmp(r0, r1); 4309 if (expr->op() == Token::EQ_STRICT) { 4310 Split(eq, if_true, if_false, fall_through); 4311 } else { 4312 Heap::RootListIndex other_nil_value = nil == kNullValue ? 4313 Heap::kUndefinedValueRootIndex : 4314 Heap::kNullValueRootIndex; 4315 __ b(eq, if_true); 4316 __ LoadRoot(r1, other_nil_value); 4317 __ cmp(r0, r1); 4318 __ b(eq, if_true); 4319 __ JumpIfSmi(r0, if_false); 4320 // It can be an undetectable object. 4321 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); 4322 __ ldrb(r1, FieldMemOperand(r1, Map::kBitFieldOffset)); 4323 __ and_(r1, r1, Operand(1 << Map::kIsUndetectable)); 4324 __ cmp(r1, Operand(1 << Map::kIsUndetectable)); 4325 Split(eq, if_true, if_false, fall_through); 4326 } 4327 context()->Plug(if_true, if_false); 4328 } 4329 4330 4331 void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) { 4332 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 4333 context()->Plug(r0); 4334 } 4335 4336 4337 Register FullCodeGenerator::result_register() { 4338 return r0; 4339 } 4340 4341 4342 Register FullCodeGenerator::context_register() { 4343 return cp; 4344 } 4345 4346 4347 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { 4348 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset); 4349 __ str(value, MemOperand(fp, frame_offset)); 4350 } 4351 4352 4353 void FullCodeGenerator::LoadContextField(Register dst, int context_index) { 4354 __ ldr(dst, ContextOperand(cp, context_index)); 4355 } 4356 4357 4358 void FullCodeGenerator::PushFunctionArgumentForContextAllocation() { 4359 Scope* declaration_scope = scope()->DeclarationScope(); 4360 if (declaration_scope->is_global_scope()) { 4361 // Contexts nested in the global context have a canonical empty function 4362 // as their closure, not the anonymous closure containing the global 4363 // code. Pass a smi sentinel and let the runtime look up the empty 4364 // function. 4365 __ mov(ip, Operand(Smi::FromInt(0))); 4366 } else if (declaration_scope->is_eval_scope()) { 4367 // Contexts created by a call to eval have the same closure as the 4368 // context calling eval, not the anonymous closure containing the eval 4369 // code. Fetch it from the context. 4370 __ ldr(ip, ContextOperand(cp, Context::CLOSURE_INDEX)); 4371 } else { 4372 ASSERT(declaration_scope->is_function_scope()); 4373 __ ldr(ip, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 4374 } 4375 __ push(ip); 4376 } 4377 4378 4379 // ---------------------------------------------------------------------------- 4380 // Non-local control flow support. 4381 4382 void FullCodeGenerator::EnterFinallyBlock() { 4383 ASSERT(!result_register().is(r1)); 4384 // Store result register while executing finally block. 4385 __ push(result_register()); 4386 // Cook return address in link register to stack (smi encoded Code* delta) 4387 __ sub(r1, lr, Operand(masm_->CodeObject())); 4388 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); 4389 STATIC_ASSERT(kSmiTag == 0); 4390 __ add(r1, r1, Operand(r1)); // Convert to smi. 4391 __ push(r1); 4392 } 4393 4394 4395 void FullCodeGenerator::ExitFinallyBlock() { 4396 ASSERT(!result_register().is(r1)); 4397 // Restore result register from stack. 4398 __ pop(r1); 4399 // Uncook return address and return. 4400 __ pop(result_register()); 4401 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); 4402 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value. 4403 __ add(pc, r1, Operand(masm_->CodeObject())); 4404 } 4405 4406 4407 #undef __ 4408 4409 #define __ ACCESS_MASM(masm()) 4410 4411 FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit( 4412 int* stack_depth, 4413 int* context_length) { 4414 // The macros used here must preserve the result register. 4415 4416 // Because the handler block contains the context of the finally 4417 // code, we can restore it directly from there for the finally code 4418 // rather than iteratively unwinding contexts via their previous 4419 // links. 4420 __ Drop(*stack_depth); // Down to the handler block. 4421 if (*context_length > 0) { 4422 // Restore the context to its dedicated register and the stack. 4423 __ ldr(cp, MemOperand(sp, StackHandlerConstants::kContextOffset)); 4424 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); 4425 } 4426 __ PopTryHandler(); 4427 __ bl(finally_entry_); 4428 4429 *stack_depth = 0; 4430 *context_length = 0; 4431 return previous_; 4432 } 4433 4434 4435 #undef __ 4436 4437 } } // namespace v8::internal 4438 4439 #endif // V8_TARGET_ARCH_ARM 4440