1 // Copyright 2014 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #if V8_TARGET_ARCH_PPC 6 7 #include "src/ast/scopes.h" 8 #include "src/code-factory.h" 9 #include "src/code-stubs.h" 10 #include "src/codegen.h" 11 #include "src/debug/debug.h" 12 #include "src/full-codegen/full-codegen.h" 13 #include "src/ic/ic.h" 14 #include "src/parsing/parser.h" 15 16 #include "src/ppc/code-stubs-ppc.h" 17 #include "src/ppc/macro-assembler-ppc.h" 18 19 namespace v8 { 20 namespace internal { 21 22 #define __ ACCESS_MASM(masm_) 23 24 // A patch site is a location in the code which it is possible to patch. This 25 // class has a number of methods to emit the code which is patchable and the 26 // method EmitPatchInfo to record a marker back to the patchable code. This 27 // marker is a cmpi rx, #yyy instruction, and x * 0x0000ffff + yyy (raw 16 bit 28 // immediate value is used) is the delta from the pc to the first instruction of 29 // the patchable code. 30 // See PatchInlinedSmiCode in ic-ppc.cc for the code that patches it 31 class JumpPatchSite BASE_EMBEDDED { 32 public: 33 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) { 34 #ifdef DEBUG 35 info_emitted_ = false; 36 #endif 37 } 38 39 ~JumpPatchSite() { DCHECK(patch_site_.is_bound() == info_emitted_); } 40 41 // When initially emitting this ensure that a jump is always generated to skip 42 // the inlined smi code. 43 void EmitJumpIfNotSmi(Register reg, Label* target) { 44 DCHECK(!patch_site_.is_bound() && !info_emitted_); 45 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); 46 __ bind(&patch_site_); 47 __ cmp(reg, reg, cr0); 48 __ beq(target, cr0); // Always taken before patched. 49 } 50 51 // When initially emitting this ensure that a jump is never generated to skip 52 // the inlined smi code. 53 void EmitJumpIfSmi(Register reg, Label* target) { 54 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); 55 DCHECK(!patch_site_.is_bound() && !info_emitted_); 56 __ bind(&patch_site_); 57 __ cmp(reg, reg, cr0); 58 __ bne(target, cr0); // Never taken before patched. 59 } 60 61 void EmitPatchInfo() { 62 if (patch_site_.is_bound()) { 63 int delta_to_patch_site = masm_->InstructionsGeneratedSince(&patch_site_); 64 Register reg; 65 // I believe this is using reg as the high bits of of the offset 66 reg.set_code(delta_to_patch_site / kOff16Mask); 67 __ cmpi(reg, Operand(delta_to_patch_site % kOff16Mask)); 68 #ifdef DEBUG 69 info_emitted_ = true; 70 #endif 71 } else { 72 __ nop(); // Signals no inlined code. 73 } 74 } 75 76 private: 77 MacroAssembler* masm_; 78 Label patch_site_; 79 #ifdef DEBUG 80 bool info_emitted_; 81 #endif 82 }; 83 84 85 // Generate code for a JS function. On entry to the function the receiver 86 // and arguments have been pushed on the stack left to right. The actual 87 // argument count matches the formal parameter count expected by the 88 // function. 89 // 90 // The live registers are: 91 // o r4: the JS function object being called (i.e., ourselves) 92 // o r6: the new target value 93 // o cp: our context 94 // o fp: our caller's frame pointer (aka r31) 95 // o sp: stack pointer 96 // o lr: return address 97 // o ip: our own function entry (required by the prologue) 98 // 99 // The function builds a JS frame. Please see JavaScriptFrameConstants in 100 // frames-ppc.h for its layout. 101 void FullCodeGenerator::Generate() { 102 CompilationInfo* info = info_; 103 profiling_counter_ = isolate()->factory()->NewCell( 104 Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate())); 105 SetFunctionPosition(literal()); 106 Comment cmnt(masm_, "[ function compiled by full code generator"); 107 108 ProfileEntryHookStub::MaybeCallEntryHook(masm_); 109 110 #ifdef DEBUG 111 if (strlen(FLAG_stop_at) > 0 && 112 info->literal()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { 113 __ stop("stop-at"); 114 } 115 #endif 116 117 if (FLAG_debug_code && info->ExpectsJSReceiverAsReceiver()) { 118 int receiver_offset = info->scope()->num_parameters() * kPointerSize; 119 __ LoadP(r5, MemOperand(sp, receiver_offset), r0); 120 __ AssertNotSmi(r5); 121 __ CompareObjectType(r5, r5, no_reg, FIRST_JS_RECEIVER_TYPE); 122 __ Assert(ge, kSloppyFunctionExpectsJSReceiverReceiver); 123 } 124 125 // Open a frame scope to indicate that there is a frame on the stack. The 126 // MANUAL indicates that the scope shouldn't actually generate code to set up 127 // the frame (that is done below). 128 FrameScope frame_scope(masm_, StackFrame::MANUAL); 129 int prologue_offset = masm_->pc_offset(); 130 131 if (prologue_offset) { 132 // Prologue logic requires it's starting address in ip and the 133 // corresponding offset from the function entry. 134 prologue_offset += Instruction::kInstrSize; 135 __ addi(ip, ip, Operand(prologue_offset)); 136 } 137 info->set_prologue_offset(prologue_offset); 138 __ Prologue(info->GeneratePreagedPrologue(), ip, prologue_offset); 139 140 { 141 Comment cmnt(masm_, "[ Allocate locals"); 142 int locals_count = info->scope()->num_stack_slots(); 143 // Generators allocate locals, if any, in context slots. 144 DCHECK(!IsGeneratorFunction(info->literal()->kind()) || locals_count == 0); 145 if (locals_count > 0) { 146 if (locals_count >= 128) { 147 Label ok; 148 __ Add(ip, sp, -(locals_count * kPointerSize), r0); 149 __ LoadRoot(r5, Heap::kRealStackLimitRootIndex); 150 __ cmpl(ip, r5); 151 __ bc_short(ge, &ok); 152 __ CallRuntime(Runtime::kThrowStackOverflow); 153 __ bind(&ok); 154 } 155 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); 156 int kMaxPushes = FLAG_optimize_for_size ? 4 : 32; 157 if (locals_count >= kMaxPushes) { 158 int loop_iterations = locals_count / kMaxPushes; 159 __ mov(r5, Operand(loop_iterations)); 160 __ mtctr(r5); 161 Label loop_header; 162 __ bind(&loop_header); 163 // Do pushes. 164 for (int i = 0; i < kMaxPushes; i++) { 165 __ push(ip); 166 } 167 // Continue loop if not done. 168 __ bdnz(&loop_header); 169 } 170 int remaining = locals_count % kMaxPushes; 171 // Emit the remaining pushes. 172 for (int i = 0; i < remaining; i++) { 173 __ push(ip); 174 } 175 } 176 } 177 178 bool function_in_register_r4 = true; 179 180 // Possibly allocate a local context. 181 if (info->scope()->num_heap_slots() > 0) { 182 // Argument to NewContext is the function, which is still in r4. 183 Comment cmnt(masm_, "[ Allocate context"); 184 bool need_write_barrier = true; 185 int slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; 186 if (info->scope()->is_script_scope()) { 187 __ push(r4); 188 __ Push(info->scope()->GetScopeInfo(info->isolate())); 189 __ CallRuntime(Runtime::kNewScriptContext); 190 PrepareForBailoutForId(BailoutId::ScriptContext(), TOS_REG); 191 // The new target value is not used, clobbering is safe. 192 DCHECK_NULL(info->scope()->new_target_var()); 193 } else { 194 if (info->scope()->new_target_var() != nullptr) { 195 __ push(r6); // Preserve new target. 196 } 197 if (slots <= FastNewContextStub::kMaximumSlots) { 198 FastNewContextStub stub(isolate(), slots); 199 __ CallStub(&stub); 200 // Result of FastNewContextStub is always in new space. 201 need_write_barrier = false; 202 } else { 203 __ push(r4); 204 __ CallRuntime(Runtime::kNewFunctionContext); 205 } 206 if (info->scope()->new_target_var() != nullptr) { 207 __ pop(r6); // Preserve new target. 208 } 209 } 210 function_in_register_r4 = false; 211 // Context is returned in r3. It replaces the context passed to us. 212 // It's saved in the stack and kept live in cp. 213 __ mr(cp, r3); 214 __ StoreP(r3, MemOperand(fp, StandardFrameConstants::kContextOffset)); 215 // Copy any necessary parameters into the context. 216 int num_parameters = info->scope()->num_parameters(); 217 int first_parameter = info->scope()->has_this_declaration() ? -1 : 0; 218 for (int i = first_parameter; i < num_parameters; i++) { 219 Variable* var = (i == -1) ? scope()->receiver() : scope()->parameter(i); 220 if (var->IsContextSlot()) { 221 int parameter_offset = StandardFrameConstants::kCallerSPOffset + 222 (num_parameters - 1 - i) * kPointerSize; 223 // Load parameter from stack. 224 __ LoadP(r3, MemOperand(fp, parameter_offset), r0); 225 // Store it in the context. 226 MemOperand target = ContextMemOperand(cp, var->index()); 227 __ StoreP(r3, target, r0); 228 229 // Update the write barrier. 230 if (need_write_barrier) { 231 __ RecordWriteContextSlot(cp, target.offset(), r3, r5, 232 kLRHasBeenSaved, kDontSaveFPRegs); 233 } else if (FLAG_debug_code) { 234 Label done; 235 __ JumpIfInNewSpace(cp, r3, &done); 236 __ Abort(kExpectedNewSpaceObject); 237 __ bind(&done); 238 } 239 } 240 } 241 } 242 243 // Register holding this function and new target are both trashed in case we 244 // bailout here. But since that can happen only when new target is not used 245 // and we allocate a context, the value of |function_in_register| is correct. 246 PrepareForBailoutForId(BailoutId::FunctionContext(), NO_REGISTERS); 247 248 // Possibly set up a local binding to the this function which is used in 249 // derived constructors with super calls. 250 Variable* this_function_var = scope()->this_function_var(); 251 if (this_function_var != nullptr) { 252 Comment cmnt(masm_, "[ This function"); 253 if (!function_in_register_r4) { 254 __ LoadP(r4, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 255 // The write barrier clobbers register again, keep it marked as such. 256 } 257 SetVar(this_function_var, r4, r3, r5); 258 } 259 260 // Possibly set up a local binding to the new target value. 261 Variable* new_target_var = scope()->new_target_var(); 262 if (new_target_var != nullptr) { 263 Comment cmnt(masm_, "[ new.target"); 264 SetVar(new_target_var, r6, r3, r5); 265 } 266 267 // Possibly allocate RestParameters 268 int rest_index; 269 Variable* rest_param = scope()->rest_parameter(&rest_index); 270 if (rest_param) { 271 Comment cmnt(masm_, "[ Allocate rest parameter array"); 272 273 int num_parameters = info->scope()->num_parameters(); 274 int offset = num_parameters * kPointerSize; 275 276 __ LoadSmiLiteral(RestParamAccessDescriptor::parameter_count(), 277 Smi::FromInt(num_parameters)); 278 __ addi(RestParamAccessDescriptor::parameter_pointer(), fp, 279 Operand(StandardFrameConstants::kCallerSPOffset + offset)); 280 __ LoadSmiLiteral(RestParamAccessDescriptor::rest_parameter_index(), 281 Smi::FromInt(rest_index)); 282 function_in_register_r4 = false; 283 284 RestParamAccessStub stub(isolate()); 285 __ CallStub(&stub); 286 287 SetVar(rest_param, r3, r4, r5); 288 } 289 290 Variable* arguments = scope()->arguments(); 291 if (arguments != NULL) { 292 // Function uses arguments object. 293 Comment cmnt(masm_, "[ Allocate arguments object"); 294 DCHECK(r4.is(ArgumentsAccessNewDescriptor::function())); 295 if (!function_in_register_r4) { 296 // Load this again, if it's used by the local context below. 297 __ LoadP(r4, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 298 } 299 // Receiver is just before the parameters on the caller's stack. 300 int num_parameters = info->scope()->num_parameters(); 301 int offset = num_parameters * kPointerSize; 302 __ LoadSmiLiteral(ArgumentsAccessNewDescriptor::parameter_count(), 303 Smi::FromInt(num_parameters)); 304 __ addi(ArgumentsAccessNewDescriptor::parameter_pointer(), fp, 305 Operand(StandardFrameConstants::kCallerSPOffset + offset)); 306 307 // Arguments to ArgumentsAccessStub: 308 // function, parameter pointer, parameter count. 309 // The stub will rewrite parameter pointer and parameter count if the 310 // previous stack frame was an arguments adapter frame. 311 bool is_unmapped = is_strict(language_mode()) || !has_simple_parameters(); 312 ArgumentsAccessStub::Type type = ArgumentsAccessStub::ComputeType( 313 is_unmapped, literal()->has_duplicate_parameters()); 314 ArgumentsAccessStub stub(isolate(), type); 315 __ CallStub(&stub); 316 317 SetVar(arguments, r3, r4, r5); 318 } 319 320 if (FLAG_trace) { 321 __ CallRuntime(Runtime::kTraceEnter); 322 } 323 324 // Visit the declarations and body unless there is an illegal 325 // redeclaration. 326 if (scope()->HasIllegalRedeclaration()) { 327 Comment cmnt(masm_, "[ Declarations"); 328 VisitForEffect(scope()->GetIllegalRedeclaration()); 329 330 } else { 331 PrepareForBailoutForId(BailoutId::FunctionEntry(), NO_REGISTERS); 332 { 333 Comment cmnt(masm_, "[ Declarations"); 334 VisitDeclarations(scope()->declarations()); 335 } 336 337 // Assert that the declarations do not use ICs. Otherwise the debugger 338 // won't be able to redirect a PC at an IC to the correct IC in newly 339 // recompiled code. 340 DCHECK_EQ(0, ic_total_count_); 341 342 { 343 Comment cmnt(masm_, "[ Stack check"); 344 PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS); 345 Label ok; 346 __ LoadRoot(ip, Heap::kStackLimitRootIndex); 347 __ cmpl(sp, ip); 348 __ bc_short(ge, &ok); 349 __ Call(isolate()->builtins()->StackCheck(), RelocInfo::CODE_TARGET); 350 __ bind(&ok); 351 } 352 353 { 354 Comment cmnt(masm_, "[ Body"); 355 DCHECK(loop_depth() == 0); 356 VisitStatements(literal()->body()); 357 DCHECK(loop_depth() == 0); 358 } 359 } 360 361 // Always emit a 'return undefined' in case control fell off the end of 362 // the body. 363 { 364 Comment cmnt(masm_, "[ return <undefined>;"); 365 __ LoadRoot(r3, Heap::kUndefinedValueRootIndex); 366 } 367 EmitReturnSequence(); 368 369 if (HasStackOverflow()) { 370 masm_->AbortConstantPoolBuilding(); 371 } 372 } 373 374 375 void FullCodeGenerator::ClearAccumulator() { 376 __ LoadSmiLiteral(r3, Smi::FromInt(0)); 377 } 378 379 380 void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) { 381 __ mov(r5, Operand(profiling_counter_)); 382 __ LoadP(r6, FieldMemOperand(r5, Cell::kValueOffset)); 383 __ SubSmiLiteral(r6, r6, Smi::FromInt(delta), r0); 384 __ StoreP(r6, FieldMemOperand(r5, Cell::kValueOffset), r0); 385 } 386 387 388 void FullCodeGenerator::EmitProfilingCounterReset() { 389 int reset_value = FLAG_interrupt_budget; 390 __ mov(r5, Operand(profiling_counter_)); 391 __ LoadSmiLiteral(r6, Smi::FromInt(reset_value)); 392 __ StoreP(r6, FieldMemOperand(r5, Cell::kValueOffset), r0); 393 } 394 395 396 void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt, 397 Label* back_edge_target) { 398 Comment cmnt(masm_, "[ Back edge bookkeeping"); 399 Label ok; 400 401 DCHECK(back_edge_target->is_bound()); 402 int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target) + 403 kCodeSizeMultiplier / 2; 404 int weight = Min(kMaxBackEdgeWeight, Max(1, distance / kCodeSizeMultiplier)); 405 EmitProfilingCounterDecrement(weight); 406 { 407 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); 408 Assembler::BlockConstantPoolEntrySharingScope prevent_entry_sharing(masm_); 409 // BackEdgeTable::PatchAt manipulates this sequence. 410 __ cmpi(r6, Operand::Zero()); 411 __ bc_short(ge, &ok); 412 __ Call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET); 413 414 // Record a mapping of this PC offset to the OSR id. This is used to find 415 // the AST id from the unoptimized code in order to use it as a key into 416 // the deoptimization input data found in the optimized code. 417 RecordBackEdge(stmt->OsrEntryId()); 418 } 419 EmitProfilingCounterReset(); 420 421 __ bind(&ok); 422 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); 423 // Record a mapping of the OSR id to this PC. This is used if the OSR 424 // entry becomes the target of a bailout. We don't expect it to be, but 425 // we want it to work if it is. 426 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS); 427 } 428 429 430 void FullCodeGenerator::EmitReturnSequence() { 431 Comment cmnt(masm_, "[ Return sequence"); 432 if (return_label_.is_bound()) { 433 __ b(&return_label_); 434 } else { 435 __ bind(&return_label_); 436 if (FLAG_trace) { 437 // Push the return value on the stack as the parameter. 438 // Runtime::TraceExit returns its parameter in r3 439 __ push(r3); 440 __ CallRuntime(Runtime::kTraceExit); 441 } 442 // Pretend that the exit is a backwards jump to the entry. 443 int weight = 1; 444 if (info_->ShouldSelfOptimize()) { 445 weight = FLAG_interrupt_budget / FLAG_self_opt_count; 446 } else { 447 int distance = masm_->pc_offset() + kCodeSizeMultiplier / 2; 448 weight = Min(kMaxBackEdgeWeight, Max(1, distance / kCodeSizeMultiplier)); 449 } 450 EmitProfilingCounterDecrement(weight); 451 Label ok; 452 __ cmpi(r6, Operand::Zero()); 453 __ bge(&ok); 454 __ push(r3); 455 __ Call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET); 456 __ pop(r3); 457 EmitProfilingCounterReset(); 458 __ bind(&ok); 459 460 // Make sure that the constant pool is not emitted inside of the return 461 // sequence. 462 { 463 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); 464 int32_t arg_count = info_->scope()->num_parameters() + 1; 465 int32_t sp_delta = arg_count * kPointerSize; 466 SetReturnPosition(literal()); 467 __ LeaveFrame(StackFrame::JAVA_SCRIPT, sp_delta); 468 __ blr(); 469 } 470 } 471 } 472 473 474 void FullCodeGenerator::StackValueContext::Plug(Variable* var) const { 475 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); 476 codegen()->GetVar(result_register(), var); 477 __ push(result_register()); 478 } 479 480 481 void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {} 482 483 484 void FullCodeGenerator::AccumulatorValueContext::Plug( 485 Heap::RootListIndex index) const { 486 __ LoadRoot(result_register(), index); 487 } 488 489 490 void FullCodeGenerator::StackValueContext::Plug( 491 Heap::RootListIndex index) const { 492 __ LoadRoot(result_register(), index); 493 __ push(result_register()); 494 } 495 496 497 void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const { 498 codegen()->PrepareForBailoutBeforeSplit(condition(), true, true_label_, 499 false_label_); 500 if (index == Heap::kUndefinedValueRootIndex || 501 index == Heap::kNullValueRootIndex || 502 index == Heap::kFalseValueRootIndex) { 503 if (false_label_ != fall_through_) __ b(false_label_); 504 } else if (index == Heap::kTrueValueRootIndex) { 505 if (true_label_ != fall_through_) __ b(true_label_); 506 } else { 507 __ LoadRoot(result_register(), index); 508 codegen()->DoTest(this); 509 } 510 } 511 512 513 void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {} 514 515 516 void FullCodeGenerator::AccumulatorValueContext::Plug( 517 Handle<Object> lit) const { 518 __ mov(result_register(), Operand(lit)); 519 } 520 521 522 void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const { 523 // Immediates cannot be pushed directly. 524 __ mov(result_register(), Operand(lit)); 525 __ push(result_register()); 526 } 527 528 529 void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const { 530 codegen()->PrepareForBailoutBeforeSplit(condition(), true, true_label_, 531 false_label_); 532 DCHECK(!lit->IsUndetectableObject()); // There are no undetectable literals. 533 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) { 534 if (false_label_ != fall_through_) __ b(false_label_); 535 } else if (lit->IsTrue() || lit->IsJSObject()) { 536 if (true_label_ != fall_through_) __ b(true_label_); 537 } else if (lit->IsString()) { 538 if (String::cast(*lit)->length() == 0) { 539 if (false_label_ != fall_through_) __ b(false_label_); 540 } else { 541 if (true_label_ != fall_through_) __ b(true_label_); 542 } 543 } else if (lit->IsSmi()) { 544 if (Smi::cast(*lit)->value() == 0) { 545 if (false_label_ != fall_through_) __ b(false_label_); 546 } else { 547 if (true_label_ != fall_through_) __ b(true_label_); 548 } 549 } else { 550 // For simplicity we always test the accumulator register. 551 __ mov(result_register(), Operand(lit)); 552 codegen()->DoTest(this); 553 } 554 } 555 556 557 void FullCodeGenerator::EffectContext::DropAndPlug(int count, 558 Register reg) const { 559 DCHECK(count > 0); 560 __ Drop(count); 561 } 562 563 564 void FullCodeGenerator::AccumulatorValueContext::DropAndPlug( 565 int count, Register reg) const { 566 DCHECK(count > 0); 567 __ Drop(count); 568 __ Move(result_register(), reg); 569 } 570 571 572 void FullCodeGenerator::StackValueContext::DropAndPlug(int count, 573 Register reg) const { 574 DCHECK(count > 0); 575 if (count > 1) __ Drop(count - 1); 576 __ StoreP(reg, MemOperand(sp, 0)); 577 } 578 579 580 void FullCodeGenerator::TestContext::DropAndPlug(int count, 581 Register reg) const { 582 DCHECK(count > 0); 583 // For simplicity we always test the accumulator register. 584 __ Drop(count); 585 __ Move(result_register(), reg); 586 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL); 587 codegen()->DoTest(this); 588 } 589 590 591 void FullCodeGenerator::EffectContext::Plug(Label* materialize_true, 592 Label* materialize_false) const { 593 DCHECK(materialize_true == materialize_false); 594 __ bind(materialize_true); 595 } 596 597 598 void FullCodeGenerator::AccumulatorValueContext::Plug( 599 Label* materialize_true, Label* materialize_false) const { 600 Label done; 601 __ bind(materialize_true); 602 __ LoadRoot(result_register(), Heap::kTrueValueRootIndex); 603 __ b(&done); 604 __ bind(materialize_false); 605 __ LoadRoot(result_register(), Heap::kFalseValueRootIndex); 606 __ bind(&done); 607 } 608 609 610 void FullCodeGenerator::StackValueContext::Plug( 611 Label* materialize_true, Label* materialize_false) const { 612 Label done; 613 __ bind(materialize_true); 614 __ LoadRoot(ip, Heap::kTrueValueRootIndex); 615 __ b(&done); 616 __ bind(materialize_false); 617 __ LoadRoot(ip, Heap::kFalseValueRootIndex); 618 __ bind(&done); 619 __ push(ip); 620 } 621 622 623 void FullCodeGenerator::TestContext::Plug(Label* materialize_true, 624 Label* materialize_false) const { 625 DCHECK(materialize_true == true_label_); 626 DCHECK(materialize_false == false_label_); 627 } 628 629 630 void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const { 631 Heap::RootListIndex value_root_index = 632 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex; 633 __ LoadRoot(result_register(), value_root_index); 634 } 635 636 637 void FullCodeGenerator::StackValueContext::Plug(bool flag) const { 638 Heap::RootListIndex value_root_index = 639 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex; 640 __ LoadRoot(ip, value_root_index); 641 __ push(ip); 642 } 643 644 645 void FullCodeGenerator::TestContext::Plug(bool flag) const { 646 codegen()->PrepareForBailoutBeforeSplit(condition(), true, true_label_, 647 false_label_); 648 if (flag) { 649 if (true_label_ != fall_through_) __ b(true_label_); 650 } else { 651 if (false_label_ != fall_through_) __ b(false_label_); 652 } 653 } 654 655 656 void FullCodeGenerator::DoTest(Expression* condition, Label* if_true, 657 Label* if_false, Label* fall_through) { 658 Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate()); 659 CallIC(ic, condition->test_id()); 660 __ CompareRoot(result_register(), Heap::kTrueValueRootIndex); 661 Split(eq, if_true, if_false, fall_through); 662 } 663 664 665 void FullCodeGenerator::Split(Condition cond, Label* if_true, Label* if_false, 666 Label* fall_through, CRegister cr) { 667 if (if_false == fall_through) { 668 __ b(cond, if_true, cr); 669 } else if (if_true == fall_through) { 670 __ b(NegateCondition(cond), if_false, cr); 671 } else { 672 __ b(cond, if_true, cr); 673 __ b(if_false); 674 } 675 } 676 677 678 MemOperand FullCodeGenerator::StackOperand(Variable* var) { 679 DCHECK(var->IsStackAllocated()); 680 // Offset is negative because higher indexes are at lower addresses. 681 int offset = -var->index() * kPointerSize; 682 // Adjust by a (parameter or local) base offset. 683 if (var->IsParameter()) { 684 offset += (info_->scope()->num_parameters() + 1) * kPointerSize; 685 } else { 686 offset += JavaScriptFrameConstants::kLocal0Offset; 687 } 688 return MemOperand(fp, offset); 689 } 690 691 692 MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) { 693 DCHECK(var->IsContextSlot() || var->IsStackAllocated()); 694 if (var->IsContextSlot()) { 695 int context_chain_length = scope()->ContextChainLength(var->scope()); 696 __ LoadContext(scratch, context_chain_length); 697 return ContextMemOperand(scratch, var->index()); 698 } else { 699 return StackOperand(var); 700 } 701 } 702 703 704 void FullCodeGenerator::GetVar(Register dest, Variable* var) { 705 // Use destination as scratch. 706 MemOperand location = VarOperand(var, dest); 707 __ LoadP(dest, location, r0); 708 } 709 710 711 void FullCodeGenerator::SetVar(Variable* var, Register src, Register scratch0, 712 Register scratch1) { 713 DCHECK(var->IsContextSlot() || var->IsStackAllocated()); 714 DCHECK(!scratch0.is(src)); 715 DCHECK(!scratch0.is(scratch1)); 716 DCHECK(!scratch1.is(src)); 717 MemOperand location = VarOperand(var, scratch0); 718 __ StoreP(src, location, r0); 719 720 // Emit the write barrier code if the location is in the heap. 721 if (var->IsContextSlot()) { 722 __ RecordWriteContextSlot(scratch0, location.offset(), src, scratch1, 723 kLRHasBeenSaved, kDontSaveFPRegs); 724 } 725 } 726 727 728 void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr, 729 bool should_normalize, 730 Label* if_true, 731 Label* if_false) { 732 // Only prepare for bailouts before splits if we're in a test 733 // context. Otherwise, we let the Visit function deal with the 734 // preparation to avoid preparing with the same AST id twice. 735 if (!context()->IsTest()) return; 736 737 Label skip; 738 if (should_normalize) __ b(&skip); 739 PrepareForBailout(expr, TOS_REG); 740 if (should_normalize) { 741 __ LoadRoot(ip, Heap::kTrueValueRootIndex); 742 __ cmp(r3, ip); 743 Split(eq, if_true, if_false, NULL); 744 __ bind(&skip); 745 } 746 } 747 748 749 void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) { 750 // The variable in the declaration always resides in the current function 751 // context. 752 DCHECK_EQ(0, scope()->ContextChainLength(variable->scope())); 753 if (generate_debug_code_) { 754 // Check that we're not inside a with or catch context. 755 __ LoadP(r4, FieldMemOperand(cp, HeapObject::kMapOffset)); 756 __ CompareRoot(r4, Heap::kWithContextMapRootIndex); 757 __ Check(ne, kDeclarationInWithContext); 758 __ CompareRoot(r4, Heap::kCatchContextMapRootIndex); 759 __ Check(ne, kDeclarationInCatchContext); 760 } 761 } 762 763 764 void FullCodeGenerator::VisitVariableDeclaration( 765 VariableDeclaration* declaration) { 766 // If it was not possible to allocate the variable at compile time, we 767 // need to "declare" it at runtime to make sure it actually exists in the 768 // local context. 769 VariableProxy* proxy = declaration->proxy(); 770 VariableMode mode = declaration->mode(); 771 Variable* variable = proxy->var(); 772 bool hole_init = mode == LET || mode == CONST || mode == CONST_LEGACY; 773 switch (variable->location()) { 774 case VariableLocation::GLOBAL: 775 case VariableLocation::UNALLOCATED: 776 globals_->Add(variable->name(), zone()); 777 globals_->Add(variable->binding_needs_init() 778 ? isolate()->factory()->the_hole_value() 779 : isolate()->factory()->undefined_value(), 780 zone()); 781 break; 782 783 case VariableLocation::PARAMETER: 784 case VariableLocation::LOCAL: 785 if (hole_init) { 786 Comment cmnt(masm_, "[ VariableDeclaration"); 787 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); 788 __ StoreP(ip, StackOperand(variable)); 789 } 790 break; 791 792 case VariableLocation::CONTEXT: 793 if (hole_init) { 794 Comment cmnt(masm_, "[ VariableDeclaration"); 795 EmitDebugCheckDeclarationContext(variable); 796 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); 797 __ StoreP(ip, ContextMemOperand(cp, variable->index()), r0); 798 // No write barrier since the_hole_value is in old space. 799 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); 800 } 801 break; 802 803 case VariableLocation::LOOKUP: { 804 Comment cmnt(masm_, "[ VariableDeclaration"); 805 __ mov(r5, Operand(variable->name())); 806 // Declaration nodes are always introduced in one of four modes. 807 DCHECK(IsDeclaredVariableMode(mode)); 808 // Push initial value, if any. 809 // Note: For variables we must not push an initial value (such as 810 // 'undefined') because we may have a (legal) redeclaration and we 811 // must not destroy the current value. 812 if (hole_init) { 813 __ LoadRoot(r3, Heap::kTheHoleValueRootIndex); 814 } else { 815 __ LoadSmiLiteral(r3, Smi::FromInt(0)); // Indicates no initial value. 816 } 817 __ Push(r5, r3); 818 __ Push(Smi::FromInt(variable->DeclarationPropertyAttributes())); 819 __ CallRuntime(Runtime::kDeclareLookupSlot); 820 break; 821 } 822 } 823 } 824 825 826 void FullCodeGenerator::VisitFunctionDeclaration( 827 FunctionDeclaration* declaration) { 828 VariableProxy* proxy = declaration->proxy(); 829 Variable* variable = proxy->var(); 830 switch (variable->location()) { 831 case VariableLocation::GLOBAL: 832 case VariableLocation::UNALLOCATED: { 833 globals_->Add(variable->name(), zone()); 834 Handle<SharedFunctionInfo> function = 835 Compiler::GetSharedFunctionInfo(declaration->fun(), script(), info_); 836 // Check for stack-overflow exception. 837 if (function.is_null()) return SetStackOverflow(); 838 globals_->Add(function, zone()); 839 break; 840 } 841 842 case VariableLocation::PARAMETER: 843 case VariableLocation::LOCAL: { 844 Comment cmnt(masm_, "[ FunctionDeclaration"); 845 VisitForAccumulatorValue(declaration->fun()); 846 __ StoreP(result_register(), StackOperand(variable)); 847 break; 848 } 849 850 case VariableLocation::CONTEXT: { 851 Comment cmnt(masm_, "[ FunctionDeclaration"); 852 EmitDebugCheckDeclarationContext(variable); 853 VisitForAccumulatorValue(declaration->fun()); 854 __ StoreP(result_register(), ContextMemOperand(cp, variable->index()), 855 r0); 856 int offset = Context::SlotOffset(variable->index()); 857 // We know that we have written a function, which is not a smi. 858 __ RecordWriteContextSlot(cp, offset, result_register(), r5, 859 kLRHasBeenSaved, kDontSaveFPRegs, 860 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); 861 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); 862 break; 863 } 864 865 case VariableLocation::LOOKUP: { 866 Comment cmnt(masm_, "[ FunctionDeclaration"); 867 __ mov(r5, Operand(variable->name())); 868 __ Push(r5); 869 // Push initial value for function declaration. 870 VisitForStackValue(declaration->fun()); 871 __ Push(Smi::FromInt(variable->DeclarationPropertyAttributes())); 872 __ CallRuntime(Runtime::kDeclareLookupSlot); 873 break; 874 } 875 } 876 } 877 878 879 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { 880 // Call the runtime to declare the globals. 881 __ mov(r4, Operand(pairs)); 882 __ LoadSmiLiteral(r3, Smi::FromInt(DeclareGlobalsFlags())); 883 __ Push(r4, r3); 884 __ CallRuntime(Runtime::kDeclareGlobals); 885 // Return value is ignored. 886 } 887 888 889 void FullCodeGenerator::DeclareModules(Handle<FixedArray> descriptions) { 890 // Call the runtime to declare the modules. 891 __ Push(descriptions); 892 __ CallRuntime(Runtime::kDeclareModules); 893 // Return value is ignored. 894 } 895 896 897 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { 898 Comment cmnt(masm_, "[ SwitchStatement"); 899 Breakable nested_statement(this, stmt); 900 SetStatementPosition(stmt); 901 902 // Keep the switch value on the stack until a case matches. 903 VisitForStackValue(stmt->tag()); 904 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); 905 906 ZoneList<CaseClause*>* clauses = stmt->cases(); 907 CaseClause* default_clause = NULL; // Can occur anywhere in the list. 908 909 Label next_test; // Recycled for each test. 910 // Compile all the tests with branches to their bodies. 911 for (int i = 0; i < clauses->length(); i++) { 912 CaseClause* clause = clauses->at(i); 913 clause->body_target()->Unuse(); 914 915 // The default is not a test, but remember it as final fall through. 916 if (clause->is_default()) { 917 default_clause = clause; 918 continue; 919 } 920 921 Comment cmnt(masm_, "[ Case comparison"); 922 __ bind(&next_test); 923 next_test.Unuse(); 924 925 // Compile the label expression. 926 VisitForAccumulatorValue(clause->label()); 927 928 // Perform the comparison as if via '==='. 929 __ LoadP(r4, MemOperand(sp, 0)); // Switch value. 930 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT); 931 JumpPatchSite patch_site(masm_); 932 if (inline_smi_code) { 933 Label slow_case; 934 __ orx(r5, r4, r3); 935 patch_site.EmitJumpIfNotSmi(r5, &slow_case); 936 937 __ cmp(r4, r3); 938 __ bne(&next_test); 939 __ Drop(1); // Switch value is no longer needed. 940 __ b(clause->body_target()); 941 __ bind(&slow_case); 942 } 943 944 // Record position before stub call for type feedback. 945 SetExpressionPosition(clause); 946 Handle<Code> ic = CodeFactory::CompareIC(isolate(), Token::EQ_STRICT, 947 strength(language_mode())).code(); 948 CallIC(ic, clause->CompareId()); 949 patch_site.EmitPatchInfo(); 950 951 Label skip; 952 __ b(&skip); 953 PrepareForBailout(clause, TOS_REG); 954 __ LoadRoot(ip, Heap::kTrueValueRootIndex); 955 __ cmp(r3, ip); 956 __ bne(&next_test); 957 __ Drop(1); 958 __ b(clause->body_target()); 959 __ bind(&skip); 960 961 __ cmpi(r3, Operand::Zero()); 962 __ bne(&next_test); 963 __ Drop(1); // Switch value is no longer needed. 964 __ b(clause->body_target()); 965 } 966 967 // Discard the test value and jump to the default if present, otherwise to 968 // the end of the statement. 969 __ bind(&next_test); 970 __ Drop(1); // Switch value is no longer needed. 971 if (default_clause == NULL) { 972 __ b(nested_statement.break_label()); 973 } else { 974 __ b(default_clause->body_target()); 975 } 976 977 // Compile all the case bodies. 978 for (int i = 0; i < clauses->length(); i++) { 979 Comment cmnt(masm_, "[ Case body"); 980 CaseClause* clause = clauses->at(i); 981 __ bind(clause->body_target()); 982 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS); 983 VisitStatements(clause->statements()); 984 } 985 986 __ bind(nested_statement.break_label()); 987 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); 988 } 989 990 991 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { 992 Comment cmnt(masm_, "[ ForInStatement"); 993 SetStatementPosition(stmt, SKIP_BREAK); 994 995 FeedbackVectorSlot slot = stmt->ForInFeedbackSlot(); 996 997 Label loop, exit; 998 ForIn loop_statement(this, stmt); 999 increment_loop_depth(); 1000 1001 // Get the object to enumerate over. If the object is null or undefined, skip 1002 // over the loop. See ECMA-262 version 5, section 12.6.4. 1003 SetExpressionAsStatementPosition(stmt->enumerable()); 1004 VisitForAccumulatorValue(stmt->enumerable()); 1005 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); 1006 __ cmp(r3, ip); 1007 __ beq(&exit); 1008 Register null_value = r7; 1009 __ LoadRoot(null_value, Heap::kNullValueRootIndex); 1010 __ cmp(r3, null_value); 1011 __ beq(&exit); 1012 1013 PrepareForBailoutForId(stmt->PrepareId(), TOS_REG); 1014 1015 // Convert the object to a JS object. 1016 Label convert, done_convert; 1017 __ JumpIfSmi(r3, &convert); 1018 __ CompareObjectType(r3, r4, r4, FIRST_JS_RECEIVER_TYPE); 1019 __ bge(&done_convert); 1020 __ bind(&convert); 1021 ToObjectStub stub(isolate()); 1022 __ CallStub(&stub); 1023 __ bind(&done_convert); 1024 PrepareForBailoutForId(stmt->ToObjectId(), TOS_REG); 1025 __ push(r3); 1026 1027 // Check for proxies. 1028 Label call_runtime; 1029 __ CompareObjectType(r3, r4, r4, JS_PROXY_TYPE); 1030 __ beq(&call_runtime); 1031 1032 // Check cache validity in generated code. This is a fast case for 1033 // the JSObject::IsSimpleEnum cache validity checks. If we cannot 1034 // guarantee cache validity, call the runtime system to check cache 1035 // validity or get the property names in a fixed array. 1036 __ CheckEnumCache(null_value, &call_runtime); 1037 1038 // The enum cache is valid. Load the map of the object being 1039 // iterated over and use the cache for the iteration. 1040 Label use_cache; 1041 __ LoadP(r3, FieldMemOperand(r3, HeapObject::kMapOffset)); 1042 __ b(&use_cache); 1043 1044 // Get the set of properties to enumerate. 1045 __ bind(&call_runtime); 1046 __ push(r3); // Duplicate the enumerable object on the stack. 1047 __ CallRuntime(Runtime::kGetPropertyNamesFast); 1048 PrepareForBailoutForId(stmt->EnumId(), TOS_REG); 1049 1050 // If we got a map from the runtime call, we can do a fast 1051 // modification check. Otherwise, we got a fixed array, and we have 1052 // to do a slow check. 1053 Label fixed_array; 1054 __ LoadP(r5, FieldMemOperand(r3, HeapObject::kMapOffset)); 1055 __ LoadRoot(ip, Heap::kMetaMapRootIndex); 1056 __ cmp(r5, ip); 1057 __ bne(&fixed_array); 1058 1059 // We got a map in register r3. Get the enumeration cache from it. 1060 Label no_descriptors; 1061 __ bind(&use_cache); 1062 1063 __ EnumLength(r4, r3); 1064 __ CmpSmiLiteral(r4, Smi::FromInt(0), r0); 1065 __ beq(&no_descriptors); 1066 1067 __ LoadInstanceDescriptors(r3, r5); 1068 __ LoadP(r5, FieldMemOperand(r5, DescriptorArray::kEnumCacheOffset)); 1069 __ LoadP(r5, 1070 FieldMemOperand(r5, DescriptorArray::kEnumCacheBridgeCacheOffset)); 1071 1072 // Set up the four remaining stack slots. 1073 __ push(r3); // Map. 1074 __ LoadSmiLiteral(r3, Smi::FromInt(0)); 1075 // Push enumeration cache, enumeration cache length (as smi) and zero. 1076 __ Push(r5, r4, r3); 1077 __ b(&loop); 1078 1079 __ bind(&no_descriptors); 1080 __ Drop(1); 1081 __ b(&exit); 1082 1083 // We got a fixed array in register r3. Iterate through that. 1084 __ bind(&fixed_array); 1085 1086 __ EmitLoadTypeFeedbackVector(r4); 1087 __ mov(r5, Operand(TypeFeedbackVector::MegamorphicSentinel(isolate()))); 1088 int vector_index = SmiFromSlot(slot)->value(); 1089 __ StoreP( 1090 r5, FieldMemOperand(r4, FixedArray::OffsetOfElementAt(vector_index)), r0); 1091 __ LoadSmiLiteral(r4, Smi::FromInt(1)); // Smi(1) indicates slow check 1092 __ Push(r4, r3); // Smi and array 1093 __ LoadP(r4, FieldMemOperand(r3, FixedArray::kLengthOffset)); 1094 __ LoadSmiLiteral(r3, Smi::FromInt(0)); 1095 __ Push(r4, r3); // Fixed array length (as smi) and initial index. 1096 1097 // Generate code for doing the condition check. 1098 __ bind(&loop); 1099 SetExpressionAsStatementPosition(stmt->each()); 1100 1101 // Load the current count to r3, load the length to r4. 1102 __ LoadP(r3, MemOperand(sp, 0 * kPointerSize)); 1103 __ LoadP(r4, MemOperand(sp, 1 * kPointerSize)); 1104 __ cmpl(r3, r4); // Compare to the array length. 1105 __ bge(loop_statement.break_label()); 1106 1107 // Get the current entry of the array into register r6. 1108 __ LoadP(r5, MemOperand(sp, 2 * kPointerSize)); 1109 __ addi(r5, r5, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); 1110 __ SmiToPtrArrayOffset(r6, r3); 1111 __ LoadPX(r6, MemOperand(r6, r5)); 1112 1113 // Get the expected map from the stack or a smi in the 1114 // permanent slow case into register r5. 1115 __ LoadP(r5, MemOperand(sp, 3 * kPointerSize)); 1116 1117 // Check if the expected map still matches that of the enumerable. 1118 // If not, we may have to filter the key. 1119 Label update_each; 1120 __ LoadP(r4, MemOperand(sp, 4 * kPointerSize)); 1121 __ LoadP(r7, FieldMemOperand(r4, HeapObject::kMapOffset)); 1122 __ cmp(r7, r5); 1123 __ beq(&update_each); 1124 1125 // Convert the entry to a string or (smi) 0 if it isn't a property 1126 // any more. If the property has been removed while iterating, we 1127 // just skip it. 1128 __ Push(r4, r6); // Enumerable and current entry. 1129 __ CallRuntime(Runtime::kForInFilter); 1130 PrepareForBailoutForId(stmt->FilterId(), TOS_REG); 1131 __ mr(r6, r3); 1132 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); 1133 __ cmp(r3, r0); 1134 __ beq(loop_statement.continue_label()); 1135 1136 // Update the 'each' property or variable from the possibly filtered 1137 // entry in register r6. 1138 __ bind(&update_each); 1139 __ mr(result_register(), r6); 1140 // Perform the assignment as if via '='. 1141 { 1142 EffectContext context(this); 1143 EmitAssignment(stmt->each(), stmt->EachFeedbackSlot()); 1144 PrepareForBailoutForId(stmt->AssignmentId(), NO_REGISTERS); 1145 } 1146 1147 // Both Crankshaft and Turbofan expect BodyId to be right before stmt->body(). 1148 PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS); 1149 // Generate code for the body of the loop. 1150 Visit(stmt->body()); 1151 1152 // Generate code for the going to the next element by incrementing 1153 // the index (smi) stored on top of the stack. 1154 __ bind(loop_statement.continue_label()); 1155 __ pop(r3); 1156 __ AddSmiLiteral(r3, r3, Smi::FromInt(1), r0); 1157 __ push(r3); 1158 1159 EmitBackEdgeBookkeeping(stmt, &loop); 1160 __ b(&loop); 1161 1162 // Remove the pointers stored on the stack. 1163 __ bind(loop_statement.break_label()); 1164 __ Drop(5); 1165 1166 // Exit and decrement the loop depth. 1167 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); 1168 __ bind(&exit); 1169 decrement_loop_depth(); 1170 } 1171 1172 1173 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info, 1174 bool pretenure) { 1175 // Use the fast case closure allocation code that allocates in new 1176 // space for nested functions that don't need literals cloning. If 1177 // we're running with the --always-opt or the --prepare-always-opt 1178 // flag, we need to use the runtime function so that the new function 1179 // we are creating here gets a chance to have its code optimized and 1180 // doesn't just get a copy of the existing unoptimized code. 1181 if (!FLAG_always_opt && !FLAG_prepare_always_opt && !pretenure && 1182 scope()->is_function_scope() && info->num_literals() == 0) { 1183 FastNewClosureStub stub(isolate(), info->language_mode(), info->kind()); 1184 __ mov(r5, Operand(info)); 1185 __ CallStub(&stub); 1186 } else { 1187 __ Push(info); 1188 __ CallRuntime(pretenure ? Runtime::kNewClosure_Tenured 1189 : Runtime::kNewClosure); 1190 } 1191 context()->Plug(r3); 1192 } 1193 1194 1195 void FullCodeGenerator::EmitSetHomeObject(Expression* initializer, int offset, 1196 FeedbackVectorSlot slot) { 1197 DCHECK(NeedsHomeObject(initializer)); 1198 __ LoadP(StoreDescriptor::ReceiverRegister(), MemOperand(sp)); 1199 __ mov(StoreDescriptor::NameRegister(), 1200 Operand(isolate()->factory()->home_object_symbol())); 1201 __ LoadP(StoreDescriptor::ValueRegister(), 1202 MemOperand(sp, offset * kPointerSize)); 1203 EmitLoadStoreICSlot(slot); 1204 CallStoreIC(); 1205 } 1206 1207 1208 void FullCodeGenerator::EmitSetHomeObjectAccumulator(Expression* initializer, 1209 int offset, 1210 FeedbackVectorSlot slot) { 1211 DCHECK(NeedsHomeObject(initializer)); 1212 __ Move(StoreDescriptor::ReceiverRegister(), r3); 1213 __ mov(StoreDescriptor::NameRegister(), 1214 Operand(isolate()->factory()->home_object_symbol())); 1215 __ LoadP(StoreDescriptor::ValueRegister(), 1216 MemOperand(sp, offset * kPointerSize)); 1217 EmitLoadStoreICSlot(slot); 1218 CallStoreIC(); 1219 } 1220 1221 1222 void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy, 1223 TypeofMode typeof_mode, 1224 Label* slow) { 1225 Register current = cp; 1226 Register next = r4; 1227 Register temp = r5; 1228 1229 Scope* s = scope(); 1230 while (s != NULL) { 1231 if (s->num_heap_slots() > 0) { 1232 if (s->calls_sloppy_eval()) { 1233 // Check that extension is "the hole". 1234 __ LoadP(temp, ContextMemOperand(current, Context::EXTENSION_INDEX)); 1235 __ JumpIfNotRoot(temp, Heap::kTheHoleValueRootIndex, slow); 1236 } 1237 // Load next context in chain. 1238 __ LoadP(next, ContextMemOperand(current, Context::PREVIOUS_INDEX)); 1239 // Walk the rest of the chain without clobbering cp. 1240 current = next; 1241 } 1242 // If no outer scope calls eval, we do not need to check more 1243 // context extensions. 1244 if (!s->outer_scope_calls_sloppy_eval() || s->is_eval_scope()) break; 1245 s = s->outer_scope(); 1246 } 1247 1248 if (s->is_eval_scope()) { 1249 Label loop, fast; 1250 if (!current.is(next)) { 1251 __ Move(next, current); 1252 } 1253 __ bind(&loop); 1254 // Terminate at native context. 1255 __ LoadP(temp, FieldMemOperand(next, HeapObject::kMapOffset)); 1256 __ LoadRoot(ip, Heap::kNativeContextMapRootIndex); 1257 __ cmp(temp, ip); 1258 __ beq(&fast); 1259 // Check that extension is "the hole". 1260 __ LoadP(temp, ContextMemOperand(next, Context::EXTENSION_INDEX)); 1261 __ JumpIfNotRoot(temp, Heap::kTheHoleValueRootIndex, slow); 1262 // Load next context in chain. 1263 __ LoadP(next, ContextMemOperand(next, Context::PREVIOUS_INDEX)); 1264 __ b(&loop); 1265 __ bind(&fast); 1266 } 1267 1268 // All extension objects were empty and it is safe to use a normal global 1269 // load machinery. 1270 EmitGlobalVariableLoad(proxy, typeof_mode); 1271 } 1272 1273 1274 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var, 1275 Label* slow) { 1276 DCHECK(var->IsContextSlot()); 1277 Register context = cp; 1278 Register next = r6; 1279 Register temp = r7; 1280 1281 for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) { 1282 if (s->num_heap_slots() > 0) { 1283 if (s->calls_sloppy_eval()) { 1284 // Check that extension is "the hole". 1285 __ LoadP(temp, ContextMemOperand(context, Context::EXTENSION_INDEX)); 1286 __ JumpIfNotRoot(temp, Heap::kTheHoleValueRootIndex, slow); 1287 } 1288 __ LoadP(next, ContextMemOperand(context, Context::PREVIOUS_INDEX)); 1289 // Walk the rest of the chain without clobbering cp. 1290 context = next; 1291 } 1292 } 1293 // Check that last extension is "the hole". 1294 __ LoadP(temp, ContextMemOperand(context, Context::EXTENSION_INDEX)); 1295 __ JumpIfNotRoot(temp, Heap::kTheHoleValueRootIndex, slow); 1296 1297 // This function is used only for loads, not stores, so it's safe to 1298 // return an cp-based operand (the write barrier cannot be allowed to 1299 // destroy the cp register). 1300 return ContextMemOperand(context, var->index()); 1301 } 1302 1303 1304 void FullCodeGenerator::EmitDynamicLookupFastCase(VariableProxy* proxy, 1305 TypeofMode typeof_mode, 1306 Label* slow, Label* done) { 1307 // Generate fast-case code for variables that might be shadowed by 1308 // eval-introduced variables. Eval is used a lot without 1309 // introducing variables. In those cases, we do not want to 1310 // perform a runtime call for all variables in the scope 1311 // containing the eval. 1312 Variable* var = proxy->var(); 1313 if (var->mode() == DYNAMIC_GLOBAL) { 1314 EmitLoadGlobalCheckExtensions(proxy, typeof_mode, slow); 1315 __ b(done); 1316 } else if (var->mode() == DYNAMIC_LOCAL) { 1317 Variable* local = var->local_if_not_shadowed(); 1318 __ LoadP(r3, ContextSlotOperandCheckExtensions(local, slow)); 1319 if (local->mode() == LET || local->mode() == CONST || 1320 local->mode() == CONST_LEGACY) { 1321 __ CompareRoot(r3, Heap::kTheHoleValueRootIndex); 1322 __ bne(done); 1323 if (local->mode() == CONST_LEGACY) { 1324 __ LoadRoot(r3, Heap::kUndefinedValueRootIndex); 1325 } else { // LET || CONST 1326 __ mov(r3, Operand(var->name())); 1327 __ push(r3); 1328 __ CallRuntime(Runtime::kThrowReferenceError); 1329 } 1330 } 1331 __ b(done); 1332 } 1333 } 1334 1335 1336 void FullCodeGenerator::EmitGlobalVariableLoad(VariableProxy* proxy, 1337 TypeofMode typeof_mode) { 1338 Variable* var = proxy->var(); 1339 DCHECK(var->IsUnallocatedOrGlobalSlot() || 1340 (var->IsLookupSlot() && var->mode() == DYNAMIC_GLOBAL)); 1341 __ LoadGlobalObject(LoadDescriptor::ReceiverRegister()); 1342 __ mov(LoadDescriptor::NameRegister(), Operand(var->name())); 1343 __ mov(LoadDescriptor::SlotRegister(), 1344 Operand(SmiFromSlot(proxy->VariableFeedbackSlot()))); 1345 CallLoadIC(typeof_mode); 1346 } 1347 1348 1349 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy, 1350 TypeofMode typeof_mode) { 1351 // Record position before possible IC call. 1352 SetExpressionPosition(proxy); 1353 PrepareForBailoutForId(proxy->BeforeId(), NO_REGISTERS); 1354 Variable* var = proxy->var(); 1355 1356 // Three cases: global variables, lookup variables, and all other types of 1357 // variables. 1358 switch (var->location()) { 1359 case VariableLocation::GLOBAL: 1360 case VariableLocation::UNALLOCATED: { 1361 Comment cmnt(masm_, "[ Global variable"); 1362 EmitGlobalVariableLoad(proxy, typeof_mode); 1363 context()->Plug(r3); 1364 break; 1365 } 1366 1367 case VariableLocation::PARAMETER: 1368 case VariableLocation::LOCAL: 1369 case VariableLocation::CONTEXT: { 1370 DCHECK_EQ(NOT_INSIDE_TYPEOF, typeof_mode); 1371 Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable" 1372 : "[ Stack variable"); 1373 if (NeedsHoleCheckForLoad(proxy)) { 1374 Label done; 1375 // Let and const need a read barrier. 1376 GetVar(r3, var); 1377 __ CompareRoot(r3, Heap::kTheHoleValueRootIndex); 1378 __ bne(&done); 1379 if (var->mode() == LET || var->mode() == CONST) { 1380 // Throw a reference error when using an uninitialized let/const 1381 // binding in harmony mode. 1382 __ mov(r3, Operand(var->name())); 1383 __ push(r3); 1384 __ CallRuntime(Runtime::kThrowReferenceError); 1385 } else { 1386 // Uninitialized legacy const bindings are unholed. 1387 DCHECK(var->mode() == CONST_LEGACY); 1388 __ LoadRoot(r3, Heap::kUndefinedValueRootIndex); 1389 } 1390 __ bind(&done); 1391 context()->Plug(r3); 1392 break; 1393 } 1394 context()->Plug(var); 1395 break; 1396 } 1397 1398 case VariableLocation::LOOKUP: { 1399 Comment cmnt(masm_, "[ Lookup variable"); 1400 Label done, slow; 1401 // Generate code for loading from variables potentially shadowed 1402 // by eval-introduced variables. 1403 EmitDynamicLookupFastCase(proxy, typeof_mode, &slow, &done); 1404 __ bind(&slow); 1405 __ mov(r4, Operand(var->name())); 1406 __ Push(cp, r4); // Context and name. 1407 Runtime::FunctionId function_id = 1408 typeof_mode == NOT_INSIDE_TYPEOF 1409 ? Runtime::kLoadLookupSlot 1410 : Runtime::kLoadLookupSlotNoReferenceError; 1411 __ CallRuntime(function_id); 1412 __ bind(&done); 1413 context()->Plug(r3); 1414 } 1415 } 1416 } 1417 1418 1419 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { 1420 Comment cmnt(masm_, "[ RegExpLiteral"); 1421 __ LoadP(r6, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 1422 __ LoadSmiLiteral(r5, Smi::FromInt(expr->literal_index())); 1423 __ mov(r4, Operand(expr->pattern())); 1424 __ LoadSmiLiteral(r3, Smi::FromInt(expr->flags())); 1425 FastCloneRegExpStub stub(isolate()); 1426 __ CallStub(&stub); 1427 context()->Plug(r3); 1428 } 1429 1430 1431 void FullCodeGenerator::EmitAccessor(ObjectLiteralProperty* property) { 1432 Expression* expression = (property == NULL) ? NULL : property->value(); 1433 if (expression == NULL) { 1434 __ LoadRoot(r4, Heap::kNullValueRootIndex); 1435 __ push(r4); 1436 } else { 1437 VisitForStackValue(expression); 1438 if (NeedsHomeObject(expression)) { 1439 DCHECK(property->kind() == ObjectLiteral::Property::GETTER || 1440 property->kind() == ObjectLiteral::Property::SETTER); 1441 int offset = property->kind() == ObjectLiteral::Property::GETTER ? 2 : 3; 1442 EmitSetHomeObject(expression, offset, property->GetSlot()); 1443 } 1444 } 1445 } 1446 1447 1448 void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { 1449 Comment cmnt(masm_, "[ ObjectLiteral"); 1450 1451 Handle<FixedArray> constant_properties = expr->constant_properties(); 1452 __ LoadP(r6, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 1453 __ LoadSmiLiteral(r5, Smi::FromInt(expr->literal_index())); 1454 __ mov(r4, Operand(constant_properties)); 1455 int flags = expr->ComputeFlags(); 1456 __ LoadSmiLiteral(r3, Smi::FromInt(flags)); 1457 if (MustCreateObjectLiteralWithRuntime(expr)) { 1458 __ Push(r6, r5, r4, r3); 1459 __ CallRuntime(Runtime::kCreateObjectLiteral); 1460 } else { 1461 FastCloneShallowObjectStub stub(isolate(), expr->properties_count()); 1462 __ CallStub(&stub); 1463 } 1464 PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); 1465 1466 // If result_saved is true the result is on top of the stack. If 1467 // result_saved is false the result is in r3. 1468 bool result_saved = false; 1469 1470 AccessorTable accessor_table(zone()); 1471 int property_index = 0; 1472 for (; property_index < expr->properties()->length(); property_index++) { 1473 ObjectLiteral::Property* property = expr->properties()->at(property_index); 1474 if (property->is_computed_name()) break; 1475 if (property->IsCompileTimeValue()) continue; 1476 1477 Literal* key = property->key()->AsLiteral(); 1478 Expression* value = property->value(); 1479 if (!result_saved) { 1480 __ push(r3); // Save result on stack 1481 result_saved = true; 1482 } 1483 switch (property->kind()) { 1484 case ObjectLiteral::Property::CONSTANT: 1485 UNREACHABLE(); 1486 case ObjectLiteral::Property::MATERIALIZED_LITERAL: 1487 DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value())); 1488 // Fall through. 1489 case ObjectLiteral::Property::COMPUTED: 1490 // It is safe to use [[Put]] here because the boilerplate already 1491 // contains computed properties with an uninitialized value. 1492 if (key->value()->IsInternalizedString()) { 1493 if (property->emit_store()) { 1494 VisitForAccumulatorValue(value); 1495 DCHECK(StoreDescriptor::ValueRegister().is(r3)); 1496 __ mov(StoreDescriptor::NameRegister(), Operand(key->value())); 1497 __ LoadP(StoreDescriptor::ReceiverRegister(), MemOperand(sp)); 1498 EmitLoadStoreICSlot(property->GetSlot(0)); 1499 CallStoreIC(); 1500 PrepareForBailoutForId(key->id(), NO_REGISTERS); 1501 1502 if (NeedsHomeObject(value)) { 1503 EmitSetHomeObjectAccumulator(value, 0, property->GetSlot(1)); 1504 } 1505 } else { 1506 VisitForEffect(value); 1507 } 1508 break; 1509 } 1510 // Duplicate receiver on stack. 1511 __ LoadP(r3, MemOperand(sp)); 1512 __ push(r3); 1513 VisitForStackValue(key); 1514 VisitForStackValue(value); 1515 if (property->emit_store()) { 1516 if (NeedsHomeObject(value)) { 1517 EmitSetHomeObject(value, 2, property->GetSlot()); 1518 } 1519 __ LoadSmiLiteral(r3, Smi::FromInt(SLOPPY)); // PropertyAttributes 1520 __ push(r3); 1521 __ CallRuntime(Runtime::kSetProperty); 1522 } else { 1523 __ Drop(3); 1524 } 1525 break; 1526 case ObjectLiteral::Property::PROTOTYPE: 1527 // Duplicate receiver on stack. 1528 __ LoadP(r3, MemOperand(sp)); 1529 __ push(r3); 1530 VisitForStackValue(value); 1531 DCHECK(property->emit_store()); 1532 __ CallRuntime(Runtime::kInternalSetPrototype); 1533 PrepareForBailoutForId(expr->GetIdForPropertySet(property_index), 1534 NO_REGISTERS); 1535 break; 1536 case ObjectLiteral::Property::GETTER: 1537 if (property->emit_store()) { 1538 accessor_table.lookup(key)->second->getter = property; 1539 } 1540 break; 1541 case ObjectLiteral::Property::SETTER: 1542 if (property->emit_store()) { 1543 accessor_table.lookup(key)->second->setter = property; 1544 } 1545 break; 1546 } 1547 } 1548 1549 // Emit code to define accessors, using only a single call to the runtime for 1550 // each pair of corresponding getters and setters. 1551 for (AccessorTable::Iterator it = accessor_table.begin(); 1552 it != accessor_table.end(); ++it) { 1553 __ LoadP(r3, MemOperand(sp)); // Duplicate receiver. 1554 __ push(r3); 1555 VisitForStackValue(it->first); 1556 EmitAccessor(it->second->getter); 1557 EmitAccessor(it->second->setter); 1558 __ LoadSmiLiteral(r3, Smi::FromInt(NONE)); 1559 __ push(r3); 1560 __ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked); 1561 } 1562 1563 // Object literals have two parts. The "static" part on the left contains no 1564 // computed property names, and so we can compute its map ahead of time; see 1565 // runtime.cc::CreateObjectLiteralBoilerplate. The second "dynamic" part 1566 // starts with the first computed property name, and continues with all 1567 // properties to its right. All the code from above initializes the static 1568 // component of the object literal, and arranges for the map of the result to 1569 // reflect the static order in which the keys appear. For the dynamic 1570 // properties, we compile them into a series of "SetOwnProperty" runtime 1571 // calls. This will preserve insertion order. 1572 for (; property_index < expr->properties()->length(); property_index++) { 1573 ObjectLiteral::Property* property = expr->properties()->at(property_index); 1574 1575 Expression* value = property->value(); 1576 if (!result_saved) { 1577 __ push(r3); // Save result on the stack 1578 result_saved = true; 1579 } 1580 1581 __ LoadP(r3, MemOperand(sp)); // Duplicate receiver. 1582 __ push(r3); 1583 1584 if (property->kind() == ObjectLiteral::Property::PROTOTYPE) { 1585 DCHECK(!property->is_computed_name()); 1586 VisitForStackValue(value); 1587 DCHECK(property->emit_store()); 1588 __ CallRuntime(Runtime::kInternalSetPrototype); 1589 PrepareForBailoutForId(expr->GetIdForPropertySet(property_index), 1590 NO_REGISTERS); 1591 } else { 1592 EmitPropertyKey(property, expr->GetIdForPropertyName(property_index)); 1593 VisitForStackValue(value); 1594 if (NeedsHomeObject(value)) { 1595 EmitSetHomeObject(value, 2, property->GetSlot()); 1596 } 1597 1598 switch (property->kind()) { 1599 case ObjectLiteral::Property::CONSTANT: 1600 case ObjectLiteral::Property::MATERIALIZED_LITERAL: 1601 case ObjectLiteral::Property::COMPUTED: 1602 if (property->emit_store()) { 1603 __ LoadSmiLiteral(r3, Smi::FromInt(NONE)); 1604 __ push(r3); 1605 __ CallRuntime(Runtime::kDefineDataPropertyUnchecked); 1606 } else { 1607 __ Drop(3); 1608 } 1609 break; 1610 1611 case ObjectLiteral::Property::PROTOTYPE: 1612 UNREACHABLE(); 1613 break; 1614 1615 case ObjectLiteral::Property::GETTER: 1616 __ mov(r3, Operand(Smi::FromInt(NONE))); 1617 __ push(r3); 1618 __ CallRuntime(Runtime::kDefineGetterPropertyUnchecked); 1619 break; 1620 1621 case ObjectLiteral::Property::SETTER: 1622 __ mov(r3, Operand(Smi::FromInt(NONE))); 1623 __ push(r3); 1624 __ CallRuntime(Runtime::kDefineSetterPropertyUnchecked); 1625 break; 1626 } 1627 } 1628 } 1629 1630 if (expr->has_function()) { 1631 DCHECK(result_saved); 1632 __ LoadP(r3, MemOperand(sp)); 1633 __ push(r3); 1634 __ CallRuntime(Runtime::kToFastProperties); 1635 } 1636 1637 if (result_saved) { 1638 context()->PlugTOS(); 1639 } else { 1640 context()->Plug(r3); 1641 } 1642 } 1643 1644 1645 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { 1646 Comment cmnt(masm_, "[ ArrayLiteral"); 1647 1648 Handle<FixedArray> constant_elements = expr->constant_elements(); 1649 bool has_fast_elements = 1650 IsFastObjectElementsKind(expr->constant_elements_kind()); 1651 Handle<FixedArrayBase> constant_elements_values( 1652 FixedArrayBase::cast(constant_elements->get(1))); 1653 1654 AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE; 1655 if (has_fast_elements && !FLAG_allocation_site_pretenuring) { 1656 // If the only customer of allocation sites is transitioning, then 1657 // we can turn it off if we don't have anywhere else to transition to. 1658 allocation_site_mode = DONT_TRACK_ALLOCATION_SITE; 1659 } 1660 1661 __ LoadP(r6, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 1662 __ LoadSmiLiteral(r5, Smi::FromInt(expr->literal_index())); 1663 __ mov(r4, Operand(constant_elements)); 1664 if (MustCreateArrayLiteralWithRuntime(expr)) { 1665 __ LoadSmiLiteral(r3, Smi::FromInt(expr->ComputeFlags())); 1666 __ Push(r6, r5, r4, r3); 1667 __ CallRuntime(Runtime::kCreateArrayLiteral); 1668 } else { 1669 FastCloneShallowArrayStub stub(isolate(), allocation_site_mode); 1670 __ CallStub(&stub); 1671 } 1672 PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); 1673 1674 bool result_saved = false; // Is the result saved to the stack? 1675 ZoneList<Expression*>* subexprs = expr->values(); 1676 int length = subexprs->length(); 1677 1678 // Emit code to evaluate all the non-constant subexpressions and to store 1679 // them into the newly cloned array. 1680 int array_index = 0; 1681 for (; array_index < length; array_index++) { 1682 Expression* subexpr = subexprs->at(array_index); 1683 if (subexpr->IsSpread()) break; 1684 // If the subexpression is a literal or a simple materialized literal it 1685 // is already set in the cloned array. 1686 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; 1687 1688 if (!result_saved) { 1689 __ push(r3); 1690 result_saved = true; 1691 } 1692 VisitForAccumulatorValue(subexpr); 1693 1694 __ LoadSmiLiteral(StoreDescriptor::NameRegister(), 1695 Smi::FromInt(array_index)); 1696 __ LoadP(StoreDescriptor::ReceiverRegister(), MemOperand(sp, 0)); 1697 EmitLoadStoreICSlot(expr->LiteralFeedbackSlot()); 1698 Handle<Code> ic = 1699 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code(); 1700 CallIC(ic); 1701 1702 PrepareForBailoutForId(expr->GetIdForElement(array_index), NO_REGISTERS); 1703 } 1704 1705 // In case the array literal contains spread expressions it has two parts. The 1706 // first part is the "static" array which has a literal index is handled 1707 // above. The second part is the part after the first spread expression 1708 // (inclusive) and these elements gets appended to the array. Note that the 1709 // number elements an iterable produces is unknown ahead of time. 1710 if (array_index < length && result_saved) { 1711 __ Pop(r3); 1712 result_saved = false; 1713 } 1714 for (; array_index < length; array_index++) { 1715 Expression* subexpr = subexprs->at(array_index); 1716 1717 __ Push(r3); 1718 if (subexpr->IsSpread()) { 1719 VisitForStackValue(subexpr->AsSpread()->expression()); 1720 __ InvokeBuiltin(Context::CONCAT_ITERABLE_TO_ARRAY_BUILTIN_INDEX, 1721 CALL_FUNCTION); 1722 } else { 1723 VisitForStackValue(subexpr); 1724 __ CallRuntime(Runtime::kAppendElement); 1725 } 1726 1727 PrepareForBailoutForId(expr->GetIdForElement(array_index), NO_REGISTERS); 1728 } 1729 1730 if (result_saved) { 1731 context()->PlugTOS(); 1732 } else { 1733 context()->Plug(r3); 1734 } 1735 } 1736 1737 1738 void FullCodeGenerator::VisitAssignment(Assignment* expr) { 1739 DCHECK(expr->target()->IsValidReferenceExpressionOrThis()); 1740 1741 Comment cmnt(masm_, "[ Assignment"); 1742 SetExpressionPosition(expr, INSERT_BREAK); 1743 1744 Property* property = expr->target()->AsProperty(); 1745 LhsKind assign_type = Property::GetAssignType(property); 1746 1747 // Evaluate LHS expression. 1748 switch (assign_type) { 1749 case VARIABLE: 1750 // Nothing to do here. 1751 break; 1752 case NAMED_PROPERTY: 1753 if (expr->is_compound()) { 1754 // We need the receiver both on the stack and in the register. 1755 VisitForStackValue(property->obj()); 1756 __ LoadP(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0)); 1757 } else { 1758 VisitForStackValue(property->obj()); 1759 } 1760 break; 1761 case NAMED_SUPER_PROPERTY: 1762 VisitForStackValue( 1763 property->obj()->AsSuperPropertyReference()->this_var()); 1764 VisitForAccumulatorValue( 1765 property->obj()->AsSuperPropertyReference()->home_object()); 1766 __ Push(result_register()); 1767 if (expr->is_compound()) { 1768 const Register scratch = r4; 1769 __ LoadP(scratch, MemOperand(sp, kPointerSize)); 1770 __ Push(scratch, result_register()); 1771 } 1772 break; 1773 case KEYED_SUPER_PROPERTY: { 1774 const Register scratch = r4; 1775 VisitForStackValue( 1776 property->obj()->AsSuperPropertyReference()->this_var()); 1777 VisitForAccumulatorValue( 1778 property->obj()->AsSuperPropertyReference()->home_object()); 1779 __ mr(scratch, result_register()); 1780 VisitForAccumulatorValue(property->key()); 1781 __ Push(scratch, result_register()); 1782 if (expr->is_compound()) { 1783 const Register scratch1 = r5; 1784 __ LoadP(scratch1, MemOperand(sp, 2 * kPointerSize)); 1785 __ Push(scratch1, scratch, result_register()); 1786 } 1787 break; 1788 } 1789 case KEYED_PROPERTY: 1790 if (expr->is_compound()) { 1791 VisitForStackValue(property->obj()); 1792 VisitForStackValue(property->key()); 1793 __ LoadP(LoadDescriptor::ReceiverRegister(), 1794 MemOperand(sp, 1 * kPointerSize)); 1795 __ LoadP(LoadDescriptor::NameRegister(), MemOperand(sp, 0)); 1796 } else { 1797 VisitForStackValue(property->obj()); 1798 VisitForStackValue(property->key()); 1799 } 1800 break; 1801 } 1802 1803 // For compound assignments we need another deoptimization point after the 1804 // variable/property load. 1805 if (expr->is_compound()) { 1806 { 1807 AccumulatorValueContext context(this); 1808 switch (assign_type) { 1809 case VARIABLE: 1810 EmitVariableLoad(expr->target()->AsVariableProxy()); 1811 PrepareForBailout(expr->target(), TOS_REG); 1812 break; 1813 case NAMED_PROPERTY: 1814 EmitNamedPropertyLoad(property); 1815 PrepareForBailoutForId(property->LoadId(), TOS_REG); 1816 break; 1817 case NAMED_SUPER_PROPERTY: 1818 EmitNamedSuperPropertyLoad(property); 1819 PrepareForBailoutForId(property->LoadId(), TOS_REG); 1820 break; 1821 case KEYED_SUPER_PROPERTY: 1822 EmitKeyedSuperPropertyLoad(property); 1823 PrepareForBailoutForId(property->LoadId(), TOS_REG); 1824 break; 1825 case KEYED_PROPERTY: 1826 EmitKeyedPropertyLoad(property); 1827 PrepareForBailoutForId(property->LoadId(), TOS_REG); 1828 break; 1829 } 1830 } 1831 1832 Token::Value op = expr->binary_op(); 1833 __ push(r3); // Left operand goes on the stack. 1834 VisitForAccumulatorValue(expr->value()); 1835 1836 AccumulatorValueContext context(this); 1837 if (ShouldInlineSmiCase(op)) { 1838 EmitInlineSmiBinaryOp(expr->binary_operation(), op, expr->target(), 1839 expr->value()); 1840 } else { 1841 EmitBinaryOp(expr->binary_operation(), op); 1842 } 1843 1844 // Deoptimization point in case the binary operation may have side effects. 1845 PrepareForBailout(expr->binary_operation(), TOS_REG); 1846 } else { 1847 VisitForAccumulatorValue(expr->value()); 1848 } 1849 1850 SetExpressionPosition(expr); 1851 1852 // Store the value. 1853 switch (assign_type) { 1854 case VARIABLE: 1855 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), 1856 expr->op(), expr->AssignmentSlot()); 1857 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); 1858 context()->Plug(r3); 1859 break; 1860 case NAMED_PROPERTY: 1861 EmitNamedPropertyAssignment(expr); 1862 break; 1863 case NAMED_SUPER_PROPERTY: 1864 EmitNamedSuperPropertyStore(property); 1865 context()->Plug(r3); 1866 break; 1867 case KEYED_SUPER_PROPERTY: 1868 EmitKeyedSuperPropertyStore(property); 1869 context()->Plug(r3); 1870 break; 1871 case KEYED_PROPERTY: 1872 EmitKeyedPropertyAssignment(expr); 1873 break; 1874 } 1875 } 1876 1877 1878 void FullCodeGenerator::VisitYield(Yield* expr) { 1879 Comment cmnt(masm_, "[ Yield"); 1880 SetExpressionPosition(expr); 1881 1882 // Evaluate yielded value first; the initial iterator definition depends on 1883 // this. It stays on the stack while we update the iterator. 1884 VisitForStackValue(expr->expression()); 1885 1886 switch (expr->yield_kind()) { 1887 case Yield::kSuspend: 1888 // Pop value from top-of-stack slot; box result into result register. 1889 EmitCreateIteratorResult(false); 1890 __ push(result_register()); 1891 // Fall through. 1892 case Yield::kInitial: { 1893 Label suspend, continuation, post_runtime, resume; 1894 1895 __ b(&suspend); 1896 __ bind(&continuation); 1897 __ RecordGeneratorContinuation(); 1898 __ b(&resume); 1899 1900 __ bind(&suspend); 1901 VisitForAccumulatorValue(expr->generator_object()); 1902 DCHECK(continuation.pos() > 0 && Smi::IsValid(continuation.pos())); 1903 __ LoadSmiLiteral(r4, Smi::FromInt(continuation.pos())); 1904 __ StoreP(r4, FieldMemOperand(r3, JSGeneratorObject::kContinuationOffset), 1905 r0); 1906 __ StoreP(cp, FieldMemOperand(r3, JSGeneratorObject::kContextOffset), r0); 1907 __ mr(r4, cp); 1908 __ RecordWriteField(r3, JSGeneratorObject::kContextOffset, r4, r5, 1909 kLRHasBeenSaved, kDontSaveFPRegs); 1910 __ addi(r4, fp, Operand(StandardFrameConstants::kExpressionsOffset)); 1911 __ cmp(sp, r4); 1912 __ beq(&post_runtime); 1913 __ push(r3); // generator object 1914 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1); 1915 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); 1916 __ bind(&post_runtime); 1917 __ pop(result_register()); 1918 EmitReturnSequence(); 1919 1920 __ bind(&resume); 1921 context()->Plug(result_register()); 1922 break; 1923 } 1924 1925 case Yield::kFinal: { 1926 VisitForAccumulatorValue(expr->generator_object()); 1927 __ LoadSmiLiteral(r4, Smi::FromInt(JSGeneratorObject::kGeneratorClosed)); 1928 __ StoreP(r4, FieldMemOperand(result_register(), 1929 JSGeneratorObject::kContinuationOffset), 1930 r0); 1931 // Pop value from top-of-stack slot, box result into result register. 1932 EmitCreateIteratorResult(true); 1933 EmitUnwindBeforeReturn(); 1934 EmitReturnSequence(); 1935 break; 1936 } 1937 1938 case Yield::kDelegating: { 1939 VisitForStackValue(expr->generator_object()); 1940 1941 // Initial stack layout is as follows: 1942 // [sp + 1 * kPointerSize] iter 1943 // [sp + 0 * kPointerSize] g 1944 1945 Label l_catch, l_try, l_suspend, l_continuation, l_resume; 1946 Label l_next, l_call; 1947 Register load_receiver = LoadDescriptor::ReceiverRegister(); 1948 Register load_name = LoadDescriptor::NameRegister(); 1949 1950 // Initial send value is undefined. 1951 __ LoadRoot(r3, Heap::kUndefinedValueRootIndex); 1952 __ b(&l_next); 1953 1954 // catch (e) { receiver = iter; f = 'throw'; arg = e; goto l_call; } 1955 __ bind(&l_catch); 1956 __ LoadRoot(load_name, Heap::kthrow_stringRootIndex); // "throw" 1957 __ LoadP(r6, MemOperand(sp, 1 * kPointerSize)); // iter 1958 __ Push(load_name, r6, r3); // "throw", iter, except 1959 __ b(&l_call); 1960 1961 // try { received = %yield result } 1962 // Shuffle the received result above a try handler and yield it without 1963 // re-boxing. 1964 __ bind(&l_try); 1965 __ pop(r3); // result 1966 int handler_index = NewHandlerTableEntry(); 1967 EnterTryBlock(handler_index, &l_catch); 1968 const int try_block_size = TryCatch::kElementCount * kPointerSize; 1969 __ push(r3); // result 1970 1971 __ b(&l_suspend); 1972 __ bind(&l_continuation); 1973 __ RecordGeneratorContinuation(); 1974 __ b(&l_resume); 1975 1976 __ bind(&l_suspend); 1977 const int generator_object_depth = kPointerSize + try_block_size; 1978 __ LoadP(r3, MemOperand(sp, generator_object_depth)); 1979 __ push(r3); // g 1980 __ Push(Smi::FromInt(handler_index)); // handler-index 1981 DCHECK(l_continuation.pos() > 0 && Smi::IsValid(l_continuation.pos())); 1982 __ LoadSmiLiteral(r4, Smi::FromInt(l_continuation.pos())); 1983 __ StoreP(r4, FieldMemOperand(r3, JSGeneratorObject::kContinuationOffset), 1984 r0); 1985 __ StoreP(cp, FieldMemOperand(r3, JSGeneratorObject::kContextOffset), r0); 1986 __ mr(r4, cp); 1987 __ RecordWriteField(r3, JSGeneratorObject::kContextOffset, r4, r5, 1988 kLRHasBeenSaved, kDontSaveFPRegs); 1989 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 2); 1990 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); 1991 __ pop(r3); // result 1992 EmitReturnSequence(); 1993 __ bind(&l_resume); // received in r3 1994 ExitTryBlock(handler_index); 1995 1996 // receiver = iter; f = 'next'; arg = received; 1997 __ bind(&l_next); 1998 1999 __ LoadRoot(load_name, Heap::knext_stringRootIndex); // "next" 2000 __ LoadP(r6, MemOperand(sp, 1 * kPointerSize)); // iter 2001 __ Push(load_name, r6, r3); // "next", iter, received 2002 2003 // result = receiver[f](arg); 2004 __ bind(&l_call); 2005 __ LoadP(load_receiver, MemOperand(sp, kPointerSize)); 2006 __ LoadP(load_name, MemOperand(sp, 2 * kPointerSize)); 2007 __ mov(LoadDescriptor::SlotRegister(), 2008 Operand(SmiFromSlot(expr->KeyedLoadFeedbackSlot()))); 2009 Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate(), SLOPPY).code(); 2010 CallIC(ic, TypeFeedbackId::None()); 2011 __ mr(r4, r3); 2012 __ StoreP(r4, MemOperand(sp, 2 * kPointerSize)); 2013 SetCallPosition(expr); 2014 __ li(r3, Operand(1)); 2015 __ Call( 2016 isolate()->builtins()->Call(ConvertReceiverMode::kNotNullOrUndefined), 2017 RelocInfo::CODE_TARGET); 2018 2019 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); 2020 __ Drop(1); // The function is still on the stack; drop it. 2021 2022 // if (!result.done) goto l_try; 2023 __ Move(load_receiver, r3); 2024 2025 __ push(load_receiver); // save result 2026 __ LoadRoot(load_name, Heap::kdone_stringRootIndex); // "done" 2027 __ mov(LoadDescriptor::SlotRegister(), 2028 Operand(SmiFromSlot(expr->DoneFeedbackSlot()))); 2029 CallLoadIC(NOT_INSIDE_TYPEOF); // r0=result.done 2030 Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate()); 2031 CallIC(bool_ic); 2032 __ CompareRoot(result_register(), Heap::kTrueValueRootIndex); 2033 __ bne(&l_try); 2034 2035 // result.value 2036 __ pop(load_receiver); // result 2037 __ LoadRoot(load_name, Heap::kvalue_stringRootIndex); // "value" 2038 __ mov(LoadDescriptor::SlotRegister(), 2039 Operand(SmiFromSlot(expr->ValueFeedbackSlot()))); 2040 CallLoadIC(NOT_INSIDE_TYPEOF); // r3=result.value 2041 context()->DropAndPlug(2, r3); // drop iter and g 2042 break; 2043 } 2044 } 2045 } 2046 2047 2048 void FullCodeGenerator::EmitGeneratorResume( 2049 Expression* generator, Expression* value, 2050 JSGeneratorObject::ResumeMode resume_mode) { 2051 // The value stays in r3, and is ultimately read by the resumed generator, as 2052 // if CallRuntime(Runtime::kSuspendJSGeneratorObject) returned it. Or it 2053 // is read to throw the value when the resumed generator is already closed. 2054 // r4 will hold the generator object until the activation has been resumed. 2055 VisitForStackValue(generator); 2056 VisitForAccumulatorValue(value); 2057 __ pop(r4); 2058 2059 // Load suspended function and context. 2060 __ LoadP(cp, FieldMemOperand(r4, JSGeneratorObject::kContextOffset)); 2061 __ LoadP(r7, FieldMemOperand(r4, JSGeneratorObject::kFunctionOffset)); 2062 2063 // Load receiver and store as the first argument. 2064 __ LoadP(r5, FieldMemOperand(r4, JSGeneratorObject::kReceiverOffset)); 2065 __ push(r5); 2066 2067 // Push holes for the rest of the arguments to the generator function. 2068 __ LoadP(r6, FieldMemOperand(r7, JSFunction::kSharedFunctionInfoOffset)); 2069 __ LoadWordArith( 2070 r6, FieldMemOperand(r6, SharedFunctionInfo::kFormalParameterCountOffset)); 2071 __ LoadRoot(r5, Heap::kTheHoleValueRootIndex); 2072 Label argument_loop, push_frame; 2073 #if V8_TARGET_ARCH_PPC64 2074 __ cmpi(r6, Operand::Zero()); 2075 __ beq(&push_frame); 2076 #else 2077 __ SmiUntag(r6, SetRC); 2078 __ beq(&push_frame, cr0); 2079 #endif 2080 __ mtctr(r6); 2081 __ bind(&argument_loop); 2082 __ push(r5); 2083 __ bdnz(&argument_loop); 2084 2085 // Enter a new JavaScript frame, and initialize its slots as they were when 2086 // the generator was suspended. 2087 Label resume_frame, done; 2088 __ bind(&push_frame); 2089 __ b(&resume_frame, SetLK); 2090 __ b(&done); 2091 __ bind(&resume_frame); 2092 // lr = return address. 2093 // fp = caller's frame pointer. 2094 // cp = callee's context, 2095 // r7 = callee's JS function. 2096 __ PushFixedFrame(r7); 2097 // Adjust FP to point to saved FP. 2098 __ addi(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp)); 2099 2100 // Load the operand stack size. 2101 __ LoadP(r6, FieldMemOperand(r4, JSGeneratorObject::kOperandStackOffset)); 2102 __ LoadP(r6, FieldMemOperand(r6, FixedArray::kLengthOffset)); 2103 __ SmiUntag(r6, SetRC); 2104 2105 // If we are sending a value and there is no operand stack, we can jump back 2106 // in directly. 2107 Label call_resume; 2108 if (resume_mode == JSGeneratorObject::NEXT) { 2109 Label slow_resume; 2110 __ bne(&slow_resume, cr0); 2111 __ LoadP(ip, FieldMemOperand(r7, JSFunction::kCodeEntryOffset)); 2112 { 2113 ConstantPoolUnavailableScope constant_pool_unavailable(masm_); 2114 if (FLAG_enable_embedded_constant_pool) { 2115 __ LoadConstantPoolPointerRegisterFromCodeTargetAddress(ip); 2116 } 2117 __ LoadP(r5, FieldMemOperand(r4, JSGeneratorObject::kContinuationOffset)); 2118 __ SmiUntag(r5); 2119 __ add(ip, ip, r5); 2120 __ LoadSmiLiteral(r5, 2121 Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)); 2122 __ StoreP(r5, FieldMemOperand(r4, JSGeneratorObject::kContinuationOffset), 2123 r0); 2124 __ Jump(ip); 2125 __ bind(&slow_resume); 2126 } 2127 } else { 2128 __ beq(&call_resume, cr0); 2129 } 2130 2131 // Otherwise, we push holes for the operand stack and call the runtime to fix 2132 // up the stack and the handlers. 2133 Label operand_loop; 2134 __ mtctr(r6); 2135 __ bind(&operand_loop); 2136 __ push(r5); 2137 __ bdnz(&operand_loop); 2138 2139 __ bind(&call_resume); 2140 DCHECK(!result_register().is(r4)); 2141 __ Push(r4, result_register()); 2142 __ Push(Smi::FromInt(resume_mode)); 2143 __ CallRuntime(Runtime::kResumeJSGeneratorObject); 2144 // Not reached: the runtime call returns elsewhere. 2145 __ stop("not-reached"); 2146 2147 __ bind(&done); 2148 context()->Plug(result_register()); 2149 } 2150 2151 2152 void FullCodeGenerator::EmitCreateIteratorResult(bool done) { 2153 Label allocate, done_allocate; 2154 2155 __ Allocate(JSIteratorResult::kSize, r3, r5, r6, &allocate, TAG_OBJECT); 2156 __ b(&done_allocate); 2157 2158 __ bind(&allocate); 2159 __ Push(Smi::FromInt(JSIteratorResult::kSize)); 2160 __ CallRuntime(Runtime::kAllocateInNewSpace); 2161 2162 __ bind(&done_allocate); 2163 __ LoadNativeContextSlot(Context::ITERATOR_RESULT_MAP_INDEX, r4); 2164 __ pop(r5); 2165 __ LoadRoot(r6, 2166 done ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex); 2167 __ LoadRoot(r7, Heap::kEmptyFixedArrayRootIndex); 2168 __ StoreP(r4, FieldMemOperand(r3, HeapObject::kMapOffset), r0); 2169 __ StoreP(r7, FieldMemOperand(r3, JSObject::kPropertiesOffset), r0); 2170 __ StoreP(r7, FieldMemOperand(r3, JSObject::kElementsOffset), r0); 2171 __ StoreP(r5, FieldMemOperand(r3, JSIteratorResult::kValueOffset), r0); 2172 __ StoreP(r6, FieldMemOperand(r3, JSIteratorResult::kDoneOffset), r0); 2173 } 2174 2175 2176 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { 2177 SetExpressionPosition(prop); 2178 Literal* key = prop->key()->AsLiteral(); 2179 DCHECK(!prop->IsSuperAccess()); 2180 2181 __ mov(LoadDescriptor::NameRegister(), Operand(key->value())); 2182 __ mov(LoadDescriptor::SlotRegister(), 2183 Operand(SmiFromSlot(prop->PropertyFeedbackSlot()))); 2184 CallLoadIC(NOT_INSIDE_TYPEOF, language_mode()); 2185 } 2186 2187 2188 void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) { 2189 // Stack: receiver, home_object. 2190 SetExpressionPosition(prop); 2191 Literal* key = prop->key()->AsLiteral(); 2192 DCHECK(!key->value()->IsSmi()); 2193 DCHECK(prop->IsSuperAccess()); 2194 2195 __ Push(key->value()); 2196 __ Push(Smi::FromInt(language_mode())); 2197 __ CallRuntime(Runtime::kLoadFromSuper); 2198 } 2199 2200 2201 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { 2202 SetExpressionPosition(prop); 2203 Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate(), language_mode()).code(); 2204 __ mov(LoadDescriptor::SlotRegister(), 2205 Operand(SmiFromSlot(prop->PropertyFeedbackSlot()))); 2206 CallIC(ic); 2207 } 2208 2209 2210 void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) { 2211 // Stack: receiver, home_object, key. 2212 SetExpressionPosition(prop); 2213 __ Push(Smi::FromInt(language_mode())); 2214 __ CallRuntime(Runtime::kLoadKeyedFromSuper); 2215 } 2216 2217 2218 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, 2219 Token::Value op, 2220 Expression* left_expr, 2221 Expression* right_expr) { 2222 Label done, smi_case, stub_call; 2223 2224 Register scratch1 = r5; 2225 Register scratch2 = r6; 2226 2227 // Get the arguments. 2228 Register left = r4; 2229 Register right = r3; 2230 __ pop(left); 2231 2232 // Perform combined smi check on both operands. 2233 __ orx(scratch1, left, right); 2234 STATIC_ASSERT(kSmiTag == 0); 2235 JumpPatchSite patch_site(masm_); 2236 patch_site.EmitJumpIfSmi(scratch1, &smi_case); 2237 2238 __ bind(&stub_call); 2239 Handle<Code> code = 2240 CodeFactory::BinaryOpIC(isolate(), op, strength(language_mode())).code(); 2241 CallIC(code, expr->BinaryOperationFeedbackId()); 2242 patch_site.EmitPatchInfo(); 2243 __ b(&done); 2244 2245 __ bind(&smi_case); 2246 // Smi case. This code works the same way as the smi-smi case in the type 2247 // recording binary operation stub. 2248 switch (op) { 2249 case Token::SAR: 2250 __ GetLeastBitsFromSmi(scratch1, right, 5); 2251 __ ShiftRightArith(right, left, scratch1); 2252 __ ClearRightImm(right, right, Operand(kSmiTagSize + kSmiShiftSize)); 2253 break; 2254 case Token::SHL: { 2255 __ GetLeastBitsFromSmi(scratch2, right, 5); 2256 #if V8_TARGET_ARCH_PPC64 2257 __ ShiftLeft_(right, left, scratch2); 2258 #else 2259 __ SmiUntag(scratch1, left); 2260 __ ShiftLeft_(scratch1, scratch1, scratch2); 2261 // Check that the *signed* result fits in a smi 2262 __ JumpIfNotSmiCandidate(scratch1, scratch2, &stub_call); 2263 __ SmiTag(right, scratch1); 2264 #endif 2265 break; 2266 } 2267 case Token::SHR: { 2268 __ SmiUntag(scratch1, left); 2269 __ GetLeastBitsFromSmi(scratch2, right, 5); 2270 __ srw(scratch1, scratch1, scratch2); 2271 // Unsigned shift is not allowed to produce a negative number. 2272 __ JumpIfNotUnsignedSmiCandidate(scratch1, r0, &stub_call); 2273 __ SmiTag(right, scratch1); 2274 break; 2275 } 2276 case Token::ADD: { 2277 __ AddAndCheckForOverflow(scratch1, left, right, scratch2, r0); 2278 __ BranchOnOverflow(&stub_call); 2279 __ mr(right, scratch1); 2280 break; 2281 } 2282 case Token::SUB: { 2283 __ SubAndCheckForOverflow(scratch1, left, right, scratch2, r0); 2284 __ BranchOnOverflow(&stub_call); 2285 __ mr(right, scratch1); 2286 break; 2287 } 2288 case Token::MUL: { 2289 Label mul_zero; 2290 #if V8_TARGET_ARCH_PPC64 2291 // Remove tag from both operands. 2292 __ SmiUntag(ip, right); 2293 __ SmiUntag(r0, left); 2294 __ Mul(scratch1, r0, ip); 2295 // Check for overflowing the smi range - no overflow if higher 33 bits of 2296 // the result are identical. 2297 __ TestIfInt32(scratch1, r0); 2298 __ bne(&stub_call); 2299 #else 2300 __ SmiUntag(ip, right); 2301 __ mullw(scratch1, left, ip); 2302 __ mulhw(scratch2, left, ip); 2303 // Check for overflowing the smi range - no overflow if higher 33 bits of 2304 // the result are identical. 2305 __ TestIfInt32(scratch2, scratch1, ip); 2306 __ bne(&stub_call); 2307 #endif 2308 // Go slow on zero result to handle -0. 2309 __ cmpi(scratch1, Operand::Zero()); 2310 __ beq(&mul_zero); 2311 #if V8_TARGET_ARCH_PPC64 2312 __ SmiTag(right, scratch1); 2313 #else 2314 __ mr(right, scratch1); 2315 #endif 2316 __ b(&done); 2317 // We need -0 if we were multiplying a negative number with 0 to get 0. 2318 // We know one of them was zero. 2319 __ bind(&mul_zero); 2320 __ add(scratch2, right, left); 2321 __ cmpi(scratch2, Operand::Zero()); 2322 __ blt(&stub_call); 2323 __ LoadSmiLiteral(right, Smi::FromInt(0)); 2324 break; 2325 } 2326 case Token::BIT_OR: 2327 __ orx(right, left, right); 2328 break; 2329 case Token::BIT_AND: 2330 __ and_(right, left, right); 2331 break; 2332 case Token::BIT_XOR: 2333 __ xor_(right, left, right); 2334 break; 2335 default: 2336 UNREACHABLE(); 2337 } 2338 2339 __ bind(&done); 2340 context()->Plug(r3); 2341 } 2342 2343 2344 void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) { 2345 // Constructor is in r3. 2346 DCHECK(lit != NULL); 2347 __ push(r3); 2348 2349 // No access check is needed here since the constructor is created by the 2350 // class literal. 2351 Register scratch = r4; 2352 __ LoadP(scratch, 2353 FieldMemOperand(r3, JSFunction::kPrototypeOrInitialMapOffset)); 2354 __ push(scratch); 2355 2356 for (int i = 0; i < lit->properties()->length(); i++) { 2357 ObjectLiteral::Property* property = lit->properties()->at(i); 2358 Expression* value = property->value(); 2359 2360 if (property->is_static()) { 2361 __ LoadP(scratch, MemOperand(sp, kPointerSize)); // constructor 2362 } else { 2363 __ LoadP(scratch, MemOperand(sp, 0)); // prototype 2364 } 2365 __ push(scratch); 2366 EmitPropertyKey(property, lit->GetIdForProperty(i)); 2367 2368 // The static prototype property is read only. We handle the non computed 2369 // property name case in the parser. Since this is the only case where we 2370 // need to check for an own read only property we special case this so we do 2371 // not need to do this for every property. 2372 if (property->is_static() && property->is_computed_name()) { 2373 __ CallRuntime(Runtime::kThrowIfStaticPrototype); 2374 __ push(r3); 2375 } 2376 2377 VisitForStackValue(value); 2378 if (NeedsHomeObject(value)) { 2379 EmitSetHomeObject(value, 2, property->GetSlot()); 2380 } 2381 2382 switch (property->kind()) { 2383 case ObjectLiteral::Property::CONSTANT: 2384 case ObjectLiteral::Property::MATERIALIZED_LITERAL: 2385 case ObjectLiteral::Property::PROTOTYPE: 2386 UNREACHABLE(); 2387 case ObjectLiteral::Property::COMPUTED: 2388 __ CallRuntime(Runtime::kDefineClassMethod); 2389 break; 2390 2391 case ObjectLiteral::Property::GETTER: 2392 __ mov(r3, Operand(Smi::FromInt(DONT_ENUM))); 2393 __ push(r3); 2394 __ CallRuntime(Runtime::kDefineGetterPropertyUnchecked); 2395 break; 2396 2397 case ObjectLiteral::Property::SETTER: 2398 __ mov(r3, Operand(Smi::FromInt(DONT_ENUM))); 2399 __ push(r3); 2400 __ CallRuntime(Runtime::kDefineSetterPropertyUnchecked); 2401 break; 2402 2403 default: 2404 UNREACHABLE(); 2405 } 2406 } 2407 2408 // Set both the prototype and constructor to have fast properties, and also 2409 // freeze them in strong mode. 2410 __ CallRuntime(Runtime::kFinalizeClassDefinition); 2411 } 2412 2413 2414 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op) { 2415 __ pop(r4); 2416 Handle<Code> code = 2417 CodeFactory::BinaryOpIC(isolate(), op, strength(language_mode())).code(); 2418 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code. 2419 CallIC(code, expr->BinaryOperationFeedbackId()); 2420 patch_site.EmitPatchInfo(); 2421 context()->Plug(r3); 2422 } 2423 2424 2425 void FullCodeGenerator::EmitAssignment(Expression* expr, 2426 FeedbackVectorSlot slot) { 2427 DCHECK(expr->IsValidReferenceExpressionOrThis()); 2428 2429 Property* prop = expr->AsProperty(); 2430 LhsKind assign_type = Property::GetAssignType(prop); 2431 2432 switch (assign_type) { 2433 case VARIABLE: { 2434 Variable* var = expr->AsVariableProxy()->var(); 2435 EffectContext context(this); 2436 EmitVariableAssignment(var, Token::ASSIGN, slot); 2437 break; 2438 } 2439 case NAMED_PROPERTY: { 2440 __ push(r3); // Preserve value. 2441 VisitForAccumulatorValue(prop->obj()); 2442 __ Move(StoreDescriptor::ReceiverRegister(), r3); 2443 __ pop(StoreDescriptor::ValueRegister()); // Restore value. 2444 __ mov(StoreDescriptor::NameRegister(), 2445 Operand(prop->key()->AsLiteral()->value())); 2446 EmitLoadStoreICSlot(slot); 2447 CallStoreIC(); 2448 break; 2449 } 2450 case NAMED_SUPER_PROPERTY: { 2451 __ Push(r3); 2452 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var()); 2453 VisitForAccumulatorValue( 2454 prop->obj()->AsSuperPropertyReference()->home_object()); 2455 // stack: value, this; r3: home_object 2456 Register scratch = r5; 2457 Register scratch2 = r6; 2458 __ mr(scratch, result_register()); // home_object 2459 __ LoadP(r3, MemOperand(sp, kPointerSize)); // value 2460 __ LoadP(scratch2, MemOperand(sp, 0)); // this 2461 __ StoreP(scratch2, MemOperand(sp, kPointerSize)); // this 2462 __ StoreP(scratch, MemOperand(sp, 0)); // home_object 2463 // stack: this, home_object; r3: value 2464 EmitNamedSuperPropertyStore(prop); 2465 break; 2466 } 2467 case KEYED_SUPER_PROPERTY: { 2468 __ Push(r3); 2469 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var()); 2470 VisitForStackValue( 2471 prop->obj()->AsSuperPropertyReference()->home_object()); 2472 VisitForAccumulatorValue(prop->key()); 2473 Register scratch = r5; 2474 Register scratch2 = r6; 2475 __ LoadP(scratch2, MemOperand(sp, 2 * kPointerSize)); // value 2476 // stack: value, this, home_object; r3: key, r6: value 2477 __ LoadP(scratch, MemOperand(sp, kPointerSize)); // this 2478 __ StoreP(scratch, MemOperand(sp, 2 * kPointerSize)); 2479 __ LoadP(scratch, MemOperand(sp, 0)); // home_object 2480 __ StoreP(scratch, MemOperand(sp, kPointerSize)); 2481 __ StoreP(r3, MemOperand(sp, 0)); 2482 __ Move(r3, scratch2); 2483 // stack: this, home_object, key; r3: value. 2484 EmitKeyedSuperPropertyStore(prop); 2485 break; 2486 } 2487 case KEYED_PROPERTY: { 2488 __ push(r3); // Preserve value. 2489 VisitForStackValue(prop->obj()); 2490 VisitForAccumulatorValue(prop->key()); 2491 __ Move(StoreDescriptor::NameRegister(), r3); 2492 __ Pop(StoreDescriptor::ValueRegister(), 2493 StoreDescriptor::ReceiverRegister()); 2494 EmitLoadStoreICSlot(slot); 2495 Handle<Code> ic = 2496 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code(); 2497 CallIC(ic); 2498 break; 2499 } 2500 } 2501 context()->Plug(r3); 2502 } 2503 2504 2505 void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot( 2506 Variable* var, MemOperand location) { 2507 __ StoreP(result_register(), location, r0); 2508 if (var->IsContextSlot()) { 2509 // RecordWrite may destroy all its register arguments. 2510 __ mr(r6, result_register()); 2511 int offset = Context::SlotOffset(var->index()); 2512 __ RecordWriteContextSlot(r4, offset, r6, r5, kLRHasBeenSaved, 2513 kDontSaveFPRegs); 2514 } 2515 } 2516 2517 2518 void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, 2519 FeedbackVectorSlot slot) { 2520 if (var->IsUnallocated()) { 2521 // Global var, const, or let. 2522 __ mov(StoreDescriptor::NameRegister(), Operand(var->name())); 2523 __ LoadGlobalObject(StoreDescriptor::ReceiverRegister()); 2524 EmitLoadStoreICSlot(slot); 2525 CallStoreIC(); 2526 2527 } else if (var->mode() == LET && op != Token::INIT) { 2528 // Non-initializing assignment to let variable needs a write barrier. 2529 DCHECK(!var->IsLookupSlot()); 2530 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); 2531 Label assign; 2532 MemOperand location = VarOperand(var, r4); 2533 __ LoadP(r6, location); 2534 __ CompareRoot(r6, Heap::kTheHoleValueRootIndex); 2535 __ bne(&assign); 2536 __ mov(r6, Operand(var->name())); 2537 __ push(r6); 2538 __ CallRuntime(Runtime::kThrowReferenceError); 2539 // Perform the assignment. 2540 __ bind(&assign); 2541 EmitStoreToStackLocalOrContextSlot(var, location); 2542 2543 } else if (var->mode() == CONST && op != Token::INIT) { 2544 // Assignment to const variable needs a write barrier. 2545 DCHECK(!var->IsLookupSlot()); 2546 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); 2547 Label const_error; 2548 MemOperand location = VarOperand(var, r4); 2549 __ LoadP(r6, location); 2550 __ CompareRoot(r6, Heap::kTheHoleValueRootIndex); 2551 __ bne(&const_error); 2552 __ mov(r6, Operand(var->name())); 2553 __ push(r6); 2554 __ CallRuntime(Runtime::kThrowReferenceError); 2555 __ bind(&const_error); 2556 __ CallRuntime(Runtime::kThrowConstAssignError); 2557 2558 } else if (var->is_this() && var->mode() == CONST && op == Token::INIT) { 2559 // Initializing assignment to const {this} needs a write barrier. 2560 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); 2561 Label uninitialized_this; 2562 MemOperand location = VarOperand(var, r4); 2563 __ LoadP(r6, location); 2564 __ CompareRoot(r6, Heap::kTheHoleValueRootIndex); 2565 __ beq(&uninitialized_this); 2566 __ mov(r4, Operand(var->name())); 2567 __ push(r4); 2568 __ CallRuntime(Runtime::kThrowReferenceError); 2569 __ bind(&uninitialized_this); 2570 EmitStoreToStackLocalOrContextSlot(var, location); 2571 2572 } else if (!var->is_const_mode() || 2573 (var->mode() == CONST && op == Token::INIT)) { 2574 if (var->IsLookupSlot()) { 2575 // Assignment to var. 2576 __ push(r3); // Value. 2577 __ mov(r4, Operand(var->name())); 2578 __ mov(r3, Operand(Smi::FromInt(language_mode()))); 2579 __ Push(cp, r4, r3); // Context, name, language mode. 2580 __ CallRuntime(Runtime::kStoreLookupSlot); 2581 } else { 2582 // Assignment to var or initializing assignment to let/const in harmony 2583 // mode. 2584 DCHECK((var->IsStackAllocated() || var->IsContextSlot())); 2585 MemOperand location = VarOperand(var, r4); 2586 if (generate_debug_code_ && var->mode() == LET && op == Token::INIT) { 2587 // Check for an uninitialized let binding. 2588 __ LoadP(r5, location); 2589 __ CompareRoot(r5, Heap::kTheHoleValueRootIndex); 2590 __ Check(eq, kLetBindingReInitialization); 2591 } 2592 EmitStoreToStackLocalOrContextSlot(var, location); 2593 } 2594 } else if (var->mode() == CONST_LEGACY && op == Token::INIT) { 2595 // Const initializers need a write barrier. 2596 DCHECK(!var->IsParameter()); // No const parameters. 2597 if (var->IsLookupSlot()) { 2598 __ push(r3); 2599 __ mov(r3, Operand(var->name())); 2600 __ Push(cp, r3); // Context and name. 2601 __ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot); 2602 } else { 2603 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); 2604 Label skip; 2605 MemOperand location = VarOperand(var, r4); 2606 __ LoadP(r5, location); 2607 __ CompareRoot(r5, Heap::kTheHoleValueRootIndex); 2608 __ bne(&skip); 2609 EmitStoreToStackLocalOrContextSlot(var, location); 2610 __ bind(&skip); 2611 } 2612 2613 } else { 2614 DCHECK(var->mode() == CONST_LEGACY && op != Token::INIT); 2615 if (is_strict(language_mode())) { 2616 __ CallRuntime(Runtime::kThrowConstAssignError); 2617 } 2618 // Silently ignore store in sloppy mode. 2619 } 2620 } 2621 2622 2623 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { 2624 // Assignment to a property, using a named store IC. 2625 Property* prop = expr->target()->AsProperty(); 2626 DCHECK(prop != NULL); 2627 DCHECK(prop->key()->IsLiteral()); 2628 2629 __ mov(StoreDescriptor::NameRegister(), 2630 Operand(prop->key()->AsLiteral()->value())); 2631 __ pop(StoreDescriptor::ReceiverRegister()); 2632 EmitLoadStoreICSlot(expr->AssignmentSlot()); 2633 CallStoreIC(); 2634 2635 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); 2636 context()->Plug(r3); 2637 } 2638 2639 2640 void FullCodeGenerator::EmitNamedSuperPropertyStore(Property* prop) { 2641 // Assignment to named property of super. 2642 // r3 : value 2643 // stack : receiver ('this'), home_object 2644 DCHECK(prop != NULL); 2645 Literal* key = prop->key()->AsLiteral(); 2646 DCHECK(key != NULL); 2647 2648 __ Push(key->value()); 2649 __ Push(r3); 2650 __ CallRuntime((is_strict(language_mode()) ? Runtime::kStoreToSuper_Strict 2651 : Runtime::kStoreToSuper_Sloppy)); 2652 } 2653 2654 2655 void FullCodeGenerator::EmitKeyedSuperPropertyStore(Property* prop) { 2656 // Assignment to named property of super. 2657 // r3 : value 2658 // stack : receiver ('this'), home_object, key 2659 DCHECK(prop != NULL); 2660 2661 __ Push(r3); 2662 __ CallRuntime((is_strict(language_mode()) 2663 ? Runtime::kStoreKeyedToSuper_Strict 2664 : Runtime::kStoreKeyedToSuper_Sloppy)); 2665 } 2666 2667 2668 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { 2669 // Assignment to a property, using a keyed store IC. 2670 __ Pop(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister()); 2671 DCHECK(StoreDescriptor::ValueRegister().is(r3)); 2672 2673 Handle<Code> ic = 2674 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code(); 2675 EmitLoadStoreICSlot(expr->AssignmentSlot()); 2676 CallIC(ic); 2677 2678 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); 2679 context()->Plug(r3); 2680 } 2681 2682 2683 void FullCodeGenerator::VisitProperty(Property* expr) { 2684 Comment cmnt(masm_, "[ Property"); 2685 SetExpressionPosition(expr); 2686 2687 Expression* key = expr->key(); 2688 2689 if (key->IsPropertyName()) { 2690 if (!expr->IsSuperAccess()) { 2691 VisitForAccumulatorValue(expr->obj()); 2692 __ Move(LoadDescriptor::ReceiverRegister(), r3); 2693 EmitNamedPropertyLoad(expr); 2694 } else { 2695 VisitForStackValue(expr->obj()->AsSuperPropertyReference()->this_var()); 2696 VisitForStackValue( 2697 expr->obj()->AsSuperPropertyReference()->home_object()); 2698 EmitNamedSuperPropertyLoad(expr); 2699 } 2700 } else { 2701 if (!expr->IsSuperAccess()) { 2702 VisitForStackValue(expr->obj()); 2703 VisitForAccumulatorValue(expr->key()); 2704 __ Move(LoadDescriptor::NameRegister(), r3); 2705 __ pop(LoadDescriptor::ReceiverRegister()); 2706 EmitKeyedPropertyLoad(expr); 2707 } else { 2708 VisitForStackValue(expr->obj()->AsSuperPropertyReference()->this_var()); 2709 VisitForStackValue( 2710 expr->obj()->AsSuperPropertyReference()->home_object()); 2711 VisitForStackValue(expr->key()); 2712 EmitKeyedSuperPropertyLoad(expr); 2713 } 2714 } 2715 PrepareForBailoutForId(expr->LoadId(), TOS_REG); 2716 context()->Plug(r3); 2717 } 2718 2719 2720 void FullCodeGenerator::CallIC(Handle<Code> code, TypeFeedbackId ast_id) { 2721 ic_total_count_++; 2722 __ Call(code, RelocInfo::CODE_TARGET, ast_id); 2723 } 2724 2725 2726 // Code common for calls using the IC. 2727 void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) { 2728 Expression* callee = expr->expression(); 2729 2730 // Get the target function. 2731 ConvertReceiverMode convert_mode; 2732 if (callee->IsVariableProxy()) { 2733 { 2734 StackValueContext context(this); 2735 EmitVariableLoad(callee->AsVariableProxy()); 2736 PrepareForBailout(callee, NO_REGISTERS); 2737 } 2738 // Push undefined as receiver. This is patched in the method prologue if it 2739 // is a sloppy mode method. 2740 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); 2741 __ push(r0); 2742 convert_mode = ConvertReceiverMode::kNullOrUndefined; 2743 } else { 2744 // Load the function from the receiver. 2745 DCHECK(callee->IsProperty()); 2746 DCHECK(!callee->AsProperty()->IsSuperAccess()); 2747 __ LoadP(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0)); 2748 EmitNamedPropertyLoad(callee->AsProperty()); 2749 PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG); 2750 // Push the target function under the receiver. 2751 __ LoadP(r0, MemOperand(sp, 0)); 2752 __ push(r0); 2753 __ StoreP(r3, MemOperand(sp, kPointerSize)); 2754 convert_mode = ConvertReceiverMode::kNotNullOrUndefined; 2755 } 2756 2757 EmitCall(expr, convert_mode); 2758 } 2759 2760 2761 void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) { 2762 Expression* callee = expr->expression(); 2763 DCHECK(callee->IsProperty()); 2764 Property* prop = callee->AsProperty(); 2765 DCHECK(prop->IsSuperAccess()); 2766 SetExpressionPosition(prop); 2767 2768 Literal* key = prop->key()->AsLiteral(); 2769 DCHECK(!key->value()->IsSmi()); 2770 // Load the function from the receiver. 2771 const Register scratch = r4; 2772 SuperPropertyReference* super_ref = prop->obj()->AsSuperPropertyReference(); 2773 VisitForAccumulatorValue(super_ref->home_object()); 2774 __ mr(scratch, r3); 2775 VisitForAccumulatorValue(super_ref->this_var()); 2776 __ Push(scratch, r3, r3, scratch); 2777 __ Push(key->value()); 2778 __ Push(Smi::FromInt(language_mode())); 2779 2780 // Stack here: 2781 // - home_object 2782 // - this (receiver) 2783 // - this (receiver) <-- LoadFromSuper will pop here and below. 2784 // - home_object 2785 // - key 2786 // - language_mode 2787 __ CallRuntime(Runtime::kLoadFromSuper); 2788 2789 // Replace home_object with target function. 2790 __ StoreP(r3, MemOperand(sp, kPointerSize)); 2791 2792 // Stack here: 2793 // - target function 2794 // - this (receiver) 2795 EmitCall(expr); 2796 } 2797 2798 2799 // Code common for calls using the IC. 2800 void FullCodeGenerator::EmitKeyedCallWithLoadIC(Call* expr, Expression* key) { 2801 // Load the key. 2802 VisitForAccumulatorValue(key); 2803 2804 Expression* callee = expr->expression(); 2805 2806 // Load the function from the receiver. 2807 DCHECK(callee->IsProperty()); 2808 __ LoadP(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0)); 2809 __ Move(LoadDescriptor::NameRegister(), r3); 2810 EmitKeyedPropertyLoad(callee->AsProperty()); 2811 PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG); 2812 2813 // Push the target function under the receiver. 2814 __ LoadP(ip, MemOperand(sp, 0)); 2815 __ push(ip); 2816 __ StoreP(r3, MemOperand(sp, kPointerSize)); 2817 2818 EmitCall(expr, ConvertReceiverMode::kNotNullOrUndefined); 2819 } 2820 2821 2822 void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) { 2823 Expression* callee = expr->expression(); 2824 DCHECK(callee->IsProperty()); 2825 Property* prop = callee->AsProperty(); 2826 DCHECK(prop->IsSuperAccess()); 2827 2828 SetExpressionPosition(prop); 2829 // Load the function from the receiver. 2830 const Register scratch = r4; 2831 SuperPropertyReference* super_ref = prop->obj()->AsSuperPropertyReference(); 2832 VisitForAccumulatorValue(super_ref->home_object()); 2833 __ mr(scratch, r3); 2834 VisitForAccumulatorValue(super_ref->this_var()); 2835 __ Push(scratch, r3, r3, scratch); 2836 VisitForStackValue(prop->key()); 2837 __ Push(Smi::FromInt(language_mode())); 2838 2839 // Stack here: 2840 // - home_object 2841 // - this (receiver) 2842 // - this (receiver) <-- LoadKeyedFromSuper will pop here and below. 2843 // - home_object 2844 // - key 2845 // - language_mode 2846 __ CallRuntime(Runtime::kLoadKeyedFromSuper); 2847 2848 // Replace home_object with target function. 2849 __ StoreP(r3, MemOperand(sp, kPointerSize)); 2850 2851 // Stack here: 2852 // - target function 2853 // - this (receiver) 2854 EmitCall(expr); 2855 } 2856 2857 2858 void FullCodeGenerator::EmitCall(Call* expr, ConvertReceiverMode mode) { 2859 // Load the arguments. 2860 ZoneList<Expression*>* args = expr->arguments(); 2861 int arg_count = args->length(); 2862 for (int i = 0; i < arg_count; i++) { 2863 VisitForStackValue(args->at(i)); 2864 } 2865 2866 PrepareForBailoutForId(expr->CallId(), NO_REGISTERS); 2867 SetCallPosition(expr); 2868 Handle<Code> ic = CodeFactory::CallIC(isolate(), arg_count, mode).code(); 2869 __ LoadSmiLiteral(r6, SmiFromSlot(expr->CallFeedbackICSlot())); 2870 __ LoadP(r4, MemOperand(sp, (arg_count + 1) * kPointerSize), r0); 2871 // Don't assign a type feedback id to the IC, since type feedback is provided 2872 // by the vector above. 2873 CallIC(ic); 2874 2875 RecordJSReturnSite(expr); 2876 // Restore context register. 2877 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); 2878 context()->DropAndPlug(1, r3); 2879 } 2880 2881 2882 void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { 2883 // r7: copy of the first argument or undefined if it doesn't exist. 2884 if (arg_count > 0) { 2885 __ LoadP(r7, MemOperand(sp, arg_count * kPointerSize), r0); 2886 } else { 2887 __ LoadRoot(r7, Heap::kUndefinedValueRootIndex); 2888 } 2889 2890 // r6: the receiver of the enclosing function. 2891 __ LoadP(r6, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 2892 2893 // r5: language mode. 2894 __ LoadSmiLiteral(r5, Smi::FromInt(language_mode())); 2895 2896 // r4: the start position of the scope the calls resides in. 2897 __ LoadSmiLiteral(r4, Smi::FromInt(scope()->start_position())); 2898 2899 // Do the runtime call. 2900 __ Push(r7, r6, r5, r4); 2901 __ CallRuntime(Runtime::kResolvePossiblyDirectEval); 2902 } 2903 2904 2905 // See http://www.ecma-international.org/ecma-262/6.0/#sec-function-calls. 2906 void FullCodeGenerator::PushCalleeAndWithBaseObject(Call* expr) { 2907 VariableProxy* callee = expr->expression()->AsVariableProxy(); 2908 if (callee->var()->IsLookupSlot()) { 2909 Label slow, done; 2910 SetExpressionPosition(callee); 2911 // Generate code for loading from variables potentially shadowed by 2912 // eval-introduced variables. 2913 EmitDynamicLookupFastCase(callee, NOT_INSIDE_TYPEOF, &slow, &done); 2914 2915 __ bind(&slow); 2916 // Call the runtime to find the function to call (returned in r3) and 2917 // the object holding it (returned in r4). 2918 DCHECK(!context_register().is(r5)); 2919 __ mov(r5, Operand(callee->name())); 2920 __ Push(context_register(), r5); 2921 __ CallRuntime(Runtime::kLoadLookupSlot); 2922 __ Push(r3, r4); // Function, receiver. 2923 PrepareForBailoutForId(expr->LookupId(), NO_REGISTERS); 2924 2925 // If fast case code has been generated, emit code to push the function 2926 // and receiver and have the slow path jump around this code. 2927 if (done.is_linked()) { 2928 Label call; 2929 __ b(&call); 2930 __ bind(&done); 2931 // Push function. 2932 __ push(r3); 2933 // Pass undefined as the receiver, which is the WithBaseObject of a 2934 // non-object environment record. If the callee is sloppy, it will patch 2935 // it up to be the global receiver. 2936 __ LoadRoot(r4, Heap::kUndefinedValueRootIndex); 2937 __ push(r4); 2938 __ bind(&call); 2939 } 2940 } else { 2941 VisitForStackValue(callee); 2942 // refEnv.WithBaseObject() 2943 __ LoadRoot(r5, Heap::kUndefinedValueRootIndex); 2944 __ push(r5); // Reserved receiver slot. 2945 } 2946 } 2947 2948 2949 void FullCodeGenerator::EmitPossiblyEvalCall(Call* expr) { 2950 // In a call to eval, we first call RuntimeHidden_ResolvePossiblyDirectEval 2951 // to resolve the function we need to call. Then we call the resolved 2952 // function using the given arguments. 2953 ZoneList<Expression*>* args = expr->arguments(); 2954 int arg_count = args->length(); 2955 2956 PushCalleeAndWithBaseObject(expr); 2957 2958 // Push the arguments. 2959 for (int i = 0; i < arg_count; i++) { 2960 VisitForStackValue(args->at(i)); 2961 } 2962 2963 // Push a copy of the function (found below the arguments) and 2964 // resolve eval. 2965 __ LoadP(r4, MemOperand(sp, (arg_count + 1) * kPointerSize), r0); 2966 __ push(r4); 2967 EmitResolvePossiblyDirectEval(arg_count); 2968 2969 // Touch up the stack with the resolved function. 2970 __ StoreP(r3, MemOperand(sp, (arg_count + 1) * kPointerSize), r0); 2971 2972 PrepareForBailoutForId(expr->EvalId(), NO_REGISTERS); 2973 2974 // Record source position for debugger. 2975 SetCallPosition(expr); 2976 __ LoadP(r4, MemOperand(sp, (arg_count + 1) * kPointerSize), r0); 2977 __ mov(r3, Operand(arg_count)); 2978 __ Call(isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); 2979 RecordJSReturnSite(expr); 2980 // Restore context register. 2981 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); 2982 context()->DropAndPlug(1, r3); 2983 } 2984 2985 2986 void FullCodeGenerator::VisitCallNew(CallNew* expr) { 2987 Comment cmnt(masm_, "[ CallNew"); 2988 // According to ECMA-262, section 11.2.2, page 44, the function 2989 // expression in new calls must be evaluated before the 2990 // arguments. 2991 2992 // Push constructor on the stack. If it's not a function it's used as 2993 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is 2994 // ignored. 2995 DCHECK(!expr->expression()->IsSuperPropertyReference()); 2996 VisitForStackValue(expr->expression()); 2997 2998 // Push the arguments ("left-to-right") on the stack. 2999 ZoneList<Expression*>* args = expr->arguments(); 3000 int arg_count = args->length(); 3001 for (int i = 0; i < arg_count; i++) { 3002 VisitForStackValue(args->at(i)); 3003 } 3004 3005 // Call the construct call builtin that handles allocation and 3006 // constructor invocation. 3007 SetConstructCallPosition(expr); 3008 3009 // Load function and argument count into r4 and r3. 3010 __ mov(r3, Operand(arg_count)); 3011 __ LoadP(r4, MemOperand(sp, arg_count * kPointerSize), r0); 3012 3013 // Record call targets in unoptimized code. 3014 __ EmitLoadTypeFeedbackVector(r5); 3015 __ LoadSmiLiteral(r6, SmiFromSlot(expr->CallNewFeedbackSlot())); 3016 3017 CallConstructStub stub(isolate()); 3018 __ Call(stub.GetCode(), RelocInfo::CODE_TARGET); 3019 PrepareForBailoutForId(expr->ReturnId(), TOS_REG); 3020 // Restore context register. 3021 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); 3022 context()->Plug(r3); 3023 } 3024 3025 3026 void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) { 3027 SuperCallReference* super_call_ref = 3028 expr->expression()->AsSuperCallReference(); 3029 DCHECK_NOT_NULL(super_call_ref); 3030 3031 // Push the super constructor target on the stack (may be null, 3032 // but the Construct builtin can deal with that properly). 3033 VisitForAccumulatorValue(super_call_ref->this_function_var()); 3034 __ AssertFunction(result_register()); 3035 __ LoadP(result_register(), 3036 FieldMemOperand(result_register(), HeapObject::kMapOffset)); 3037 __ LoadP(result_register(), 3038 FieldMemOperand(result_register(), Map::kPrototypeOffset)); 3039 __ Push(result_register()); 3040 3041 // Push the arguments ("left-to-right") on the stack. 3042 ZoneList<Expression*>* args = expr->arguments(); 3043 int arg_count = args->length(); 3044 for (int i = 0; i < arg_count; i++) { 3045 VisitForStackValue(args->at(i)); 3046 } 3047 3048 // Call the construct call builtin that handles allocation and 3049 // constructor invocation. 3050 SetConstructCallPosition(expr); 3051 3052 // Load new target into r6. 3053 VisitForAccumulatorValue(super_call_ref->new_target_var()); 3054 __ mr(r6, result_register()); 3055 3056 // Load function and argument count into r1 and r0. 3057 __ mov(r3, Operand(arg_count)); 3058 __ LoadP(r4, MemOperand(sp, arg_count * kPointerSize)); 3059 3060 __ Call(isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); 3061 3062 RecordJSReturnSite(expr); 3063 3064 // Restore context register. 3065 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); 3066 context()->Plug(r3); 3067 } 3068 3069 3070 void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) { 3071 ZoneList<Expression*>* args = expr->arguments(); 3072 DCHECK(args->length() == 1); 3073 3074 VisitForAccumulatorValue(args->at(0)); 3075 3076 Label materialize_true, materialize_false; 3077 Label* if_true = NULL; 3078 Label* if_false = NULL; 3079 Label* fall_through = NULL; 3080 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, 3081 &if_false, &fall_through); 3082 3083 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); 3084 __ TestIfSmi(r3, r0); 3085 Split(eq, if_true, if_false, fall_through, cr0); 3086 3087 context()->Plug(if_true, if_false); 3088 } 3089 3090 3091 void FullCodeGenerator::EmitIsJSReceiver(CallRuntime* expr) { 3092 ZoneList<Expression*>* args = expr->arguments(); 3093 DCHECK(args->length() == 1); 3094 3095 VisitForAccumulatorValue(args->at(0)); 3096 3097 Label materialize_true, materialize_false; 3098 Label* if_true = NULL; 3099 Label* if_false = NULL; 3100 Label* fall_through = NULL; 3101 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, 3102 &if_false, &fall_through); 3103 3104 __ JumpIfSmi(r3, if_false); 3105 __ CompareObjectType(r3, r4, r4, FIRST_JS_RECEIVER_TYPE); 3106 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); 3107 Split(ge, if_true, if_false, fall_through); 3108 3109 context()->Plug(if_true, if_false); 3110 } 3111 3112 3113 void FullCodeGenerator::EmitIsSimdValue(CallRuntime* expr) { 3114 ZoneList<Expression*>* args = expr->arguments(); 3115 DCHECK(args->length() == 1); 3116 3117 VisitForAccumulatorValue(args->at(0)); 3118 3119 Label materialize_true, materialize_false; 3120 Label* if_true = NULL; 3121 Label* if_false = NULL; 3122 Label* fall_through = NULL; 3123 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, 3124 &if_false, &fall_through); 3125 3126 __ JumpIfSmi(r3, if_false); 3127 __ CompareObjectType(r3, r4, r4, SIMD128_VALUE_TYPE); 3128 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); 3129 Split(eq, if_true, if_false, fall_through); 3130 3131 context()->Plug(if_true, if_false); 3132 } 3133 3134 3135 void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) { 3136 ZoneList<Expression*>* args = expr->arguments(); 3137 DCHECK(args->length() == 1); 3138 3139 VisitForAccumulatorValue(args->at(0)); 3140 3141 Label materialize_true, materialize_false; 3142 Label* if_true = NULL; 3143 Label* if_false = NULL; 3144 Label* fall_through = NULL; 3145 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, 3146 &if_false, &fall_through); 3147 3148 __ JumpIfSmi(r3, if_false); 3149 __ CompareObjectType(r3, r4, r5, FIRST_FUNCTION_TYPE); 3150 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); 3151 Split(ge, if_true, if_false, fall_through); 3152 3153 context()->Plug(if_true, if_false); 3154 } 3155 3156 3157 void FullCodeGenerator::EmitIsMinusZero(CallRuntime* expr) { 3158 ZoneList<Expression*>* args = expr->arguments(); 3159 DCHECK(args->length() == 1); 3160 3161 VisitForAccumulatorValue(args->at(0)); 3162 3163 Label materialize_true, materialize_false; 3164 Label* if_true = NULL; 3165 Label* if_false = NULL; 3166 Label* fall_through = NULL; 3167 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, 3168 &if_false, &fall_through); 3169 3170 __ CheckMap(r3, r4, Heap::kHeapNumberMapRootIndex, if_false, DO_SMI_CHECK); 3171 #if V8_TARGET_ARCH_PPC64 3172 __ LoadP(r4, FieldMemOperand(r3, HeapNumber::kValueOffset)); 3173 __ li(r5, Operand(1)); 3174 __ rotrdi(r5, r5, 1); // r5 = 0x80000000_00000000 3175 __ cmp(r4, r5); 3176 #else 3177 __ lwz(r5, FieldMemOperand(r3, HeapNumber::kExponentOffset)); 3178 __ lwz(r4, FieldMemOperand(r3, HeapNumber::kMantissaOffset)); 3179 Label skip; 3180 __ lis(r0, Operand(SIGN_EXT_IMM16(0x8000))); 3181 __ cmp(r5, r0); 3182 __ bne(&skip); 3183 __ cmpi(r4, Operand::Zero()); 3184 __ bind(&skip); 3185 #endif 3186 3187 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); 3188 Split(eq, if_true, if_false, fall_through); 3189 3190 context()->Plug(if_true, if_false); 3191 } 3192 3193 3194 void FullCodeGenerator::EmitIsArray(CallRuntime* expr) { 3195 ZoneList<Expression*>* args = expr->arguments(); 3196 DCHECK(args->length() == 1); 3197 3198 VisitForAccumulatorValue(args->at(0)); 3199 3200 Label materialize_true, materialize_false; 3201 Label* if_true = NULL; 3202 Label* if_false = NULL; 3203 Label* fall_through = NULL; 3204 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, 3205 &if_false, &fall_through); 3206 3207 __ JumpIfSmi(r3, if_false); 3208 __ CompareObjectType(r3, r4, r4, JS_ARRAY_TYPE); 3209 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); 3210 Split(eq, if_true, if_false, fall_through); 3211 3212 context()->Plug(if_true, if_false); 3213 } 3214 3215 3216 void FullCodeGenerator::EmitIsTypedArray(CallRuntime* expr) { 3217 ZoneList<Expression*>* args = expr->arguments(); 3218 DCHECK(args->length() == 1); 3219 3220 VisitForAccumulatorValue(args->at(0)); 3221 3222 Label materialize_true, materialize_false; 3223 Label* if_true = NULL; 3224 Label* if_false = NULL; 3225 Label* fall_through = NULL; 3226 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, 3227 &if_false, &fall_through); 3228 3229 __ JumpIfSmi(r3, if_false); 3230 __ CompareObjectType(r3, r4, r4, JS_TYPED_ARRAY_TYPE); 3231 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); 3232 Split(eq, if_true, if_false, fall_through); 3233 3234 context()->Plug(if_true, if_false); 3235 } 3236 3237 3238 void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) { 3239 ZoneList<Expression*>* args = expr->arguments(); 3240 DCHECK(args->length() == 1); 3241 3242 VisitForAccumulatorValue(args->at(0)); 3243 3244 Label materialize_true, materialize_false; 3245 Label* if_true = NULL; 3246 Label* if_false = NULL; 3247 Label* fall_through = NULL; 3248 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, 3249 &if_false, &fall_through); 3250 3251 __ JumpIfSmi(r3, if_false); 3252 __ CompareObjectType(r3, r4, r4, JS_REGEXP_TYPE); 3253 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); 3254 Split(eq, if_true, if_false, fall_through); 3255 3256 context()->Plug(if_true, if_false); 3257 } 3258 3259 3260 void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) { 3261 ZoneList<Expression*>* args = expr->arguments(); 3262 DCHECK(args->length() == 1); 3263 3264 VisitForAccumulatorValue(args->at(0)); 3265 3266 Label materialize_true, materialize_false; 3267 Label* if_true = NULL; 3268 Label* if_false = NULL; 3269 Label* fall_through = NULL; 3270 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, 3271 &if_false, &fall_through); 3272 3273 __ JumpIfSmi(r3, if_false); 3274 __ CompareObjectType(r3, r4, r4, JS_PROXY_TYPE); 3275 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); 3276 Split(eq, if_true, if_false, fall_through); 3277 3278 context()->Plug(if_true, if_false); 3279 } 3280 3281 3282 void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) { 3283 ZoneList<Expression*>* args = expr->arguments(); 3284 DCHECK(args->length() == 2); 3285 3286 // Load the two objects into registers and perform the comparison. 3287 VisitForStackValue(args->at(0)); 3288 VisitForAccumulatorValue(args->at(1)); 3289 3290 Label materialize_true, materialize_false; 3291 Label* if_true = NULL; 3292 Label* if_false = NULL; 3293 Label* fall_through = NULL; 3294 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, 3295 &if_false, &fall_through); 3296 3297 __ pop(r4); 3298 __ cmp(r3, r4); 3299 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); 3300 Split(eq, if_true, if_false, fall_through); 3301 3302 context()->Plug(if_true, if_false); 3303 } 3304 3305 3306 void FullCodeGenerator::EmitArguments(CallRuntime* expr) { 3307 ZoneList<Expression*>* args = expr->arguments(); 3308 DCHECK(args->length() == 1); 3309 3310 // ArgumentsAccessStub expects the key in r4 and the formal 3311 // parameter count in r3. 3312 VisitForAccumulatorValue(args->at(0)); 3313 __ mr(r4, r3); 3314 __ LoadSmiLiteral(r3, Smi::FromInt(info_->scope()->num_parameters())); 3315 ArgumentsAccessStub stub(isolate(), ArgumentsAccessStub::READ_ELEMENT); 3316 __ CallStub(&stub); 3317 context()->Plug(r3); 3318 } 3319 3320 3321 void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) { 3322 DCHECK(expr->arguments()->length() == 0); 3323 Label exit; 3324 // Get the number of formal parameters. 3325 __ LoadSmiLiteral(r3, Smi::FromInt(info_->scope()->num_parameters())); 3326 3327 // Check if the calling frame is an arguments adaptor frame. 3328 __ LoadP(r5, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); 3329 __ LoadP(r6, MemOperand(r5, StandardFrameConstants::kContextOffset)); 3330 __ CmpSmiLiteral(r6, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR), r0); 3331 __ bne(&exit); 3332 3333 // Arguments adaptor case: Read the arguments length from the 3334 // adaptor frame. 3335 __ LoadP(r3, MemOperand(r5, ArgumentsAdaptorFrameConstants::kLengthOffset)); 3336 3337 __ bind(&exit); 3338 context()->Plug(r3); 3339 } 3340 3341 3342 void FullCodeGenerator::EmitClassOf(CallRuntime* expr) { 3343 ZoneList<Expression*>* args = expr->arguments(); 3344 DCHECK(args->length() == 1); 3345 Label done, null, function, non_function_constructor; 3346 3347 VisitForAccumulatorValue(args->at(0)); 3348 3349 // If the object is not a JSReceiver, we return null. 3350 __ JumpIfSmi(r3, &null); 3351 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); 3352 __ CompareObjectType(r3, r3, r4, FIRST_JS_RECEIVER_TYPE); 3353 // Map is now in r3. 3354 __ blt(&null); 3355 3356 // Return 'Function' for JSFunction objects. 3357 __ cmpi(r4, Operand(JS_FUNCTION_TYPE)); 3358 __ beq(&function); 3359 3360 // Check if the constructor in the map is a JS function. 3361 Register instance_type = r5; 3362 __ GetMapConstructor(r3, r3, r4, instance_type); 3363 __ cmpi(instance_type, Operand(JS_FUNCTION_TYPE)); 3364 __ bne(&non_function_constructor); 3365 3366 // r3 now contains the constructor function. Grab the 3367 // instance class name from there. 3368 __ LoadP(r3, FieldMemOperand(r3, JSFunction::kSharedFunctionInfoOffset)); 3369 __ LoadP(r3, 3370 FieldMemOperand(r3, SharedFunctionInfo::kInstanceClassNameOffset)); 3371 __ b(&done); 3372 3373 // Functions have class 'Function'. 3374 __ bind(&function); 3375 __ LoadRoot(r3, Heap::kFunction_stringRootIndex); 3376 __ b(&done); 3377 3378 // Objects with a non-function constructor have class 'Object'. 3379 __ bind(&non_function_constructor); 3380 __ LoadRoot(r3, Heap::kObject_stringRootIndex); 3381 __ b(&done); 3382 3383 // Non-JS objects have class null. 3384 __ bind(&null); 3385 __ LoadRoot(r3, Heap::kNullValueRootIndex); 3386 3387 // All done. 3388 __ bind(&done); 3389 3390 context()->Plug(r3); 3391 } 3392 3393 3394 void FullCodeGenerator::EmitValueOf(CallRuntime* expr) { 3395 ZoneList<Expression*>* args = expr->arguments(); 3396 DCHECK(args->length() == 1); 3397 VisitForAccumulatorValue(args->at(0)); // Load the object. 3398 3399 Label done; 3400 // If the object is a smi return the object. 3401 __ JumpIfSmi(r3, &done); 3402 // If the object is not a value type, return the object. 3403 __ CompareObjectType(r3, r4, r4, JS_VALUE_TYPE); 3404 __ bne(&done); 3405 __ LoadP(r3, FieldMemOperand(r3, JSValue::kValueOffset)); 3406 3407 __ bind(&done); 3408 context()->Plug(r3); 3409 } 3410 3411 3412 void FullCodeGenerator::EmitIsDate(CallRuntime* expr) { 3413 ZoneList<Expression*>* args = expr->arguments(); 3414 DCHECK_EQ(1, args->length()); 3415 3416 VisitForAccumulatorValue(args->at(0)); 3417 3418 Label materialize_true, materialize_false; 3419 Label* if_true = nullptr; 3420 Label* if_false = nullptr; 3421 Label* fall_through = nullptr; 3422 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, 3423 &if_false, &fall_through); 3424 3425 __ JumpIfSmi(r3, if_false); 3426 __ CompareObjectType(r3, r4, r4, JS_DATE_TYPE); 3427 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); 3428 Split(eq, if_true, if_false, fall_through); 3429 3430 context()->Plug(if_true, if_false); 3431 } 3432 3433 3434 void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) { 3435 ZoneList<Expression*>* args = expr->arguments(); 3436 DCHECK_EQ(3, args->length()); 3437 3438 Register string = r3; 3439 Register index = r4; 3440 Register value = r5; 3441 3442 VisitForStackValue(args->at(0)); // index 3443 VisitForStackValue(args->at(1)); // value 3444 VisitForAccumulatorValue(args->at(2)); // string 3445 __ Pop(index, value); 3446 3447 if (FLAG_debug_code) { 3448 __ TestIfSmi(value, r0); 3449 __ Check(eq, kNonSmiValue, cr0); 3450 __ TestIfSmi(index, r0); 3451 __ Check(eq, kNonSmiIndex, cr0); 3452 __ SmiUntag(index, index); 3453 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag; 3454 __ EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type); 3455 __ SmiTag(index, index); 3456 } 3457 3458 __ SmiUntag(value); 3459 __ addi(ip, string, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); 3460 __ SmiToByteArrayOffset(r0, index); 3461 __ stbx(value, MemOperand(ip, r0)); 3462 context()->Plug(string); 3463 } 3464 3465 3466 void FullCodeGenerator::EmitTwoByteSeqStringSetChar(CallRuntime* expr) { 3467 ZoneList<Expression*>* args = expr->arguments(); 3468 DCHECK_EQ(3, args->length()); 3469 3470 Register string = r3; 3471 Register index = r4; 3472 Register value = r5; 3473 3474 VisitForStackValue(args->at(0)); // index 3475 VisitForStackValue(args->at(1)); // value 3476 VisitForAccumulatorValue(args->at(2)); // string 3477 __ Pop(index, value); 3478 3479 if (FLAG_debug_code) { 3480 __ TestIfSmi(value, r0); 3481 __ Check(eq, kNonSmiValue, cr0); 3482 __ TestIfSmi(index, r0); 3483 __ Check(eq, kNonSmiIndex, cr0); 3484 __ SmiUntag(index, index); 3485 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; 3486 __ EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type); 3487 __ SmiTag(index, index); 3488 } 3489 3490 __ SmiUntag(value); 3491 __ addi(ip, string, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); 3492 __ SmiToShortArrayOffset(r0, index); 3493 __ sthx(value, MemOperand(ip, r0)); 3494 context()->Plug(string); 3495 } 3496 3497 3498 void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) { 3499 ZoneList<Expression*>* args = expr->arguments(); 3500 DCHECK(args->length() == 2); 3501 VisitForStackValue(args->at(0)); // Load the object. 3502 VisitForAccumulatorValue(args->at(1)); // Load the value. 3503 __ pop(r4); // r3 = value. r4 = object. 3504 3505 Label done; 3506 // If the object is a smi, return the value. 3507 __ JumpIfSmi(r4, &done); 3508 3509 // If the object is not a value type, return the value. 3510 __ CompareObjectType(r4, r5, r5, JS_VALUE_TYPE); 3511 __ bne(&done); 3512 3513 // Store the value. 3514 __ StoreP(r3, FieldMemOperand(r4, JSValue::kValueOffset), r0); 3515 // Update the write barrier. Save the value as it will be 3516 // overwritten by the write barrier code and is needed afterward. 3517 __ mr(r5, r3); 3518 __ RecordWriteField(r4, JSValue::kValueOffset, r5, r6, kLRHasBeenSaved, 3519 kDontSaveFPRegs); 3520 3521 __ bind(&done); 3522 context()->Plug(r3); 3523 } 3524 3525 3526 void FullCodeGenerator::EmitToInteger(CallRuntime* expr) { 3527 ZoneList<Expression*>* args = expr->arguments(); 3528 DCHECK_EQ(1, args->length()); 3529 3530 // Load the argument into r3 and convert it. 3531 VisitForAccumulatorValue(args->at(0)); 3532 3533 // Convert the object to an integer. 3534 Label done_convert; 3535 __ JumpIfSmi(r3, &done_convert); 3536 __ Push(r3); 3537 __ CallRuntime(Runtime::kToInteger); 3538 __ bind(&done_convert); 3539 context()->Plug(r3); 3540 } 3541 3542 3543 void FullCodeGenerator::EmitToName(CallRuntime* expr) { 3544 ZoneList<Expression*>* args = expr->arguments(); 3545 DCHECK_EQ(1, args->length()); 3546 3547 // Load the argument into r3 and convert it. 3548 VisitForAccumulatorValue(args->at(0)); 3549 3550 Label convert, done_convert; 3551 __ JumpIfSmi(r3, &convert); 3552 STATIC_ASSERT(FIRST_NAME_TYPE == FIRST_TYPE); 3553 __ CompareObjectType(r3, r4, r4, LAST_NAME_TYPE); 3554 __ ble(&done_convert); 3555 __ bind(&convert); 3556 __ Push(r3); 3557 __ CallRuntime(Runtime::kToName); 3558 __ bind(&done_convert); 3559 context()->Plug(r3); 3560 } 3561 3562 3563 void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) { 3564 ZoneList<Expression*>* args = expr->arguments(); 3565 DCHECK(args->length() == 1); 3566 VisitForAccumulatorValue(args->at(0)); 3567 3568 Label done; 3569 StringCharFromCodeGenerator generator(r3, r4); 3570 generator.GenerateFast(masm_); 3571 __ b(&done); 3572 3573 NopRuntimeCallHelper call_helper; 3574 generator.GenerateSlow(masm_, call_helper); 3575 3576 __ bind(&done); 3577 context()->Plug(r4); 3578 } 3579 3580 3581 void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) { 3582 ZoneList<Expression*>* args = expr->arguments(); 3583 DCHECK(args->length() == 2); 3584 VisitForStackValue(args->at(0)); 3585 VisitForAccumulatorValue(args->at(1)); 3586 3587 Register object = r4; 3588 Register index = r3; 3589 Register result = r6; 3590 3591 __ pop(object); 3592 3593 Label need_conversion; 3594 Label index_out_of_range; 3595 Label done; 3596 StringCharCodeAtGenerator generator(object, index, result, &need_conversion, 3597 &need_conversion, &index_out_of_range, 3598 STRING_INDEX_IS_NUMBER); 3599 generator.GenerateFast(masm_); 3600 __ b(&done); 3601 3602 __ bind(&index_out_of_range); 3603 // When the index is out of range, the spec requires us to return 3604 // NaN. 3605 __ LoadRoot(result, Heap::kNanValueRootIndex); 3606 __ b(&done); 3607 3608 __ bind(&need_conversion); 3609 // Load the undefined value into the result register, which will 3610 // trigger conversion. 3611 __ LoadRoot(result, Heap::kUndefinedValueRootIndex); 3612 __ b(&done); 3613 3614 NopRuntimeCallHelper call_helper; 3615 generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper); 3616 3617 __ bind(&done); 3618 context()->Plug(result); 3619 } 3620 3621 3622 void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) { 3623 ZoneList<Expression*>* args = expr->arguments(); 3624 DCHECK(args->length() == 2); 3625 VisitForStackValue(args->at(0)); 3626 VisitForAccumulatorValue(args->at(1)); 3627 3628 Register object = r4; 3629 Register index = r3; 3630 Register scratch = r6; 3631 Register result = r3; 3632 3633 __ pop(object); 3634 3635 Label need_conversion; 3636 Label index_out_of_range; 3637 Label done; 3638 StringCharAtGenerator generator(object, index, scratch, result, 3639 &need_conversion, &need_conversion, 3640 &index_out_of_range, STRING_INDEX_IS_NUMBER); 3641 generator.GenerateFast(masm_); 3642 __ b(&done); 3643 3644 __ bind(&index_out_of_range); 3645 // When the index is out of range, the spec requires us to return 3646 // the empty string. 3647 __ LoadRoot(result, Heap::kempty_stringRootIndex); 3648 __ b(&done); 3649 3650 __ bind(&need_conversion); 3651 // Move smi zero into the result register, which will trigger 3652 // conversion. 3653 __ LoadSmiLiteral(result, Smi::FromInt(0)); 3654 __ b(&done); 3655 3656 NopRuntimeCallHelper call_helper; 3657 generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper); 3658 3659 __ bind(&done); 3660 context()->Plug(result); 3661 } 3662 3663 3664 void FullCodeGenerator::EmitCall(CallRuntime* expr) { 3665 ZoneList<Expression*>* args = expr->arguments(); 3666 DCHECK_LE(2, args->length()); 3667 // Push target, receiver and arguments onto the stack. 3668 for (Expression* const arg : *args) { 3669 VisitForStackValue(arg); 3670 } 3671 PrepareForBailoutForId(expr->CallId(), NO_REGISTERS); 3672 // Move target to r4. 3673 int const argc = args->length() - 2; 3674 __ LoadP(r4, MemOperand(sp, (argc + 1) * kPointerSize)); 3675 // Call the target. 3676 __ mov(r3, Operand(argc)); 3677 __ Call(isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); 3678 // Restore context register. 3679 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); 3680 // Discard the function left on TOS. 3681 context()->DropAndPlug(1, r3); 3682 } 3683 3684 3685 void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) { 3686 ZoneList<Expression*>* args = expr->arguments(); 3687 VisitForAccumulatorValue(args->at(0)); 3688 3689 Label materialize_true, materialize_false; 3690 Label* if_true = NULL; 3691 Label* if_false = NULL; 3692 Label* fall_through = NULL; 3693 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, 3694 &if_false, &fall_through); 3695 3696 __ lwz(r3, FieldMemOperand(r3, String::kHashFieldOffset)); 3697 // PPC - assume ip is free 3698 __ mov(ip, Operand(String::kContainsCachedArrayIndexMask)); 3699 __ and_(r0, r3, ip, SetRC); 3700 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); 3701 Split(eq, if_true, if_false, fall_through, cr0); 3702 3703 context()->Plug(if_true, if_false); 3704 } 3705 3706 3707 void FullCodeGenerator::EmitGetCachedArrayIndex(CallRuntime* expr) { 3708 ZoneList<Expression*>* args = expr->arguments(); 3709 DCHECK(args->length() == 1); 3710 VisitForAccumulatorValue(args->at(0)); 3711 3712 __ AssertString(r3); 3713 3714 __ lwz(r3, FieldMemOperand(r3, String::kHashFieldOffset)); 3715 __ IndexFromHash(r3, r3); 3716 3717 context()->Plug(r3); 3718 } 3719 3720 3721 void FullCodeGenerator::EmitGetSuperConstructor(CallRuntime* expr) { 3722 ZoneList<Expression*>* args = expr->arguments(); 3723 DCHECK_EQ(1, args->length()); 3724 VisitForAccumulatorValue(args->at(0)); 3725 __ AssertFunction(r3); 3726 __ LoadP(r3, FieldMemOperand(r3, HeapObject::kMapOffset)); 3727 __ LoadP(r3, FieldMemOperand(r3, Map::kPrototypeOffset)); 3728 context()->Plug(r3); 3729 } 3730 3731 3732 void FullCodeGenerator::EmitFastOneByteArrayJoin(CallRuntime* expr) { 3733 Label bailout, done, one_char_separator, long_separator, non_trivial_array, 3734 not_size_one_array, loop, empty_separator_loop, one_char_separator_loop, 3735 one_char_separator_loop_entry, long_separator_loop; 3736 ZoneList<Expression*>* args = expr->arguments(); 3737 DCHECK(args->length() == 2); 3738 VisitForStackValue(args->at(1)); 3739 VisitForAccumulatorValue(args->at(0)); 3740 3741 // All aliases of the same register have disjoint lifetimes. 3742 Register array = r3; 3743 Register elements = no_reg; // Will be r3. 3744 Register result = no_reg; // Will be r3. 3745 Register separator = r4; 3746 Register array_length = r5; 3747 Register result_pos = no_reg; // Will be r5 3748 Register string_length = r6; 3749 Register string = r7; 3750 Register element = r8; 3751 Register elements_end = r9; 3752 Register scratch1 = r10; 3753 Register scratch2 = r11; 3754 3755 // Separator operand is on the stack. 3756 __ pop(separator); 3757 3758 // Check that the array is a JSArray. 3759 __ JumpIfSmi(array, &bailout); 3760 __ CompareObjectType(array, scratch1, scratch2, JS_ARRAY_TYPE); 3761 __ bne(&bailout); 3762 3763 // Check that the array has fast elements. 3764 __ CheckFastElements(scratch1, scratch2, &bailout); 3765 3766 // If the array has length zero, return the empty string. 3767 __ LoadP(array_length, FieldMemOperand(array, JSArray::kLengthOffset)); 3768 __ SmiUntag(array_length); 3769 __ cmpi(array_length, Operand::Zero()); 3770 __ bne(&non_trivial_array); 3771 __ LoadRoot(r3, Heap::kempty_stringRootIndex); 3772 __ b(&done); 3773 3774 __ bind(&non_trivial_array); 3775 3776 // Get the FixedArray containing array's elements. 3777 elements = array; 3778 __ LoadP(elements, FieldMemOperand(array, JSArray::kElementsOffset)); 3779 array = no_reg; // End of array's live range. 3780 3781 // Check that all array elements are sequential one-byte strings, and 3782 // accumulate the sum of their lengths, as a smi-encoded value. 3783 __ li(string_length, Operand::Zero()); 3784 __ addi(element, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); 3785 __ ShiftLeftImm(elements_end, array_length, Operand(kPointerSizeLog2)); 3786 __ add(elements_end, element, elements_end); 3787 // Loop condition: while (element < elements_end). 3788 // Live values in registers: 3789 // elements: Fixed array of strings. 3790 // array_length: Length of the fixed array of strings (not smi) 3791 // separator: Separator string 3792 // string_length: Accumulated sum of string lengths (smi). 3793 // element: Current array element. 3794 // elements_end: Array end. 3795 if (generate_debug_code_) { 3796 __ cmpi(array_length, Operand::Zero()); 3797 __ Assert(gt, kNoEmptyArraysHereInEmitFastOneByteArrayJoin); 3798 } 3799 __ bind(&loop); 3800 __ LoadP(string, MemOperand(element)); 3801 __ addi(element, element, Operand(kPointerSize)); 3802 __ JumpIfSmi(string, &bailout); 3803 __ LoadP(scratch1, FieldMemOperand(string, HeapObject::kMapOffset)); 3804 __ lbz(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); 3805 __ JumpIfInstanceTypeIsNotSequentialOneByte(scratch1, scratch2, &bailout); 3806 __ LoadP(scratch1, FieldMemOperand(string, SeqOneByteString::kLengthOffset)); 3807 3808 __ AddAndCheckForOverflow(string_length, string_length, scratch1, scratch2, 3809 r0); 3810 __ BranchOnOverflow(&bailout); 3811 3812 __ cmp(element, elements_end); 3813 __ blt(&loop); 3814 3815 // If array_length is 1, return elements[0], a string. 3816 __ cmpi(array_length, Operand(1)); 3817 __ bne(¬_size_one_array); 3818 __ LoadP(r3, FieldMemOperand(elements, FixedArray::kHeaderSize)); 3819 __ b(&done); 3820 3821 __ bind(¬_size_one_array); 3822 3823 // Live values in registers: 3824 // separator: Separator string 3825 // array_length: Length of the array. 3826 // string_length: Sum of string lengths (smi). 3827 // elements: FixedArray of strings. 3828 3829 // Check that the separator is a flat one-byte string. 3830 __ JumpIfSmi(separator, &bailout); 3831 __ LoadP(scratch1, FieldMemOperand(separator, HeapObject::kMapOffset)); 3832 __ lbz(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); 3833 __ JumpIfInstanceTypeIsNotSequentialOneByte(scratch1, scratch2, &bailout); 3834 3835 // Add (separator length times array_length) - separator length to the 3836 // string_length to get the length of the result string. 3837 __ LoadP(scratch1, 3838 FieldMemOperand(separator, SeqOneByteString::kLengthOffset)); 3839 __ sub(string_length, string_length, scratch1); 3840 #if V8_TARGET_ARCH_PPC64 3841 __ SmiUntag(scratch1, scratch1); 3842 __ Mul(scratch2, array_length, scratch1); 3843 // Check for smi overflow. No overflow if higher 33 bits of 64-bit result are 3844 // zero. 3845 __ ShiftRightImm(ip, scratch2, Operand(31), SetRC); 3846 __ bne(&bailout, cr0); 3847 __ SmiTag(scratch2, scratch2); 3848 #else 3849 // array_length is not smi but the other values are, so the result is a smi 3850 __ mullw(scratch2, array_length, scratch1); 3851 __ mulhw(ip, array_length, scratch1); 3852 // Check for smi overflow. No overflow if higher 33 bits of 64-bit result are 3853 // zero. 3854 __ cmpi(ip, Operand::Zero()); 3855 __ bne(&bailout); 3856 __ cmpwi(scratch2, Operand::Zero()); 3857 __ blt(&bailout); 3858 #endif 3859 3860 __ AddAndCheckForOverflow(string_length, string_length, scratch2, scratch1, 3861 r0); 3862 __ BranchOnOverflow(&bailout); 3863 __ SmiUntag(string_length); 3864 3865 // Bailout for large object allocations. 3866 __ Cmpi(string_length, Operand(Page::kMaxRegularHeapObjectSize), r0); 3867 __ bgt(&bailout); 3868 3869 // Get first element in the array to free up the elements register to be used 3870 // for the result. 3871 __ addi(element, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); 3872 result = elements; // End of live range for elements. 3873 elements = no_reg; 3874 // Live values in registers: 3875 // element: First array element 3876 // separator: Separator string 3877 // string_length: Length of result string (not smi) 3878 // array_length: Length of the array. 3879 __ AllocateOneByteString(result, string_length, scratch1, scratch2, 3880 elements_end, &bailout); 3881 // Prepare for looping. Set up elements_end to end of the array. Set 3882 // result_pos to the position of the result where to write the first 3883 // character. 3884 __ ShiftLeftImm(elements_end, array_length, Operand(kPointerSizeLog2)); 3885 __ add(elements_end, element, elements_end); 3886 result_pos = array_length; // End of live range for array_length. 3887 array_length = no_reg; 3888 __ addi(result_pos, result, 3889 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); 3890 3891 // Check the length of the separator. 3892 __ LoadP(scratch1, 3893 FieldMemOperand(separator, SeqOneByteString::kLengthOffset)); 3894 __ CmpSmiLiteral(scratch1, Smi::FromInt(1), r0); 3895 __ beq(&one_char_separator); 3896 __ bgt(&long_separator); 3897 3898 // Empty separator case 3899 __ bind(&empty_separator_loop); 3900 // Live values in registers: 3901 // result_pos: the position to which we are currently copying characters. 3902 // element: Current array element. 3903 // elements_end: Array end. 3904 3905 // Copy next array element to the result. 3906 __ LoadP(string, MemOperand(element)); 3907 __ addi(element, element, Operand(kPointerSize)); 3908 __ LoadP(string_length, FieldMemOperand(string, String::kLengthOffset)); 3909 __ SmiUntag(string_length); 3910 __ addi(string, string, 3911 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); 3912 __ CopyBytes(string, result_pos, string_length, scratch1); 3913 __ cmp(element, elements_end); 3914 __ blt(&empty_separator_loop); // End while (element < elements_end). 3915 DCHECK(result.is(r3)); 3916 __ b(&done); 3917 3918 // One-character separator case 3919 __ bind(&one_char_separator); 3920 // Replace separator with its one-byte character value. 3921 __ lbz(separator, FieldMemOperand(separator, SeqOneByteString::kHeaderSize)); 3922 // Jump into the loop after the code that copies the separator, so the first 3923 // element is not preceded by a separator 3924 __ b(&one_char_separator_loop_entry); 3925 3926 __ bind(&one_char_separator_loop); 3927 // Live values in registers: 3928 // result_pos: the position to which we are currently copying characters. 3929 // element: Current array element. 3930 // elements_end: Array end. 3931 // separator: Single separator one-byte char (in lower byte). 3932 3933 // Copy the separator character to the result. 3934 __ stb(separator, MemOperand(result_pos)); 3935 __ addi(result_pos, result_pos, Operand(1)); 3936 3937 // Copy next array element to the result. 3938 __ bind(&one_char_separator_loop_entry); 3939 __ LoadP(string, MemOperand(element)); 3940 __ addi(element, element, Operand(kPointerSize)); 3941 __ LoadP(string_length, FieldMemOperand(string, String::kLengthOffset)); 3942 __ SmiUntag(string_length); 3943 __ addi(string, string, 3944 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); 3945 __ CopyBytes(string, result_pos, string_length, scratch1); 3946 __ cmpl(element, elements_end); 3947 __ blt(&one_char_separator_loop); // End while (element < elements_end). 3948 DCHECK(result.is(r3)); 3949 __ b(&done); 3950 3951 // Long separator case (separator is more than one character). Entry is at the 3952 // label long_separator below. 3953 __ bind(&long_separator_loop); 3954 // Live values in registers: 3955 // result_pos: the position to which we are currently copying characters. 3956 // element: Current array element. 3957 // elements_end: Array end. 3958 // separator: Separator string. 3959 3960 // Copy the separator to the result. 3961 __ LoadP(string_length, FieldMemOperand(separator, String::kLengthOffset)); 3962 __ SmiUntag(string_length); 3963 __ addi(string, separator, 3964 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); 3965 __ CopyBytes(string, result_pos, string_length, scratch1); 3966 3967 __ bind(&long_separator); 3968 __ LoadP(string, MemOperand(element)); 3969 __ addi(element, element, Operand(kPointerSize)); 3970 __ LoadP(string_length, FieldMemOperand(string, String::kLengthOffset)); 3971 __ SmiUntag(string_length); 3972 __ addi(string, string, 3973 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); 3974 __ CopyBytes(string, result_pos, string_length, scratch1); 3975 __ cmpl(element, elements_end); 3976 __ blt(&long_separator_loop); // End while (element < elements_end). 3977 DCHECK(result.is(r3)); 3978 __ b(&done); 3979 3980 __ bind(&bailout); 3981 __ LoadRoot(r3, Heap::kUndefinedValueRootIndex); 3982 __ bind(&done); 3983 context()->Plug(r3); 3984 } 3985 3986 3987 void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) { 3988 DCHECK(expr->arguments()->length() == 0); 3989 ExternalReference debug_is_active = 3990 ExternalReference::debug_is_active_address(isolate()); 3991 __ mov(ip, Operand(debug_is_active)); 3992 __ lbz(r3, MemOperand(ip)); 3993 __ SmiTag(r3); 3994 context()->Plug(r3); 3995 } 3996 3997 3998 void FullCodeGenerator::EmitCreateIterResultObject(CallRuntime* expr) { 3999 ZoneList<Expression*>* args = expr->arguments(); 4000 DCHECK_EQ(2, args->length()); 4001 VisitForStackValue(args->at(0)); 4002 VisitForStackValue(args->at(1)); 4003 4004 Label runtime, done; 4005 4006 __ Allocate(JSIteratorResult::kSize, r3, r5, r6, &runtime, TAG_OBJECT); 4007 __ LoadNativeContextSlot(Context::ITERATOR_RESULT_MAP_INDEX, r4); 4008 __ Pop(r5, r6); 4009 __ LoadRoot(r7, Heap::kEmptyFixedArrayRootIndex); 4010 __ StoreP(r4, FieldMemOperand(r3, HeapObject::kMapOffset), r0); 4011 __ StoreP(r7, FieldMemOperand(r3, JSObject::kPropertiesOffset), r0); 4012 __ StoreP(r7, FieldMemOperand(r3, JSObject::kElementsOffset), r0); 4013 __ StoreP(r5, FieldMemOperand(r3, JSIteratorResult::kValueOffset), r0); 4014 __ StoreP(r6, FieldMemOperand(r3, JSIteratorResult::kDoneOffset), r0); 4015 STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize); 4016 __ b(&done); 4017 4018 __ bind(&runtime); 4019 __ CallRuntime(Runtime::kCreateIterResultObject); 4020 4021 __ bind(&done); 4022 context()->Plug(r3); 4023 } 4024 4025 4026 void FullCodeGenerator::EmitLoadJSRuntimeFunction(CallRuntime* expr) { 4027 // Push undefined as the receiver. 4028 __ LoadRoot(r3, Heap::kUndefinedValueRootIndex); 4029 __ push(r3); 4030 4031 __ LoadNativeContextSlot(expr->context_index(), r3); 4032 } 4033 4034 4035 void FullCodeGenerator::EmitCallJSRuntimeFunction(CallRuntime* expr) { 4036 ZoneList<Expression*>* args = expr->arguments(); 4037 int arg_count = args->length(); 4038 4039 SetCallPosition(expr); 4040 __ LoadP(r4, MemOperand(sp, (arg_count + 1) * kPointerSize), r0); 4041 __ mov(r3, Operand(arg_count)); 4042 __ Call(isolate()->builtins()->Call(ConvertReceiverMode::kNullOrUndefined), 4043 RelocInfo::CODE_TARGET); 4044 } 4045 4046 4047 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { 4048 ZoneList<Expression*>* args = expr->arguments(); 4049 int arg_count = args->length(); 4050 4051 if (expr->is_jsruntime()) { 4052 Comment cmnt(masm_, "[ CallRuntime"); 4053 EmitLoadJSRuntimeFunction(expr); 4054 4055 // Push the target function under the receiver. 4056 __ LoadP(ip, MemOperand(sp, 0)); 4057 __ push(ip); 4058 __ StoreP(r3, MemOperand(sp, kPointerSize)); 4059 4060 // Push the arguments ("left-to-right"). 4061 for (int i = 0; i < arg_count; i++) { 4062 VisitForStackValue(args->at(i)); 4063 } 4064 4065 PrepareForBailoutForId(expr->CallId(), NO_REGISTERS); 4066 EmitCallJSRuntimeFunction(expr); 4067 4068 // Restore context register. 4069 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); 4070 4071 context()->DropAndPlug(1, r3); 4072 4073 } else { 4074 const Runtime::Function* function = expr->function(); 4075 switch (function->function_id) { 4076 #define CALL_INTRINSIC_GENERATOR(Name) \ 4077 case Runtime::kInline##Name: { \ 4078 Comment cmnt(masm_, "[ Inline" #Name); \ 4079 return Emit##Name(expr); \ 4080 } 4081 FOR_EACH_FULL_CODE_INTRINSIC(CALL_INTRINSIC_GENERATOR) 4082 #undef CALL_INTRINSIC_GENERATOR 4083 default: { 4084 Comment cmnt(masm_, "[ CallRuntime for unhandled intrinsic"); 4085 // Push the arguments ("left-to-right"). 4086 for (int i = 0; i < arg_count; i++) { 4087 VisitForStackValue(args->at(i)); 4088 } 4089 4090 // Call the C runtime function. 4091 PrepareForBailoutForId(expr->CallId(), NO_REGISTERS); 4092 __ CallRuntime(expr->function(), arg_count); 4093 context()->Plug(r3); 4094 } 4095 } 4096 } 4097 } 4098 4099 4100 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { 4101 switch (expr->op()) { 4102 case Token::DELETE: { 4103 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); 4104 Property* property = expr->expression()->AsProperty(); 4105 VariableProxy* proxy = expr->expression()->AsVariableProxy(); 4106 4107 if (property != NULL) { 4108 VisitForStackValue(property->obj()); 4109 VisitForStackValue(property->key()); 4110 __ CallRuntime(is_strict(language_mode()) 4111 ? Runtime::kDeleteProperty_Strict 4112 : Runtime::kDeleteProperty_Sloppy); 4113 context()->Plug(r3); 4114 } else if (proxy != NULL) { 4115 Variable* var = proxy->var(); 4116 // Delete of an unqualified identifier is disallowed in strict mode but 4117 // "delete this" is allowed. 4118 bool is_this = var->HasThisName(isolate()); 4119 DCHECK(is_sloppy(language_mode()) || is_this); 4120 if (var->IsUnallocatedOrGlobalSlot()) { 4121 __ LoadGlobalObject(r5); 4122 __ mov(r4, Operand(var->name())); 4123 __ Push(r5, r4); 4124 __ CallRuntime(Runtime::kDeleteProperty_Sloppy); 4125 context()->Plug(r3); 4126 } else if (var->IsStackAllocated() || var->IsContextSlot()) { 4127 // Result of deleting non-global, non-dynamic variables is false. 4128 // The subexpression does not have side effects. 4129 context()->Plug(is_this); 4130 } else { 4131 // Non-global variable. Call the runtime to try to delete from the 4132 // context where the variable was introduced. 4133 DCHECK(!context_register().is(r5)); 4134 __ mov(r5, Operand(var->name())); 4135 __ Push(context_register(), r5); 4136 __ CallRuntime(Runtime::kDeleteLookupSlot); 4137 context()->Plug(r3); 4138 } 4139 } else { 4140 // Result of deleting non-property, non-variable reference is true. 4141 // The subexpression may have side effects. 4142 VisitForEffect(expr->expression()); 4143 context()->Plug(true); 4144 } 4145 break; 4146 } 4147 4148 case Token::VOID: { 4149 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); 4150 VisitForEffect(expr->expression()); 4151 context()->Plug(Heap::kUndefinedValueRootIndex); 4152 break; 4153 } 4154 4155 case Token::NOT: { 4156 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); 4157 if (context()->IsEffect()) { 4158 // Unary NOT has no side effects so it's only necessary to visit the 4159 // subexpression. Match the optimizing compiler by not branching. 4160 VisitForEffect(expr->expression()); 4161 } else if (context()->IsTest()) { 4162 const TestContext* test = TestContext::cast(context()); 4163 // The labels are swapped for the recursive call. 4164 VisitForControl(expr->expression(), test->false_label(), 4165 test->true_label(), test->fall_through()); 4166 context()->Plug(test->true_label(), test->false_label()); 4167 } else { 4168 // We handle value contexts explicitly rather than simply visiting 4169 // for control and plugging the control flow into the context, 4170 // because we need to prepare a pair of extra administrative AST ids 4171 // for the optimizing compiler. 4172 DCHECK(context()->IsAccumulatorValue() || context()->IsStackValue()); 4173 Label materialize_true, materialize_false, done; 4174 VisitForControl(expr->expression(), &materialize_false, 4175 &materialize_true, &materialize_true); 4176 __ bind(&materialize_true); 4177 PrepareForBailoutForId(expr->MaterializeTrueId(), NO_REGISTERS); 4178 __ LoadRoot(r3, Heap::kTrueValueRootIndex); 4179 if (context()->IsStackValue()) __ push(r3); 4180 __ b(&done); 4181 __ bind(&materialize_false); 4182 PrepareForBailoutForId(expr->MaterializeFalseId(), NO_REGISTERS); 4183 __ LoadRoot(r3, Heap::kFalseValueRootIndex); 4184 if (context()->IsStackValue()) __ push(r3); 4185 __ bind(&done); 4186 } 4187 break; 4188 } 4189 4190 case Token::TYPEOF: { 4191 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); 4192 { 4193 AccumulatorValueContext context(this); 4194 VisitForTypeofValue(expr->expression()); 4195 } 4196 __ mr(r6, r3); 4197 TypeofStub typeof_stub(isolate()); 4198 __ CallStub(&typeof_stub); 4199 context()->Plug(r3); 4200 break; 4201 } 4202 4203 default: 4204 UNREACHABLE(); 4205 } 4206 } 4207 4208 4209 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { 4210 DCHECK(expr->expression()->IsValidReferenceExpressionOrThis()); 4211 4212 Comment cmnt(masm_, "[ CountOperation"); 4213 4214 Property* prop = expr->expression()->AsProperty(); 4215 LhsKind assign_type = Property::GetAssignType(prop); 4216 4217 // Evaluate expression and get value. 4218 if (assign_type == VARIABLE) { 4219 DCHECK(expr->expression()->AsVariableProxy()->var() != NULL); 4220 AccumulatorValueContext context(this); 4221 EmitVariableLoad(expr->expression()->AsVariableProxy()); 4222 } else { 4223 // Reserve space for result of postfix operation. 4224 if (expr->is_postfix() && !context()->IsEffect()) { 4225 __ LoadSmiLiteral(ip, Smi::FromInt(0)); 4226 __ push(ip); 4227 } 4228 switch (assign_type) { 4229 case NAMED_PROPERTY: { 4230 // Put the object both on the stack and in the register. 4231 VisitForStackValue(prop->obj()); 4232 __ LoadP(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0)); 4233 EmitNamedPropertyLoad(prop); 4234 break; 4235 } 4236 4237 case NAMED_SUPER_PROPERTY: { 4238 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var()); 4239 VisitForAccumulatorValue( 4240 prop->obj()->AsSuperPropertyReference()->home_object()); 4241 __ Push(result_register()); 4242 const Register scratch = r4; 4243 __ LoadP(scratch, MemOperand(sp, kPointerSize)); 4244 __ Push(scratch, result_register()); 4245 EmitNamedSuperPropertyLoad(prop); 4246 break; 4247 } 4248 4249 case KEYED_SUPER_PROPERTY: { 4250 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var()); 4251 VisitForAccumulatorValue( 4252 prop->obj()->AsSuperPropertyReference()->home_object()); 4253 const Register scratch = r4; 4254 const Register scratch1 = r5; 4255 __ mr(scratch, result_register()); 4256 VisitForAccumulatorValue(prop->key()); 4257 __ Push(scratch, result_register()); 4258 __ LoadP(scratch1, MemOperand(sp, 2 * kPointerSize)); 4259 __ Push(scratch1, scratch, result_register()); 4260 EmitKeyedSuperPropertyLoad(prop); 4261 break; 4262 } 4263 4264 case KEYED_PROPERTY: { 4265 VisitForStackValue(prop->obj()); 4266 VisitForStackValue(prop->key()); 4267 __ LoadP(LoadDescriptor::ReceiverRegister(), 4268 MemOperand(sp, 1 * kPointerSize)); 4269 __ LoadP(LoadDescriptor::NameRegister(), MemOperand(sp, 0)); 4270 EmitKeyedPropertyLoad(prop); 4271 break; 4272 } 4273 4274 case VARIABLE: 4275 UNREACHABLE(); 4276 } 4277 } 4278 4279 // We need a second deoptimization point after loading the value 4280 // in case evaluating the property load my have a side effect. 4281 if (assign_type == VARIABLE) { 4282 PrepareForBailout(expr->expression(), TOS_REG); 4283 } else { 4284 PrepareForBailoutForId(prop->LoadId(), TOS_REG); 4285 } 4286 4287 // Inline smi case if we are in a loop. 4288 Label stub_call, done; 4289 JumpPatchSite patch_site(masm_); 4290 4291 int count_value = expr->op() == Token::INC ? 1 : -1; 4292 if (ShouldInlineSmiCase(expr->op())) { 4293 Label slow; 4294 patch_site.EmitJumpIfNotSmi(r3, &slow); 4295 4296 // Save result for postfix expressions. 4297 if (expr->is_postfix()) { 4298 if (!context()->IsEffect()) { 4299 // Save the result on the stack. If we have a named or keyed property 4300 // we store the result under the receiver that is currently on top 4301 // of the stack. 4302 switch (assign_type) { 4303 case VARIABLE: 4304 __ push(r3); 4305 break; 4306 case NAMED_PROPERTY: 4307 __ StoreP(r3, MemOperand(sp, kPointerSize)); 4308 break; 4309 case NAMED_SUPER_PROPERTY: 4310 __ StoreP(r3, MemOperand(sp, 2 * kPointerSize)); 4311 break; 4312 case KEYED_PROPERTY: 4313 __ StoreP(r3, MemOperand(sp, 2 * kPointerSize)); 4314 break; 4315 case KEYED_SUPER_PROPERTY: 4316 __ StoreP(r3, MemOperand(sp, 3 * kPointerSize)); 4317 break; 4318 } 4319 } 4320 } 4321 4322 Register scratch1 = r4; 4323 Register scratch2 = r5; 4324 __ LoadSmiLiteral(scratch1, Smi::FromInt(count_value)); 4325 __ AddAndCheckForOverflow(r3, r3, scratch1, scratch2, r0); 4326 __ BranchOnNoOverflow(&done); 4327 // Call stub. Undo operation first. 4328 __ sub(r3, r3, scratch1); 4329 __ b(&stub_call); 4330 __ bind(&slow); 4331 } 4332 if (!is_strong(language_mode())) { 4333 ToNumberStub convert_stub(isolate()); 4334 __ CallStub(&convert_stub); 4335 PrepareForBailoutForId(expr->ToNumberId(), TOS_REG); 4336 } 4337 4338 // Save result for postfix expressions. 4339 if (expr->is_postfix()) { 4340 if (!context()->IsEffect()) { 4341 // Save the result on the stack. If we have a named or keyed property 4342 // we store the result under the receiver that is currently on top 4343 // of the stack. 4344 switch (assign_type) { 4345 case VARIABLE: 4346 __ push(r3); 4347 break; 4348 case NAMED_PROPERTY: 4349 __ StoreP(r3, MemOperand(sp, kPointerSize)); 4350 break; 4351 case NAMED_SUPER_PROPERTY: 4352 __ StoreP(r3, MemOperand(sp, 2 * kPointerSize)); 4353 break; 4354 case KEYED_PROPERTY: 4355 __ StoreP(r3, MemOperand(sp, 2 * kPointerSize)); 4356 break; 4357 case KEYED_SUPER_PROPERTY: 4358 __ StoreP(r3, MemOperand(sp, 3 * kPointerSize)); 4359 break; 4360 } 4361 } 4362 } 4363 4364 __ bind(&stub_call); 4365 __ mr(r4, r3); 4366 __ LoadSmiLiteral(r3, Smi::FromInt(count_value)); 4367 4368 SetExpressionPosition(expr); 4369 4370 Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), Token::ADD, 4371 strength(language_mode())).code(); 4372 CallIC(code, expr->CountBinOpFeedbackId()); 4373 patch_site.EmitPatchInfo(); 4374 __ bind(&done); 4375 4376 if (is_strong(language_mode())) { 4377 PrepareForBailoutForId(expr->ToNumberId(), TOS_REG); 4378 } 4379 // Store the value returned in r3. 4380 switch (assign_type) { 4381 case VARIABLE: 4382 if (expr->is_postfix()) { 4383 { 4384 EffectContext context(this); 4385 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), 4386 Token::ASSIGN, expr->CountSlot()); 4387 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); 4388 context.Plug(r3); 4389 } 4390 // For all contexts except EffectConstant We have the result on 4391 // top of the stack. 4392 if (!context()->IsEffect()) { 4393 context()->PlugTOS(); 4394 } 4395 } else { 4396 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), 4397 Token::ASSIGN, expr->CountSlot()); 4398 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); 4399 context()->Plug(r3); 4400 } 4401 break; 4402 case NAMED_PROPERTY: { 4403 __ mov(StoreDescriptor::NameRegister(), 4404 Operand(prop->key()->AsLiteral()->value())); 4405 __ pop(StoreDescriptor::ReceiverRegister()); 4406 EmitLoadStoreICSlot(expr->CountSlot()); 4407 CallStoreIC(); 4408 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); 4409 if (expr->is_postfix()) { 4410 if (!context()->IsEffect()) { 4411 context()->PlugTOS(); 4412 } 4413 } else { 4414 context()->Plug(r3); 4415 } 4416 break; 4417 } 4418 case NAMED_SUPER_PROPERTY: { 4419 EmitNamedSuperPropertyStore(prop); 4420 if (expr->is_postfix()) { 4421 if (!context()->IsEffect()) { 4422 context()->PlugTOS(); 4423 } 4424 } else { 4425 context()->Plug(r3); 4426 } 4427 break; 4428 } 4429 case KEYED_SUPER_PROPERTY: { 4430 EmitKeyedSuperPropertyStore(prop); 4431 if (expr->is_postfix()) { 4432 if (!context()->IsEffect()) { 4433 context()->PlugTOS(); 4434 } 4435 } else { 4436 context()->Plug(r3); 4437 } 4438 break; 4439 } 4440 case KEYED_PROPERTY: { 4441 __ Pop(StoreDescriptor::ReceiverRegister(), 4442 StoreDescriptor::NameRegister()); 4443 Handle<Code> ic = 4444 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code(); 4445 EmitLoadStoreICSlot(expr->CountSlot()); 4446 CallIC(ic); 4447 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); 4448 if (expr->is_postfix()) { 4449 if (!context()->IsEffect()) { 4450 context()->PlugTOS(); 4451 } 4452 } else { 4453 context()->Plug(r3); 4454 } 4455 break; 4456 } 4457 } 4458 } 4459 4460 4461 void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, 4462 Expression* sub_expr, 4463 Handle<String> check) { 4464 Label materialize_true, materialize_false; 4465 Label* if_true = NULL; 4466 Label* if_false = NULL; 4467 Label* fall_through = NULL; 4468 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, 4469 &if_false, &fall_through); 4470 4471 { 4472 AccumulatorValueContext context(this); 4473 VisitForTypeofValue(sub_expr); 4474 } 4475 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); 4476 4477 Factory* factory = isolate()->factory(); 4478 if (String::Equals(check, factory->number_string())) { 4479 __ JumpIfSmi(r3, if_true); 4480 __ LoadP(r3, FieldMemOperand(r3, HeapObject::kMapOffset)); 4481 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); 4482 __ cmp(r3, ip); 4483 Split(eq, if_true, if_false, fall_through); 4484 } else if (String::Equals(check, factory->string_string())) { 4485 __ JumpIfSmi(r3, if_false); 4486 __ CompareObjectType(r3, r3, r4, FIRST_NONSTRING_TYPE); 4487 Split(lt, if_true, if_false, fall_through); 4488 } else if (String::Equals(check, factory->symbol_string())) { 4489 __ JumpIfSmi(r3, if_false); 4490 __ CompareObjectType(r3, r3, r4, SYMBOL_TYPE); 4491 Split(eq, if_true, if_false, fall_through); 4492 } else if (String::Equals(check, factory->boolean_string())) { 4493 __ CompareRoot(r3, Heap::kTrueValueRootIndex); 4494 __ beq(if_true); 4495 __ CompareRoot(r3, Heap::kFalseValueRootIndex); 4496 Split(eq, if_true, if_false, fall_through); 4497 } else if (String::Equals(check, factory->undefined_string())) { 4498 __ CompareRoot(r3, Heap::kUndefinedValueRootIndex); 4499 __ beq(if_true); 4500 __ JumpIfSmi(r3, if_false); 4501 // Check for undetectable objects => true. 4502 __ LoadP(r3, FieldMemOperand(r3, HeapObject::kMapOffset)); 4503 __ lbz(r4, FieldMemOperand(r3, Map::kBitFieldOffset)); 4504 __ andi(r0, r4, Operand(1 << Map::kIsUndetectable)); 4505 Split(ne, if_true, if_false, fall_through, cr0); 4506 4507 } else if (String::Equals(check, factory->function_string())) { 4508 __ JumpIfSmi(r3, if_false); 4509 __ LoadP(r3, FieldMemOperand(r3, HeapObject::kMapOffset)); 4510 __ lbz(r4, FieldMemOperand(r3, Map::kBitFieldOffset)); 4511 __ andi(r4, r4, 4512 Operand((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable))); 4513 __ cmpi(r4, Operand(1 << Map::kIsCallable)); 4514 Split(eq, if_true, if_false, fall_through); 4515 } else if (String::Equals(check, factory->object_string())) { 4516 __ JumpIfSmi(r3, if_false); 4517 __ CompareRoot(r3, Heap::kNullValueRootIndex); 4518 __ beq(if_true); 4519 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); 4520 __ CompareObjectType(r3, r3, r4, FIRST_JS_RECEIVER_TYPE); 4521 __ blt(if_false); 4522 // Check for callable or undetectable objects => false. 4523 __ lbz(r4, FieldMemOperand(r3, Map::kBitFieldOffset)); 4524 __ andi(r0, r4, 4525 Operand((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable))); 4526 Split(eq, if_true, if_false, fall_through, cr0); 4527 // clang-format off 4528 #define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \ 4529 } else if (String::Equals(check, factory->type##_string())) { \ 4530 __ JumpIfSmi(r3, if_false); \ 4531 __ LoadP(r3, FieldMemOperand(r3, HeapObject::kMapOffset)); \ 4532 __ CompareRoot(r3, Heap::k##Type##MapRootIndex); \ 4533 Split(eq, if_true, if_false, fall_through); 4534 SIMD128_TYPES(SIMD128_TYPE) 4535 #undef SIMD128_TYPE 4536 // clang-format on 4537 } else { 4538 if (if_false != fall_through) __ b(if_false); 4539 } 4540 context()->Plug(if_true, if_false); 4541 } 4542 4543 4544 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { 4545 Comment cmnt(masm_, "[ CompareOperation"); 4546 SetExpressionPosition(expr); 4547 4548 // First we try a fast inlined version of the compare when one of 4549 // the operands is a literal. 4550 if (TryLiteralCompare(expr)) return; 4551 4552 // Always perform the comparison for its control flow. Pack the result 4553 // into the expression's context after the comparison is performed. 4554 Label materialize_true, materialize_false; 4555 Label* if_true = NULL; 4556 Label* if_false = NULL; 4557 Label* fall_through = NULL; 4558 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, 4559 &if_false, &fall_through); 4560 4561 Token::Value op = expr->op(); 4562 VisitForStackValue(expr->left()); 4563 switch (op) { 4564 case Token::IN: 4565 VisitForStackValue(expr->right()); 4566 __ CallRuntime(Runtime::kHasProperty); 4567 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL); 4568 __ CompareRoot(r3, Heap::kTrueValueRootIndex); 4569 Split(eq, if_true, if_false, fall_through); 4570 break; 4571 4572 case Token::INSTANCEOF: { 4573 VisitForAccumulatorValue(expr->right()); 4574 __ pop(r4); 4575 InstanceOfStub stub(isolate()); 4576 __ CallStub(&stub); 4577 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL); 4578 __ CompareRoot(r3, Heap::kTrueValueRootIndex); 4579 Split(eq, if_true, if_false, fall_through); 4580 break; 4581 } 4582 4583 default: { 4584 VisitForAccumulatorValue(expr->right()); 4585 Condition cond = CompareIC::ComputeCondition(op); 4586 __ pop(r4); 4587 4588 bool inline_smi_code = ShouldInlineSmiCase(op); 4589 JumpPatchSite patch_site(masm_); 4590 if (inline_smi_code) { 4591 Label slow_case; 4592 __ orx(r5, r3, r4); 4593 patch_site.EmitJumpIfNotSmi(r5, &slow_case); 4594 __ cmp(r4, r3); 4595 Split(cond, if_true, if_false, NULL); 4596 __ bind(&slow_case); 4597 } 4598 4599 Handle<Code> ic = CodeFactory::CompareIC( 4600 isolate(), op, strength(language_mode())).code(); 4601 CallIC(ic, expr->CompareOperationFeedbackId()); 4602 patch_site.EmitPatchInfo(); 4603 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); 4604 __ cmpi(r3, Operand::Zero()); 4605 Split(cond, if_true, if_false, fall_through); 4606 } 4607 } 4608 4609 // Convert the result of the comparison into one expected for this 4610 // expression's context. 4611 context()->Plug(if_true, if_false); 4612 } 4613 4614 4615 void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr, 4616 Expression* sub_expr, 4617 NilValue nil) { 4618 Label materialize_true, materialize_false; 4619 Label* if_true = NULL; 4620 Label* if_false = NULL; 4621 Label* fall_through = NULL; 4622 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, 4623 &if_false, &fall_through); 4624 4625 VisitForAccumulatorValue(sub_expr); 4626 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); 4627 if (expr->op() == Token::EQ_STRICT) { 4628 Heap::RootListIndex nil_value = nil == kNullValue 4629 ? Heap::kNullValueRootIndex 4630 : Heap::kUndefinedValueRootIndex; 4631 __ LoadRoot(r4, nil_value); 4632 __ cmp(r3, r4); 4633 Split(eq, if_true, if_false, fall_through); 4634 } else { 4635 Handle<Code> ic = CompareNilICStub::GetUninitialized(isolate(), nil); 4636 CallIC(ic, expr->CompareOperationFeedbackId()); 4637 __ CompareRoot(r3, Heap::kTrueValueRootIndex); 4638 Split(eq, if_true, if_false, fall_through); 4639 } 4640 context()->Plug(if_true, if_false); 4641 } 4642 4643 4644 void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) { 4645 __ LoadP(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 4646 context()->Plug(r3); 4647 } 4648 4649 4650 Register FullCodeGenerator::result_register() { return r3; } 4651 4652 4653 Register FullCodeGenerator::context_register() { return cp; } 4654 4655 4656 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { 4657 DCHECK_EQ(static_cast<int>(POINTER_SIZE_ALIGN(frame_offset)), frame_offset); 4658 __ StoreP(value, MemOperand(fp, frame_offset), r0); 4659 } 4660 4661 4662 void FullCodeGenerator::LoadContextField(Register dst, int context_index) { 4663 __ LoadP(dst, ContextMemOperand(cp, context_index), r0); 4664 } 4665 4666 4667 void FullCodeGenerator::PushFunctionArgumentForContextAllocation() { 4668 Scope* closure_scope = scope()->ClosureScope(); 4669 if (closure_scope->is_script_scope() || 4670 closure_scope->is_module_scope()) { 4671 // Contexts nested in the native context have a canonical empty function 4672 // as their closure, not the anonymous closure containing the global 4673 // code. 4674 __ LoadNativeContextSlot(Context::CLOSURE_INDEX, ip); 4675 } else if (closure_scope->is_eval_scope()) { 4676 // Contexts created by a call to eval have the same closure as the 4677 // context calling eval, not the anonymous closure containing the eval 4678 // code. Fetch it from the context. 4679 __ LoadP(ip, ContextMemOperand(cp, Context::CLOSURE_INDEX)); 4680 } else { 4681 DCHECK(closure_scope->is_function_scope()); 4682 __ LoadP(ip, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 4683 } 4684 __ push(ip); 4685 } 4686 4687 4688 // ---------------------------------------------------------------------------- 4689 // Non-local control flow support. 4690 4691 void FullCodeGenerator::EnterFinallyBlock() { 4692 DCHECK(!result_register().is(r4)); 4693 // Store result register while executing finally block. 4694 __ push(result_register()); 4695 // Cook return address in link register to stack (smi encoded Code* delta) 4696 __ mflr(r4); 4697 __ mov(ip, Operand(masm_->CodeObject())); 4698 __ sub(r4, r4, ip); 4699 __ SmiTag(r4); 4700 4701 // Store result register while executing finally block. 4702 __ push(r4); 4703 4704 // Store pending message while executing finally block. 4705 ExternalReference pending_message_obj = 4706 ExternalReference::address_of_pending_message_obj(isolate()); 4707 __ mov(ip, Operand(pending_message_obj)); 4708 __ LoadP(r4, MemOperand(ip)); 4709 __ push(r4); 4710 4711 ClearPendingMessage(); 4712 } 4713 4714 4715 void FullCodeGenerator::ExitFinallyBlock() { 4716 DCHECK(!result_register().is(r4)); 4717 // Restore pending message from stack. 4718 __ pop(r4); 4719 ExternalReference pending_message_obj = 4720 ExternalReference::address_of_pending_message_obj(isolate()); 4721 __ mov(ip, Operand(pending_message_obj)); 4722 __ StoreP(r4, MemOperand(ip)); 4723 4724 // Restore result register from stack. 4725 __ pop(r4); 4726 4727 // Uncook return address and return. 4728 __ pop(result_register()); 4729 __ SmiUntag(r4); 4730 __ mov(ip, Operand(masm_->CodeObject())); 4731 __ add(ip, ip, r4); 4732 __ mtctr(ip); 4733 __ bctr(); 4734 } 4735 4736 4737 void FullCodeGenerator::ClearPendingMessage() { 4738 DCHECK(!result_register().is(r4)); 4739 ExternalReference pending_message_obj = 4740 ExternalReference::address_of_pending_message_obj(isolate()); 4741 __ LoadRoot(r4, Heap::kTheHoleValueRootIndex); 4742 __ mov(ip, Operand(pending_message_obj)); 4743 __ StoreP(r4, MemOperand(ip)); 4744 } 4745 4746 4747 void FullCodeGenerator::EmitLoadStoreICSlot(FeedbackVectorSlot slot) { 4748 DCHECK(!slot.IsInvalid()); 4749 __ mov(VectorStoreICTrampolineDescriptor::SlotRegister(), 4750 Operand(SmiFromSlot(slot))); 4751 } 4752 4753 4754 #undef __ 4755 4756 4757 void BackEdgeTable::PatchAt(Code* unoptimized_code, Address pc, 4758 BackEdgeState target_state, 4759 Code* replacement_code) { 4760 Address mov_address = Assembler::target_address_from_return_address(pc); 4761 Address cmp_address = mov_address - 2 * Assembler::kInstrSize; 4762 Isolate* isolate = unoptimized_code->GetIsolate(); 4763 CodePatcher patcher(isolate, cmp_address, 1); 4764 4765 switch (target_state) { 4766 case INTERRUPT: { 4767 // <decrement profiling counter> 4768 // cmpi r6, 0 4769 // bge <ok> ;; not changed 4770 // mov r12, <interrupt stub address> 4771 // mtlr r12 4772 // blrl 4773 // <reset profiling counter> 4774 // ok-label 4775 patcher.masm()->cmpi(r6, Operand::Zero()); 4776 break; 4777 } 4778 case ON_STACK_REPLACEMENT: 4779 case OSR_AFTER_STACK_CHECK: 4780 // <decrement profiling counter> 4781 // crset 4782 // bge <ok> ;; not changed 4783 // mov r12, <on-stack replacement address> 4784 // mtlr r12 4785 // blrl 4786 // <reset profiling counter> 4787 // ok-label ----- pc_after points here 4788 4789 // Set the LT bit such that bge is a NOP 4790 patcher.masm()->crset(Assembler::encode_crbit(cr7, CR_LT)); 4791 break; 4792 } 4793 4794 // Replace the stack check address in the mov sequence with the 4795 // entry address of the replacement code. 4796 Assembler::set_target_address_at(isolate, mov_address, unoptimized_code, 4797 replacement_code->entry()); 4798 4799 unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch( 4800 unoptimized_code, mov_address, replacement_code); 4801 } 4802 4803 4804 BackEdgeTable::BackEdgeState BackEdgeTable::GetBackEdgeState( 4805 Isolate* isolate, Code* unoptimized_code, Address pc) { 4806 Address mov_address = Assembler::target_address_from_return_address(pc); 4807 Address cmp_address = mov_address - 2 * Assembler::kInstrSize; 4808 Address interrupt_address = 4809 Assembler::target_address_at(mov_address, unoptimized_code); 4810 4811 if (Assembler::IsCmpImmediate(Assembler::instr_at(cmp_address))) { 4812 DCHECK(interrupt_address == isolate->builtins()->InterruptCheck()->entry()); 4813 return INTERRUPT; 4814 } 4815 4816 DCHECK(Assembler::IsCrSet(Assembler::instr_at(cmp_address))); 4817 4818 if (interrupt_address == isolate->builtins()->OnStackReplacement()->entry()) { 4819 return ON_STACK_REPLACEMENT; 4820 } 4821 4822 DCHECK(interrupt_address == 4823 isolate->builtins()->OsrAfterStackCheck()->entry()); 4824 return OSR_AFTER_STACK_CHECK; 4825 } 4826 } // namespace internal 4827 } // namespace v8 4828 #endif // V8_TARGET_ARCH_PPC 4829