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