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