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