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