1d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke// Copyright 2010 the V8 project authors. All rights reserved. 2a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Redistribution and use in source and binary forms, with or without 3a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// modification, are permitted provided that the following conditions are 4a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// met: 5a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 6a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// * Redistributions of source code must retain the above copyright 7a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// notice, this list of conditions and the following disclaimer. 8a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// * Redistributions in binary form must reproduce the above 9a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// copyright notice, this list of conditions and the following 10a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// disclaimer in the documentation and/or other materials provided 11a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// with the distribution. 12a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// * Neither the name of Google Inc. nor the names of its 13a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// contributors may be used to endorse or promote products derived 14a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// from this software without specific prior written permission. 15a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 16a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 28a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "v8.h" 29a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 30a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "bootstrapper.h" 31a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "codegen-inl.h" 32d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include "compiler.h" 33a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "debug.h" 34a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "ic-inl.h" 35a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "parser.h" 364515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke#include "regexp-macro-assembler.h" 37a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "register-allocator-inl.h" 38a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "scopes.h" 39a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 40a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace v8 { 41a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace internal { 42a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 43a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#define __ ACCESS_MASM(masm_) 44a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 45a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ------------------------------------------------------------------------- 46a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Platform-specific DeferredCode functions. 47a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 48a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DeferredCode::SaveRegisters() { 49a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) { 50a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int action = registers_[i]; 51a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (action == kPush) { 52a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(RegisterAllocator::ToRegister(i)); 53a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (action != kIgnore && (action & kSyncedFlag) == 0) { 54a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(Operand(rbp, action), RegisterAllocator::ToRegister(i)); 55a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 56a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 57a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 58a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 593ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block 60a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DeferredCode::RestoreRegisters() { 61a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Restore registers in reverse order due to the stack. 62a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = RegisterAllocator::kNumRegisters - 1; i >= 0; i--) { 63a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int action = registers_[i]; 64a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (action == kPush) { 65a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(RegisterAllocator::ToRegister(i)); 66a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (action != kIgnore) { 67a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block action &= ~kSyncedFlag; 68a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(RegisterAllocator::ToRegister(i), Operand(rbp, action)); 69a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 70a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 71a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 72a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 73a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 74a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ------------------------------------------------------------------------- 75a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// CodeGenState implementation. 76a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 77a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockCodeGenState::CodeGenState(CodeGenerator* owner) 78a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block : owner_(owner), 79a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination_(NULL), 80a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block previous_(NULL) { 81a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block owner_->set_state(this); 82a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 83a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 84a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 85a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockCodeGenState::CodeGenState(CodeGenerator* owner, 86a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ControlDestination* destination) 87a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block : owner_(owner), 88a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination_(destination), 89a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block previous_(owner->state()) { 90a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block owner_->set_state(this); 91a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 92a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 93a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 94a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockCodeGenState::~CodeGenState() { 95a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(owner_->state() == this); 96a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block owner_->set_state(previous_); 97a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 98a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 99a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ------------------------------------------------------------------------- 101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Deferred code objects 102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// These subclasses of DeferredCode add pieces of code to the end of generated 104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// code. They are branched to from the generated code, and 105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// keep some slower code out of the main body of the generated code. 106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Many of them call a code stub or a runtime function. 107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass DeferredInlineSmiAdd: public DeferredCode { 109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public: 110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block DeferredInlineSmiAdd(Register dst, 111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Smi* value, 112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block OverwriteMode overwrite_mode) 113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block : dst_(dst), value_(value), overwrite_mode_(overwrite_mode) { 114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block set_comment("[ DeferredInlineSmiAdd"); 115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block virtual void Generate(); 118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private: 120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register dst_; 121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Smi* value_; 122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block OverwriteMode overwrite_mode_; 123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// The result of value + src is in dst. It either overflowed or was not 127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// smi tagged. Undo the speculative addition and call the appropriate 128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// specialized stub for add. The result is left in dst. 129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass DeferredInlineSmiAddReversed: public DeferredCode { 130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public: 131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block DeferredInlineSmiAddReversed(Register dst, 132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Smi* value, 133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block OverwriteMode overwrite_mode) 134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block : dst_(dst), value_(value), overwrite_mode_(overwrite_mode) { 135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block set_comment("[ DeferredInlineSmiAddReversed"); 136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block virtual void Generate(); 139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private: 141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register dst_; 142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Smi* value_; 143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block OverwriteMode overwrite_mode_; 144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass DeferredInlineSmiSub: public DeferredCode { 148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public: 149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block DeferredInlineSmiSub(Register dst, 150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Smi* value, 151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block OverwriteMode overwrite_mode) 152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block : dst_(dst), value_(value), overwrite_mode_(overwrite_mode) { 153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block set_comment("[ DeferredInlineSmiSub"); 154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block virtual void Generate(); 157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private: 159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register dst_; 160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Smi* value_; 161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block OverwriteMode overwrite_mode_; 162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Call the appropriate binary operation stub to compute src op value 166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// and leave the result in dst. 167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass DeferredInlineSmiOperation: public DeferredCode { 168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public: 169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block DeferredInlineSmiOperation(Token::Value op, 170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register dst, 171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register src, 172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Smi* value, 173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block OverwriteMode overwrite_mode) 174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block : op_(op), 175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block dst_(dst), 176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block src_(src), 177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block value_(value), 178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block overwrite_mode_(overwrite_mode) { 179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block set_comment("[ DeferredInlineSmiOperation"); 180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block virtual void Generate(); 183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private: 185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Token::Value op_; 186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register dst_; 187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register src_; 188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Smi* value_; 189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block OverwriteMode overwrite_mode_; 190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass FloatingPointHelper : public AllStatic { 194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public: 195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Code pattern for loading a floating point value. Input value must 196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // be either a smi or a heap number object (fp value). Requirements: 197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // operand on TOS+1. Returns operand as floating point number on FPU 198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // stack. 199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block static void LoadFloatOperand(MacroAssembler* masm, Register scratch); 200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Code pattern for loading a floating point value. Input value must 202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // be either a smi or a heap number object (fp value). Requirements: 203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // operand in src register. Returns operand as floating point number 204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // in XMM register 205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block static void LoadFloatOperand(MacroAssembler* masm, 206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register src, 207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block XMMRegister dst); 208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Code pattern for loading floating point values. Input values must 210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // be either smi or heap number objects (fp values). Requirements: 2114515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // operand_1 in rdx, operand_2 in rax; Returns operands as 212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // floating point numbers in XMM registers. 213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block static void LoadFloatOperands(MacroAssembler* masm, 214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block XMMRegister dst1, 215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block XMMRegister dst2); 216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2174515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Similar to LoadFloatOperands, assumes that the operands are smis. 2184515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke static void LoadFloatOperandsFromSmis(MacroAssembler* masm, 2194515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke XMMRegister dst1, 2204515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke XMMRegister dst2); 2214515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Code pattern for loading floating point values onto the fp stack. 223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Input values must be either smi or heap number objects (fp values). 224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Requirements: 225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Register version: operands in registers lhs and rhs. 226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Stack version: operands on TOS+1 and TOS+2. 227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Returns operands as floating point numbers on fp stack. 228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block static void LoadFloatOperands(MacroAssembler* masm, 229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register lhs, 230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register rhs); 231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Test if operands are smi or number objects (fp). Requirements: 233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // operand_1 in rax, operand_2 in rdx; falls through on float or smi 234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // operands, jumps to the non_float label otherwise. 2353ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block static void CheckNumberOperands(MacroAssembler* masm, 2363ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block Label* non_float); 237d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 238d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Takes the operands in rdx and rax and loads them as integers in rax 239d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // and rcx. 240d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke static void LoadAsIntegers(MacroAssembler* masm, 241d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke bool use_sse3, 242d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Label* operand_conversion_failure); 243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ----------------------------------------------------------------------------- 247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// CodeGenerator implementation. 248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2493100271588b61cbc1dc472a3f2f105d2eed8497fAndrei PopescuCodeGenerator::CodeGenerator(MacroAssembler* masm) 2503100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu : deferred_(8), 2514515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke masm_(masm), 2523100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu info_(NULL), 253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_(NULL), 254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block allocator_(NULL), 255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block state_(NULL), 256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block loop_nesting_(0), 257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block function_return_is_shadowed_(false), 258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block in_spilled_code_(false) { 259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2623100271588b61cbc1dc472a3f2f105d2eed8497fAndrei PopescuScope* CodeGenerator::scope() { return info_->function()->scope(); } 2633100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu 2643100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu 265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { 266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Call the runtime to declare the globals. The inevitable call 267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // will sync frame elements to memory anyway, so we do it eagerly to 268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // allow us to push the arguments directly into place. 269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->SyncRange(0, frame_->element_count() - 1); 270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(kScratchRegister, pairs, RelocInfo::EMBEDDED_OBJECT); 2723ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block frame_->EmitPush(rsi); // The context is the first argument. 273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(kScratchRegister); 2743ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block frame_->EmitPush(Smi::FromInt(is_eval() ? 1 : 0)); 275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 3); 276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return value is ignored. 277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 280402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescuvoid CodeGenerator::Generate(CompilationInfo* info) { 281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Record the position for debugging purposes. 2823100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu CodeForFunctionPosition(info->function()); 283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Initialize state. 2853100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu info_ = info; 286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(allocator_ == NULL); 287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block RegisterAllocator register_allocator(this); 288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block allocator_ = ®ister_allocator; 289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(frame_ == NULL); 290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_ = new VirtualFrame(); 291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block set_in_spilled_code(false); 292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Adjust for function-level loop nesting. 2944515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke loop_nesting_ += info->loop_nesting(); 295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget::set_compiling_deferred_code(false); 297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef DEBUG 299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (strlen(FLAG_stop_at) > 0 && 3003100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { 301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->SpillAll(); 302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ int3(); 303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif 305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // New scope to get automatic timing calculation. 307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block { // NOLINT 308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block HistogramTimerScope codegen_timer(&Counters::code_generation); 309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CodeGenState state(this); 310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Entry: 312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Stack: receiver, arguments, return address. 313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rbp: caller's frame pointer 314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rsp: stack pointer 315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rdi: called JS function 316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rsi: callee's context 317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block allocator_->Initialize(); 318a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 319402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu if (info->mode() == CompilationInfo::PRIMARY) { 3204515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke frame_->Enter(); 3214515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 3224515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Allocate space for locals and initialize them. 3234515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke frame_->AllocateStackSlots(); 3244515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 3254515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Allocate the local context if needed. 3263100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu int heap_slots = scope()->num_heap_slots(); 3274515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke if (heap_slots > 0) { 3284515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Comment cmnt(masm_, "[ allocate local context"); 3294515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Allocate local context. 3304515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Get outer context and create a new context based on it. 3314515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke frame_->PushFunction(); 3324515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Result context; 3334515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke if (heap_slots <= FastNewContextStub::kMaximumSlots) { 3344515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke FastNewContextStub stub(heap_slots); 3354515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke context = frame_->CallStub(&stub, 1); 3364515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke } else { 3374515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke context = frame_->CallRuntime(Runtime::kNewContext, 1); 3384515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke } 339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3404515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Update context local. 3414515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke frame_->SaveContextRegister(); 342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3434515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Verify that the runtime call result and rsi agree. 3444515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke if (FLAG_debug_code) { 3454515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ cmpq(context.reg(), rsi); 3464515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ Assert(equal, "Runtime::NewContext should end up in rsi"); 3474515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke } 348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3504515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // TODO(1241774): Improve this code: 3514515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // 1) only needed if we have a context 3524515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // 2) no need to recompute context ptr every single time 3534515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // 3) don't copy parameter operand code from SlotOperand! 3544515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke { 3554515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Comment cmnt2(masm_, "[ copy context parameters into .context"); 3564515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Note that iteration order is relevant here! If we have the same 3574515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // parameter twice (e.g., function (x, y, x)), and that parameter 3584515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // needs to be copied into the context, it must be the last argument 3594515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // passed to the parameter that needs to be copied. This is a rare 3604515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // case so we don't check for it, instead we rely on the copying 3614515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // order: such a parameter is copied repeatedly into the same 3624515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // context location and thus the last value is what is seen inside 3634515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // the function. 3643100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu for (int i = 0; i < scope()->num_parameters(); i++) { 3653100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu Variable* par = scope()->parameter(i); 3664515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Slot* slot = par->slot(); 3674515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke if (slot != NULL && slot->type() == Slot::CONTEXT) { 3684515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // The use of SlotOperand below is safe in unspilled code 3694515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // because the slot is guaranteed to be a context slot. 3704515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // 3714515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // There are no parameters in the global scope. 3723100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu ASSERT(!scope()->is_global_scope()); 3734515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke frame_->PushParameterAt(i); 3744515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Result value = frame_->Pop(); 3754515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke value.ToRegister(); 3764515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 3774515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // SlotOperand loads context.reg() with the context object 3784515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // stored to, used below in RecordWrite. 3794515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Result context = allocator_->Allocate(); 3804515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke ASSERT(context.is_valid()); 3814515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(SlotOperand(slot, context.reg()), value.reg()); 3824515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; 3834515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Result scratch = allocator_->Allocate(); 3844515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke ASSERT(scratch.is_valid()); 3854515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke frame_->Spill(context.reg()); 3864515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke frame_->Spill(value.reg()); 3874515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ RecordWrite(context.reg(), offset, value.reg(), scratch.reg()); 3884515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke } 389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3924515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Store the arguments object. This must happen after context 3934515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // initialization because the arguments object may be stored in 3944515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // the context. 3954515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke if (ArgumentsMode() != NO_ARGUMENTS_ALLOCATION) { 3964515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke StoreArgumentsObject(true); 3974515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke } 398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3994515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Initialize ThisFunction reference if present. 4003100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu if (scope()->is_function_scope() && scope()->function() != NULL) { 4014515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke frame_->Push(Factory::the_hole_value()); 4023100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu StoreToSlot(scope()->function()->slot(), NOT_CONST_INIT); 4034515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke } 4044515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke } else { 4054515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // When used as the secondary compiler for splitting, rbp, rsi, 4064515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // and rdi have been pushed on the stack. Adjust the virtual 4074515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // frame to match this state. 4084515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke frame_->Adjust(3); 4094515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke allocator_->Unuse(rdi); 410402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 411402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Bind all the bailout labels to the beginning of the function. 412402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu List<CompilationInfo::Bailout*>* bailouts = info->bailouts(); 413402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu for (int i = 0; i < bailouts->length(); i++) { 414402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ bind(bailouts->at(i)->label()); 415402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu } 416e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } 417e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 4184515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Initialize the function return target after the locals are set 4194515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // up, because it needs the expected frame height from the frame. 4204515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke function_return_.set_direction(JumpTarget::BIDIRECTIONAL); 4214515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke function_return_is_shadowed_ = false; 4224515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Generate code to 'execute' declarations and initialize functions 424a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // (source elements). In case of an illegal redeclaration we need to 425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // handle that instead of processing the declarations. 4263100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu if (scope()->HasIllegalRedeclaration()) { 427a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ illegal redeclarations"); 4283100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu scope()->VisitIllegalRedeclaration(this); 429a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 430a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ declarations"); 4313100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu ProcessDeclarations(scope()->declarations()); 432a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Bail out if a stack-overflow exception occurred when processing 433a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // declarations. 434a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (HasStackOverflow()) return; 435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 437a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (FLAG_trace) { 438a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->CallRuntime(Runtime::kTraceEnter, 0); 439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Ignore the return value. 440a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 441a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CheckStack(); 442a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 443a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Compile the body of the function in a vanilla state. Don't 444a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // bother compiling all the code if the scope has an illegal 445a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // redeclaration. 4463100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu if (!scope()->HasIllegalRedeclaration()) { 447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ function body"); 448a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef DEBUG 449a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool is_builtin = Bootstrapper::IsActive(); 450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool should_trace = 451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls; 452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (should_trace) { 453a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->CallRuntime(Runtime::kDebugTrace, 0); 454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Ignore the return value. 455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif 4573100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu VisitStatements(info->function()->body()); 458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 459a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Handle the return from the function. 460a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (has_valid_frame()) { 461a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If there is a valid frame, control flow can fall off the end of 462a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // the body. In that case there is an implicit return statement. 463a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!function_return_is_shadowed_); 4643100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu CodeForReturnPosition(info->function()); 465a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->PrepareForReturn(); 466a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result undefined(Factory::undefined_value()); 467a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (function_return_.is_bound()) { 468a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block function_return_.Jump(&undefined); 469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 470a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block function_return_.Bind(&undefined); 471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GenerateReturnSequence(&undefined); 472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 473a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (function_return_.is_linked()) { 474a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If the return target has dangling jumps to it, then we have not 475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // yet generated the return sequence. This can happen when (a) 476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // control does not flow off the end of the body so we did not 477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // compile an artificial return statement just above, and (b) there 478a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // are return statements in the body but (c) they are all shadowed. 479a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result return_value; 480a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block function_return_.Bind(&return_value); 481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GenerateReturnSequence(&return_value); 482a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 485a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Adjust for function-level loop nesting. 4874515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke loop_nesting_ -= info->loop_nesting(); 488a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 489a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Code generation state must be reset. 490a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(state_ == NULL); 491a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(loop_nesting() == 0); 492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!function_return_is_shadowed_); 493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block function_return_.Unuse(); 494a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block DeleteFrame(); 495a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 496a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Process any deferred code using the register allocator. 497a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!HasStackOverflow()) { 498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block HistogramTimerScope deferred_timer(&Counters::deferred_code_generation); 499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget::set_compiling_deferred_code(true); 500a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ProcessDeferred(); 501a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget::set_compiling_deferred_code(false); 502a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 503a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 504a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // There is no need to delete the register allocator, it is a 505a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // stack-allocated local. 506a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block allocator_ = NULL; 507a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 508a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 509a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenerateReturnSequence(Result* return_value) { 510a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The return value is a live (but not currently reference counted) 511a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // reference to rax. This is safe because the current frame does not 512a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // contain a reference to rax (it is prepared for the return by spilling 513a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // all registers). 514a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (FLAG_trace) { 515a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(return_value); 516a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block *return_value = frame_->CallRuntime(Runtime::kTraceExit, 1); 517a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 518a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return_value->ToRegister(rax); 519a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 520a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Add a label for checking the size of the code used for returning. 521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef DEBUG 522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label check_exit_codesize; 523a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block masm_->bind(&check_exit_codesize); 524a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif 525a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 526a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Leave the frame and return popping the arguments and the 527a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // receiver. 528a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Exit(); 5293100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu masm_->ret((scope()->num_parameters() + 1) * kPointerSize); 530a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef ENABLE_DEBUGGER_SUPPORT 531a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Add padding that will be overwritten by a debugger breakpoint. 532a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // frame_->Exit() generates "movq rsp, rbp; pop rbp; ret k" 533a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // with length 7 (3 + 1 + 3). 534d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block const int kPadding = Assembler::kJSReturnSequenceLength - 7; 535a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = 0; i < kPadding; ++i) { 536a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block masm_->int3(); 537a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 538a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the size of the code used for returning matches what is 539a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // expected by the debugger. 540d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block ASSERT_EQ(Assembler::kJSReturnSequenceLength, 541a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); 542a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif 543a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block DeleteFrame(); 544a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 545a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 546a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 547a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef DEBUG 548a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool CodeGenerator::HasValidEntryRegisters() { 549a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return (allocator()->count(rax) == (frame()->is_used(rax) ? 1 : 0)) 550a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block && (allocator()->count(rbx) == (frame()->is_used(rbx) ? 1 : 0)) 551a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block && (allocator()->count(rcx) == (frame()->is_used(rcx) ? 1 : 0)) 552a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block && (allocator()->count(rdx) == (frame()->is_used(rdx) ? 1 : 0)) 553a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block && (allocator()->count(rdi) == (frame()->is_used(rdi) ? 1 : 0)) 554a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block && (allocator()->count(r8) == (frame()->is_used(r8) ? 1 : 0)) 555a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block && (allocator()->count(r9) == (frame()->is_used(r9) ? 1 : 0)) 556a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block && (allocator()->count(r11) == (frame()->is_used(r11) ? 1 : 0)) 557a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block && (allocator()->count(r14) == (frame()->is_used(r14) ? 1 : 0)) 558a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block && (allocator()->count(r15) == (frame()->is_used(r15) ? 1 : 0)) 559a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block && (allocator()->count(r12) == (frame()->is_used(r12) ? 1 : 0)); 560a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 561a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif 562a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 563a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 564a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass DeferredReferenceGetKeyedValue: public DeferredCode { 565a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public: 566a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block explicit DeferredReferenceGetKeyedValue(Register dst, 567a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register receiver, 568a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register key, 569a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool is_global) 570a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block : dst_(dst), receiver_(receiver), key_(key), is_global_(is_global) { 571a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block set_comment("[ DeferredReferenceGetKeyedValue"); 572a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 573a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 574a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block virtual void Generate(); 575a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 576a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label* patch_site() { return &patch_site_; } 577a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 578a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private: 579a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label patch_site_; 580a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register dst_; 581a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register receiver_; 582a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register key_; 583a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool is_global_; 584a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 585a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 586a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 587a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DeferredReferenceGetKeyedValue::Generate() { 588a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(receiver_); // First IC argument. 589a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(key_); // Second IC argument. 590a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 591a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Calculate the delta from the IC call instruction to the map check 592a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // movq instruction in the inlined version. This delta is stored in 593a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // a test(rax, delta) instruction after the call so that we can find 594a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // it in the IC initialization code and patch the movq instruction. 595a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // This means that we cannot allow test instructions after calls to 596a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // KeyedLoadIC stubs in other places. 597a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); 598a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block RelocInfo::Mode mode = is_global_ 599a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ? RelocInfo::CODE_TARGET_CONTEXT 600a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block : RelocInfo::CODE_TARGET; 601a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Call(ic, mode); 602a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The delta from the start of the map-compare instruction to the 603a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // test instruction. We use masm_-> directly here instead of the __ 604a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // macro because the macro sometimes uses macro expansion to turn 605a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // into something that can't return a value. This is encountered 606a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // when doing generated code coverage tests. 607a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); 608a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Here we use masm_-> instead of the __ macro because this is the 609a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // instruction that gets patched and coverage code gets in the way. 610a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // TODO(X64): Consider whether it's worth switching the test to a 611a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // 7-byte NOP with non-zero immediate (0f 1f 80 xxxxxxxx) which won't 612a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // be generated normally. 613a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block masm_->testl(rax, Immediate(-delta_to_patch_site)); 614a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ IncrementCounter(&Counters::keyed_load_inline_miss, 1); 615a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 616a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!dst_.is(rax)) __ movq(dst_, rax); 617a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(key_); 618a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(receiver_); 619a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 620a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 621a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 622a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass DeferredReferenceSetKeyedValue: public DeferredCode { 623a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public: 624a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block DeferredReferenceSetKeyedValue(Register value, 625a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register key, 626a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register receiver) 627a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block : value_(value), key_(key), receiver_(receiver) { 628a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block set_comment("[ DeferredReferenceSetKeyedValue"); 629a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 630a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 631a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block virtual void Generate(); 632a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 633a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label* patch_site() { return &patch_site_; } 634a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 635a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private: 636a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register value_; 637a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register key_; 638a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register receiver_; 639a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label patch_site_; 640a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 641a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 642a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 643a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DeferredReferenceSetKeyedValue::Generate() { 644a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ IncrementCounter(&Counters::keyed_store_inline_miss, 1); 645a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Push receiver and key arguments on the stack. 646a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(receiver_); 647a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(key_); 648a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Move value argument to eax as expected by the IC stub. 649a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!value_.is(rax)) __ movq(rax, value_); 650a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Call the IC stub. 651a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); 652a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Call(ic, RelocInfo::CODE_TARGET); 653a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The delta from the start of the map-compare instructions (initial movq) 654a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // to the test instruction. We use masm_-> directly here instead of the 655a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // __ macro because the macro sometimes uses macro expansion to turn 656a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // into something that can't return a value. This is encountered 657a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // when doing generated code coverage tests. 658a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); 659a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Here we use masm_-> instead of the __ macro because this is the 660a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // instruction that gets patched and coverage code gets in the way. 661a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block masm_->testl(rax, Immediate(-delta_to_patch_site)); 662a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Restore value (returned from store IC), key and receiver 663a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // registers. 664a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!value_.is(rax)) __ movq(value_, rax); 665a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(key_); 666a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(receiver_); 667a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 668a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 669a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 670d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarkevoid CodeGenerator::CallApplyLazy(Expression* applicand, 671a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Expression* receiver, 672a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block VariableProxy* arguments, 673a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int position) { 674d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // An optimized implementation of expressions of the form 675d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // x.apply(y, arguments). 676d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // If the arguments object of the scope has not been allocated, 677d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // and x.apply is Function.prototype.apply, this optimization 678d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // just copies y and the arguments of the current function on the 679d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // stack, as receiver and arguments, and calls x. 680d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // In the implementation comments, we call x the applicand 681d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // and y the receiver. 682a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(ArgumentsMode() == LAZY_ARGUMENTS_ALLOCATION); 683a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(arguments->IsArguments()); 684a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 685d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Load applicand.apply onto the stack. This will usually 686a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // give us a megamorphic load site. Not super, but it works. 687d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Load(applicand); 688d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Handle<String> name = Factory::LookupAsciiSymbol("apply"); 689d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke frame()->Push(name); 690d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Result answer = frame()->CallLoadIC(RelocInfo::CODE_TARGET); 691d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ nop(); 692d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke frame()->Push(&answer); 693a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 694a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load the receiver and the existing arguments object onto the 695a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // expression stack. Avoid allocating the arguments object here. 696a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(receiver); 6973100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu LoadFromSlot(scope()->arguments()->var()->slot(), NOT_INSIDE_TYPEOF); 698a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 699a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Emit the source position information after having loaded the 700a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // receiver and the arguments. 701a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CodeForSourcePosition(position); 702d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Contents of frame at this point: 703d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Frame[0]: arguments object of the current function or the hole. 704d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Frame[1]: receiver 705d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Frame[2]: applicand.apply 706d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Frame[3]: applicand. 707a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 708a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check if the arguments object has been lazily allocated 709a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // already. If so, just use that instead of copying the arguments 710a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // from the stack. This also deals with cases where a local variable 711a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // named 'arguments' has been introduced. 712a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Dup(); 713a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result probe = frame_->Pop(); 714d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke { VirtualFrame::SpilledScope spilled_scope; 715d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Label slow, done; 716d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke bool try_lazy = true; 717d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke if (probe.is_constant()) { 718d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke try_lazy = probe.handle()->IsTheHole(); 719d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke } else { 720d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ CompareRoot(probe.reg(), Heap::kTheHoleValueRootIndex); 721d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke probe.Unuse(); 722d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(not_equal, &slow); 723d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke } 724a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 725d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke if (try_lazy) { 726d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Label build_args; 727d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Get rid of the arguments object probe. 728d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke frame_->Drop(); // Can be called on a spilled frame. 729d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Stack now has 3 elements on it. 730d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Contents of stack at this point: 731d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rsp[0]: receiver 732d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rsp[1]: applicand.apply 733d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rsp[2]: applicand. 734d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 735d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Check that the receiver really is a JavaScript object. 736d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(rax, Operand(rsp, 0)); 737d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Condition is_smi = masm_->CheckSmi(rax); 738d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(is_smi, &build_args); 739a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We allow all JSObjects including JSFunctions. As long as 740a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // JS_FUNCTION_TYPE is the last instance type and it is right 741a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // after LAST_JS_OBJECT_TYPE, we do not have to check the upper 742a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // bound. 743a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); 744a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1); 745d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx); 746d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(below, &build_args); 747d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 748d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Check that applicand.apply is Function.prototype.apply. 749d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(rax, Operand(rsp, kPointerSize)); 750d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke is_smi = masm_->CheckSmi(rax); 751d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(is_smi, &build_args); 752d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ CmpObjectType(rax, JS_FUNCTION_TYPE, rcx); 753d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(not_equal, &build_args); 754d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(rax, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset)); 755a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<Code> apply_code(Builtins::builtin(Builtins::FunctionApply)); 756d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ Cmp(FieldOperand(rax, SharedFunctionInfo::kCodeOffset), apply_code); 757d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(not_equal, &build_args); 758d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 759d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Check that applicand is a function. 760d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(rdi, Operand(rsp, 2 * kPointerSize)); 761d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke is_smi = masm_->CheckSmi(rdi); 762d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(is_smi, &build_args); 763d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); 764d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(not_equal, &build_args); 765d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 766d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Copy the arguments to this function possibly from the 767d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // adaptor frame below it. 768d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Label invoke, adapted; 769d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); 770d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ SmiCompare(Operand(rdx, StandardFrameConstants::kContextOffset), 771d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); 772d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(equal, &adapted); 773d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 774d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // No arguments adaptor frame. Copy fixed number of arguments. 7753100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu __ movq(rax, Immediate(scope()->num_parameters())); 7763100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu for (int i = 0; i < scope()->num_parameters(); i++) { 777d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ push(frame_->ParameterAt(i)); 778d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke } 779d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ jmp(&invoke); 780d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 781d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Arguments adaptor frame present. Copy arguments from there, but 782d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // avoid copying too many arguments to avoid stack overflows. 783d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ bind(&adapted); 784d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke static const uint32_t kArgumentsLimit = 1 * KB; 785d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(rax, Operand(rdx, ArgumentsAdaptorFrameConstants::kLengthOffset)); 786d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ SmiToInteger32(rax, rax); 787d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(rcx, rax); 788d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ cmpq(rax, Immediate(kArgumentsLimit)); 789d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(above, &build_args); 790d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 791d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Loop through the arguments pushing them onto the execution 792d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // stack. We don't inform the virtual frame of the push, so we don't 793d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // have to worry about getting rid of the elements from the virtual 794d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // frame. 795d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Label loop; 796d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rcx is a small non-negative integer, due to the test above. 797d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ testl(rcx, rcx); 798d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(zero, &invoke); 799d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ bind(&loop); 800d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ push(Operand(rdx, rcx, times_pointer_size, 1 * kPointerSize)); 801d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ decl(rcx); 802d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(not_zero, &loop); 803d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 804d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Invoke the function. 805d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ bind(&invoke); 806d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke ParameterCount actual(rax); 807d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ InvokeFunction(rdi, actual, CALL_FUNCTION); 808d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Drop applicand.apply and applicand from the stack, and push 809d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // the result of the function call, but leave the spilled frame 810d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // unchanged, with 3 elements, so it is correct when we compile the 811d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // slow-case code. 812d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ addq(rsp, Immediate(2 * kPointerSize)); 813d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ push(rax); 814d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Stack now has 1 element: 815d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rsp[0]: result 816d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ jmp(&done); 817d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 818d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Slow-case: Allocate the arguments object since we know it isn't 819d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // there, and fall-through to the slow-case where we call 820d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // applicand.apply. 821d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ bind(&build_args); 822d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Stack now has 3 elements, because we have jumped from where: 823d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rsp[0]: receiver 824d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rsp[1]: applicand.apply 825d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rsp[2]: applicand. 826d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 827d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // StoreArgumentsObject requires a correct frame, and may modify it. 828d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Result arguments_object = StoreArgumentsObject(false); 829d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke frame_->SpillAll(); 830d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke arguments_object.ToRegister(); 831d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke frame_->EmitPush(arguments_object.reg()); 832d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke arguments_object.Unuse(); 833d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Stack and frame now have 4 elements. 834d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ bind(&slow); 835a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 836a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 837d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Generic computation of x.apply(y, args) with no special optimization. 838d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Flip applicand.apply and applicand on the stack, so 839d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // applicand looks like the receiver of the applicand.apply call. 840d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Then process it as a normal function call. 841d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(rax, Operand(rsp, 3 * kPointerSize)); 842d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(rbx, Operand(rsp, 2 * kPointerSize)); 843d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(Operand(rsp, 2 * kPointerSize), rax); 844d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(Operand(rsp, 3 * kPointerSize), rbx); 845d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 846d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke CallFunctionStub call_function(2, NOT_IN_LOOP, NO_CALL_FUNCTION_FLAGS); 847d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Result res = frame_->CallStub(&call_function, 3); 848d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // The function and its two arguments have been dropped. 849d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke frame_->Drop(1); // Drop the receiver as well. 850d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke res.ToRegister(); 851d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke frame_->EmitPush(res.reg()); 852d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Stack now has 1 element: 853d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rsp[0]: result 854d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke if (try_lazy) __ bind(&done); 855d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke } // End of spilled scope. 856d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Restore the context register after a call. 857a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->RestoreContextRegister(); 858a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 859a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 860a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 861a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass DeferredStackCheck: public DeferredCode { 862a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public: 863a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block DeferredStackCheck() { 864a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block set_comment("[ DeferredStackCheck"); 865a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 866a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 867a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block virtual void Generate(); 868a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 869a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 870a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 871a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DeferredStackCheck::Generate() { 872a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block StackCheckStub stub; 873a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CallStub(&stub); 874a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 875a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 876a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 877a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::CheckStack() { 878d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block DeferredStackCheck* deferred = new DeferredStackCheck; 879d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ CompareRoot(rsp, Heap::kStackLimitRootIndex); 880d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block deferred->Branch(below); 881d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block deferred->BindExit(); 882a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 883a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 884a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 885a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitAndSpill(Statement* statement) { 886a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // TODO(X64): No architecture specific code. Move to shared location. 887a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(in_spilled_code()); 888a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block set_in_spilled_code(false); 889a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Visit(statement); 890a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (frame_ != NULL) { 891a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->SpillAll(); 892a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 893a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block set_in_spilled_code(true); 894a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 895a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 896a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 897a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitStatementsAndSpill(ZoneList<Statement*>* statements) { 898a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(in_spilled_code()); 899a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block set_in_spilled_code(false); 900a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block VisitStatements(statements); 901a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (frame_ != NULL) { 902a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->SpillAll(); 903a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 904a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block set_in_spilled_code(true); 905a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 906a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 907a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 908a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitStatements(ZoneList<Statement*>* statements) { 909a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!in_spilled_code()); 910a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = 0; has_valid_frame() && i < statements->length(); i++) { 911a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Visit(statements->at(i)); 912a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 913a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 914a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 915a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 916a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitBlock(Block* node) { 917a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!in_spilled_code()); 918a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ Block"); 919a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CodeForStatementPosition(node); 920a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); 921a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block VisitStatements(node->statements()); 922a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (node->break_target()->is_linked()) { 923a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block node->break_target()->Bind(); 924a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 925a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block node->break_target()->Unuse(); 926a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 927a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 928a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 929a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitDeclaration(Declaration* node) { 930a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ Declaration"); 931a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Variable* var = node->proxy()->var(); 932a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(var != NULL); // must have been resolved 933a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Slot* slot = var->slot(); 934a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 935a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If it was not possible to allocate the variable at compile time, 936a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // we need to "declare" it at runtime to make sure it actually 937a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // exists in the local context. 938a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (slot != NULL && slot->type() == Slot::LOOKUP) { 939a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Variables with a "LOOKUP" slot were introduced as non-locals 940a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // during variable resolution and must have mode DYNAMIC. 941a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(var->is_dynamic()); 942a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // For now, just do a runtime call. Sync the virtual frame eagerly 943a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // so we can simply push the arguments into place. 944a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->SyncRange(0, frame_->element_count() - 1); 945a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(rsi); 946a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(kScratchRegister, var->name(), RelocInfo::EMBEDDED_OBJECT); 947a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(kScratchRegister); 948a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Declaration nodes are always introduced in one of two modes. 949a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST); 950a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY; 9513ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block frame_->EmitPush(Smi::FromInt(attr)); 952a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Push initial value, if any. 953a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Note: For variables we must not push an initial value (such as 954a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // 'undefined') because we may have a (legal) redeclaration and we 955a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // must not destroy the current value. 956a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (node->mode() == Variable::CONST) { 957a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(Heap::kTheHoleValueRootIndex); 958a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (node->fun() != NULL) { 959a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(node->fun()); 960a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 9613ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block frame_->EmitPush(Smi::FromInt(0)); // no initial value! 962a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 963a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result ignored = frame_->CallRuntime(Runtime::kDeclareContextSlot, 4); 964a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Ignore the return value (declarations are statements). 965a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return; 966a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 967a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 968a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!var->is_global()); 969a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 970a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If we have a function or a constant, we need to initialize the variable. 971a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Expression* val = NULL; 972a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (node->mode() == Variable::CONST) { 973a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block val = new Literal(Factory::the_hole_value()); 974a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 975a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block val = node->fun(); // NULL if we don't have a function 976a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 977a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 978a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (val != NULL) { 979a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block { 980a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Set the initial value. 981a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Reference target(this, node->proxy()); 982a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(val); 983a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block target.SetValue(NOT_CONST_INIT); 984a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The reference is removed from the stack (preserving TOS) when 985a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // it goes out of scope. 986a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 987a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get rid of the assigned value (declarations are statements). 988a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Drop(); 989a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 990a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 991a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 992a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 993a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) { 994a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!in_spilled_code()); 995a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ ExpressionStatement"); 996a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CodeForStatementPosition(node); 997a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Expression* expression = node->expression(); 998a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block expression->MarkAsStatement(); 999a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(expression); 1000a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Remove the lingering expression result from the top of stack. 1001a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Drop(); 1002a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1003a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1004a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1005a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitEmptyStatement(EmptyStatement* node) { 1006a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!in_spilled_code()); 1007a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "// EmptyStatement"); 1008a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CodeForStatementPosition(node); 1009a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // nothing to do 1010a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1011a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1012a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1013a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitIfStatement(IfStatement* node) { 1014a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!in_spilled_code()); 1015a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ IfStatement"); 1016a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Generate different code depending on which parts of the if statement 1017a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // are present or not. 1018a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool has_then_stm = node->HasThenStatement(); 1019a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool has_else_stm = node->HasElseStatement(); 1020a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1021a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CodeForStatementPosition(node); 1022a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget exit; 1023a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (has_then_stm && has_else_stm) { 1024a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget then; 1025a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget else_; 1026a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ControlDestination dest(&then, &else_, true); 1027d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block LoadCondition(node->condition(), &dest, true); 1028a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1029a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (dest.false_was_fall_through()) { 1030a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The else target was bound, so we compile the else part first. 1031a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Visit(node->else_statement()); 1032a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1033a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We may have dangling jumps to the then part. 1034a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (then.is_linked()) { 1035a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (has_valid_frame()) exit.Jump(); 1036a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block then.Bind(); 1037a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Visit(node->then_statement()); 1038a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1039a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 1040a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The then target was bound, so we compile the then part first. 1041a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Visit(node->then_statement()); 1042a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1043a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (else_.is_linked()) { 1044a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (has_valid_frame()) exit.Jump(); 1045a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block else_.Bind(); 1046a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Visit(node->else_statement()); 1047a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1048a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1049a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1050a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (has_then_stm) { 1051a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!has_else_stm); 1052a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget then; 1053a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ControlDestination dest(&then, &exit, true); 1054d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block LoadCondition(node->condition(), &dest, true); 1055a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1056a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (dest.false_was_fall_through()) { 1057a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The exit label was bound. We may have dangling jumps to the 1058a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // then part. 1059a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (then.is_linked()) { 1060a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exit.Unuse(); 1061a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exit.Jump(); 1062a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block then.Bind(); 1063a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Visit(node->then_statement()); 1064a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1065a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 1066a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The then label was bound. 1067a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Visit(node->then_statement()); 1068a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1069a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1070a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (has_else_stm) { 1071a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!has_then_stm); 1072a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget else_; 1073a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ControlDestination dest(&exit, &else_, false); 1074d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block LoadCondition(node->condition(), &dest, true); 1075a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1076a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (dest.true_was_fall_through()) { 1077a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The exit label was bound. We may have dangling jumps to the 1078a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // else part. 1079a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (else_.is_linked()) { 1080a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exit.Unuse(); 1081a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exit.Jump(); 1082a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block else_.Bind(); 1083a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Visit(node->else_statement()); 1084a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1085a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 1086a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The else label was bound. 1087a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Visit(node->else_statement()); 1088a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1089a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1090a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 1091a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!has_then_stm && !has_else_stm); 1092a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We only care about the condition's side effects (not its value 1093a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // or control flow effect). LoadCondition is called without 1094a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // forcing control flow. 1095a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ControlDestination dest(&exit, &exit, true); 1096d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block LoadCondition(node->condition(), &dest, false); 1097a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!dest.is_used()) { 1098a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We got a value on the frame rather than (or in addition to) 1099a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // control flow. 1100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Drop(); 1101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (exit.is_linked()) { 1105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exit.Bind(); 1106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitContinueStatement(ContinueStatement* node) { 1111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!in_spilled_code()); 1112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ ContinueStatement"); 1113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CodeForStatementPosition(node); 1114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block node->target()->continue_target()->Jump(); 1115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitBreakStatement(BreakStatement* node) { 1119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!in_spilled_code()); 1120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ BreakStatement"); 1121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CodeForStatementPosition(node); 1122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block node->target()->break_target()->Jump(); 1123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitReturnStatement(ReturnStatement* node) { 1127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!in_spilled_code()); 1128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ ReturnStatement"); 1129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CodeForStatementPosition(node); 1131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(node->expression()); 1132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result return_value = frame_->Pop(); 1133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (function_return_is_shadowed_) { 1134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block function_return_.Jump(&return_value); 1135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 1136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->PrepareForReturn(); 1137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (function_return_.is_bound()) { 1138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If the function return label is already bound we reuse the 1139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // code by jumping to the return site. 1140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block function_return_.Jump(&return_value); 1141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 1142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block function_return_.Bind(&return_value); 1143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GenerateReturnSequence(&return_value); 1144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { 1150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!in_spilled_code()); 1151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ WithEnterStatement"); 1152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CodeForStatementPosition(node); 1153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(node->expression()); 1154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result context; 1155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (node->is_catch_block()) { 1156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block context = frame_->CallRuntime(Runtime::kPushCatchContext, 1); 1157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 1158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block context = frame_->CallRuntime(Runtime::kPushContext, 1); 1159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Update context local. 1162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->SaveContextRegister(); 1163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Verify that the runtime call result and rsi agree. 1165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (FLAG_debug_code) { 1166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ cmpq(context.reg(), rsi); 1167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Assert(equal, "Runtime::NewContext should end up in rsi"); 1168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitWithExitStatement(WithExitStatement* node) { 1173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!in_spilled_code()); 1174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ WithExitStatement"); 1175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CodeForStatementPosition(node); 1176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Pop context. 1177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rsi, ContextOperand(rsi, Context::PREVIOUS_INDEX)); 1178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Update context local. 1179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->SaveContextRegister(); 1180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { 1184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // TODO(X64): This code is completely generic and should be moved somewhere 1185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // where it can be shared between architectures. 1186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!in_spilled_code()); 1187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ SwitchStatement"); 1188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CodeForStatementPosition(node); 1189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); 1190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Compile the switch value. 1192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(node->tag()); 1193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ZoneList<CaseClause*>* cases = node->cases(); 1195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int length = cases->length(); 1196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CaseClause* default_clause = NULL; 1197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget next_test; 1199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Compile the case label expressions and comparisons. Exit early 1200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // if a comparison is unconditionally true. The target next_test is 1201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // bound before the loop in order to indicate control flow to the 1202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // first comparison. 1203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block next_test.Bind(); 1204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = 0; i < length && !next_test.is_unused(); i++) { 1205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CaseClause* clause = cases->at(i); 1206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The default is not a test, but remember it for later. 1207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (clause->is_default()) { 1208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block default_clause = clause; 1209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block continue; 1210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ Case comparison"); 1213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We recycle the same target next_test for each test. Bind it if 1214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // the previous test has not done so and then unuse it for the 1215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // loop. 1216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (next_test.is_linked()) { 1217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block next_test.Bind(); 1218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block next_test.Unuse(); 1220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Duplicate the switch value. 1222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Dup(); 1223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Compile the label expression. 1225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(clause->label()); 1226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Compare and branch to the body if true or the next test if 1228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // false. Prefer the next test as a fall through. 1229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ControlDestination dest(clause->body_target(), &next_test, false); 1230402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Comparison(node, equal, true, &dest); 1231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If the comparison fell through to the true target, jump to the 1233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // actual body. 1234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (dest.true_was_fall_through()) { 1235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block clause->body_target()->Unuse(); 1236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block clause->body_target()->Jump(); 1237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If there was control flow to a next test from the last one 1241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // compiled, compile a jump to the default or break target. 1242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!next_test.is_unused()) { 1243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (next_test.is_linked()) { 1244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block next_test.Bind(); 1245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Drop the switch value. 1247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Drop(); 1248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (default_clause != NULL) { 1249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block default_clause->body_target()->Jump(); 1250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 1251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block node->break_target()->Jump(); 1252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The last instruction emitted was a jump, either to the default 1256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // clause or the break target, or else to a case body from the loop 1257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // that compiles the tests. 1258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!has_valid_frame()); 1259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Compile case bodies as needed. 1260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = 0; i < length; i++) { 1261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CaseClause* clause = cases->at(i); 1262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // There are two ways to reach the body: from the corresponding 1264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // test or as the fall through of the previous body. 1265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (clause->body_target()->is_linked() || has_valid_frame()) { 1266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (clause->body_target()->is_linked()) { 1267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (has_valid_frame()) { 1268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If we have both a jump to the test and a fall through, put 1269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // a jump on the fall through path to avoid the dropping of 1270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // the switch value on the test path. The exception is the 1271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // default which has already had the switch value dropped. 1272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (clause->is_default()) { 1273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block clause->body_target()->Bind(); 1274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 1275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget body; 1276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block body.Jump(); 1277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block clause->body_target()->Bind(); 1278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Drop(); 1279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block body.Bind(); 1280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 1282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // No fall through to worry about. 1283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block clause->body_target()->Bind(); 1284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!clause->is_default()) { 1285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Drop(); 1286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 1289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Otherwise, we have only fall through. 1290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(has_valid_frame()); 1291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We are now prepared to compile the body. 1294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ Case body"); 1295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block VisitStatements(clause->statements()); 1296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block clause->body_target()->Unuse(); 1298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We may not have a valid frame here so bind the break target only 1301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // if needed. 1302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (node->break_target()->is_linked()) { 1303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block node->break_target()->Bind(); 1304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block node->break_target()->Unuse(); 1306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 13093ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Blockvoid CodeGenerator::VisitDoWhileStatement(DoWhileStatement* node) { 1310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!in_spilled_code()); 13113ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block Comment cmnt(masm_, "[ DoWhileStatement"); 1312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CodeForStatementPosition(node); 1313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); 13143ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block JumpTarget body(JumpTarget::BIDIRECTIONAL); 13153ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block IncrementLoopNesting(); 13163ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block 13173ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block ConditionAnalysis info = AnalyzeCondition(node->cond()); 13183ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Label the top of the loop for the backward jump if necessary. 13193ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block switch (info) { 13203ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block case ALWAYS_TRUE: 13213ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Use the continue target. 13223ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); 13233ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->continue_target()->Bind(); 13243ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block break; 13253ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block case ALWAYS_FALSE: 13263ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // No need to label it. 13273ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); 13283ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block break; 13293ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block case DONT_KNOW: 13303ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Continue is the test, so use the backward body target. 13313ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); 13323ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block body.Bind(); 13333ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block break; 13343ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block } 1335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 13363ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block CheckStack(); // TODO(1222600): ignore if body contains calls. 13373ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block Visit(node->body()); 13383ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block 13393ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Compile the test. 13403ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block switch (info) { 13413ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block case ALWAYS_TRUE: 13423ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // If control flow can fall off the end of the body, jump back 13433ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // to the top and bind the break target at the exit. 13443ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block if (has_valid_frame()) { 13453ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->continue_target()->Jump(); 1346a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 13473ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block if (node->break_target()->is_linked()) { 13483ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->break_target()->Bind(); 13493ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block } 13503ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block break; 13513ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block case ALWAYS_FALSE: 13523ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // We may have had continues or breaks in the body. 13533ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block if (node->continue_target()->is_linked()) { 13543ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->continue_target()->Bind(); 13553ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block } 13563ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block if (node->break_target()->is_linked()) { 13573ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->break_target()->Bind(); 13583ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block } 13593ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block break; 13603ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block case DONT_KNOW: 13613ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // We have to compile the test expression if it can be reached by 13623ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // control flow falling out of the body or via continue. 13633ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block if (node->continue_target()->is_linked()) { 13643ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->continue_target()->Bind(); 13653ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block } 13663ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block if (has_valid_frame()) { 1367d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Comment cmnt(masm_, "[ DoWhileCondition"); 1368d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block CodeForDoWhileConditionPosition(node); 13693ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block ControlDestination dest(&body, node->break_target(), false); 1370d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block LoadCondition(node->cond(), &dest, true); 13713ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block } 13723ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block if (node->break_target()->is_linked()) { 13733ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->break_target()->Bind(); 13743ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block } 13753ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block break; 1376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 13783ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block DecrementLoopNesting(); 13793ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->continue_target()->Unuse(); 13803ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->break_target()->Unuse(); 13813ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block} 1382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 13833ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block 13843ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Blockvoid CodeGenerator::VisitWhileStatement(WhileStatement* node) { 13853ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block ASSERT(!in_spilled_code()); 13863ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block Comment cmnt(masm_, "[ WhileStatement"); 13873ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block CodeForStatementPosition(node); 13883ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block 13893ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // If the condition is always false and has no side effects, we do not 13903ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // need to compile anything. 13913ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block ConditionAnalysis info = AnalyzeCondition(node->cond()); 13923ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block if (info == ALWAYS_FALSE) return; 13933ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block 13943ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Do not duplicate conditions that may have function literal 13953ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // subexpressions. This can cause us to compile the function literal 13963ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // twice. 13973ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block bool test_at_bottom = !node->may_have_function_literal(); 13983ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); 13993ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block IncrementLoopNesting(); 14003ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block JumpTarget body; 14013ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block if (test_at_bottom) { 14023ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block body.set_direction(JumpTarget::BIDIRECTIONAL); 14033ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block } 14043ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block 14053ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Based on the condition analysis, compile the test as necessary. 14063ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block switch (info) { 14073ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block case ALWAYS_TRUE: 14083ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // We will not compile the test expression. Label the top of the 14093ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // loop with the continue target. 14103ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); 14113ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->continue_target()->Bind(); 14123ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block break; 14133ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block case DONT_KNOW: { 14143ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block if (test_at_bottom) { 14153ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Continue is the test at the bottom, no need to label the test 14163ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // at the top. The body is a backward target. 1417a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); 1418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 14193ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Label the test at the top as the continue target. The body 14203ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // is a forward-only target. 14213ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); 14223ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->continue_target()->Bind(); 1423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 14243ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Compile the test with the body as the true target and preferred 14253ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // fall-through and with the break target as the false target. 14263ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block ControlDestination dest(&body, node->break_target(), true); 1427d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block LoadCondition(node->cond(), &dest, true); 14283ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block 14293ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block if (dest.false_was_fall_through()) { 14303ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // If we got the break target as fall-through, the test may have 14313ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // been unconditionally false (if there are no jumps to the 14323ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // body). 14333ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block if (!body.is_linked()) { 14343ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block DecrementLoopNesting(); 14353ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block return; 1436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1437a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 14383ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Otherwise, jump around the body on the fall through and then 14393ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // bind the body target. 14403ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->break_target()->Unuse(); 14413ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->break_target()->Jump(); 14423ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block body.Bind(); 14433ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block } 14443ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block break; 14453ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block } 14463ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block case ALWAYS_FALSE: 14473ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block UNREACHABLE(); 14483ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block break; 14493ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block } 1450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 14513ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block CheckStack(); // TODO(1222600): ignore if body contains calls. 14523ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block Visit(node->body()); 14533ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block 14543ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Based on the condition analysis, compile the backward jump as 14553ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // necessary. 14563ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block switch (info) { 14573ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block case ALWAYS_TRUE: 14583ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // The loop body has been labeled with the continue target. 14593ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block if (has_valid_frame()) { 14603ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->continue_target()->Jump(); 14613ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block } 14623ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block break; 14633ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block case DONT_KNOW: 14643ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block if (test_at_bottom) { 14653ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // If we have chosen to recompile the test at the bottom, 14663ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // then it is the continue target. 1467a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (node->continue_target()->is_linked()) { 1468a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block node->continue_target()->Bind(); 1469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1470a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (has_valid_frame()) { 14713ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // The break target is the fall-through (body is a backward 14723ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // jump from here and thus an invalid fall-through). 1473a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ControlDestination dest(&body, node->break_target(), false); 1474d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block LoadCondition(node->cond(), &dest, true); 1475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 14763ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block } else { 14773ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // If we have chosen not to recompile the test at the 14783ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // bottom, jump back to the one at the top. 14793ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block if (has_valid_frame()) { 14803ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->continue_target()->Jump(); 1481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1482a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 14843ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block case ALWAYS_FALSE: 14853ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block UNREACHABLE(); 14863ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block break; 14873ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block } 14883ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block 14893ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // The break target may be already bound (by the condition), or there 14903ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // may not be a valid frame. Bind it only if needed. 14913ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block if (node->break_target()->is_linked()) { 14923ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->break_target()->Bind(); 14933ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block } 14943ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block DecrementLoopNesting(); 14953ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block} 1496a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1497a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 14983ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Blockvoid CodeGenerator::VisitForStatement(ForStatement* node) { 14993ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block ASSERT(!in_spilled_code()); 15003ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block Comment cmnt(masm_, "[ ForStatement"); 15013ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block CodeForStatementPosition(node); 1502a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 15033ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Compile the init expression if present. 15043ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block if (node->init() != NULL) { 15053ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block Visit(node->init()); 15063ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block } 1507a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 15083ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // If the condition is always false and has no side effects, we do not 15093ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // need to compile anything else. 15103ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block ConditionAnalysis info = AnalyzeCondition(node->cond()); 15113ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block if (info == ALWAYS_FALSE) return; 1512a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 15133ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Do not duplicate conditions that may have function literal 15143ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // subexpressions. This can cause us to compile the function literal 15153ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // twice. 15163ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block bool test_at_bottom = !node->may_have_function_literal(); 15173ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); 15183ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block IncrementLoopNesting(); 15193ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block 15203ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Target for backward edge if no test at the bottom, otherwise 15213ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // unused. 15223ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block JumpTarget loop(JumpTarget::BIDIRECTIONAL); 15233ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block 15243ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Target for backward edge if there is a test at the bottom, 15253ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // otherwise used as target for test at the top. 15263ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block JumpTarget body; 15273ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block if (test_at_bottom) { 15283ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block body.set_direction(JumpTarget::BIDIRECTIONAL); 15293ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block } 15303ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block 15313ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Based on the condition analysis, compile the test as necessary. 15323ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block switch (info) { 15333ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block case ALWAYS_TRUE: 15343ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // We will not compile the test expression. Label the top of the 15353ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // loop. 15363ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block if (node->next() == NULL) { 15373ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Use the continue target if there is no update expression. 1538a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); 1539a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block node->continue_target()->Bind(); 1540a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 15413ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Otherwise use the backward loop target. 15423ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); 15433ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block loop.Bind(); 1544a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 15453ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block break; 15463ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block case DONT_KNOW: { 15473ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block if (test_at_bottom) { 15483ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Continue is either the update expression or the test at the 15493ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // bottom, no need to label the test at the top. 15503ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); 15513ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block } else if (node->next() == NULL) { 15523ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // We are not recompiling the test at the bottom and there is no 15533ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // update expression. 15543ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); 15553ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->continue_target()->Bind(); 1556a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 15573ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // We are not recompiling the test at the bottom and there is an 15583ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // update expression. 15593ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); 15603ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block loop.Bind(); 1561a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1562a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 15633ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Compile the test with the body as the true target and preferred 15643ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // fall-through and with the break target as the false target. 15653ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block ControlDestination dest(&body, node->break_target(), true); 1566d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block LoadCondition(node->cond(), &dest, true); 15673ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block 15683ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block if (dest.false_was_fall_through()) { 15693ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // If we got the break target as fall-through, the test may have 15703ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // been unconditionally false (if there are no jumps to the 15713ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // body). 15723ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block if (!body.is_linked()) { 15733ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block DecrementLoopNesting(); 15743ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block return; 15753ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block } 15763ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block 15773ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Otherwise, jump around the body on the fall through and then 15783ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // bind the body target. 15793ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->break_target()->Unuse(); 15803ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->break_target()->Jump(); 15813ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block body.Bind(); 1582a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1583a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 1584a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 15853ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block case ALWAYS_FALSE: 15863ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block UNREACHABLE(); 15873ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block break; 15883ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block } 1589a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 15903ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block CheckStack(); // TODO(1222600): ignore if body contains calls. 15913ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block Visit(node->body()); 1592a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 15933ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // If there is an update expression, compile it if necessary. 15943ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block if (node->next() != NULL) { 15953ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block if (node->continue_target()->is_linked()) { 15963ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->continue_target()->Bind(); 15973ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block } 1598a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 15993ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Control can reach the update by falling out of the body or by a 16003ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // continue. 16013ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block if (has_valid_frame()) { 16023ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Record the source position of the statement as this code which 16033ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // is after the code for the body actually belongs to the loop 16043ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // statement and not the body. 16053ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block CodeForStatementPosition(node); 16063ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block Visit(node->next()); 16073ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block } 16083ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block } 1609a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 16103ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Based on the condition analysis, compile the backward jump as 16113ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // necessary. 16123ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block switch (info) { 16133ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block case ALWAYS_TRUE: 16143ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block if (has_valid_frame()) { 1615a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (node->next() == NULL) { 16163ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->continue_target()->Jump(); 1617a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 16183ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block loop.Jump(); 1619a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1620a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 16213ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block break; 16223ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block case DONT_KNOW: 16233ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block if (test_at_bottom) { 1624a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (node->continue_target()->is_linked()) { 16253ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // We can have dangling jumps to the continue target if there 16263ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // was no update expression. 1627a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block node->continue_target()->Bind(); 1628a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 16293ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Control can reach the test at the bottom by falling out of 16303ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // the body, by a continue in the body, or from the update 16313ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // expression. 1632a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (has_valid_frame()) { 16333ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // The break target is the fall-through (body is a backward 16343ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // jump from here). 16353ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block ControlDestination dest(&body, node->break_target(), false); 1636d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block LoadCondition(node->cond(), &dest, true); 1637a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 16383ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block } else { 16393ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Otherwise, jump back to the test at the top. 1640a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (has_valid_frame()) { 1641a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (node->next() == NULL) { 1642a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block node->continue_target()->Jump(); 1643a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 1644a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block loop.Jump(); 1645a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1646a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1647a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1648a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 16493ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block case ALWAYS_FALSE: 16503ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block UNREACHABLE(); 16513ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block break; 1652a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1653a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 16543ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // The break target may be already bound (by the condition), or there 16553ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // may not be a valid frame. Bind it only if needed. 16563ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block if (node->break_target()->is_linked()) { 16573ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->break_target()->Bind(); 16583ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block } 1659a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block DecrementLoopNesting(); 1660a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1661a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1662a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1663a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitForInStatement(ForInStatement* node) { 1664a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!in_spilled_code()); 1665a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block VirtualFrame::SpilledScope spilled_scope; 1666a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ ForInStatement"); 1667a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CodeForStatementPosition(node); 1668a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1669a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget primitive; 1670a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget jsobject; 1671a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget fixed_array; 1672a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget entry(JumpTarget::BIDIRECTIONAL); 1673a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget end_del_check; 1674a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget exit; 1675a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1676a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the object to enumerate over (converted to JSObject). 1677a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block LoadAndSpill(node->enumerable()); 1678a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1679a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Both SpiderMonkey and kjs ignore null and undefined in contrast 1680a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // to the specification. 12.6.4 mandates a call to ToObject. 1681a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPop(rax); 1682a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1683a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rax: value to be iterated over 1684a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); 1685a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exit.Branch(equal); 1686a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CompareRoot(rax, Heap::kNullValueRootIndex); 1687a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exit.Branch(equal); 1688a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1689a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Stack layout in body: 1690a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // [iteration counter (smi)] <- slot 0 1691a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // [length of array] <- slot 1 1692a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // [FixedArray] <- slot 2 1693a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // [Map or 0] <- slot 3 1694a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // [Object] <- slot 4 1695a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1696a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check if enumerable is already a JSObject 1697a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rax: value to be iterated over 1698a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Condition is_smi = masm_->CheckSmi(rax); 1699a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block primitive.Branch(is_smi); 1700a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx); 1701a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block jsobject.Branch(above_equal); 1702a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1703a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block primitive.Bind(); 1704a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(rax); 1705a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION, 1); 1706a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // function call returns the value in rax, which is where we want it below 1707a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1708a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block jsobject.Bind(); 1709a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the set of properties (as a FixedArray or Map). 1710a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rax: value to be iterated over 1711d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block frame_->EmitPush(rax); // Push the object being iterated over. 1712d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 1713a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1714d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Check cache validity in generated code. This is a fast case for 1715d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // the JSObject::IsSimpleEnum cache validity checks. If we cannot 1716d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // guarantee cache validity, call the runtime system to check cache 1717d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // validity or get the property names in a fixed array. 1718d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block JumpTarget call_runtime; 1719d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block JumpTarget loop(JumpTarget::BIDIRECTIONAL); 1720d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block JumpTarget check_prototype; 1721d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block JumpTarget use_cache; 1722d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ movq(rcx, rax); 1723d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block loop.Bind(); 1724d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Check that there are no elements. 1725d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ movq(rdx, FieldOperand(rcx, JSObject::kElementsOffset)); 1726d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ CompareRoot(rdx, Heap::kEmptyFixedArrayRootIndex); 1727d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block call_runtime.Branch(not_equal); 1728d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Check that instance descriptors are not empty so that we can 1729d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // check for an enum cache. Leave the map in ebx for the subsequent 1730d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // prototype load. 1731d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ movq(rbx, FieldOperand(rcx, HeapObject::kMapOffset)); 1732d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ movq(rdx, FieldOperand(rbx, Map::kInstanceDescriptorsOffset)); 1733d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ CompareRoot(rdx, Heap::kEmptyDescriptorArrayRootIndex); 1734d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block call_runtime.Branch(equal); 1735d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Check that there in an enum cache in the non-empty instance 1736d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // descriptors. This is the case if the next enumeration index 1737d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // field does not contain a smi. 1738d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ movq(rdx, FieldOperand(rdx, DescriptorArray::kEnumerationIndexOffset)); 1739d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block is_smi = masm_->CheckSmi(rdx); 1740d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block call_runtime.Branch(is_smi); 1741d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // For all objects but the receiver, check that the cache is empty. 1742d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ cmpq(rcx, rax); 1743d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block check_prototype.Branch(equal); 1744d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ movq(rdx, FieldOperand(rdx, DescriptorArray::kEnumCacheBridgeCacheOffset)); 1745d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ CompareRoot(rdx, Heap::kEmptyFixedArrayRootIndex); 1746d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block call_runtime.Branch(not_equal); 1747d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block check_prototype.Bind(); 1748d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Load the prototype from the map and loop if non-null. 1749d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ movq(rcx, FieldOperand(rbx, Map::kPrototypeOffset)); 1750d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ CompareRoot(rcx, Heap::kNullValueRootIndex); 1751d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block loop.Branch(not_equal); 1752d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // The enum cache is valid. Load the map of the object being 1753d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // iterated over and use the cache for the iteration. 1754d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset)); 1755d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block use_cache.Jump(); 1756d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 1757d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block call_runtime.Bind(); 1758d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Call the runtime to get the property names for the object. 1759a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(rax); // push the Object (slot 4) for the runtime call 1760a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1); 1761a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1762a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If we got a Map, we can do a fast modification check. 1763a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Otherwise, we got a FixedArray, and we have to do a slow check. 1764a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rax: map or fixed array (result from call to 1765a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Runtime::kGetPropertyNamesFast) 1766a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rdx, rax); 1767a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset)); 1768a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CompareRoot(rcx, Heap::kMetaMapRootIndex); 1769a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block fixed_array.Branch(not_equal); 1770a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1771d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block use_cache.Bind(); 1772a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get enum cache 1773d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // rax: map (either the result from a call to 1774d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Runtime::kGetPropertyNamesFast or has been fetched directly from 1775d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // the object) 1776a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rcx, rax); 1777a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rcx, FieldOperand(rcx, Map::kInstanceDescriptorsOffset)); 1778a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the bridge array held in the enumeration index field. 1779a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rcx, FieldOperand(rcx, DescriptorArray::kEnumerationIndexOffset)); 1780a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the cache from the bridge array. 1781a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rdx, FieldOperand(rcx, DescriptorArray::kEnumCacheBridgeCacheOffset)); 1782a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1783a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(rax); // <- slot 3 1784a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(rdx); // <- slot 2 1785a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movl(rax, FieldOperand(rdx, FixedArray::kLengthOffset)); 1786a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Integer32ToSmi(rax, rax); 1787a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(rax); // <- slot 1 17883ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block frame_->EmitPush(Smi::FromInt(0)); // <- slot 0 1789a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block entry.Jump(); 1790a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1791a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block fixed_array.Bind(); 1792a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rax: fixed array (result from call to Runtime::kGetPropertyNamesFast) 17933ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block frame_->EmitPush(Smi::FromInt(0)); // <- slot 3 1794a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(rax); // <- slot 2 1795a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1796a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Push the length of the array and the initial index onto the stack. 1797a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movl(rax, FieldOperand(rax, FixedArray::kLengthOffset)); 1798a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Integer32ToSmi(rax, rax); 1799a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(rax); // <- slot 1 18003ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block frame_->EmitPush(Smi::FromInt(0)); // <- slot 0 1801a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1802a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Condition. 1803a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block entry.Bind(); 1804a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Grab the current frame's height for the break and continue 1805a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // targets only after all the state is pushed on the frame. 1806a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); 1807a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); 1808a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1809a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rax, frame_->ElementAt(0)); // load the current count 18103ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ SmiCompare(frame_->ElementAt(1), rax); // compare to the array length 18113ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block node->break_target()->Branch(below_equal); 1812a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1813a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the i'th entry of the array. 1814a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rdx, frame_->ElementAt(2)); 1815a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block SmiIndex index = masm_->SmiToIndex(rbx, rax, kPointerSizeLog2); 1816a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rbx, 1817a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block FieldOperand(rdx, index.reg, index.scale, FixedArray::kHeaderSize)); 1818a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1819a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the expected map from the stack or a zero map in the 1820a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // permanent slow case rax: current iteration count rbx: i'th entry 1821a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // of the enum cache 1822a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rdx, frame_->ElementAt(3)); 1823a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check if the expected map still matches that of the enumerable. 1824a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If not, we have to filter the key. 1825a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rax: current iteration count 1826a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rbx: i'th entry of the enum cache 1827a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rdx: expected map value 1828a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rcx, frame_->ElementAt(4)); 1829a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset)); 1830a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ cmpq(rcx, rdx); 1831a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block end_del_check.Branch(equal); 1832a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1833a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Convert the entry to a string (or null if it isn't a property anymore). 1834a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(frame_->ElementAt(4)); // push enumerable 1835a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(rbx); // push entry 1836a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION, 2); 1837a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rbx, rax); 1838a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1839a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If the property has been removed while iterating, we just skip it. 1840a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CompareRoot(rbx, Heap::kNullValueRootIndex); 1841a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block node->continue_target()->Branch(equal); 1842a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1843a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block end_del_check.Bind(); 1844a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Store the entry in the 'each' expression and take another spin in the 1845a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // loop. rdx: i'th entry of the enum cache (or string there of) 1846a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(rbx); 1847a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block { Reference each(this, node->each()); 1848a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Loading a reference may leave the frame in an unspilled state. 1849a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->SpillAll(); 1850a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!each.is_illegal()) { 1851a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (each.size() > 0) { 1852a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(frame_->ElementAt(each.size())); 1853d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke each.SetValue(NOT_CONST_INIT); 1854d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke frame_->Drop(2); // Drop the original and the copy of the element. 1855d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke } else { 1856d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // If the reference has size zero then we can use the value below 1857d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // the reference as if it were above the reference, instead of pushing 1858d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // a new copy of it above the reference. 1859d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke each.SetValue(NOT_CONST_INIT); 1860d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke frame_->Drop(); // Drop the original of the element. 1861a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1862a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1863a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1864a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Unloading a reference may leave the frame in an unspilled state. 1865a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->SpillAll(); 1866a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1867a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Body. 1868a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CheckStack(); // TODO(1222600): ignore if body contains calls. 1869a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block VisitAndSpill(node->body()); 1870a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1871a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Next. Reestablish a spilled frame in case we are coming here via 1872a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // a continue in the body. 1873a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block node->continue_target()->Bind(); 1874a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->SpillAll(); 1875a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPop(rax); 18763ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ SmiAddConstant(rax, rax, Smi::FromInt(1)); 1877a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(rax); 1878a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block entry.Jump(); 1879a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1880a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Cleanup. No need to spill because VirtualFrame::Drop is safe for 1881a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // any frame. 1882a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block node->break_target()->Bind(); 1883a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Drop(5); 1884a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1885a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Exit. 1886a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exit.Bind(); 1887a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1888a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block node->continue_target()->Unuse(); 1889a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block node->break_target()->Unuse(); 1890a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1891a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 18923ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Blockvoid CodeGenerator::VisitTryCatchStatement(TryCatchStatement* node) { 1893a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!in_spilled_code()); 1894a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block VirtualFrame::SpilledScope spilled_scope; 18953ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block Comment cmnt(masm_, "[ TryCatchStatement"); 1896a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CodeForStatementPosition(node); 1897a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1898a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget try_block; 1899a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget exit; 1900a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1901a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block try_block.Call(); 1902a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // --- Catch block --- 1903a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(rax); 1904a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1905a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Store the caught exception in the catch variable. 1906e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Variable* catch_var = node->catch_var()->var(); 1907e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke ASSERT(catch_var != NULL && catch_var->slot() != NULL); 1908e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke StoreToSlot(catch_var->slot(), NOT_CONST_INIT); 1909a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1910a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Remove the exception from the stack. 1911a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Drop(); 1912a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1913a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block VisitStatementsAndSpill(node->catch_block()->statements()); 1914a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (has_valid_frame()) { 1915a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exit.Jump(); 1916a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1917a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1918a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1919a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // --- Try block --- 1920a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block try_block.Bind(); 1921a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1922a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->PushTryHandler(TRY_CATCH_HANDLER); 1923a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int handler_height = frame_->height(); 1924a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1925a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Shadow the jump targets for all escapes from the try block, including 1926a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // returns. During shadowing, the original target is hidden as the 1927a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ShadowTarget and operations on the original actually affect the 1928a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // shadowing target. 1929a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // 1930a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We should probably try to unify the escaping targets and the return 1931a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // target. 1932a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int nof_escapes = node->escaping_targets()->length(); 1933a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block List<ShadowTarget*> shadows(1 + nof_escapes); 1934a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1935a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Add the shadow target for the function return. 1936a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block static const int kReturnShadowIndex = 0; 1937a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block shadows.Add(new ShadowTarget(&function_return_)); 1938a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool function_return_was_shadowed = function_return_is_shadowed_; 1939a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block function_return_is_shadowed_ = true; 1940a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(shadows[kReturnShadowIndex]->other_target() == &function_return_); 1941a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1942a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Add the remaining shadow targets. 1943a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = 0; i < nof_escapes; i++) { 1944a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block shadows.Add(new ShadowTarget(node->escaping_targets()->at(i))); 1945a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1946a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1947a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Generate code for the statements in the try block. 1948a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block VisitStatementsAndSpill(node->try_block()->statements()); 1949a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1950a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Stop the introduced shadowing and count the number of required unlinks. 1951a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // After shadowing stops, the original targets are unshadowed and the 1952a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ShadowTargets represent the formerly shadowing targets. 1953a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool has_unlinks = false; 1954a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = 0; i < shadows.length(); i++) { 1955a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block shadows[i]->StopShadowing(); 1956a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block has_unlinks = has_unlinks || shadows[i]->is_linked(); 1957a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1958a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block function_return_is_shadowed_ = function_return_was_shadowed; 1959a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1960a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get an external reference to the handler address. 1961a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ExternalReference handler_address(Top::k_handler_address); 1962a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1963a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Make sure that there's nothing left on the stack above the 1964a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // handler structure. 1965a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (FLAG_debug_code) { 1966a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(kScratchRegister, handler_address); 1967a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ cmpq(rsp, Operand(kScratchRegister, 0)); 1968a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Assert(equal, "stack pointer should point to top handler"); 1969a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1970a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1971a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If we can fall off the end of the try block, unlink from try chain. 1972a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (has_valid_frame()) { 1973a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The next handler address is on top of the frame. Unlink from 1974a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // the handler list and drop the rest of this handler from the 1975a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // frame. 1976a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(StackHandlerConstants::kNextOffset == 0); 1977a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(kScratchRegister, handler_address); 1978a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPop(Operand(kScratchRegister, 0)); 1979a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); 1980a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (has_unlinks) { 1981a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exit.Jump(); 1982a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1983a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1984a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1985a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Generate unlink code for the (formerly) shadowing targets that 1986a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // have been jumped to. Deallocate each shadow target. 1987a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result return_value; 1988a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = 0; i < shadows.length(); i++) { 1989a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (shadows[i]->is_linked()) { 1990a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Unlink from try chain; be careful not to destroy the TOS if 1991a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // there is one. 1992a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (i == kReturnShadowIndex) { 1993a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block shadows[i]->Bind(&return_value); 1994a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return_value.ToRegister(rax); 1995a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 1996a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block shadows[i]->Bind(); 1997a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1998a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Because we can be jumping here (to spilled code) from 1999a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // unspilled code, we need to reestablish a spilled frame at 2000a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // this block. 2001a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->SpillAll(); 2002a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2003a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Reload sp from the top handler, because some statements that we 2004a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // break from (eg, for...in) may have left stuff on the stack. 2005a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(kScratchRegister, handler_address); 2006a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rsp, Operand(kScratchRegister, 0)); 2007a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Forget(frame_->height() - handler_height); 2008a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2009a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(StackHandlerConstants::kNextOffset == 0); 2010a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(kScratchRegister, handler_address); 2011a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPop(Operand(kScratchRegister, 0)); 2012a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); 2013a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2014a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (i == kReturnShadowIndex) { 2015a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!function_return_is_shadowed_) frame_->PrepareForReturn(); 2016a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block shadows[i]->other_target()->Jump(&return_value); 2017a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 2018a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block shadows[i]->other_target()->Jump(); 2019a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2020a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2021a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2022a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2023a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exit.Bind(); 2024a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2025a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2026a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 20273ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Blockvoid CodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* node) { 2028a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!in_spilled_code()); 2029a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block VirtualFrame::SpilledScope spilled_scope; 20303ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block Comment cmnt(masm_, "[ TryFinallyStatement"); 2031a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CodeForStatementPosition(node); 2032a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2033a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // State: Used to keep track of reason for entering the finally 2034a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // block. Should probably be extended to hold information for 2035a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // break/continue from within the try block. 2036a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block enum { FALLING, THROWING, JUMPING }; 2037a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2038a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget try_block; 2039a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget finally_block; 2040a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2041a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block try_block.Call(); 2042a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2043a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(rax); 2044a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // In case of thrown exceptions, this is where we continue. 20453ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ Move(rcx, Smi::FromInt(THROWING)); 2046a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block finally_block.Jump(); 2047a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2048a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // --- Try block --- 2049a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block try_block.Bind(); 2050a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2051a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->PushTryHandler(TRY_FINALLY_HANDLER); 2052a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int handler_height = frame_->height(); 2053a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2054a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Shadow the jump targets for all escapes from the try block, including 2055a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // returns. During shadowing, the original target is hidden as the 2056a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ShadowTarget and operations on the original actually affect the 2057a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // shadowing target. 2058a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // 2059a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We should probably try to unify the escaping targets and the return 2060a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // target. 2061a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int nof_escapes = node->escaping_targets()->length(); 2062a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block List<ShadowTarget*> shadows(1 + nof_escapes); 2063a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2064a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Add the shadow target for the function return. 2065a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block static const int kReturnShadowIndex = 0; 2066a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block shadows.Add(new ShadowTarget(&function_return_)); 2067a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool function_return_was_shadowed = function_return_is_shadowed_; 2068a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block function_return_is_shadowed_ = true; 2069a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(shadows[kReturnShadowIndex]->other_target() == &function_return_); 2070a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2071a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Add the remaining shadow targets. 2072a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = 0; i < nof_escapes; i++) { 2073a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block shadows.Add(new ShadowTarget(node->escaping_targets()->at(i))); 2074a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2075a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2076a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Generate code for the statements in the try block. 2077a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block VisitStatementsAndSpill(node->try_block()->statements()); 2078a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2079a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Stop the introduced shadowing and count the number of required unlinks. 2080a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // After shadowing stops, the original targets are unshadowed and the 2081a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ShadowTargets represent the formerly shadowing targets. 2082a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int nof_unlinks = 0; 2083a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = 0; i < shadows.length(); i++) { 2084a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block shadows[i]->StopShadowing(); 2085a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (shadows[i]->is_linked()) nof_unlinks++; 2086a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2087a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block function_return_is_shadowed_ = function_return_was_shadowed; 2088a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2089a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get an external reference to the handler address. 2090a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ExternalReference handler_address(Top::k_handler_address); 2091a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2092a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If we can fall off the end of the try block, unlink from the try 2093a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // chain and set the state on the frame to FALLING. 2094a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (has_valid_frame()) { 2095a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The next handler address is on top of the frame. 2096a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(StackHandlerConstants::kNextOffset == 0); 2097a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(kScratchRegister, handler_address); 2098a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPop(Operand(kScratchRegister, 0)); 2099a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); 2100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Fake a top of stack value (unneeded when FALLING) and set the 2102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // state in ecx, then jump around the unlink blocks if any. 2103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(Heap::kUndefinedValueRootIndex); 21043ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ Move(rcx, Smi::FromInt(FALLING)); 2105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (nof_unlinks > 0) { 2106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block finally_block.Jump(); 2107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Generate code to unlink and set the state for the (formerly) 2111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // shadowing targets that have been jumped to. 2112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = 0; i < shadows.length(); i++) { 2113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (shadows[i]->is_linked()) { 2114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If we have come from the shadowed return, the return value is 2115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // on the virtual frame. We must preserve it until it is 2116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // pushed. 2117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (i == kReturnShadowIndex) { 2118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result return_value; 2119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block shadows[i]->Bind(&return_value); 2120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return_value.ToRegister(rax); 2121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 2122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block shadows[i]->Bind(); 2123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Because we can be jumping here (to spilled code) from 2125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // unspilled code, we need to reestablish a spilled frame at 2126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // this block. 2127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->SpillAll(); 2128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Reload sp from the top handler, because some statements that 2130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // we break from (eg, for...in) may have left stuff on the 2131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // stack. 2132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(kScratchRegister, handler_address); 2133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rsp, Operand(kScratchRegister, 0)); 2134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Forget(frame_->height() - handler_height); 2135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Unlink this handler and drop it from the frame. 2137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(StackHandlerConstants::kNextOffset == 0); 2138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(kScratchRegister, handler_address); 2139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPop(Operand(kScratchRegister, 0)); 2140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); 2141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (i == kReturnShadowIndex) { 2143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If this target shadowed the function return, materialize 2144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // the return value on the stack. 2145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(rax); 2146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 2147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Fake TOS for targets that shadowed breaks and continues. 2148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(Heap::kUndefinedValueRootIndex); 2149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 21503ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ Move(rcx, Smi::FromInt(JUMPING + i)); 2151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (--nof_unlinks > 0) { 2152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If this is not the last unlink block, jump around the next. 2153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block finally_block.Jump(); 2154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // --- Finally block --- 2159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block finally_block.Bind(); 2160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Push the state on the stack. 2162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(rcx); 2163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We keep two elements on the stack - the (possibly faked) result 2165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // and the state - while evaluating the finally block. 2166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // 2167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Generate code for the statements in the finally block. 2168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block VisitStatementsAndSpill(node->finally_block()->statements()); 2169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (has_valid_frame()) { 2171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Restore state and return value or faked TOS. 2172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPop(rcx); 2173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPop(rax); 2174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Generate code to jump to the right destination for all used 2177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // formerly shadowing targets. Deallocate each shadow target. 2178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = 0; i < shadows.length(); i++) { 2179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (has_valid_frame() && shadows[i]->is_bound()) { 2180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block BreakTarget* original = shadows[i]->other_target(); 21813ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ SmiCompare(rcx, Smi::FromInt(JUMPING + i)); 2182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (i == kReturnShadowIndex) { 2183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The return value is (already) in rax. 2184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result return_value = allocator_->Allocate(rax); 2185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(return_value.is_valid()); 2186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (function_return_is_shadowed_) { 2187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block original->Branch(equal, &return_value); 2188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 2189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Branch around the preparation for return which may emit 2190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // code. 2191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget skip; 2192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block skip.Branch(not_equal); 2193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->PrepareForReturn(); 2194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block original->Jump(&return_value); 2195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block skip.Bind(); 2196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 2198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block original->Branch(equal); 2199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (has_valid_frame()) { 2204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check if we need to rethrow the exception. 2205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget exit; 22063ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ SmiCompare(rcx, Smi::FromInt(THROWING)); 2207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exit.Branch(not_equal); 2208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Rethrow exception. 2210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(rax); // undo pop from above 2211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->CallRuntime(Runtime::kReThrow, 1); 2212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Done. 2214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exit.Bind(); 2215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { 2220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!in_spilled_code()); 2221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ DebuggerStatement"); 2222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CodeForStatementPosition(node); 2223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef ENABLE_DEBUGGER_SUPPORT 2224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Spill everything, even constants, to the frame. 2225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->SpillAll(); 22264515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 2227402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu frame_->DebugBreak(); 2228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Ignore the return value. 2229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif 2230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) { 2234e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke ASSERT(boilerplate->IsBoilerplate()); 2235e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 2236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The inevitable call will sync frame elements to memory anyway, so 2237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // we do it eagerly to allow us to push the arguments directly into 2238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // place. 2239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->SyncRange(0, frame_->element_count() - 1); 2240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2241e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Use the fast case closure allocation code that allocates in new 2242e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // space for nested functions that don't need literals cloning. 2243e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke if (scope()->is_function_scope() && boilerplate->NumberOfLiterals() == 0) { 2244e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke FastNewClosureStub stub; 2245e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke frame_->Push(boilerplate); 2246e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Result answer = frame_->CallStub(&stub, 1); 2247e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke frame_->Push(&answer); 2248e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } else { 2249e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Call the runtime to instantiate the function boilerplate 2250e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // object. 2251e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke frame_->EmitPush(rsi); 2252e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke frame_->EmitPush(boilerplate); 2253e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Result result = frame_->CallRuntime(Runtime::kNewClosure, 2); 2254e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke frame_->Push(&result); 2255e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } 2256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { 2260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ FunctionLiteral"); 2261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Build the function boilerplate and instantiate it. 2263d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Handle<JSFunction> boilerplate = 22643100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu Compiler::BuildBoilerplate(node, script(), this); 2265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check for stack-overflow exception. 2266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (HasStackOverflow()) return; 2267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block InstantiateBoilerplate(boilerplate); 2268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitFunctionBoilerplateLiteral( 2272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block FunctionBoilerplateLiteral* node) { 2273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); 2274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block InstantiateBoilerplate(node->boilerplate()); 2275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitConditional(Conditional* node) { 2279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ Conditional"); 2280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget then; 2281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget else_; 2282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget exit; 2283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ControlDestination dest(&then, &else_, true); 2284d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block LoadCondition(node->condition(), &dest, true); 2285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (dest.false_was_fall_through()) { 2287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The else target was bound, so we compile the else part first. 2288d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Load(node->else_expression()); 2289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (then.is_linked()) { 2291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exit.Jump(); 2292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block then.Bind(); 2293d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Load(node->then_expression()); 2294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 2296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The then target was bound, so we compile the then part first. 2297d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Load(node->then_expression()); 2298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (else_.is_linked()) { 2300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exit.Jump(); 2301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block else_.Bind(); 2302d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Load(node->else_expression()); 2303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exit.Bind(); 2307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitSlot(Slot* node) { 2311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ Slot"); 2312d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block LoadFromSlotCheckForArguments(node, NOT_INSIDE_TYPEOF); 2313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitVariableProxy(VariableProxy* node) { 2317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ VariableProxy"); 2318a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Variable* var = node->var(); 2319a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Expression* expr = var->rewrite(); 2320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (expr != NULL) { 2321a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Visit(expr); 2322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 2323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(var->is_global()); 2324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Reference ref(this, node); 2325d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block ref.GetValue(); 2326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitLiteral(Literal* node) { 2331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ Literal"); 2332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(node->handle()); 2333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Materialize the regexp literal 'node' in the literals array 2337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 'literals' of the function. Leave the regexp boilerplate in 2338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 'boilerplate'. 2339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass DeferredRegExpLiteral: public DeferredCode { 2340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public: 2341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block DeferredRegExpLiteral(Register boilerplate, 2342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register literals, 2343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block RegExpLiteral* node) 2344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block : boilerplate_(boilerplate), literals_(literals), node_(node) { 2345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block set_comment("[ DeferredRegExpLiteral"); 2346a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block void Generate(); 2349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private: 2351a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register boilerplate_; 2352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register literals_; 2353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block RegExpLiteral* node_; 2354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 2355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2357a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DeferredRegExpLiteral::Generate() { 2358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Since the entry is undefined we call the runtime system to 2359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // compute the literal. 2360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Literal array (0). 2361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(literals_); 2362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Literal index (1). 23633ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ Push(Smi::FromInt(node_->literal_index())); 2364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // RegExp pattern (2). 2365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Push(node_->pattern()); 2366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // RegExp flags (3). 2367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Push(node_->flags()); 2368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); 2369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!boilerplate_.is(rax)) __ movq(boilerplate_, rax); 2370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) { 2374a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ RegExp Literal"); 2375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Retrieve the literals array and check the allocated entry. Begin 2377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // with a writable copy of the function of this activation in a 2378a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // register. 2379a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->PushFunction(); 2380a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result literals = frame_->Pop(); 2381a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block literals.ToRegister(); 2382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Spill(literals.reg()); 2383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load the literals array of the function. 2385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(literals.reg(), 2386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block FieldOperand(literals.reg(), JSFunction::kLiteralsOffset)); 2387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load the literal at the ast saved index. 2389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result boilerplate = allocator_->Allocate(); 2390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(boilerplate.is_valid()); 2391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int literal_offset = 2392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block FixedArray::kHeaderSize + node->literal_index() * kPointerSize; 2393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(boilerplate.reg(), FieldOperand(literals.reg(), literal_offset)); 2394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2395a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check whether we need to materialize the RegExp object. If so, 2396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // jump to the deferred code passing the literals array. 2397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block DeferredRegExpLiteral* deferred = 2398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block new DeferredRegExpLiteral(boilerplate.reg(), literals.reg(), node); 2399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CompareRoot(boilerplate.reg(), Heap::kUndefinedValueRootIndex); 2400a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block deferred->Branch(equal); 2401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block deferred->BindExit(); 2402a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block literals.Unuse(); 2403a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2404a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Push the boilerplate object. 2405a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&boilerplate); 2406a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2407a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2408a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2409a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { 2410a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ ObjectLiteral"); 2411a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2412e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Load a writable copy of the function of this activation in a 2413a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // register. 2414a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->PushFunction(); 2415a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result literals = frame_->Pop(); 2416a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block literals.ToRegister(); 2417a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Spill(literals.reg()); 2418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load the literals array of the function. 2420a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(literals.reg(), 2421a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block FieldOperand(literals.reg(), JSFunction::kLiteralsOffset)); 2422e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Literal array. 2423e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke frame_->Push(&literals); 2424e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Literal index. 2425e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke frame_->Push(Smi::FromInt(node->literal_index())); 2426e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Constant properties. 2427e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke frame_->Push(node->constant_properties()); 2428e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Result clone; 2429e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke if (node->depth() > 1) { 2430e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke clone = frame_->CallRuntime(Runtime::kCreateObjectLiteral, 3); 2431e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } else { 2432e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke clone = frame_->CallRuntime(Runtime::kCreateObjectLiteralShallow, 3); 2433a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2434a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&clone); 2435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = 0; i < node->properties()->length(); i++) { 2437a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ObjectLiteral::Property* property = node->properties()->at(i); 2438a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block switch (property->kind()) { 2439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case ObjectLiteral::Property::CONSTANT: 2440a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 2441a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case ObjectLiteral::Property::MATERIALIZED_LITERAL: 2442a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (CompileTimeValue::IsCompileTimeValue(property->value())) break; 2443a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // else fall through. 2444a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case ObjectLiteral::Property::COMPUTED: { 2445a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<Object> key(property->key()->handle()); 2446a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (key->IsSymbol()) { 2447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Duplicate the object as the IC receiver. 2448a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Dup(); 2449a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(property->value()); 2450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(key); 2451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result ignored = frame_->CallStoreIC(); 2452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 2453a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Fall through 2455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case ObjectLiteral::Property::PROTOTYPE: { 2457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Duplicate the object as an argument to the runtime call. 2458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Dup(); 2459a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(property->key()); 2460a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(property->value()); 2461a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result ignored = frame_->CallRuntime(Runtime::kSetProperty, 3); 2462a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Ignore the result. 2463a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 2464a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2465a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case ObjectLiteral::Property::SETTER: { 2466a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Duplicate the object as an argument to the runtime call. 2467a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Dup(); 2468a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(property->key()); 2469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(Smi::FromInt(1)); 2470a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(property->value()); 2471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result ignored = frame_->CallRuntime(Runtime::kDefineAccessor, 4); 2472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Ignore the result. 2473a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 2474a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case ObjectLiteral::Property::GETTER: { 2476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Duplicate the object as an argument to the runtime call. 2477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Dup(); 2478a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(property->key()); 2479a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(Smi::FromInt(0)); 2480a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(property->value()); 2481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result ignored = frame_->CallRuntime(Runtime::kDefineAccessor, 4); 2482a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Ignore the result. 2483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 2484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2485a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block default: UNREACHABLE(); 2486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2487a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2488a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2489a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2490a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2491a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { 2492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ ArrayLiteral"); 2493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2494e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Load a writable copy of the function of this activation in a 2495a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // register. 2496a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->PushFunction(); 2497a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result literals = frame_->Pop(); 2498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block literals.ToRegister(); 2499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Spill(literals.reg()); 2500a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2501a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load the literals array of the function. 2502a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(literals.reg(), 2503a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block FieldOperand(literals.reg(), JSFunction::kLiteralsOffset)); 2504402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 2505e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke frame_->Push(&literals); 2506e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke frame_->Push(Smi::FromInt(node->literal_index())); 2507e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke frame_->Push(node->constant_elements()); 2508402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu int length = node->values()->length(); 2509e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Result clone; 2510e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke if (node->depth() > 1) { 2511e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke clone = frame_->CallRuntime(Runtime::kCreateArrayLiteral, 3); 2512402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu } else if (length > FastCloneShallowArrayStub::kMaximumLength) { 2513e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke clone = frame_->CallRuntime(Runtime::kCreateArrayLiteralShallow, 3); 2514402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu } else { 2515402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu FastCloneShallowArrayStub stub(length); 2516402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu clone = frame_->CallStub(&stub, 3); 2517a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2518a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&clone); 2519a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2520a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Generate code to set the elements in the array that are not 2521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // literals. 2522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = 0; i < node->values()->length(); i++) { 2523a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Expression* value = node->values()->at(i); 2524a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2525a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If value is a literal the property value is already set in the 2526a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // boilerplate object. 2527a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (value->AsLiteral() != NULL) continue; 2528a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If value is a materialized literal the property value is already set 2529a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // in the boilerplate object if it is simple. 2530a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (CompileTimeValue::IsCompileTimeValue(value)) continue; 2531a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2532a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The property must be set by generated code. 2533a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(value); 2534a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2535a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the property value off the stack. 2536a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result prop_value = frame_->Pop(); 2537a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block prop_value.ToRegister(); 2538a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2539a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Fetch the array literal while leaving a copy on the stack and 2540a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // use it to get the elements array. 2541a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Dup(); 2542a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result elements = frame_->Pop(); 2543a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block elements.ToRegister(); 2544a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Spill(elements.reg()); 2545a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the elements FixedArray. 2546a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(elements.reg(), 2547a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block FieldOperand(elements.reg(), JSObject::kElementsOffset)); 2548a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2549a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Write to the indexed properties array. 2550a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int offset = i * kPointerSize + FixedArray::kHeaderSize; 2551a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(FieldOperand(elements.reg(), offset), prop_value.reg()); 2552a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2553a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Update the write barrier for the array address. 2554a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Spill(prop_value.reg()); // Overwritten by the write barrier. 2555a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result scratch = allocator_->Allocate(); 2556a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(scratch.is_valid()); 2557a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ RecordWrite(elements.reg(), offset, prop_value.reg(), scratch.reg()); 2558a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2559a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2560a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2561a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2562a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* node) { 2563a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!in_spilled_code()); 2564a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Call runtime routine to allocate the catch extension object and 2565a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // assign the exception value to the catch variable. 2566a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ CatchExtensionObject"); 2567a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(node->key()); 2568a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(node->value()); 2569a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result result = 2570a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->CallRuntime(Runtime::kCreateCatchExtensionObject, 2); 2571a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&result); 2572a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2573a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2574a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2575a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitAssignment(Assignment* node) { 2576a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ Assignment"); 2577a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2578d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke { Reference target(this, node->target(), node->is_compound()); 2579a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (target.is_illegal()) { 2580a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Fool the virtual frame into thinking that we left the assignment's 2581a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // value on the frame. 2582a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(Smi::FromInt(0)); 2583a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return; 2584a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2585a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Variable* var = node->target()->AsVariableProxy()->AsVariable(); 2586a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2587a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (node->starts_initialization_block()) { 2588a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(target.type() == Reference::NAMED || 2589a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block target.type() == Reference::KEYED); 2590a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Change to slow case in the beginning of an initialization 2591a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // block to avoid the quadratic behavior of repeatedly adding 2592a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // fast properties. 2593a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2594a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The receiver is the argument to the runtime call. It is the 2595a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // first value pushed when the reference was loaded to the 2596a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // frame. 2597a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->PushElementAt(target.size() - 1); 2598a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result ignored = frame_->CallRuntime(Runtime::kToSlowProperties, 1); 2599a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2600d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke if (node->ends_initialization_block()) { 2601d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Add an extra copy of the receiver to the frame, so that it can be 2602d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // converted back to fast case after the assignment. 2603d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke ASSERT(target.type() == Reference::NAMED || 2604d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke target.type() == Reference::KEYED); 2605d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke if (target.type() == Reference::NAMED) { 2606d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke frame_->Dup(); 2607d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Dup target receiver on stack. 2608d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke } else { 2609d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke ASSERT(target.type() == Reference::KEYED); 2610d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Result temp = frame_->Pop(); 2611d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke frame_->Dup(); 2612d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke frame_->Push(&temp); 2613d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke } 2614d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke } 2615a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (node->op() == Token::ASSIGN || 2616a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block node->op() == Token::INIT_VAR || 2617a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block node->op() == Token::INIT_CONST) { 2618a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(node->value()); 2619a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2620d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke } else { // Assignment is a compound assignment. 2621a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Literal* literal = node->value()->AsLiteral(); 2622a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool overwrite_value = 2623a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block (node->value()->AsBinaryOperation() != NULL && 2624a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); 2625a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Variable* right_var = node->value()->AsVariableProxy()->AsVariable(); 2626a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // There are two cases where the target is not read in the right hand 2627a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // side, that are easy to test for: the right hand side is a literal, 2628a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // or the right hand side is a different variable. TakeValue invalidates 2629a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // the target, with an implicit promise that it will be written to again 2630a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // before it is read. 2631a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (literal != NULL || (right_var != NULL && right_var != var)) { 2632d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block target.TakeValue(); 2633a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 2634d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block target.GetValue(); 2635a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2636a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(node->value()); 2637a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GenericBinaryOperation(node->binary_op(), 2638a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block node->type(), 2639a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); 2640a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2641a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2642a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (var != NULL && 2643a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var->mode() == Variable::CONST && 2644a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) { 2645a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Assignment ignored - leave the value on the stack. 2646d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke UnloadReference(&target); 2647a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 2648a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CodeForSourcePosition(node->position()); 2649a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (node->op() == Token::INIT_CONST) { 2650a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Dynamic constant initializations must use the function context 2651a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // and initialize the actual constant declared. Dynamic variable 2652a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // initializations are simply assignments and use SetValue. 2653a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block target.SetValue(CONST_INIT); 2654a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 2655a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block target.SetValue(NOT_CONST_INIT); 2656a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2657a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (node->ends_initialization_block()) { 2658d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke ASSERT(target.type() == Reference::UNLOADED); 2659a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // End of initialization block. Revert to fast case. The 2660d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // argument to the runtime call is the extra copy of the receiver, 2661d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // which is below the value of the assignment. 2662d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Swap the receiver and the value of the assignment expression. 2663d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Result lhs = frame_->Pop(); 2664d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Result receiver = frame_->Pop(); 2665d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke frame_->Push(&lhs); 2666d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke frame_->Push(&receiver); 2667a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1); 2668a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2669a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2670a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2671a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2672a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2673a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2674a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitThrow(Throw* node) { 2675a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ Throw"); 2676a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(node->exception()); 2677a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result result = frame_->CallRuntime(Runtime::kThrow, 1); 2678a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&result); 2679a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2680a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2681a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2682a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitProperty(Property* node) { 2683a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ Property"); 2684a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Reference property(this, node); 2685d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block property.GetValue(); 2686a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2687a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2688a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2689a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitCall(Call* node) { 2690a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ Call"); 2691a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2692a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ZoneList<Expression*>* args = node->arguments(); 2693a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2694a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check if the function is a variable or a property. 2695a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Expression* function = node->expression(); 2696a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Variable* var = function->AsVariableProxy()->AsVariable(); 2697a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Property* property = function->AsProperty(); 2698a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2699a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ------------------------------------------------------------------------ 2700a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Fast-case: Use inline caching. 2701a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // --- 2702a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // According to ECMA-262, section 11.2.3, page 44, the function to call 2703a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // must be resolved after the arguments have been evaluated. The IC code 2704a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // automatically handles this by loading the arguments before the function 2705a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // is resolved in cache misses (this also holds for megamorphic calls). 2706a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ------------------------------------------------------------------------ 2707a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2708a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (var != NULL && var->is_possibly_eval()) { 2709a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ---------------------------------- 2710a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // JavaScript example: 'eval(arg)' // eval is not known to be shadowed 2711a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ---------------------------------- 2712a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2713a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // In a call to eval, we first call %ResolvePossiblyDirectEval to 2714a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // resolve the function we need to call and the receiver of the 2715a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // call. Then we call the resolved function using the given 2716a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // arguments. 2717a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2718a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Prepare the stack for the call to the resolved function. 2719a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(function); 2720a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2721a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Allocate a frame slot for the receiver. 2722a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(Factory::undefined_value()); 2723a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int arg_count = args->length(); 2724a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = 0; i < arg_count; i++) { 2725a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(args->at(i)); 2726a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2727a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2728a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Prepare the stack for the call to ResolvePossiblyDirectEval. 2729a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->PushElementAt(arg_count + 1); 2730a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (arg_count > 0) { 2731a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->PushElementAt(arg_count); 2732a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 2733a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(Factory::undefined_value()); 2734a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2735a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2736e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Push the receiver. 2737e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke frame_->PushParameterAt(-1); 2738e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 2739a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Resolve the call. 2740a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result result = 2741e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke frame_->CallRuntime(Runtime::kResolvePossiblyDirectEval, 3); 2742a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2743e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // The runtime call returns a pair of values in rax (function) and 2744e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rdx (receiver). Touch up the stack with the right values. 2745e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Result receiver = allocator_->Allocate(rdx); 2746e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke frame_->SetElementAt(arg_count + 1, &result); 2747e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke frame_->SetElementAt(arg_count, &receiver); 2748e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke receiver.Unuse(); 2749a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2750a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Call the function. 2751a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CodeForSourcePosition(node->position()); 2752a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP; 2753e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke CallFunctionStub call_function(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); 2754a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block result = frame_->CallStub(&call_function, arg_count + 1); 2755a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2756a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Restore the context and overwrite the function on the stack with 2757a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // the result. 2758a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->RestoreContextRegister(); 2759a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->SetElementAt(0, &result); 2760a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2761a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (var != NULL && !var->is_this() && var->is_global()) { 2762a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ---------------------------------- 2763a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // JavaScript example: 'foo(1, 2, 3)' // foo is global 2764a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ---------------------------------- 2765a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2766a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Pass the global object as the receiver and let the IC stub 2767a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // patch the stack to use the global proxy as 'this' in the 2768a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // invoked function. 2769a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block LoadGlobal(); 2770a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2771a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load the arguments. 2772a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int arg_count = args->length(); 2773a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = 0; i < arg_count; i++) { 2774a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(args->at(i)); 2775a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2776a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2777402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Push the name of the function on the frame. 2778402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu frame_->Push(var->name()); 2779402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 2780a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Call the IC initialization code. 2781a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CodeForSourcePosition(node->position()); 2782a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result result = frame_->CallCallIC(RelocInfo::CODE_TARGET_CONTEXT, 2783a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block arg_count, 2784a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block loop_nesting()); 2785a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->RestoreContextRegister(); 2786a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Replace the function on the stack with the result. 2787402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu frame_->Push(&result); 2788a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2789a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (var != NULL && var->slot() != NULL && 2790a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var->slot()->type() == Slot::LOOKUP) { 2791a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ---------------------------------- 2792a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // JavaScript example: 'with (obj) foo(1, 2, 3)' // foo is in obj 2793a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ---------------------------------- 2794a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2795a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load the function from the context. Sync the frame so we can 2796a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // push the arguments directly into place. 2797a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->SyncRange(0, frame_->element_count() - 1); 2798a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(rsi); 2799a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(var->name()); 2800a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->CallRuntime(Runtime::kLoadContextSlot, 2); 2801a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The runtime call returns a pair of values in rax and rdx. The 2802a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // looked-up function is in rax and the receiver is in rdx. These 2803a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // register references are not ref counted here. We spill them 2804a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // eagerly since they are arguments to an inevitable call (and are 2805a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // not sharable by the arguments). 2806a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!allocator()->is_used(rax)); 2807a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(rax); 2808a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2809a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load the receiver. 2810a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!allocator()->is_used(rdx)); 2811a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(rdx); 2812a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2813a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Call the function. 2814e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke CallWithArguments(args, NO_CALL_FUNCTION_FLAGS, node->position()); 2815a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2816a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (property != NULL) { 2817a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check if the key is a literal string. 2818a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Literal* literal = property->key()->AsLiteral(); 2819a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2820a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (literal != NULL && literal->handle()->IsSymbol()) { 2821a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ------------------------------------------------------------------ 2822a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)' 2823a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ------------------------------------------------------------------ 2824a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2825a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<String> name = Handle<String>::cast(literal->handle()); 2826a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2827a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (ArgumentsMode() == LAZY_ARGUMENTS_ALLOCATION && 2828a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block name->IsEqualTo(CStrVector("apply")) && 2829a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block args->length() == 2 && 2830a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block args->at(1)->AsVariableProxy() != NULL && 2831a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block args->at(1)->AsVariableProxy()->IsArguments()) { 2832a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Use the optimized Function.prototype.apply that avoids 2833a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // allocating lazily allocated arguments objects. 2834d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke CallApplyLazy(property->obj(), 2835a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block args->at(0), 2836a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block args->at(1)->AsVariableProxy(), 2837a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block node->position()); 2838a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2839a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 2840402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Push the receiver onto the frame. 2841a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(property->obj()); 2842a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2843a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load the arguments. 2844a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int arg_count = args->length(); 2845a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = 0; i < arg_count; i++) { 2846a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(args->at(i)); 2847a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2848a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2849402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Push the name of the function onto the frame. 2850402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu frame_->Push(name); 2851402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 2852a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Call the IC initialization code. 2853a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CodeForSourcePosition(node->position()); 2854a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result result = frame_->CallCallIC(RelocInfo::CODE_TARGET, 2855a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block arg_count, 2856a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block loop_nesting()); 2857a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->RestoreContextRegister(); 2858402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu frame_->Push(&result); 2859a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2860a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2861a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 2862a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ------------------------------------------- 2863a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // JavaScript example: 'array[index](1, 2, 3)' 2864a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ------------------------------------------- 2865a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2866a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load the function to call from the property through a reference. 2867a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (property->is_synthetic()) { 2868d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Reference ref(this, property, false); 2869d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke ref.GetValue(); 2870a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Use global object as receiver. 2871a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block LoadGlobalReceiver(); 2872a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 2873d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Reference ref(this, property, false); 2874d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke ASSERT(ref.size() == 2); 2875d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Result key = frame_->Pop(); 2876d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke frame_->Dup(); // Duplicate the receiver. 2877d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke frame_->Push(&key); 2878d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke ref.GetValue(); 2879d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Top of frame contains function to call, with duplicate copy of 2880d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // receiver below it. Swap them. 2881d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Result function = frame_->Pop(); 2882d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Result receiver = frame_->Pop(); 2883d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke frame_->Push(&function); 2884d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke frame_->Push(&receiver); 2885a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2886a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2887a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Call the function. 2888e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke CallWithArguments(args, RECEIVER_MIGHT_BE_VALUE, node->position()); 2889a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2890a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2891a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 2892a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ---------------------------------- 2893a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // JavaScript example: 'foo(1, 2, 3)' // foo is not global 2894a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ---------------------------------- 2895a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2896a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load the function. 2897a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(function); 2898a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2899a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Pass the global proxy as the receiver. 2900a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block LoadGlobalReceiver(); 2901a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2902a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Call the function. 2903e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke CallWithArguments(args, NO_CALL_FUNCTION_FLAGS, node->position()); 2904a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2905a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2906a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2907a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2908a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitCallNew(CallNew* node) { 2909a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ CallNew"); 2910a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2911a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // According to ECMA-262, section 11.2.2, page 44, the function 2912a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // expression in new calls must be evaluated before the 2913a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // arguments. This is different from ordinary calls, where the 2914a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // actual function to call is resolved after the arguments have been 2915a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // evaluated. 2916a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2917a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Compute function to call and use the global object as the 2918a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // receiver. There is no need to use the global proxy here because 2919a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // it will always be replaced with a newly allocated object. 2920a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(node->expression()); 2921a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block LoadGlobal(); 2922a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2923a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Push the arguments ("left-to-right") on the stack. 2924a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ZoneList<Expression*>* args = node->arguments(); 2925a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int arg_count = args->length(); 2926a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = 0; i < arg_count; i++) { 2927a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(args->at(i)); 2928a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2929a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2930a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Call the construct call builtin that handles allocation and 2931a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // constructor invocation. 2932a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CodeForSourcePosition(node->position()); 2933a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result result = frame_->CallConstructor(arg_count); 2934a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Replace the function on the stack with the result. 2935a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->SetElementAt(0, &result); 2936a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2937a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2938a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2939a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitCallRuntime(CallRuntime* node) { 2940a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (CheckForInlineRuntimeCall(node)) { 2941a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return; 2942a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2943a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2944a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ZoneList<Expression*>* args = node->arguments(); 2945a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ CallRuntime"); 2946a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Runtime::Function* function = node->function(); 2947a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2948a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (function == NULL) { 2949a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Push the builtins object found in the current global object. 2950a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result temp = allocator()->Allocate(); 2951a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(temp.is_valid()); 2952a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(temp.reg(), GlobalObject()); 2953a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(temp.reg(), 2954a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block FieldOperand(temp.reg(), GlobalObject::kBuiltinsOffset)); 2955a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&temp); 2956a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2957a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2958a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Push the arguments ("left-to-right"). 2959a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int arg_count = args->length(); 2960a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = 0; i < arg_count; i++) { 2961a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(args->at(i)); 2962a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2963a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2964a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (function == NULL) { 2965a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Call the JS runtime function. 2966402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu frame_->Push(node->name()); 2967a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result answer = frame_->CallCallIC(RelocInfo::CODE_TARGET, 2968a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block arg_count, 2969a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block loop_nesting_); 2970a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->RestoreContextRegister(); 2971402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu frame_->Push(&answer); 2972a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 2973a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Call the C runtime function. 2974a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result answer = frame_->CallRuntime(function, arg_count); 2975a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&answer); 2976a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2977a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2978a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2979a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2980a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { 2981a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ UnaryOperation"); 2982a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2983a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Token::Value op = node->op(); 2984a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2985a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (op == Token::NOT) { 2986a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Swap the true and false targets but keep the same actual label 2987a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // as the fall through. 2988a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->Invert(); 2989d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block LoadCondition(node->expression(), destination(), true); 2990a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Swap the labels back. 2991a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->Invert(); 2992a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2993a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (op == Token::DELETE) { 2994a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Property* property = node->expression()->AsProperty(); 2995a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (property != NULL) { 2996a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(property->obj()); 2997a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(property->key()); 2998a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result answer = frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2); 2999a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&answer); 3000a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return; 3001a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3002a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3003a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Variable* variable = node->expression()->AsVariableProxy()->AsVariable(); 3004a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (variable != NULL) { 3005a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Slot* slot = variable->slot(); 3006a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (variable->is_global()) { 3007a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block LoadGlobal(); 3008a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(variable->name()); 3009a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result answer = frame_->InvokeBuiltin(Builtins::DELETE, 3010a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CALL_FUNCTION, 2); 3011a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&answer); 3012a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return; 3013a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3014a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (slot != NULL && slot->type() == Slot::LOOKUP) { 3015a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Call the runtime to look up the context holding the named 3016a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // variable. Sync the virtual frame eagerly so we can push the 3017a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // arguments directly into place. 3018a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->SyncRange(0, frame_->element_count() - 1); 3019a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(rsi); 3020a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(variable->name()); 3021a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result context = frame_->CallRuntime(Runtime::kLookupContext, 2); 3022a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(context.is_register()); 3023a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(context.reg()); 3024a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block context.Unuse(); 3025a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(variable->name()); 3026a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result answer = frame_->InvokeBuiltin(Builtins::DELETE, 3027a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CALL_FUNCTION, 2); 3028a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&answer); 3029a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return; 3030a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3031a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3032a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Default: Result of deleting non-global, not dynamically 3033a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // introduced variables is false. 3034a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(Factory::false_value()); 3035a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3036a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 3037a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Default: Result of deleting expressions is true. 3038a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(node->expression()); // may have side-effects 3039a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->SetElementAt(0, Factory::true_value()); 3040a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3041a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3042a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (op == Token::TYPEOF) { 3043a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Special case for loading the typeof expression; see comment on 3044a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // LoadTypeofExpression(). 3045a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block LoadTypeofExpression(node->expression()); 3046a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result answer = frame_->CallRuntime(Runtime::kTypeof, 1); 3047a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&answer); 3048a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3049a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (op == Token::VOID) { 3050a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Expression* expression = node->expression(); 3051a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (expression && expression->AsLiteral() && ( 3052a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block expression->AsLiteral()->IsTrue() || 3053a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block expression->AsLiteral()->IsFalse() || 3054a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block expression->AsLiteral()->handle()->IsNumber() || 3055a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block expression->AsLiteral()->handle()->IsString() || 3056a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block expression->AsLiteral()->handle()->IsJSRegExp() || 3057a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block expression->AsLiteral()->IsNull())) { 3058a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Omit evaluating the value of the primitive literal. 3059a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // It will be discarded anyway, and can have no side effect. 3060a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(Factory::undefined_value()); 3061a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 3062a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(node->expression()); 3063a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->SetElementAt(0, Factory::undefined_value()); 3064a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3065a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3066a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 3067d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke bool overwrite = 3068d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke (node->expression()->AsBinaryOperation() != NULL && 3069d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke node->expression()->AsBinaryOperation()->ResultOverwriteAllowed()); 3070a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(node->expression()); 3071a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block switch (op) { 3072a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::NOT: 3073a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::DELETE: 3074a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::TYPEOF: 3075a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block UNREACHABLE(); // handled above 3076a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 3077a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3078a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::SUB: { 3079e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke GenericUnaryOpStub stub(Token::SUB, overwrite); 3080a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result operand = frame_->Pop(); 3081a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result answer = frame_->CallStub(&stub, &operand); 3082a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&answer); 3083a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 3084a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3085a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3086a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::BIT_NOT: { 3087a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Smi check. 3088a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget smi_label; 3089a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget continue_label; 3090a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result operand = frame_->Pop(); 3091a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block operand.ToRegister(); 3092a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3093a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Condition is_smi = masm_->CheckSmi(operand.reg()); 3094a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block smi_label.Branch(is_smi, &operand); 3095a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3096d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke GenericUnaryOpStub stub(Token::BIT_NOT, overwrite); 3097d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Result answer = frame_->CallStub(&stub, &operand); 3098a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block continue_label.Jump(&answer); 3099d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 3100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block smi_label.Bind(&answer); 3101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block answer.ToRegister(); 3102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Spill(answer.reg()); 3103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ SmiNot(answer.reg(), answer.reg()); 3104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block continue_label.Bind(&answer); 3105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&answer); 3106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 3107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::ADD: { 3110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Smi check. 3111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget continue_label; 3112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result operand = frame_->Pop(); 3113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block operand.ToRegister(); 3114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Condition is_smi = masm_->CheckSmi(operand.reg()); 3115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block continue_label.Branch(is_smi, &operand); 3116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&operand); 3117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result answer = frame_->InvokeBuiltin(Builtins::TO_NUMBER, 3118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CALL_FUNCTION, 1); 3119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block continue_label.Bind(&answer); 3121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&answer); 3122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 3123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block default: 3126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block UNREACHABLE(); 3127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 3130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// The value in dst was optimistically incremented or decremented. The 3133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// result overflowed or was not smi tagged. Undo the operation, call 3134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// into the runtime to convert the argument to a number, and call the 3135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// specialized add or subtract stub. The result is left in dst. 3136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass DeferredPrefixCountOperation: public DeferredCode { 3137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public: 3138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block DeferredPrefixCountOperation(Register dst, bool is_increment) 3139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block : dst_(dst), is_increment_(is_increment) { 3140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block set_comment("[ DeferredCountOperation"); 3141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block virtual void Generate(); 3144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private: 3146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register dst_; 3147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool is_increment_; 3148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 3149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DeferredPrefixCountOperation::Generate() { 3152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(dst_); 3153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); 3154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(rax); 31553ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ Push(Smi::FromInt(1)); 3156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (is_increment_) { 3157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CallRuntime(Runtime::kNumberAdd, 2); 3158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 3159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CallRuntime(Runtime::kNumberSub, 2); 3160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!dst_.is(rax)) __ movq(dst_, rax); 3162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 3163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// The value in dst was optimistically incremented or decremented. The 3166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// result overflowed or was not smi tagged. Undo the operation and call 3167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// into the runtime to convert the argument to a number. Update the 3168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// original value in old. Call the specialized add or subtract stub. 3169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// The result is left in dst. 3170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass DeferredPostfixCountOperation: public DeferredCode { 3171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public: 3172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block DeferredPostfixCountOperation(Register dst, Register old, bool is_increment) 3173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block : dst_(dst), old_(old), is_increment_(is_increment) { 3174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block set_comment("[ DeferredCountOperation"); 3175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block virtual void Generate(); 3178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private: 3180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register dst_; 3181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register old_; 3182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool is_increment_; 3183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 3184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DeferredPostfixCountOperation::Generate() { 3187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(dst_); 3188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); 3189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Save the result of ToNumber to use as the old value. 3191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(rax); 3192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Call the runtime for the addition or subtraction. 3194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(rax); 31953ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ Push(Smi::FromInt(1)); 3196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (is_increment_) { 3197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CallRuntime(Runtime::kNumberAdd, 2); 3198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 3199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CallRuntime(Runtime::kNumberSub, 2); 3200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!dst_.is(rax)) __ movq(dst_, rax); 3202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(old_); 3203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 3204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitCountOperation(CountOperation* node) { 3207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ CountOperation"); 3208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool is_postfix = node->is_postfix(); 3210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool is_increment = node->op() == Token::INC; 3211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Variable* var = node->expression()->AsVariableProxy()->AsVariable(); 3213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool is_const = (var != NULL && var->mode() == Variable::CONST); 3214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Postfix operations need a stack slot under the reference to hold 3216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // the old value while the new value is being stored. This is so that 3217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // in the case that storing the new value requires a call, the old 3218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // value will be in the frame to be spilled. 3219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (is_postfix) frame_->Push(Smi::FromInt(0)); 3220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3221d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // A constant reference is not saved to, so the reference is not a 3222d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // compound assignment reference. 3223d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke { Reference target(this, node->expression(), !is_const); 3224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (target.is_illegal()) { 3225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Spoof the virtual frame to have the expected height (one higher 3226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // than on entry). 3227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!is_postfix) frame_->Push(Smi::FromInt(0)); 3228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return; 3229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3230d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block target.TakeValue(); 3231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result new_value = frame_->Pop(); 3233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block new_value.ToRegister(); 3234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result old_value; // Only allocated in the postfix case. 3236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (is_postfix) { 3237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Allocate a temporary to preserve the old value. 3238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block old_value = allocator_->Allocate(); 3239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(old_value.is_valid()); 3240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(old_value.reg(), new_value.reg()); 3241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Ensure the new value is writable. 3243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Spill(new_value.reg()); 3244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block DeferredCode* deferred = NULL; 3246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (is_postfix) { 3247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block deferred = new DeferredPostfixCountOperation(new_value.reg(), 3248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block old_value.reg(), 3249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block is_increment); 3250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 3251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block deferred = new DeferredPrefixCountOperation(new_value.reg(), 3252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block is_increment); 3253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 32553ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ JumpIfNotSmi(new_value.reg(), deferred->entry_label()); 3256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (is_increment) { 32573ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ SmiAddConstant(kScratchRegister, 32583ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block new_value.reg(), 32593ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block Smi::FromInt(1), 32603ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block deferred->entry_label()); 3261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 32623ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ SmiSubConstant(kScratchRegister, 32633ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block new_value.reg(), 32643ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block Smi::FromInt(1), 32653ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block deferred->entry_label()); 3266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(new_value.reg(), kScratchRegister); 3268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block deferred->BindExit(); 3269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Postfix: store the old value in the allocated slot under the 3271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // reference. 3272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (is_postfix) frame_->SetElementAt(target.size(), &old_value); 3273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&new_value); 3275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Non-constant: update the reference. 3276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!is_const) target.SetValue(NOT_CONST_INIT); 3277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Postfix: drop the new value and use the old. 3280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (is_postfix) frame_->Drop(); 3281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 3282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { 3285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // TODO(X64): This code was copied verbatim from codegen-ia32. 3286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Either find a reason to change it or move it to a shared location. 3287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ BinaryOperation"); 3289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Token::Value op = node->op(); 3290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // According to ECMA-262 section 11.11, page 58, the binary logical 3292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // operators must yield the result of one of the two expressions 3293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // before any ToBoolean() conversions. This means that the value 3294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // produced by a && or || operator is not necessarily a boolean. 3295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // NOTE: If the left hand side produces a materialized value (not 3297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // control flow), we force the right hand side to do the same. This 3298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // is necessary because we assume that if we get control flow on the 3299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // last path out of an expression we got it on all paths. 3300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (op == Token::AND) { 3301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget is_true; 3302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ControlDestination dest(&is_true, destination()->false_target(), true); 3303d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block LoadCondition(node->left(), &dest, false); 3304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (dest.false_was_fall_through()) { 3306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The current false target was used as the fall-through. If 3307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // there are no dangling jumps to is_true then the left 3308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // subexpression was unconditionally false. Otherwise we have 3309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // paths where we do have to evaluate the right subexpression. 3310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (is_true.is_linked()) { 3311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We need to compile the right subexpression. If the jump to 3312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // the current false target was a forward jump then we have a 3313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // valid frame, we have just bound the false target, and we 3314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // have to jump around the code for the right subexpression. 3315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (has_valid_frame()) { 3316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->false_target()->Unuse(); 3317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->false_target()->Jump(); 3318a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3319a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block is_true.Bind(); 3320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The left subexpression compiled to control flow, so the 3321a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // right one is free to do so as well. 3322d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block LoadCondition(node->right(), destination(), false); 3323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 3324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We have actually just jumped to or bound the current false 3325a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // target but the current control destination is not marked as 3326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // used. 3327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->Use(false); 3328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (dest.is_used()) { 3331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The left subexpression compiled to control flow (and is_true 3332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // was just bound), so the right is free to do so as well. 3333d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block LoadCondition(node->right(), destination(), false); 3334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 3336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We have a materialized value on the frame, so we exit with 3337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // one on all paths. There are possibly also jumps to is_true 3338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // from nested subexpressions. 3339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget pop_and_continue; 3340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget exit; 3341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Avoid popping the result if it converts to 'false' using the 3343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // standard ToBoolean() conversion as described in ECMA-262, 3344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // section 9.2, page 30. 3345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // 3346a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Duplicate the TOS value. The duplicate will be popped by 3347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ToBoolean. 3348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Dup(); 3349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ControlDestination dest(&pop_and_continue, &exit, true); 3350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ToBoolean(&dest); 3351a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Pop the result of evaluating the first part. 3353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Drop(); 3354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Compile right side expression. 3356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block is_true.Bind(); 3357a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(node->right()); 3358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Exit (always with a materialized value). 3360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exit.Bind(); 3361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (op == Token::OR) { 3364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget is_false; 3365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ControlDestination dest(destination()->true_target(), &is_false, false); 3366d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block LoadCondition(node->left(), &dest, false); 3367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (dest.true_was_fall_through()) { 3369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The current true target was used as the fall-through. If 3370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // there are no dangling jumps to is_false then the left 3371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // subexpression was unconditionally true. Otherwise we have 3372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // paths where we do have to evaluate the right subexpression. 3373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (is_false.is_linked()) { 3374a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We need to compile the right subexpression. If the jump to 3375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // the current true target was a forward jump then we have a 3376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // valid frame, we have just bound the true target, and we 3377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // have to jump around the code for the right subexpression. 3378a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (has_valid_frame()) { 3379a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->true_target()->Unuse(); 3380a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->true_target()->Jump(); 3381a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block is_false.Bind(); 3383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The left subexpression compiled to control flow, so the 3384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // right one is free to do so as well. 3385d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block LoadCondition(node->right(), destination(), false); 3386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 3387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We have just jumped to or bound the current true target but 3388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // the current control destination is not marked as used. 3389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->Use(true); 3390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (dest.is_used()) { 3393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The left subexpression compiled to control flow (and is_false 3394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // was just bound), so the right is free to do so as well. 3395d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block LoadCondition(node->right(), destination(), false); 3396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 3398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We have a materialized value on the frame, so we exit with 3399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // one on all paths. There are possibly also jumps to is_false 3400a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // from nested subexpressions. 3401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget pop_and_continue; 3402a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget exit; 3403a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3404a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Avoid popping the result if it converts to 'true' using the 3405a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // standard ToBoolean() conversion as described in ECMA-262, 3406a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // section 9.2, page 30. 3407a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // 3408a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Duplicate the TOS value. The duplicate will be popped by 3409a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ToBoolean. 3410a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Dup(); 3411a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ControlDestination dest(&exit, &pop_and_continue, false); 3412a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ToBoolean(&dest); 3413a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3414a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Pop the result of evaluating the first part. 3415a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Drop(); 3416a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3417a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Compile right side expression. 3418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block is_false.Bind(); 3419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(node->right()); 3420a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3421a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Exit (always with a materialized value). 3422a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exit.Bind(); 3423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3424a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 3426a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // NOTE: The code below assumes that the slow cases (calls to runtime) 3427a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // never return a constant/immutable object. 3428a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block OverwriteMode overwrite_mode = NO_OVERWRITE; 3429a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (node->left()->AsBinaryOperation() != NULL && 3430a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block node->left()->AsBinaryOperation()->ResultOverwriteAllowed()) { 3431a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block overwrite_mode = OVERWRITE_LEFT; 3432a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (node->right()->AsBinaryOperation() != NULL && 3433a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block node->right()->AsBinaryOperation()->ResultOverwriteAllowed()) { 3434a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block overwrite_mode = OVERWRITE_RIGHT; 3435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3437a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(node->left()); 3438a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(node->right()); 3439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GenericBinaryOperation(node->op(), node->type(), overwrite_mode); 3440a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3441a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 3442a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3443a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3444a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3445a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitCompareOperation(CompareOperation* node) { 3446a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ CompareOperation"); 3447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3448a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the expressions from the node. 3449a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Expression* left = node->left(); 3450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Expression* right = node->right(); 3451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Token::Value op = node->op(); 3452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // To make typeof testing for natives implemented in JavaScript really 3453a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // efficient, we generate special code for expressions of the form: 3454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // 'typeof <expression> == <string>'. 3455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block UnaryOperation* operation = left->AsUnaryOperation(); 3456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if ((op == Token::EQ || op == Token::EQ_STRICT) && 3457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block (operation != NULL && operation->op() == Token::TYPEOF) && 3458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block (right->AsLiteral() != NULL && 3459a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block right->AsLiteral()->handle()->IsString())) { 3460a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<String> check(Handle<String>::cast(right->AsLiteral()->handle())); 3461a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3462a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load the operand and move it to a register. 3463a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block LoadTypeofExpression(operation->expression()); 3464a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result answer = frame_->Pop(); 3465a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block answer.ToRegister(); 3466a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3467a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (check->Equals(Heap::number_symbol())) { 3468a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Condition is_smi = masm_->CheckSmi(answer.reg()); 3469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->true_target()->Branch(is_smi); 3470a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Spill(answer.reg()); 3471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(answer.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); 3472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CompareRoot(answer.reg(), Heap::kHeapNumberMapRootIndex); 3473a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block answer.Unuse(); 3474a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->Split(equal); 3475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (check->Equals(Heap::string_symbol())) { 3477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Condition is_smi = masm_->CheckSmi(answer.reg()); 3478a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->false_target()->Branch(is_smi); 3479a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3480a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // It can be an undetectable string object. 3481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(kScratchRegister, 3482a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block FieldOperand(answer.reg(), HeapObject::kMapOffset)); 3483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset), 3484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Immediate(1 << Map::kIsUndetectable)); 3485a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->false_target()->Branch(not_zero); 3486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CmpInstanceType(kScratchRegister, FIRST_NONSTRING_TYPE); 3487a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block answer.Unuse(); 3488a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->Split(below); // Unsigned byte comparison needed. 3489a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3490a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (check->Equals(Heap::boolean_symbol())) { 3491a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CompareRoot(answer.reg(), Heap::kTrueValueRootIndex); 3492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->true_target()->Branch(equal); 3493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CompareRoot(answer.reg(), Heap::kFalseValueRootIndex); 3494a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block answer.Unuse(); 3495a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->Split(equal); 3496a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3497a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (check->Equals(Heap::undefined_symbol())) { 3498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CompareRoot(answer.reg(), Heap::kUndefinedValueRootIndex); 3499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->true_target()->Branch(equal); 3500a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3501a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Condition is_smi = masm_->CheckSmi(answer.reg()); 3502a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->false_target()->Branch(is_smi); 3503a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3504a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // It can be an undetectable object. 3505a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(kScratchRegister, 3506a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block FieldOperand(answer.reg(), HeapObject::kMapOffset)); 3507a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset), 3508a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Immediate(1 << Map::kIsUndetectable)); 3509a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block answer.Unuse(); 3510a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->Split(not_zero); 3511a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3512a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (check->Equals(Heap::function_symbol())) { 3513a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Condition is_smi = masm_->CheckSmi(answer.reg()); 3514a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->false_target()->Branch(is_smi); 3515a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Spill(answer.reg()); 3516a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CmpObjectType(answer.reg(), JS_FUNCTION_TYPE, answer.reg()); 3517d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block destination()->true_target()->Branch(equal); 3518d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Regular expressions are callable so typeof == 'function'. 3519d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ CmpInstanceType(answer.reg(), JS_REGEXP_TYPE); 3520a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block answer.Unuse(); 3521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->Split(equal); 3522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3523a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (check->Equals(Heap::object_symbol())) { 3524a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Condition is_smi = masm_->CheckSmi(answer.reg()); 3525a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->false_target()->Branch(is_smi); 3526a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CompareRoot(answer.reg(), Heap::kNullValueRootIndex); 3527a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->true_target()->Branch(equal); 3528a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3529d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Regular expressions are typeof == 'function', not 'object'. 3530d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ CmpObjectType(answer.reg(), JS_REGEXP_TYPE, kScratchRegister); 3531d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block destination()->false_target()->Branch(equal); 3532d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 3533a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // It can be an undetectable object. 3534a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset), 3535a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Immediate(1 << Map::kIsUndetectable)); 3536a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->false_target()->Branch(not_zero); 3537a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CmpInstanceType(kScratchRegister, FIRST_JS_OBJECT_TYPE); 3538a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->false_target()->Branch(below); 3539a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CmpInstanceType(kScratchRegister, LAST_JS_OBJECT_TYPE); 3540a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block answer.Unuse(); 3541a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->Split(below_equal); 3542a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 3543a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Uncommon case: typeof testing against a string literal that is 3544a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // never returned from the typeof operator. 3545a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block answer.Unuse(); 3546a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->Goto(false); 3547a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3548a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return; 3549a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3550a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3551a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Condition cc = no_condition; 3552a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool strict = false; 3553a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block switch (op) { 3554a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::EQ_STRICT: 3555a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block strict = true; 3556a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Fall through 3557a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::EQ: 3558a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block cc = equal; 3559a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 3560a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::LT: 3561a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block cc = less; 3562a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 3563a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::GT: 3564a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block cc = greater; 3565a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 3566a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::LTE: 3567a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block cc = less_equal; 3568a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 3569a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::GTE: 3570a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block cc = greater_equal; 3571a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 3572a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::IN: { 3573a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(left); 3574a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(right); 3575a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result answer = frame_->InvokeBuiltin(Builtins::IN, CALL_FUNCTION, 2); 3576a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&answer); // push the result 3577a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return; 3578a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3579a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::INSTANCEOF: { 3580a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(left); 3581a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(right); 3582a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block InstanceofStub stub; 3583a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result answer = frame_->CallStub(&stub, 2); 3584a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block answer.ToRegister(); 3585a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ testq(answer.reg(), answer.reg()); 3586a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block answer.Unuse(); 3587a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->Split(zero); 3588a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return; 3589a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3590a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block default: 3591a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block UNREACHABLE(); 3592a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3593a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(left); 3594a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(right); 3595402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Comparison(node, cc, strict, destination()); 3596a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 3597a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3598a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3599a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitThisFunction(ThisFunction* node) { 3600a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->PushFunction(); 3601a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 3602a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3603a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3604a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { 3605a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(args->length() == 1); 3606a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3607a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ArgumentsAccessStub expects the key in rdx and the formal 3608a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // parameter count in rax. 3609a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(args->at(0)); 3610a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result key = frame_->Pop(); 3611a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Explicitly create a constant result. 36123100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu Result count(Handle<Smi>(Smi::FromInt(scope()->num_parameters()))); 3613a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Call the shared stub to get to arguments[key]. 3614a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); 3615a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result result = frame_->CallStub(&stub, &key, &count); 3616a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&result); 3617a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 3618a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3619a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3620a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { 3621a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(args->length() == 1); 3622a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(args->at(0)); 3623a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result value = frame_->Pop(); 3624a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block value.ToRegister(); 3625a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(value.is_valid()); 3626a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Condition is_smi = masm_->CheckSmi(value.reg()); 3627a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->false_target()->Branch(is_smi); 3628a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // It is a heap object - get map. 3629a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check if the object is a JS array or not. 3630a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CmpObjectType(value.reg(), JS_ARRAY_TYPE, kScratchRegister); 3631a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block value.Unuse(); 3632a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->Split(equal); 3633a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 3634a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3635a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3636402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescuvoid CodeGenerator::GenerateIsRegExp(ZoneList<Expression*>* args) { 3637402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu ASSERT(args->length() == 1); 3638402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Load(args->at(0)); 3639402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Result value = frame_->Pop(); 3640402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu value.ToRegister(); 3641402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu ASSERT(value.is_valid()); 3642402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Condition is_smi = masm_->CheckSmi(value.reg()); 3643402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu destination()->false_target()->Branch(is_smi); 3644402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // It is a heap object - get map. 3645402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Check if the object is a regexp. 3646402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ CmpObjectType(value.reg(), JS_REGEXP_TYPE, kScratchRegister); 3647402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu value.Unuse(); 3648402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu destination()->Split(equal); 3649402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu} 3650402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 3651402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 3652d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) { 3653d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // This generates a fast version of: 3654d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp') 3655d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block ASSERT(args->length() == 1); 3656d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Load(args->at(0)); 3657d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Result obj = frame_->Pop(); 3658d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block obj.ToRegister(); 3659d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Condition is_smi = masm_->CheckSmi(obj.reg()); 3660d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block destination()->false_target()->Branch(is_smi); 3661d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 3662d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ Move(kScratchRegister, Factory::null_value()); 3663d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ cmpq(obj.reg(), kScratchRegister); 3664d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block destination()->true_target()->Branch(equal); 3665d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 3666d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ movq(kScratchRegister, FieldOperand(obj.reg(), HeapObject::kMapOffset)); 3667d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Undetectable objects behave like undefined when tested with typeof. 3668d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset), 3669d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Immediate(1 << Map::kIsUndetectable)); 3670d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block destination()->false_target()->Branch(not_zero); 3671d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ CmpInstanceType(kScratchRegister, FIRST_JS_OBJECT_TYPE); 3672d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block destination()->false_target()->Branch(less); 3673d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ CmpInstanceType(kScratchRegister, LAST_JS_OBJECT_TYPE); 3674d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block obj.Unuse(); 3675d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block destination()->Split(less_equal); 3676d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block} 3677d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 3678d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 3679d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid CodeGenerator::GenerateIsFunction(ZoneList<Expression*>* args) { 3680d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // This generates a fast version of: 3681d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // (%_ClassOf(arg) === 'Function') 3682d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block ASSERT(args->length() == 1); 3683d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Load(args->at(0)); 3684d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Result obj = frame_->Pop(); 3685d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block obj.ToRegister(); 3686d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Condition is_smi = masm_->CheckSmi(obj.reg()); 3687d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block destination()->false_target()->Branch(is_smi); 3688d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ CmpObjectType(obj.reg(), JS_FUNCTION_TYPE, kScratchRegister); 3689d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block obj.Unuse(); 3690d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block destination()->Split(equal); 3691d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block} 3692d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 3693d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 3694d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarkevoid CodeGenerator::GenerateIsUndetectableObject(ZoneList<Expression*>* args) { 3695d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke ASSERT(args->length() == 1); 3696d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Load(args->at(0)); 3697d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Result obj = frame_->Pop(); 3698d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke obj.ToRegister(); 3699d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Condition is_smi = masm_->CheckSmi(obj.reg()); 3700d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke destination()->false_target()->Branch(is_smi); 3701d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(kScratchRegister, FieldOperand(obj.reg(), HeapObject::kMapOffset)); 3702d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movzxbl(kScratchRegister, 3703d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke FieldOperand(kScratchRegister, Map::kBitFieldOffset)); 3704d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ testl(kScratchRegister, Immediate(1 << Map::kIsUndetectable)); 3705d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke obj.Unuse(); 3706d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke destination()->Split(not_zero); 3707d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke} 3708d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 3709d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 3710a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) { 3711a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(args->length() == 0); 3712a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3713a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the frame pointer for the calling frame. 3714a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result fp = allocator()->Allocate(); 3715a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(fp.reg(), Operand(rbp, StandardFrameConstants::kCallerFPOffset)); 3716a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3717a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Skip the arguments adaptor frame if it exists. 3718a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label check_frame_marker; 37193ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ SmiCompare(Operand(fp.reg(), StandardFrameConstants::kContextOffset), 37203ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); 3721a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, &check_frame_marker); 3722a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(fp.reg(), Operand(fp.reg(), StandardFrameConstants::kCallerFPOffset)); 3723a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3724a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check the marker in the calling frame. 3725a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&check_frame_marker); 37263ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ SmiCompare(Operand(fp.reg(), StandardFrameConstants::kMarkerOffset), 37273ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block Smi::FromInt(StackFrame::CONSTRUCT)); 3728a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block fp.Unuse(); 3729a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->Split(equal); 3730a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 3731a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3732a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3733a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) { 3734a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(args->length() == 0); 3735a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ArgumentsAccessStub takes the parameter count as an input argument 3736a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // in register eax. Create a constant result for it. 37373100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu Result count(Handle<Smi>(Smi::FromInt(scope()->num_parameters()))); 3738a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Call the shared stub to get to the arguments.length. 3739a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH); 3740a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result result = frame_->CallStub(&stub, &count); 3741a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&result); 3742a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 3743a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3744a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3745a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { 3746a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment(masm_, "[ GenerateFastCharCodeAt"); 3747a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(args->length() == 2); 3748a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3749a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label slow_case; 3750a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label end; 3751a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label not_a_flat_string; 3752a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label try_again_with_new_string; 3753a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label ascii_string; 3754a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label got_char_code; 3755a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3756a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(args->at(0)); 3757a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(args->at(1)); 3758a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result index = frame_->Pop(); 3759a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result object = frame_->Pop(); 3760a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3761a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get register rcx to use as shift amount later. 3762a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result shift_amount; 3763a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (object.is_register() && object.reg().is(rcx)) { 3764a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result fresh = allocator_->Allocate(); 3765a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block shift_amount = object; 3766a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block object = fresh; 3767a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(object.reg(), rcx); 3768a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3769a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (index.is_register() && index.reg().is(rcx)) { 3770a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result fresh = allocator_->Allocate(); 3771a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block shift_amount = index; 3772a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block index = fresh; 3773a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(index.reg(), rcx); 3774a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3775a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // There could be references to ecx in the frame. Allocating will 3776a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // spill them, otherwise spill explicitly. 3777a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (shift_amount.is_valid()) { 3778a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Spill(rcx); 3779a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 3780a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block shift_amount = allocator()->Allocate(rcx); 3781a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3782a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(shift_amount.is_register()); 3783a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(shift_amount.reg().is(rcx)); 3784a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(allocator_->count(rcx) == 1); 3785a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3786a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We will mutate the index register and possibly the object register. 3787a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The case where they are somehow the same register is handled 3788a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // because we only mutate them in the case where the receiver is a 3789a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // heap object and the index is not. 3790a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block object.ToRegister(); 3791a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block index.ToRegister(); 3792a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Spill(object.reg()); 3793a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Spill(index.reg()); 3794a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3795a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We need a single extra temporary register. 3796a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result temp = allocator()->Allocate(); 3797a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(temp.is_valid()); 3798a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3799a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // There is no virtual frame effect from here up to the final result 3800a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // push. 3801a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3802a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If the receiver is a smi trigger the slow case. 3803a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfSmi(object.reg(), &slow_case); 3804a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3805a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If the index is negative or non-smi trigger the slow case. 3806a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfNotPositiveSmi(index.reg(), &slow_case); 3807a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3808a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Untag the index. 3809a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ SmiToInteger32(index.reg(), index.reg()); 3810a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3811a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&try_again_with_new_string); 3812a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Fetch the instance type of the receiver into rcx. 3813a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rcx, FieldOperand(object.reg(), HeapObject::kMapOffset)); 3814a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movzxbl(rcx, FieldOperand(rcx, Map::kInstanceTypeOffset)); 3815a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If the receiver is not a string trigger the slow case. 3816a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ testb(rcx, Immediate(kIsNotStringMask)); 3817a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_zero, &slow_case); 3818a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3819a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check for index out of range. 3820d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ cmpl(index.reg(), FieldOperand(object.reg(), String::kLengthOffset)); 3821a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(greater_equal, &slow_case); 3822a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Reload the instance type (into the temp register this time).. 3823a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(temp.reg(), FieldOperand(object.reg(), HeapObject::kMapOffset)); 3824a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movzxbl(temp.reg(), FieldOperand(temp.reg(), Map::kInstanceTypeOffset)); 3825a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3826a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We need special handling for non-flat strings. 3827d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block ASSERT_EQ(0, kSeqStringTag); 3828a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ testb(temp.reg(), Immediate(kStringRepresentationMask)); 3829a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_zero, ¬_a_flat_string); 3830a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check for 1-byte or 2-byte string. 3831d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block ASSERT_EQ(0, kTwoByteStringTag); 3832a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ testb(temp.reg(), Immediate(kStringEncodingMask)); 3833a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_zero, &ascii_string); 3834a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3835a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // 2-byte string. 3836a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load the 2-byte character code into the temp register. 3837a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movzxwl(temp.reg(), FieldOperand(object.reg(), 3838a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block index.reg(), 3839a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block times_2, 3840a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block SeqTwoByteString::kHeaderSize)); 3841a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ jmp(&got_char_code); 3842a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3843a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ASCII string. 3844a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&ascii_string); 3845a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load the byte into the temp register. 3846a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movzxbl(temp.reg(), FieldOperand(object.reg(), 3847a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block index.reg(), 3848a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block times_1, 3849a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block SeqAsciiString::kHeaderSize)); 3850a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&got_char_code); 3851a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Integer32ToSmi(temp.reg(), temp.reg()); 3852a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ jmp(&end); 3853a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3854a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Handle non-flat strings. 3855a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(¬_a_flat_string); 3856a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ and_(temp.reg(), Immediate(kStringRepresentationMask)); 3857a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ cmpb(temp.reg(), Immediate(kConsStringTag)); 3858a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, &slow_case); 3859a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3860a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ConsString. 3861d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Check that the right hand side is the empty string (ie if this is really a 3862d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // flat string in a cons string). If that is not the case we would rather go 3863d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // to the runtime system now, to flatten the string. 3864d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ movq(temp.reg(), FieldOperand(object.reg(), ConsString::kSecondOffset)); 3865d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ CompareRoot(temp.reg(), Heap::kEmptyStringRootIndex); 3866d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ j(not_equal, &slow_case); 3867d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Get the first of the two strings. 3868a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(object.reg(), FieldOperand(object.reg(), ConsString::kFirstOffset)); 3869a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ jmp(&try_again_with_new_string); 3870a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3871a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&slow_case); 3872a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Move the undefined value into the result register, which will 3873a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // trigger the slow case. 3874a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ LoadRoot(temp.reg(), Heap::kUndefinedValueRootIndex); 3875a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3876a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&end); 3877a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&temp); 3878a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 3879a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3880a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3881a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { 3882a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(args->length() == 1); 3883a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(args->at(0)); 3884a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result value = frame_->Pop(); 3885a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block value.ToRegister(); 3886a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(value.is_valid()); 3887a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Condition positive_smi = masm_->CheckPositiveSmi(value.reg()); 3888a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block value.Unuse(); 3889a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->Split(positive_smi); 3890a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 3891a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3892a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3893a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { 3894a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(args->length() == 1); 3895a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(args->at(0)); 3896a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result value = frame_->Pop(); 3897a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block value.ToRegister(); 3898a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(value.is_valid()); 3899a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Condition is_smi = masm_->CheckSmi(value.reg()); 3900a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block value.Unuse(); 3901a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->Split(is_smi); 3902a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 3903a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3904a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3905a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenerateLog(ZoneList<Expression*>* args) { 3906a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Conditionally generate a log call. 3907a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Args: 3908a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // 0 (literal string): The type of logging (corresponds to the flags). 3909a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // This is used to determine whether or not to generate the log call. 3910a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // 1 (string): Format string. Access the string at argument index 2 3911a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // with '%2s' (see Logger::LogRuntime for all the formats). 3912a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // 2 (array): Arguments to the format string. 3913a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT_EQ(args->length(), 3); 3914a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef ENABLE_LOGGING_AND_PROFILING 3915a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (ShouldGenerateLog(args->at(0))) { 3916a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(args->at(1)); 3917a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(args->at(2)); 3918a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->CallRuntime(Runtime::kLog, 2); 3919a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3920a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif 3921a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Finally, we're expected to leave a value on the top of the stack. 3922a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(Factory::undefined_value()); 3923a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 3924a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3925a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3926a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { 3927a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(args->length() == 2); 3928a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3929a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load the two objects into registers and perform the comparison. 3930a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(args->at(0)); 3931a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(args->at(1)); 3932a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result right = frame_->Pop(); 3933a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result left = frame_->Pop(); 3934a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block right.ToRegister(); 3935a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block left.ToRegister(); 3936a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ cmpq(right.reg(), left.reg()); 3937a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block right.Unuse(); 3938a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block left.Unuse(); 3939a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block destination()->Split(equal); 3940a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 3941a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3942a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3943a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenerateGetFramePointer(ZoneList<Expression*>* args) { 3944a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(args->length() == 0); 3945a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // RBP value is aligned, so it should be tagged as a smi (without necesarily 39463ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // being padded as a smi, so it should not be treated as a smi.). 3947a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(kSmiTag == 0 && kSmiTagSize == 1); 3948a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result rbp_as_smi = allocator_->Allocate(); 3949a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(rbp_as_smi.is_valid()); 3950a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rbp_as_smi.reg(), rbp); 3951a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&rbp_as_smi); 3952a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 3953a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3954a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3955a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenerateRandomPositiveSmi(ZoneList<Expression*>* args) { 3956a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(args->length() == 0); 3957a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->SpillAll(); 3958a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(rsi); 3959a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3960a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Make sure the frame is aligned like the OS expects. 3961a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block static const int kFrameAlignment = OS::ActivationFrameAlignment(); 3962a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (kFrameAlignment > 0) { 3963a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(IsPowerOf2(kFrameAlignment)); 3964a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rbx, rsp); // Save in AMD-64 abi callee-saved register. 3965a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ and_(rsp, Immediate(-kFrameAlignment)); 3966a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3967a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3968a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Call V8::RandomPositiveSmi(). 3969a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Call(FUNCTION_ADDR(V8::RandomPositiveSmi), RelocInfo::RUNTIME_ENTRY); 3970a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3971a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Restore stack pointer from callee-saved register. 3972a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (kFrameAlignment > 0) { 3973a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rsp, rbx); 3974a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3975a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3976a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(rsi); 3977a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result result = allocator_->Allocate(rax); 3978a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&result); 3979a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 3980a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3981a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3982e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid CodeGenerator::GenerateRegExpExec(ZoneList<Expression*>* args) { 3983e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke ASSERT_EQ(args->length(), 4); 3984a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3985e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Load the arguments on the stack and call the runtime system. 3986a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(args->at(0)); 3987e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Load(args->at(1)); 3988e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Load(args->at(2)); 3989e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Load(args->at(3)); 39904515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke RegExpExecStub stub; 39914515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Result result = frame_->CallStub(&stub, 4); 3992e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke frame_->Push(&result); 3993e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke} 3994a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3995a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3996402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescuvoid CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) { 3997402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu ASSERT_EQ(args->length(), 1); 3998402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 3999402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Load the argument on the stack and jump to the runtime. 4000402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Load(args->at(0)); 4001402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 4002402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Result answer = frame_->CallRuntime(Runtime::kNumberToString, 1); 4003402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu frame_->Push(&answer); 4004402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu} 4005402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 4006402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 4007402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescuvoid CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) { 4008402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu ASSERT_EQ(args->length(), 1); 4009402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Load the argument on the stack and jump to the runtime. 4010402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Load(args->at(0)); 4011402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Result answer = frame_->CallRuntime(Runtime::kMath_sin, 1); 4012402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu frame_->Push(&answer); 4013402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu} 4014402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 4015402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 4016402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescuvoid CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) { 4017402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu ASSERT_EQ(args->length(), 1); 4018402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Load the argument on the stack and jump to the runtime. 4019402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Load(args->at(0)); 4020402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Result answer = frame_->CallRuntime(Runtime::kMath_cos, 1); 4021402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu frame_->Push(&answer); 4022402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu} 4023402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 4024402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 4025e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid CodeGenerator::GenerateStringAdd(ZoneList<Expression*>* args) { 4026e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke ASSERT_EQ(2, args->length()); 4027a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4028e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Load(args->at(0)); 4029e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Load(args->at(1)); 4030a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4031e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke StringAddStub stub(NO_STRING_ADD_FLAGS); 4032e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Result answer = frame_->CallStub(&stub, 2); 4033e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke frame_->Push(&answer); 4034e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke} 4035a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4036e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 4037e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid CodeGenerator::GenerateSubString(ZoneList<Expression*>* args) { 4038e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke ASSERT_EQ(3, args->length()); 4039e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 4040e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Load(args->at(0)); 4041e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Load(args->at(1)); 4042e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Load(args->at(2)); 4043e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 4044d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke SubStringStub stub; 4045d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Result answer = frame_->CallStub(&stub, 3); 4046a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&answer); 4047a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 4048a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4049a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4050e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid CodeGenerator::GenerateStringCompare(ZoneList<Expression*>* args) { 4051d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block ASSERT_EQ(2, args->length()); 4052d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 4053d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Load(args->at(0)); 4054d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Load(args->at(1)); 4055d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 4056e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke StringCompareStub stub; 4057e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Result answer = frame_->CallStub(&stub, 2); 4058d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block frame_->Push(&answer); 4059d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block} 4060d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 4061d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 4062a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenerateClassOf(ZoneList<Expression*>* args) { 4063a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(args->length() == 1); 4064a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget leave, null, function, non_function_constructor; 4065a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(args->at(0)); // Load the object. 4066a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result obj = frame_->Pop(); 4067a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block obj.ToRegister(); 4068a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Spill(obj.reg()); 4069a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4070a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If the object is a smi, we return null. 4071a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Condition is_smi = masm_->CheckSmi(obj.reg()); 4072a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block null.Branch(is_smi); 4073a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4074a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the object is a JS object but take special care of JS 4075a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // functions to make sure they have 'Function' as their class. 4076a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4077a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CmpObjectType(obj.reg(), FIRST_JS_OBJECT_TYPE, obj.reg()); 4078a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block null.Branch(below); 4079a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4080a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // As long as JS_FUNCTION_TYPE is the last instance type and it is 4081a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // right after LAST_JS_OBJECT_TYPE, we can avoid checking for 4082a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // LAST_JS_OBJECT_TYPE. 4083a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); 4084a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1); 4085a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CmpInstanceType(obj.reg(), JS_FUNCTION_TYPE); 4086a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block function.Branch(equal); 4087a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4088a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check if the constructor in the map is a function. 4089a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(obj.reg(), FieldOperand(obj.reg(), Map::kConstructorOffset)); 4090a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CmpObjectType(obj.reg(), JS_FUNCTION_TYPE, kScratchRegister); 4091a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block non_function_constructor.Branch(not_equal); 4092a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4093a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The obj register now contains the constructor function. Grab the 4094a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // instance class name from there. 4095a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(obj.reg(), 4096a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block FieldOperand(obj.reg(), JSFunction::kSharedFunctionInfoOffset)); 4097a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(obj.reg(), 4098a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block FieldOperand(obj.reg(), 4099a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block SharedFunctionInfo::kInstanceClassNameOffset)); 4100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&obj); 4101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block leave.Jump(); 4102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Functions have class 'Function'. 4104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block function.Bind(); 4105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(Factory::function_class_symbol()); 4106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block leave.Jump(); 4107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Objects with a non-function constructor have class 'Object'. 4109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block non_function_constructor.Bind(); 4110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(Factory::Object_symbol()); 4111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block leave.Jump(); 4112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Non-JS objects have class null. 4114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block null.Bind(); 4115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(Factory::null_value()); 4116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // All done. 4118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block leave.Bind(); 4119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 4120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) { 4123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(args->length() == 2); 4124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget leave; 4125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(args->at(0)); // Load the object. 4126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(args->at(1)); // Load the value. 4127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result value = frame_->Pop(); 4128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result object = frame_->Pop(); 4129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block value.ToRegister(); 4130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block object.ToRegister(); 4131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // if (object->IsSmi()) return value. 4133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Condition is_smi = masm_->CheckSmi(object.reg()); 4134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block leave.Branch(is_smi, &value); 4135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // It is a heap object - get its map. 4137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result scratch = allocator_->Allocate(); 4138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(scratch.is_valid()); 4139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // if (!object->IsJSValue()) return value. 4140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CmpObjectType(object.reg(), JS_VALUE_TYPE, scratch.reg()); 4141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block leave.Branch(not_equal, &value); 4142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Store the value. 4144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(FieldOperand(object.reg(), JSValue::kValueOffset), value.reg()); 4145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Update the write barrier. Save the value as it will be 4146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // overwritten by the write barrier code and is needed afterward. 4147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result duplicate_value = allocator_->Allocate(); 4148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(duplicate_value.is_valid()); 4149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(duplicate_value.reg(), value.reg()); 4150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The object register is also overwritten by the write barrier and 4151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // possibly aliased in the frame. 4152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Spill(object.reg()); 4153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ RecordWrite(object.reg(), JSValue::kValueOffset, duplicate_value.reg(), 4154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block scratch.reg()); 4155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block object.Unuse(); 4156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block scratch.Unuse(); 4157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block duplicate_value.Unuse(); 4158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Leave. 4160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block leave.Bind(&value); 4161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&value); 4162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 4163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { 4166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(args->length() == 1); 4167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget leave; 4168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(args->at(0)); // Load the object. 4169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Dup(); 4170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result object = frame_->Pop(); 4171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block object.ToRegister(); 4172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(object.is_valid()); 4173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // if (object->IsSmi()) return object. 4174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Condition is_smi = masm_->CheckSmi(object.reg()); 4175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block leave.Branch(is_smi); 4176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // It is a heap object - get map. 4177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result temp = allocator()->Allocate(); 4178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(temp.is_valid()); 4179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // if (!object->IsJSValue()) return object. 4180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CmpObjectType(object.reg(), JS_VALUE_TYPE, temp.reg()); 4181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block leave.Branch(not_equal); 4182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(temp.reg(), FieldOperand(object.reg(), JSValue::kValueOffset)); 4183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block object.Unuse(); 4184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->SetElementAt(0, &temp); 4185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block leave.Bind(); 4186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 4187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ----------------------------------------------------------------------------- 4190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// CodeGenerator implementation of Expressions 4191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4192d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid CodeGenerator::LoadAndSpill(Expression* expression) { 4193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // TODO(x64): No architecture specific code. Move to shared location. 4194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(in_spilled_code()); 4195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block set_in_spilled_code(false); 4196d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Load(expression); 4197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->SpillAll(); 4198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block set_in_spilled_code(true); 4199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 4200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4202d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid CodeGenerator::Load(Expression* expr) { 4203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef DEBUG 4204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int original_height = frame_->height(); 4205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif 4206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!in_spilled_code()); 4207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget true_target; 4208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget false_target; 4209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ControlDestination dest(&true_target, &false_target, true); 4210d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block LoadCondition(expr, &dest, false); 4211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (dest.false_was_fall_through()) { 4213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The false target was just bound. 4214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget loaded; 4215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(Factory::false_value()); 4216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // There may be dangling jumps to the true target. 4217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (true_target.is_linked()) { 4218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block loaded.Jump(); 4219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block true_target.Bind(); 4220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(Factory::true_value()); 4221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block loaded.Bind(); 4222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (dest.is_used()) { 4225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // There is true, and possibly false, control flow (with true as 4226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // the fall through). 4227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget loaded; 4228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(Factory::true_value()); 4229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (false_target.is_linked()) { 4230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block loaded.Jump(); 4231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block false_target.Bind(); 4232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(Factory::false_value()); 4233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block loaded.Bind(); 4234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 4237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We have a valid value on top of the frame, but we still may 4238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // have dangling jumps to the true and false targets from nested 4239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // subexpressions (eg, the left subexpressions of the 4240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // short-circuited boolean operators). 4241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(has_valid_frame()); 4242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (true_target.is_linked() || false_target.is_linked()) { 4243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget loaded; 4244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block loaded.Jump(); // Don't lose the current TOS. 4245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (true_target.is_linked()) { 4246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block true_target.Bind(); 4247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(Factory::true_value()); 4248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (false_target.is_linked()) { 4249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block loaded.Jump(); 4250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (false_target.is_linked()) { 4253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block false_target.Bind(); 4254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(Factory::false_value()); 4255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block loaded.Bind(); 4257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(has_valid_frame()); 4261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(frame_->height() == original_height + 1); 4262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 4263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Emit code to load the value of an expression to the top of the 4266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// frame. If the expression is boolean-valued it may be compiled (or 4267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// partially compiled) into control flow to the control destination. 4268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// If force_control is true, control flow is forced. 4269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::LoadCondition(Expression* x, 4270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ControlDestination* dest, 4271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool force_control) { 4272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!in_spilled_code()); 4273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int original_height = frame_->height(); 4274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4275d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block { CodeGenState new_state(this, dest); 4276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Visit(x); 4277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If we hit a stack overflow, we may not have actually visited 4279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // the expression. In that case, we ensure that we have a 4280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // valid-looking frame state because we will continue to generate 4281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // code as we unwind the C++ stack. 4282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // 4283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // It's possible to have both a stack overflow and a valid frame 4284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // state (eg, a subexpression overflowed, visiting it returned 4285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // with a dummied frame state, and visiting this expression 4286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // returned with a normal-looking state). 4287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (HasStackOverflow() && 4288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block !dest->is_used() && 4289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->height() == original_height) { 4290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block dest->Goto(true); 4291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (force_control && !dest->is_used()) { 4295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Convert the TOS value into flow to the control destination. 4296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // TODO(X64): Make control flow to control destinations work. 4297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ToBoolean(dest); 4298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!(force_control && !dest->is_used())); 4301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(dest->is_used() || frame_->height() == original_height + 1); 4302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 4303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ECMA-262, section 9.2, page 30: ToBoolean(). Pop the top of stack and 4306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// convert it to a boolean in the condition code register or jump to 4307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 'false_target'/'true_target' as appropriate. 4308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::ToBoolean(ControlDestination* dest) { 4309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ ToBoolean"); 4310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The value to convert should be popped from the frame. 4312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result value = frame_->Pop(); 4313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block value.ToRegister(); 4314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4315402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu if (value.is_number()) { 4316402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Comment cmnt(masm_, "ONLY_NUMBER"); 4317402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Fast case if NumberInfo indicates only numbers. 4318402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu if (FLAG_debug_code) { 4319402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ AbortIfNotNumber(value.reg(), "ToBoolean operand is not a number."); 4320402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu } 4321402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Smi => false iff zero. 4322402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ SmiCompare(value.reg(), Smi::FromInt(0)); 4323402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu dest->false_target()->Branch(equal); 4324402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Condition is_smi = masm_->CheckSmi(value.reg()); 4325402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu dest->true_target()->Branch(is_smi); 4326402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ fldz(); 4327402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ fld_d(FieldOperand(value.reg(), HeapNumber::kValueOffset)); 4328402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ FCmp(); 4329402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu value.Unuse(); 4330402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu dest->Split(not_zero); 4331402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu } else { 4332402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Fast case checks. 4333402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // 'false' => false. 4334402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ CompareRoot(value.reg(), Heap::kFalseValueRootIndex); 4335402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu dest->false_target()->Branch(equal); 4336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4337402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // 'true' => true. 4338402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ CompareRoot(value.reg(), Heap::kTrueValueRootIndex); 4339402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu dest->true_target()->Branch(equal); 4340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4341402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // 'undefined' => false. 4342402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ CompareRoot(value.reg(), Heap::kUndefinedValueRootIndex); 4343402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu dest->false_target()->Branch(equal); 4344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4345402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Smi => false iff zero. 4346402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ SmiCompare(value.reg(), Smi::FromInt(0)); 4347402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu dest->false_target()->Branch(equal); 4348402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Condition is_smi = masm_->CheckSmi(value.reg()); 4349402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu dest->true_target()->Branch(is_smi); 4350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4351402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Call the stub for all other cases. 4352402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu frame_->Push(&value); // Undo the Pop() from above. 4353402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu ToBooleanStub stub; 4354402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Result temp = frame_->CallStub(&stub, 1); 4355402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Convert the result to a condition code. 4356402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ testq(temp.reg(), temp.reg()); 4357402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu temp.Unuse(); 4358402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu dest->Split(not_equal); 4359402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu } 4360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 4361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::LoadUnsafeSmi(Register target, Handle<Object> value) { 4364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block UNIMPLEMENTED(); 4365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // TODO(X64): Implement security policy for loads of smis. 4366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 4367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool CodeGenerator::IsUnsafeSmi(Handle<Object> value) { 4370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return false; 4371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 4372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//------------------------------------------------------------------------------ 4374a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// CodeGenerator implementation of variables, lookups, and stores. 4375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4376d91b9f7d46489a9ee00f9cb415630299c76a502bLeon ClarkeReference::Reference(CodeGenerator* cgen, 4377d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Expression* expression, 4378d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke bool persist_after_get) 4379d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke : cgen_(cgen), 4380d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke expression_(expression), 4381d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke type_(ILLEGAL), 4382d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke persist_after_get_(persist_after_get) { 4383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block cgen->LoadReference(this); 4384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 4385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockReference::~Reference() { 4388d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke ASSERT(is_unloaded() || is_illegal()); 4389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 4390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::LoadReference(Reference* ref) { 4393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // References are loaded from both spilled and unspilled code. Set the 4394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // state to unspilled to allow that (and explicitly spill after 4395a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // construction at the construction sites). 4396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool was_in_spilled_code = in_spilled_code_; 4397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block in_spilled_code_ = false; 4398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ LoadReference"); 4400a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Expression* e = ref->expression(); 4401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Property* property = e->AsProperty(); 4402a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Variable* var = e->AsVariableProxy()->AsVariable(); 4403a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4404a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (property != NULL) { 4405a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The expression is either a property or a variable proxy that rewrites 4406a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // to a property. 4407a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(property->obj()); 4408e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke if (property->key()->IsPropertyName()) { 4409a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ref->set_type(Reference::NAMED); 4410a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 4411a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(property->key()); 4412a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ref->set_type(Reference::KEYED); 4413a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4414a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (var != NULL) { 4415a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The expression is a variable proxy that does not rewrite to a 4416a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // property. Global variables are treated as named property references. 4417a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (var->is_global()) { 4418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block LoadGlobal(); 4419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ref->set_type(Reference::NAMED); 4420a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 4421a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(var->slot() != NULL); 4422a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ref->set_type(Reference::SLOT); 4423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4424a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 4425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Anything else is a runtime error. 4426a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(e); 4427a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->CallRuntime(Runtime::kThrowReferenceError, 1); 4428a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4429a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4430a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block in_spilled_code_ = was_in_spilled_code; 4431a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 4432a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4433a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4434a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::UnloadReference(Reference* ref) { 4435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Pop a reference from the stack while preserving TOS. 4436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ UnloadReference"); 4437a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Nip(ref->size()); 4438d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke ref->set_unloaded(); 4439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 4440a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4441a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4442a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockOperand CodeGenerator::SlotOperand(Slot* slot, Register tmp) { 4443a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Currently, this assertion will fail if we try to assign to 4444a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // a constant variable that is constant because it is read-only 4445a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // (such as the variable referring to a named function expression). 4446a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We need to implement assignments to read-only variables. 4447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Ideally, we should do this during AST generation (by converting 4448a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // such assignments into expression statements); however, in general 4449a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // we may not be able to make the decision until past AST generation, 4450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // that is when the entire program is known. 4451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(slot != NULL); 4452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int index = slot->index(); 4453a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block switch (slot->type()) { 4454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Slot::PARAMETER: 4455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return frame_->ParameterAt(index); 4456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Slot::LOCAL: 4458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return frame_->LocalAt(index); 4459a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4460a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Slot::CONTEXT: { 4461a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Follow the context chain if necessary. 4462a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!tmp.is(rsi)); // do not overwrite context register 4463a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register context = rsi; 4464a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int chain_length = scope()->ContextChainLength(slot->var()->scope()); 4465a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = 0; i < chain_length; i++) { 4466a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load the closure. 4467a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // (All contexts, even 'with' contexts, have a closure, 4468a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // and it is the same for all contexts inside a function. 4469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // There is no need to go to the function context first.) 4470a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(tmp, ContextOperand(context, Context::CLOSURE_INDEX)); 4471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load the function context (which is the incoming, outer context). 4472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(tmp, FieldOperand(tmp, JSFunction::kContextOffset)); 4473a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block context = tmp; 4474a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We may have a 'with' context now. Get the function context. 4476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // (In fact this mov may never be the needed, since the scope analysis 4477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // may not permit a direct context access in this case and thus we are 4478a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // always at a function context. However it is safe to dereference be- 4479a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // cause the function context of a function context is itself. Before 4480a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // deleting this mov we should try to create a counter-example first, 4481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // though...) 4482a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(tmp, ContextOperand(context, Context::FCONTEXT_INDEX)); 4483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return ContextOperand(tmp, index); 4484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4485a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block default: 4487a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block UNREACHABLE(); 4488a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return Operand(rsp, 0); 4489a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4490a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 4491a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockOperand CodeGenerator::ContextSlotOperandCheckExtensions(Slot* slot, 4494a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result tmp, 4495a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget* slow) { 4496a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(slot->type() == Slot::CONTEXT); 4497a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(tmp.is_register()); 4498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register context = rsi; 4499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4500a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) { 4501a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (s->num_heap_slots() > 0) { 4502a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (s->calls_eval()) { 4503a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that extension is NULL. 4504a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), 4505a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Immediate(0)); 4506a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block slow->Branch(not_equal, not_taken); 4507a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4508a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(tmp.reg(), ContextOperand(context, Context::CLOSURE_INDEX)); 4509a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(tmp.reg(), FieldOperand(tmp.reg(), JSFunction::kContextOffset)); 4510a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block context = tmp.reg(); 4511a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4512a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4513a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that last extension is NULL. 4514a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0)); 4515a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block slow->Branch(not_equal, not_taken); 4516a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(tmp.reg(), ContextOperand(context, Context::FCONTEXT_INDEX)); 4517a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return ContextOperand(tmp.reg(), slot->index()); 4518a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 4519a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4520a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { 4522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (slot->type() == Slot::LOOKUP) { 4523a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(slot->var()->is_dynamic()); 4524a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4525a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget slow; 4526a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget done; 4527a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result value; 4528a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4529a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Generate fast-case code for variables that might be shadowed by 4530a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // eval-introduced variables. Eval is used a lot without 4531a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // introducing variables. In those cases, we do not want to 4532a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // perform a runtime call for all variables in the scope 4533a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // containing the eval. 4534a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { 4535a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block value = LoadFromGlobalSlotCheckExtensions(slot, typeof_state, &slow); 4536a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If there was no control flow to slow, we can exit early. 4537a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!slow.is_linked()) { 4538a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&value); 4539a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return; 4540a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4541a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4542a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block done.Jump(&value); 4543a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4544a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { 4545a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot(); 4546a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Only generate the fast case for locals that rewrite to slots. 4547a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // This rules out argument loads. 4548a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (potential_slot != NULL) { 4549a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Allocate a fresh register to use as a temp in 4550a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ContextSlotOperandCheckExtensions and to hold the result 4551a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // value. 4552a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block value = allocator_->Allocate(); 4553a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(value.is_valid()); 4554a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(value.reg(), 4555a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ContextSlotOperandCheckExtensions(potential_slot, 4556a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block value, 4557a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block &slow)); 4558a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (potential_slot->var()->mode() == Variable::CONST) { 4559a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CompareRoot(value.reg(), Heap::kTheHoleValueRootIndex); 4560a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block done.Branch(not_equal, &value); 4561a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ LoadRoot(value.reg(), Heap::kUndefinedValueRootIndex); 4562a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4563a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // There is always control flow to slow from 4564a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ContextSlotOperandCheckExtensions so we have to jump around 4565a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // it. 4566a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block done.Jump(&value); 4567a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4568a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4569a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4570a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block slow.Bind(); 4571a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // A runtime call is inevitable. We eagerly sync frame elements 4572a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // to memory so that we can push the arguments directly into place 4573a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // on top of the frame. 4574a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->SyncRange(0, frame_->element_count() - 1); 4575a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(rsi); 4576a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(kScratchRegister, slot->var()->name(), RelocInfo::EMBEDDED_OBJECT); 4577a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(kScratchRegister); 4578a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (typeof_state == INSIDE_TYPEOF) { 4579a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block value = 4580a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); 4581a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 4582a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block value = frame_->CallRuntime(Runtime::kLoadContextSlot, 2); 4583a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4584a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4585a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block done.Bind(&value); 4586a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&value); 4587a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4588a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (slot->var()->mode() == Variable::CONST) { 4589a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Const slots may contain 'the hole' value (the constant hasn't been 4590a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // initialized yet) which needs to be converted into the 'undefined' 4591a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // value. 4592a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // 4593a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We currently spill the virtual frame because constants use the 4594a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // potentially unsafe direct-frame access of SlotOperand. 4595a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block VirtualFrame::SpilledScope spilled_scope; 4596a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ Load const"); 4597a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget exit; 4598a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rcx, SlotOperand(slot, rcx)); 4599a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CompareRoot(rcx, Heap::kTheHoleValueRootIndex); 4600a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exit.Branch(not_equal); 4601a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ LoadRoot(rcx, Heap::kUndefinedValueRootIndex); 4602a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exit.Bind(); 4603a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(rcx); 4604a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4605a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (slot->type() == Slot::PARAMETER) { 4606a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->PushParameterAt(slot->index()); 4607a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4608a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (slot->type() == Slot::LOCAL) { 4609a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->PushLocalAt(slot->index()); 4610a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4611a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 4612a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The other remaining slot types (LOOKUP and GLOBAL) cannot reach 4613a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // here. 4614a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // 4615a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The use of SlotOperand below is safe for an unspilled frame 4616a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // because it will always be a context slot. 4617a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(slot->type() == Slot::CONTEXT); 4618a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result temp = allocator_->Allocate(); 4619a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(temp.is_valid()); 4620a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(temp.reg(), SlotOperand(slot, temp.reg())); 4621a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&temp); 4622a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4623a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 4624a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4625a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4626a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::LoadFromSlotCheckForArguments(Slot* slot, 4627a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block TypeofState state) { 4628a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block LoadFromSlot(slot, state); 4629a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4630a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Bail out quickly if we're not using lazy arguments allocation. 4631a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (ArgumentsMode() != LAZY_ARGUMENTS_ALLOCATION) return; 4632a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4633a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ... or if the slot isn't a non-parameter arguments slot. 4634a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (slot->type() == Slot::PARAMETER || !slot->is_arguments()) return; 4635a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4636a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Pop the loaded value from the stack. 4637a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result value = frame_->Pop(); 4638a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4639a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If the loaded value is a constant, we know if the arguments 4640a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // object has been lazily loaded yet. 4641a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (value.is_constant()) { 4642a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (value.handle()->IsTheHole()) { 4643a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result arguments = StoreArgumentsObject(false); 4644a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&arguments); 4645a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 4646a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&value); 4647a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4648a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return; 4649a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4650a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4651a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The loaded value is in a register. If it is the sentinel that 4652a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // indicates that we haven't loaded the arguments object yet, we 4653a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // need to do it now. 4654a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget exit; 4655a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CompareRoot(value.reg(), Heap::kTheHoleValueRootIndex); 4656a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&value); 4657a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exit.Branch(not_equal); 4658a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result arguments = StoreArgumentsObject(false); 4659a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->SetElementAt(0, &arguments); 4660a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exit.Bind(); 4661a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 4662a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4663a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4664a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) { 4665a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (slot->type() == Slot::LOOKUP) { 4666a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(slot->var()->is_dynamic()); 4667a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4668a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // For now, just do a runtime call. Since the call is inevitable, 4669a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // we eagerly sync the virtual frame so we can directly push the 4670a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // arguments into place. 4671a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->SyncRange(0, frame_->element_count() - 1); 4672a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4673a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(rsi); 4674a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(slot->var()->name()); 4675a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4676a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result value; 4677a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (init_state == CONST_INIT) { 4678a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Same as the case for a normal store, but ignores attribute 4679a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // (e.g. READ_ONLY) of context slot so that we can initialize const 4680a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // properties (introduced via eval("const foo = (some expr);")). Also, 4681a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // uses the current function context instead of the top context. 4682a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // 4683a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Note that we must declare the foo upon entry of eval(), via a 4684a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // context slot declaration, but we cannot initialize it at the same 4685a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // time, because the const declaration may be at the end of the eval 4686a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // code (sigh...) and the const variable may have been used before 4687a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // (where its value is 'undefined'). Thus, we can only do the 4688a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // initialization when we actually encounter the expression and when 4689a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // the expression operands are defined and valid, and thus we need the 4690a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // split into 2 operations: declaration of the context slot followed 4691a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // by initialization. 4692a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block value = frame_->CallRuntime(Runtime::kInitializeConstContextSlot, 3); 4693a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 4694a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block value = frame_->CallRuntime(Runtime::kStoreContextSlot, 3); 4695a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4696a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Storing a variable must keep the (new) value on the expression 4697a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // stack. This is necessary for compiling chained assignment 4698a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // expressions. 4699a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&value); 4700a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 4701a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!slot->var()->is_dynamic()); 4702a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4703a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget exit; 4704a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (init_state == CONST_INIT) { 4705a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(slot->var()->mode() == Variable::CONST); 4706a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Only the first const initialization must be executed (the slot 4707a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // still contains 'the hole' value). When the assignment is executed, 4708a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // the code is identical to a normal store (see below). 4709a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // 4710a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We spill the frame in the code below because the direct-frame 4711a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // access of SlotOperand is potentially unsafe with an unspilled 4712a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // frame. 4713a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block VirtualFrame::SpilledScope spilled_scope; 4714a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ Init const"); 4715a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rcx, SlotOperand(slot, rcx)); 4716a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CompareRoot(rcx, Heap::kTheHoleValueRootIndex); 4717a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exit.Branch(not_equal); 4718a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4719a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4720a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We must execute the store. Storing a variable must keep the (new) 4721a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // value on the stack. This is necessary for compiling assignment 4722a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // expressions. 4723a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // 4724a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Note: We will reach here even with slot->var()->mode() == 4725a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Variable::CONST because of const declarations which will initialize 4726a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // consts to 'the hole' value and by doing so, end up calling this code. 4727a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (slot->type() == Slot::PARAMETER) { 4728a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->StoreToParameterAt(slot->index()); 4729a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (slot->type() == Slot::LOCAL) { 4730a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->StoreToLocalAt(slot->index()); 4731a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 4732a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The other slot types (LOOKUP and GLOBAL) cannot reach here. 4733a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // 4734a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The use of SlotOperand below is safe for an unspilled frame 4735a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // because the slot is a context slot. 4736a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(slot->type() == Slot::CONTEXT); 4737a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Dup(); 4738a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result value = frame_->Pop(); 4739a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block value.ToRegister(); 4740a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result start = allocator_->Allocate(); 4741a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(start.is_valid()); 4742a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(SlotOperand(slot, start.reg()), value.reg()); 4743a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // RecordWrite may destroy the value registers. 4744a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // 4745a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // TODO(204): Avoid actually spilling when the value is not 4746a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // needed (probably the common case). 4747a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Spill(value.reg()); 4748a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; 4749a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result temp = allocator_->Allocate(); 4750a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(temp.is_valid()); 4751a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ RecordWrite(start.reg(), offset, value.reg(), temp.reg()); 4752a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The results start, value, and temp are unused by going out of 4753a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // scope. 4754a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4755a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4756a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exit.Bind(); 4757a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4758a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 4759a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4760a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4761a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockResult CodeGenerator::LoadFromGlobalSlotCheckExtensions( 4762a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Slot* slot, 4763a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block TypeofState typeof_state, 4764a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget* slow) { 4765a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that no extension objects have been created by calls to 4766a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // eval from the current scope to the global scope. 4767a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register context = rsi; 4768a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result tmp = allocator_->Allocate(); 4769a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(tmp.is_valid()); // All non-reserved registers were available. 4770a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4771a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Scope* s = scope(); 4772a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block while (s != NULL) { 4773a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (s->num_heap_slots() > 0) { 4774a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (s->calls_eval()) { 4775a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that extension is NULL. 4776a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), 4777a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Immediate(0)); 4778a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block slow->Branch(not_equal, not_taken); 4779a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4780a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load next context in chain. 4781a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(tmp.reg(), ContextOperand(context, Context::CLOSURE_INDEX)); 4782a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(tmp.reg(), FieldOperand(tmp.reg(), JSFunction::kContextOffset)); 4783a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block context = tmp.reg(); 4784a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4785a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If no outer scope calls eval, we do not need to check more 4786a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // context extensions. If we have reached an eval scope, we check 4787a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // all extensions from this point. 4788a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break; 4789a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block s = s->outer_scope(); 4790a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4791a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4792a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (s->is_eval_scope()) { 4793a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Loop up the context chain. There is no frame effect so it is 4794a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // safe to use raw labels here. 4795a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label next, fast; 4796a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!context.is(tmp.reg())) { 4797a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(tmp.reg(), context); 4798a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4799a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load map for comparison into register, outside loop. 4800a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ LoadRoot(kScratchRegister, Heap::kGlobalContextMapRootIndex); 4801a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&next); 4802a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Terminate at global context. 4803a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ cmpq(kScratchRegister, FieldOperand(tmp.reg(), HeapObject::kMapOffset)); 4804a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(equal, &fast); 4805a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that extension is NULL. 4806a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ cmpq(ContextOperand(tmp.reg(), Context::EXTENSION_INDEX), Immediate(0)); 4807a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block slow->Branch(not_equal); 4808a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load next context in chain. 4809a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(tmp.reg(), ContextOperand(tmp.reg(), Context::CLOSURE_INDEX)); 4810a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(tmp.reg(), FieldOperand(tmp.reg(), JSFunction::kContextOffset)); 4811a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ jmp(&next); 4812a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&fast); 4813a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4814a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block tmp.Unuse(); 4815a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4816a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // All extension objects were empty and it is safe to use a global 4817a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // load IC call. 4818a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block LoadGlobal(); 4819a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(slot->var()->name()); 4820a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) 4821a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ? RelocInfo::CODE_TARGET 4822a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block : RelocInfo::CODE_TARGET_CONTEXT; 4823a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result answer = frame_->CallLoadIC(mode); 4824a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // A test rax instruction following the call signals that the inobject 4825a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // property case was inlined. Ensure that there is not a test rax 4826a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // instruction here. 4827a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block masm_->nop(); 4828a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Discard the global object. The result is in answer. 4829a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Drop(); 4830a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return answer; 4831a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 4832a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4833a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4834a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::LoadGlobal() { 4835a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (in_spilled_code()) { 4836a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->EmitPush(GlobalObject()); 4837a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 4838a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result temp = allocator_->Allocate(); 4839a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(temp.reg(), GlobalObject()); 4840a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&temp); 4841a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4842a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 4843a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4844a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4845a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::LoadGlobalReceiver() { 4846a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result temp = allocator_->Allocate(); 4847a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register reg = temp.reg(); 4848a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(reg, GlobalObject()); 4849a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(reg, FieldOperand(reg, GlobalObject::kGlobalReceiverOffset)); 4850a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&temp); 4851a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 4852a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4853a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 48543100271588b61cbc1dc472a3f2f105d2eed8497fAndrei PopescuArgumentsAllocationMode CodeGenerator::ArgumentsMode() { 48553100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu if (scope()->arguments() == NULL) return NO_ARGUMENTS_ALLOCATION; 48563100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu ASSERT(scope()->arguments_shadow() != NULL); 4857a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We don't want to do lazy arguments allocation for functions that 4858a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // have heap-allocated contexts, because it interfers with the 4859a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // uninitialized const tracking in the context objects. 48603100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu return (scope()->num_heap_slots() > 0) 4861a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ? EAGER_ARGUMENTS_ALLOCATION 4862a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block : LAZY_ARGUMENTS_ALLOCATION; 4863a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 4864a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4865a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4866a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockResult CodeGenerator::StoreArgumentsObject(bool initial) { 4867a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ArgumentsAllocationMode mode = ArgumentsMode(); 4868a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(mode != NO_ARGUMENTS_ALLOCATION); 4869a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4870a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ store arguments object"); 4871a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (mode == LAZY_ARGUMENTS_ALLOCATION && initial) { 4872a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // When using lazy arguments allocation, we store the hole value 4873a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // as a sentinel indicating that the arguments object hasn't been 4874a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // allocated yet. 4875a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(Factory::the_hole_value()); 4876a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 4877a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); 4878a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->PushFunction(); 4879a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->PushReceiverSlotAddress(); 48803100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu frame_->Push(Smi::FromInt(scope()->num_parameters())); 4881a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result result = frame_->CallStub(&stub, 3); 4882a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&result); 4883a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4884a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4885e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 48863100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu Variable* arguments = scope()->arguments()->var(); 48873100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu Variable* shadow = scope()->arguments_shadow()->var(); 4888e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke ASSERT(arguments != NULL && arguments->slot() != NULL); 4889e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke ASSERT(shadow != NULL && shadow->slot() != NULL); 4890e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke JumpTarget done; 4891e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke bool skip_arguments = false; 4892e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke if (mode == LAZY_ARGUMENTS_ALLOCATION && !initial) { 4893e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // We have to skip storing into the arguments slot if it has 4894e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // already been written to. This can happen if the a function 4895e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // has a local variable named 'arguments'. 48963100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu LoadFromSlot(scope()->arguments()->var()->slot(), NOT_INSIDE_TYPEOF); 4897e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Result probe = frame_->Pop(); 4898e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke if (probe.is_constant()) { 4899e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // We have to skip updating the arguments object if it has been 4900e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // assigned a proper value. 4901e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke skip_arguments = !probe.handle()->IsTheHole(); 4902e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } else { 4903e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ CompareRoot(probe.reg(), Heap::kTheHoleValueRootIndex); 4904e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke probe.Unuse(); 4905e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke done.Branch(not_equal); 4906a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4907a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4908e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke if (!skip_arguments) { 4909e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke StoreToSlot(arguments->slot(), NOT_CONST_INIT); 4910e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke if (mode == LAZY_ARGUMENTS_ALLOCATION) done.Bind(); 4911e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } 4912e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke StoreToSlot(shadow->slot(), NOT_CONST_INIT); 4913a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return frame_->Pop(); 4914a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 4915a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4916a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4917d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid CodeGenerator::LoadTypeofExpression(Expression* expr) { 4918d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Special handling of identifiers as subexpressions of typeof. 4919d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Variable* variable = expr->AsVariableProxy()->AsVariable(); 4920a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (variable != NULL && !variable->is_this() && variable->is_global()) { 4921d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // For a global variable we build the property reference 4922d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // <global>.<variable> and perform a (regular non-contextual) property 4923d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // load to make sure we do not get reference errors. 4924a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX); 4925a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Literal key(variable->name()); 4926a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Property property(&global, &key, RelocInfo::kNoPosition); 4927d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Reference ref(this, &property); 4928d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block ref.GetValue(); 4929d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } else if (variable != NULL && variable->slot() != NULL) { 4930d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // For a variable that rewrites to a slot, we signal it is the immediate 4931d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // subexpression of a typeof. 4932d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block LoadFromSlotCheckForArguments(variable->slot(), INSIDE_TYPEOF); 4933a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 4934d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Anything else can be handled normally. 4935d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Load(expr); 4936a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4937a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 4938a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4939a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4940402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescuvoid CodeGenerator::Comparison(AstNode* node, 4941402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Condition cc, 4942a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool strict, 4943a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ControlDestination* dest) { 4944a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Strict only makes sense for equality comparisons. 4945a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!strict || cc == equal); 4946a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4947a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result left_side; 4948a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result right_side; 4949a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. 4950a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (cc == greater || cc == less_equal) { 4951a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block cc = ReverseCondition(cc); 4952a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block left_side = frame_->Pop(); 4953a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block right_side = frame_->Pop(); 4954a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 4955a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block right_side = frame_->Pop(); 4956a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block left_side = frame_->Pop(); 4957a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4958a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(cc == less || cc == equal || cc == greater_equal); 4959a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4960a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If either side is a constant smi, optimize the comparison. 4961a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool left_side_constant_smi = 4962a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block left_side.is_constant() && left_side.handle()->IsSmi(); 4963a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool right_side_constant_smi = 4964a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block right_side.is_constant() && right_side.handle()->IsSmi(); 4965a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool left_side_constant_null = 4966a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block left_side.is_constant() && left_side.handle()->IsNull(); 4967a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool right_side_constant_null = 4968a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block right_side.is_constant() && right_side.handle()->IsNull(); 4969a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4970a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (left_side_constant_smi || right_side_constant_smi) { 4971a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (left_side_constant_smi && right_side_constant_smi) { 4972a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Trivial case, comparing two constants. 4973a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int left_value = Smi::cast(*left_side.handle())->value(); 4974a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int right_value = Smi::cast(*right_side.handle())->value(); 4975a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block switch (cc) { 4976a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case less: 4977a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block dest->Goto(left_value < right_value); 4978a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 4979a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case equal: 4980a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block dest->Goto(left_value == right_value); 4981a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 4982a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case greater_equal: 4983a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block dest->Goto(left_value >= right_value); 4984a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 4985a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block default: 4986a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block UNREACHABLE(); 4987a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4988402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu } else { 4989402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Only one side is a constant Smi. 4990a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If left side is a constant Smi, reverse the operands. 4991a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Since one side is a constant Smi, conversion order does not matter. 4992a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (left_side_constant_smi) { 4993a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result temp = left_side; 4994a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block left_side = right_side; 4995a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block right_side = temp; 4996a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block cc = ReverseCondition(cc); 4997a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // This may reintroduce greater or less_equal as the value of cc. 4998a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // CompareStub and the inline code both support all values of cc. 4999a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5000a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Implement comparison against a constant Smi, inlining the case 5001a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // where both sides are Smis. 5002a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block left_side.ToRegister(); 5003402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Register left_reg = left_side.reg(); 5004402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Handle<Object> right_val = right_side.handle(); 5005a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5006a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Here we split control flow to the stub call and inlined cases 5007a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // before finally splitting it to the control destination. We use 5008a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // a jump target and branching to duplicate the virtual frame at 5009a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // the first split. We manually handle the off-frame references 5010a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // by reconstituting them on the non-fall-through path. 5011a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget is_smi; 5012a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5013a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Condition left_is_smi = masm_->CheckSmi(left_side.reg()); 5014a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block is_smi.Branch(left_is_smi); 5015a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5016402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu bool is_for_loop_compare = (node->AsCompareOperation() != NULL) 5017402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu && node->AsCompareOperation()->is_for_loop_condition(); 5018402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu if (!is_for_loop_compare && right_val->IsSmi()) { 5019402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Right side is a constant smi and left side has been checked 5020402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // not to be a smi. 5021402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu JumpTarget not_number; 5022402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ Cmp(FieldOperand(left_reg, HeapObject::kMapOffset), 5023402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Factory::heap_number_map()); 5024402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu not_number.Branch(not_equal, &left_side); 5025402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ movsd(xmm1, 5026402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu FieldOperand(left_reg, HeapNumber::kValueOffset)); 5027402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu int value = Smi::cast(*right_val)->value(); 5028402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu if (value == 0) { 5029402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ xorpd(xmm0, xmm0); 5030402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu } else { 5031402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Result temp = allocator()->Allocate(); 5032402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ movl(temp.reg(), Immediate(value)); 5033402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ cvtlsi2sd(xmm0, temp.reg()); 5034402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu temp.Unuse(); 5035402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu } 5036402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ ucomisd(xmm1, xmm0); 5037402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Jump to builtin for NaN. 5038402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu not_number.Branch(parity_even, &left_side); 5039402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu left_side.Unuse(); 5040402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Condition double_cc = cc; 5041402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu switch (cc) { 5042402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu case less: double_cc = below; break; 5043402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu case equal: double_cc = equal; break; 5044402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu case less_equal: double_cc = below_equal; break; 5045402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu case greater: double_cc = above; break; 5046402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu case greater_equal: double_cc = above_equal; break; 5047402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu default: UNREACHABLE(); 5048402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu } 5049402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu dest->true_target()->Branch(double_cc); 5050402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu dest->false_target()->Jump(); 5051402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu not_number.Bind(&left_side); 5052402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu } 5053402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 5054a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Setup and call the compare stub. 5055a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CompareStub stub(cc, strict); 5056a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result result = frame_->CallStub(&stub, &left_side, &right_side); 5057a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block result.ToRegister(); 5058a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ testq(result.reg(), result.reg()); 5059a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block result.Unuse(); 5060a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block dest->true_target()->Branch(cc); 5061a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block dest->false_target()->Jump(); 5062a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5063a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block is_smi.Bind(); 5064a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block left_side = Result(left_reg); 5065a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block right_side = Result(right_val); 5066a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Test smi equality and comparison by signed int comparison. 5067a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Both sides are smis, so we can use an Immediate. 50683ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ SmiCompare(left_side.reg(), Smi::cast(*right_side.handle())); 5069a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block left_side.Unuse(); 5070a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block right_side.Unuse(); 5071a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block dest->Split(cc); 5072a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5073a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (cc == equal && 5074a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block (left_side_constant_null || right_side_constant_null)) { 5075a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // To make null checks efficient, we check if either the left side or 5076a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // the right side is the constant 'null'. 5077a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If so, we optimize the code by inlining a null check instead of 5078a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // calling the (very) general runtime routine for checking equality. 5079a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result operand = left_side_constant_null ? right_side : left_side; 5080a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block right_side.Unuse(); 5081a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block left_side.Unuse(); 5082a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block operand.ToRegister(); 5083a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CompareRoot(operand.reg(), Heap::kNullValueRootIndex); 5084a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (strict) { 5085a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block operand.Unuse(); 5086a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block dest->Split(equal); 5087a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 5088a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The 'null' value is only equal to 'undefined' if using non-strict 5089a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // comparisons. 5090a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block dest->true_target()->Branch(equal); 5091a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CompareRoot(operand.reg(), Heap::kUndefinedValueRootIndex); 5092a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block dest->true_target()->Branch(equal); 5093a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Condition is_smi = masm_->CheckSmi(operand.reg()); 5094a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block dest->false_target()->Branch(is_smi); 5095a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5096a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // It can be an undetectable object. 5097a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Use a scratch register in preference to spilling operand.reg(). 5098a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result temp = allocator()->Allocate(); 5099a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(temp.is_valid()); 5100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(temp.reg(), 51013ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block FieldOperand(operand.reg(), HeapObject::kMapOffset)); 5102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ testb(FieldOperand(temp.reg(), Map::kBitFieldOffset), 5103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Immediate(1 << Map::kIsUndetectable)); 5104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block temp.Unuse(); 5105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block operand.Unuse(); 5106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block dest->Split(not_zero); 5107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { // Neither side is a constant Smi or null. 5109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If either side is a non-smi constant, skip the smi check. 5110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool known_non_smi = 5111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block (left_side.is_constant() && !left_side.handle()->IsSmi()) || 5112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block (right_side.is_constant() && !right_side.handle()->IsSmi()); 5113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block left_side.ToRegister(); 5114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block right_side.ToRegister(); 5115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (known_non_smi) { 5117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // When non-smi, call out to the compare stub. 5118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CompareStub stub(cc, strict); 5119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result answer = frame_->CallStub(&stub, &left_side, &right_side); 5120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The result is a Smi, which is negative, zero, or positive. 51213ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ SmiTest(answer.reg()); // Sets both zero and sign flag. 5122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block answer.Unuse(); 5123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block dest->Split(cc); 5124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 5125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Here we split control flow to the stub call and inlined cases 5126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // before finally splitting it to the control destination. We use 5127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // a jump target and branching to duplicate the virtual frame at 5128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // the first split. We manually handle the off-frame references 5129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // by reconstituting them on the non-fall-through path. 5130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JumpTarget is_smi; 5131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register left_reg = left_side.reg(); 5132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register right_reg = right_side.reg(); 5133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Condition both_smi = masm_->CheckBothSmi(left_reg, right_reg); 5135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block is_smi.Branch(both_smi); 5136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // When non-smi, call out to the compare stub. 5137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CompareStub stub(cc, strict); 5138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result answer = frame_->CallStub(&stub, &left_side, &right_side); 51393ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ SmiTest(answer.reg()); // Sets both zero and sign flags. 5140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block answer.Unuse(); 5141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block dest->true_target()->Branch(cc); 5142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block dest->false_target()->Jump(); 5143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block is_smi.Bind(); 5145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block left_side = Result(left_reg); 5146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block right_side = Result(right_reg); 51473ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ SmiCompare(left_side.reg(), right_side.reg()); 5148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block right_side.Unuse(); 5149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block left_side.Unuse(); 5150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block dest->Split(cc); 5151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 5154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass DeferredInlineBinaryOperation: public DeferredCode { 5157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public: 5158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block DeferredInlineBinaryOperation(Token::Value op, 5159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register dst, 5160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register left, 5161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register right, 5162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block OverwriteMode mode) 5163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block : op_(op), dst_(dst), left_(left), right_(right), mode_(mode) { 5164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block set_comment("[ DeferredInlineBinaryOperation"); 5165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block virtual void Generate(); 5168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private: 5170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Token::Value op_; 5171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register dst_; 5172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register left_; 5173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register right_; 5174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block OverwriteMode mode_; 5175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 5176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DeferredInlineBinaryOperation::Generate() { 5179d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block GenericBinaryOpStub stub(op_, mode_, NO_SMI_CODE_IN_STUB); 5180d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block stub.GenerateCall(masm_, left_, right_); 5181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!dst_.is(rax)) __ movq(dst_, rax); 5182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 5183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenericBinaryOperation(Token::Value op, 5186e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke StaticType* type, 5187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block OverwriteMode overwrite_mode) { 5188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm_, "[ BinaryOperation"); 5189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt_token(masm_, Token::String(op)); 5190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (op == Token::COMMA) { 5192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Simply discard left value. 5193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Nip(1); 5194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return; 5195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result right = frame_->Pop(); 5198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result left = frame_->Pop(); 5199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (op == Token::ADD) { 5201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool left_is_string = left.is_constant() && left.handle()->IsString(); 5202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool right_is_string = right.is_constant() && right.handle()->IsString(); 5203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (left_is_string || right_is_string) { 5204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&left); 5205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&right); 5206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result answer; 5207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (left_is_string) { 5208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (right_is_string) { 5209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // TODO(lrn): if both are constant strings 5210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- do a compile time cons, if allocation during codegen is allowed. 5211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block answer = frame_->CallRuntime(Runtime::kStringAdd, 2); 5212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 5213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block answer = 5214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->InvokeBuiltin(Builtins::STRING_ADD_LEFT, CALL_FUNCTION, 2); 5215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (right_is_string) { 5217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block answer = 5218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->InvokeBuiltin(Builtins::STRING_ADD_RIGHT, CALL_FUNCTION, 2); 5219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(&answer); 5221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return; 5222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Neither operand is known to be a string. 5224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5226402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu bool left_is_smi_constant = left.is_constant() && left.handle()->IsSmi(); 5227402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu bool left_is_non_smi_constant = left.is_constant() && !left.handle()->IsSmi(); 5228402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu bool right_is_smi_constant = right.is_constant() && right.handle()->IsSmi(); 5229402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu bool right_is_non_smi_constant = 5230402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu right.is_constant() && !right.handle()->IsSmi(); 5231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5232402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu if (left_is_smi_constant && right_is_smi_constant) { 5233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Compute the constant result at compile time, and leave it on the frame. 5234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int left_int = Smi::cast(*left.handle())->value(); 5235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int right_int = Smi::cast(*right.handle())->value(); 5236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (FoldConstantSmis(op, left_int, right_int)) return; 5237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5239402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Get number type of left and right sub-expressions. 5240402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu NumberInfo::Type operands_type = 5241402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu NumberInfo::Combine(left.number_info(), right.number_info()); 5242402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 5243d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Result answer; 5244402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu if (left_is_non_smi_constant || right_is_non_smi_constant) { 5245402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu GenericBinaryOpStub stub(op, 5246402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu overwrite_mode, 5247402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu NO_SMI_CODE_IN_STUB, 5248402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu operands_type); 52494515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke answer = stub.GenerateCall(masm_, frame_, &left, &right); 5250402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu } else if (right_is_smi_constant) { 5251d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke answer = ConstantSmiBinaryOperation(op, &left, right.handle(), 5252d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke type, false, overwrite_mode); 5253402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu } else if (left_is_smi_constant) { 5254d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke answer = ConstantSmiBinaryOperation(op, &right, left.handle(), 5255d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke type, true, overwrite_mode); 5256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 5257d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Set the flags based on the operation, type and loop nesting level. 5258d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Bit operations always assume they likely operate on Smis. Still only 5259d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // generate the inline Smi check code if this operation is part of a loop. 5260d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // For all other operations only inline the Smi check code for likely smis 5261d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // if the operation is part of a loop. 5262d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke if (loop_nesting() > 0 && (Token::IsBitOp(op) || type->IsLikelySmi())) { 5263d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke answer = LikelySmiBinaryOperation(op, &left, &right, overwrite_mode); 5264d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke } else { 5265402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu GenericBinaryOpStub stub(op, 5266402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu overwrite_mode, 5267402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu NO_GENERIC_BINARY_FLAGS, 5268402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu operands_type); 52694515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke answer = stub.GenerateCall(masm_, frame_, &left, &right); 5270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5272402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 5273402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Set NumberInfo of result according to the operation performed. 5274402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // We rely on the fact that smis have a 32 bit payload on x64. 5275402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu ASSERT(kSmiValueSize == 32); 5276402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu NumberInfo::Type result_type = NumberInfo::kUnknown; 5277402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu switch (op) { 5278402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu case Token::COMMA: 5279402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu result_type = right.number_info(); 5280402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu break; 5281402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu case Token::OR: 5282402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu case Token::AND: 5283402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Result type can be either of the two input types. 5284402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu result_type = operands_type; 5285402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu break; 5286402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu case Token::BIT_OR: 5287402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu case Token::BIT_XOR: 5288402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu case Token::BIT_AND: 5289402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Result is always a smi. 5290402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu result_type = NumberInfo::kSmi; 5291402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu break; 5292402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu case Token::SAR: 5293402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu case Token::SHL: 5294402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Result is always a smi. 5295402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu result_type = NumberInfo::kSmi; 5296402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu break; 5297402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu case Token::SHR: 5298402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Result of x >>> y is always a smi if y >= 1, otherwise a number. 5299402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu result_type = (right.is_constant() && right.handle()->IsSmi() 5300402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu && Smi::cast(*right.handle())->value() >= 1) 5301402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu ? NumberInfo::kSmi 5302402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu : NumberInfo::kNumber; 5303402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu break; 5304402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu case Token::ADD: 5305402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Result could be a string or a number. Check types of inputs. 5306402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu result_type = NumberInfo::IsNumber(operands_type) 5307402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu ? NumberInfo::kNumber 5308402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu : NumberInfo::kUnknown; 5309402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu break; 5310402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu case Token::SUB: 5311402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu case Token::MUL: 5312402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu case Token::DIV: 5313402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu case Token::MOD: 5314402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Result is always a number. 5315402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu result_type = NumberInfo::kNumber; 5316402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu break; 5317402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu default: 5318402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu UNREACHABLE(); 5319402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu } 5320402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu answer.set_number_info(result_type); 5321d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke frame_->Push(&answer); 5322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 5323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5325a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Emit a LoadIC call to get the value from receiver and leave it in 5326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// dst. The receiver register is restored after the call. 5327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass DeferredReferenceGetNamedValue: public DeferredCode { 5328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public: 5329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block DeferredReferenceGetNamedValue(Register dst, 5330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register receiver, 5331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<String> name) 5332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block : dst_(dst), receiver_(receiver), name_(name) { 5333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block set_comment("[ DeferredReferenceGetNamedValue"); 5334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block virtual void Generate(); 5337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label* patch_site() { return &patch_site_; } 5339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private: 5341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label patch_site_; 5342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register dst_; 5343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register receiver_; 5344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<String> name_; 5345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 5346a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DeferredReferenceGetNamedValue::Generate() { 5349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(receiver_); 5350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Move(rcx, name_); 5351a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); 5352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Call(ic, RelocInfo::CODE_TARGET); 5353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The call must be followed by a test rax instruction to indicate 5354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // that the inobject property case was inlined. 5355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // 5356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Store the delta to the map check instruction here in the test 5357a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // instruction. Use masm_-> instead of the __ macro since the 5358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // latter can't return a value. 5359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); 5360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Here we use masm_-> instead of the __ macro because this is the 5361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // instruction that gets patched and coverage code gets in the way. 5362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block masm_->testl(rax, Immediate(-delta_to_patch_site)); 5363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ IncrementCounter(&Counters::named_load_inline_miss, 1); 5364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!dst_.is(rax)) __ movq(dst_, rax); 5366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(receiver_); 5367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 5368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DeferredInlineSmiAdd::Generate() { 5371d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block GenericBinaryOpStub igostub(Token::ADD, overwrite_mode_, NO_SMI_CODE_IN_STUB); 5372d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block igostub.GenerateCall(masm_, dst_, value_); 5373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!dst_.is(rax)) __ movq(dst_, rax); 5374a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 5375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DeferredInlineSmiAddReversed::Generate() { 5378d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block GenericBinaryOpStub igostub(Token::ADD, overwrite_mode_, NO_SMI_CODE_IN_STUB); 5379d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block igostub.GenerateCall(masm_, value_, dst_); 5380a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!dst_.is(rax)) __ movq(dst_, rax); 5381a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 5382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DeferredInlineSmiSub::Generate() { 5385d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block GenericBinaryOpStub igostub(Token::SUB, overwrite_mode_, NO_SMI_CODE_IN_STUB); 5386d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block igostub.GenerateCall(masm_, dst_, value_); 5387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!dst_.is(rax)) __ movq(dst_, rax); 5388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 5389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DeferredInlineSmiOperation::Generate() { 5392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // For mod we don't generate all the Smi code inline. 5393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GenericBinaryOpStub stub( 5394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block op_, 5395a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block overwrite_mode_, 5396d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block (op_ == Token::MOD) ? NO_GENERIC_BINARY_FLAGS : NO_SMI_CODE_IN_STUB); 5397d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block stub.GenerateCall(masm_, src_, value_); 5398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!dst_.is(rax)) __ movq(dst_, rax); 5399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 5400a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5402d91b9f7d46489a9ee00f9cb415630299c76a502bLeon ClarkeResult CodeGenerator::ConstantSmiBinaryOperation(Token::Value op, 5403d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Result* operand, 5404d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Handle<Object> value, 5405d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke StaticType* type, 5406d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke bool reversed, 5407d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke OverwriteMode overwrite_mode) { 5408a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // NOTE: This is an attempt to inline (a bit) more of the code for 5409a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // some possible smi operations (like + and -) when (at least) one 5410a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // of the operands is a constant smi. 5411a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Consumes the argument "operand". 5412a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5413a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // TODO(199): Optimize some special cases of operations involving a 5414a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // smi literal (multiply by 2, shift by 0, etc.). 5415a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (IsUnsafeSmi(value)) { 5416a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result unsafe_operand(value); 5417a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (reversed) { 5418d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke return LikelySmiBinaryOperation(op, &unsafe_operand, operand, 5419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block overwrite_mode); 5420a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 5421d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke return LikelySmiBinaryOperation(op, operand, &unsafe_operand, 5422a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block overwrite_mode); 5423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5424a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5426a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the literal value. 5427a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Smi* smi_value = Smi::cast(*value); 5428a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int int_value = smi_value->value(); 5429a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5430d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Result answer; 5431a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block switch (op) { 5432a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::ADD: { 5433a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block operand->ToRegister(); 5434a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Spill(operand->reg()); 5435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block DeferredCode* deferred = NULL; 5436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (reversed) { 5437a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block deferred = new DeferredInlineSmiAddReversed(operand->reg(), 5438a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block smi_value, 5439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block overwrite_mode); 5440a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 5441a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block deferred = new DeferredInlineSmiAdd(operand->reg(), 5442a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block smi_value, 5443a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block overwrite_mode); 5444a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5445a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfNotSmi(operand->reg(), deferred->entry_label()); 5446a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ SmiAddConstant(operand->reg(), 5447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block operand->reg(), 54483ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block smi_value, 5449a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block deferred->entry_label()); 5450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block deferred->BindExit(); 5451d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke answer = *operand; 5452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 5453a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::SUB: { 5456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (reversed) { 5457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result constant_operand(value); 5458d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke answer = LikelySmiBinaryOperation(op, &constant_operand, operand, 5459d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke overwrite_mode); 5460a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 5461a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block operand->ToRegister(); 5462a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Spill(operand->reg()); 5463a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block DeferredCode* deferred = new DeferredInlineSmiSub(operand->reg(), 5464a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block smi_value, 5465a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block overwrite_mode); 5466a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfNotSmi(operand->reg(), deferred->entry_label()); 5467a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // A smi currently fits in a 32-bit Immediate. 5468a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ SmiSubConstant(operand->reg(), 5469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block operand->reg(), 54703ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block smi_value, 5471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block deferred->entry_label()); 5472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block deferred->BindExit(); 5473d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke answer = *operand; 5474a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 5476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5478a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::SAR: 5479a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (reversed) { 5480a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result constant_operand(value); 5481d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke answer = LikelySmiBinaryOperation(op, &constant_operand, operand, 5482d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke overwrite_mode); 5483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 5484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Only the least significant 5 bits of the shift value are used. 5485a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // In the slow case, this masking is done inside the runtime call. 5486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int shift_value = int_value & 0x1f; 5487a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block operand->ToRegister(); 5488a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Spill(operand->reg()); 5489a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block DeferredInlineSmiOperation* deferred = 5490a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block new DeferredInlineSmiOperation(op, 5491a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block operand->reg(), 5492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block operand->reg(), 5493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block smi_value, 5494a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block overwrite_mode); 5495a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfNotSmi(operand->reg(), deferred->entry_label()); 5496a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ SmiShiftArithmeticRightConstant(operand->reg(), 5497a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block operand->reg(), 5498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block shift_value); 5499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block deferred->BindExit(); 5500d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke answer = *operand; 5501a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5502a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 5503a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5504a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::SHR: 5505a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (reversed) { 5506a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result constant_operand(value); 5507d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke answer = LikelySmiBinaryOperation(op, &constant_operand, operand, 5508d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke overwrite_mode); 5509a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 5510a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Only the least significant 5 bits of the shift value are used. 5511a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // In the slow case, this masking is done inside the runtime call. 5512a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int shift_value = int_value & 0x1f; 5513a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block operand->ToRegister(); 5514d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke answer = allocator()->Allocate(); 5515a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(answer.is_valid()); 5516a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block DeferredInlineSmiOperation* deferred = 5517a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block new DeferredInlineSmiOperation(op, 5518a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block answer.reg(), 5519a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block operand->reg(), 5520a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block smi_value, 5521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block overwrite_mode); 5522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfNotSmi(operand->reg(), deferred->entry_label()); 5523a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ SmiShiftLogicalRightConstant(answer.reg(), 55243ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block operand->reg(), 55253ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block shift_value, 55263ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block deferred->entry_label()); 5527a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block deferred->BindExit(); 5528a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block operand->Unuse(); 5529a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5530a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 5531a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5532a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::SHL: 5533a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (reversed) { 5534a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result constant_operand(value); 5535d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke answer = LikelySmiBinaryOperation(op, &constant_operand, operand, 5536d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke overwrite_mode); 5537a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 5538a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Only the least significant 5 bits of the shift value are used. 5539a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // In the slow case, this masking is done inside the runtime call. 5540a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int shift_value = int_value & 0x1f; 5541a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block operand->ToRegister(); 5542a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (shift_value == 0) { 5543a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Spill operand so it can be overwritten in the slow case. 5544a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Spill(operand->reg()); 5545a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block DeferredInlineSmiOperation* deferred = 5546a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block new DeferredInlineSmiOperation(op, 5547a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block operand->reg(), 5548a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block operand->reg(), 5549a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block smi_value, 5550a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block overwrite_mode); 5551a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfNotSmi(operand->reg(), deferred->entry_label()); 5552a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block deferred->BindExit(); 5553d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke answer = *operand; 5554a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 5555a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Use a fresh temporary for nonzero shift values. 5556d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke answer = allocator()->Allocate(); 5557a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(answer.is_valid()); 5558a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block DeferredInlineSmiOperation* deferred = 5559a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block new DeferredInlineSmiOperation(op, 5560a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block answer.reg(), 5561a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block operand->reg(), 5562a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block smi_value, 5563a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block overwrite_mode); 5564a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfNotSmi(operand->reg(), deferred->entry_label()); 5565a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ SmiShiftLeftConstant(answer.reg(), 5566a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block operand->reg(), 5567a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block shift_value, 5568a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block deferred->entry_label()); 5569a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block deferred->BindExit(); 5570a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block operand->Unuse(); 5571a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5572a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5573a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 5574a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5575a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::BIT_OR: 5576a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::BIT_XOR: 5577a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::BIT_AND: { 5578a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block operand->ToRegister(); 5579a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Spill(operand->reg()); 5580a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (reversed) { 5581a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Bit operations with a constant smi are commutative. 5582a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We can swap left and right operands with no problem. 5583a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Swap left and right overwrite modes. 0->0, 1->2, 2->1. 5584a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block overwrite_mode = static_cast<OverwriteMode>((2 * overwrite_mode) % 3); 5585a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5586a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block DeferredCode* deferred = new DeferredInlineSmiOperation(op, 5587a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block operand->reg(), 5588a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block operand->reg(), 5589a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block smi_value, 5590a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block overwrite_mode); 5591a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfNotSmi(operand->reg(), deferred->entry_label()); 5592a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (op == Token::BIT_AND) { 55933ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ SmiAndConstant(operand->reg(), operand->reg(), smi_value); 5594a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (op == Token::BIT_XOR) { 5595a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (int_value != 0) { 55963ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ SmiXorConstant(operand->reg(), operand->reg(), smi_value); 5597a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5598a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 5599a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(op == Token::BIT_OR); 5600a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (int_value != 0) { 56013ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ SmiOrConstant(operand->reg(), operand->reg(), smi_value); 5602a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5603a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5604a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block deferred->BindExit(); 5605d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke answer = *operand; 5606a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 5607a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5608a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5609a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Generate inline code for mod of powers of 2 and negative powers of 2. 5610a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::MOD: 5611a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!reversed && 5612a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int_value != 0 && 5613a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block (IsPowerOf2(int_value) || IsPowerOf2(-int_value))) { 5614a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block operand->ToRegister(); 5615a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Spill(operand->reg()); 56163ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block DeferredCode* deferred = 56173ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block new DeferredInlineSmiOperation(op, 56183ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block operand->reg(), 56193ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block operand->reg(), 56203ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block smi_value, 56213ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block overwrite_mode); 5622a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check for negative or non-Smi left hand side. 5623a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfNotPositiveSmi(operand->reg(), deferred->entry_label()); 5624a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (int_value < 0) int_value = -int_value; 5625a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (int_value == 1) { 56263ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ Move(operand->reg(), Smi::FromInt(0)); 5627a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 56283ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ SmiAndConstant(operand->reg(), 56293ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block operand->reg(), 56303ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block Smi::FromInt(int_value - 1)); 5631a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5632a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block deferred->BindExit(); 5633d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke answer = *operand; 5634a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; // This break only applies if we generated code for MOD. 5635a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5636a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Fall through if we did not find a power of 2 on the right hand side! 5637a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The next case must be the default. 5638a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5639a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block default: { 5640a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result constant_operand(value); 5641a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (reversed) { 5642d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke answer = LikelySmiBinaryOperation(op, &constant_operand, operand, 5643d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke overwrite_mode); 5644a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 5645d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke answer = LikelySmiBinaryOperation(op, operand, &constant_operand, 5646d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke overwrite_mode); 5647a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5648a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 5649a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5650a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5651d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke ASSERT(answer.is_valid()); 5652d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke return answer; 5653a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 5654a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5655d91b9f7d46489a9ee00f9cb415630299c76a502bLeon ClarkeResult CodeGenerator::LikelySmiBinaryOperation(Token::Value op, 5656d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Result* left, 5657d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Result* right, 5658d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke OverwriteMode overwrite_mode) { 5659d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Result answer; 5660a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Special handling of div and mod because they use fixed registers. 5661a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (op == Token::DIV || op == Token::MOD) { 5662a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We need rax as the quotient register, rdx as the remainder 5663a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // register, neither left nor right in rax or rdx, and left copied 5664a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // to rax. 5665a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result quotient; 5666a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result remainder; 5667a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool left_is_in_rax = false; 5668a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Step 1: get rax for quotient. 5669a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if ((left->is_register() && left->reg().is(rax)) || 5670a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block (right->is_register() && right->reg().is(rax))) { 5671a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // One or both is in rax. Use a fresh non-rdx register for 5672a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // them. 5673a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result fresh = allocator_->Allocate(); 5674a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(fresh.is_valid()); 5675a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (fresh.reg().is(rdx)) { 5676a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block remainder = fresh; 5677a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block fresh = allocator_->Allocate(); 5678a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(fresh.is_valid()); 5679a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5680a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (left->is_register() && left->reg().is(rax)) { 5681a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block quotient = *left; 5682a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block *left = fresh; 5683a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block left_is_in_rax = true; 5684a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5685a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (right->is_register() && right->reg().is(rax)) { 5686a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block quotient = *right; 5687a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block *right = fresh; 5688a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5689a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(fresh.reg(), rax); 5690a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 5691a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Neither left nor right is in rax. 5692a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block quotient = allocator_->Allocate(rax); 5693a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5694a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(quotient.is_register() && quotient.reg().is(rax)); 5695a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!(left->is_register() && left->reg().is(rax))); 5696a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!(right->is_register() && right->reg().is(rax))); 5697a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5698a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Step 2: get rdx for remainder if necessary. 5699a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!remainder.is_valid()) { 5700a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if ((left->is_register() && left->reg().is(rdx)) || 5701a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block (right->is_register() && right->reg().is(rdx))) { 5702a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result fresh = allocator_->Allocate(); 5703a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(fresh.is_valid()); 5704a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (left->is_register() && left->reg().is(rdx)) { 5705a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block remainder = *left; 5706a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block *left = fresh; 5707a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5708a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (right->is_register() && right->reg().is(rdx)) { 5709a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block remainder = *right; 5710a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block *right = fresh; 5711a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5712a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(fresh.reg(), rdx); 5713a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 5714a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Neither left nor right is in rdx. 5715a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block remainder = allocator_->Allocate(rdx); 5716a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5717a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5718a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(remainder.is_register() && remainder.reg().is(rdx)); 5719a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!(left->is_register() && left->reg().is(rdx))); 5720a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!(right->is_register() && right->reg().is(rdx))); 5721a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5722a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block left->ToRegister(); 5723a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block right->ToRegister(); 5724a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Spill(rax); 5725a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Spill(rdx); 5726a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5727a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that left and right are smi tagged. 5728a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block DeferredInlineBinaryOperation* deferred = 5729a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block new DeferredInlineBinaryOperation(op, 5730a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block (op == Token::DIV) ? rax : rdx, 5731a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block left->reg(), 5732a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block right->reg(), 5733a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block overwrite_mode); 5734a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfNotBothSmi(left->reg(), right->reg(), deferred->entry_label()); 5735a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5736a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (op == Token::DIV) { 5737a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ SmiDiv(rax, left->reg(), right->reg(), deferred->entry_label()); 5738a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block deferred->BindExit(); 5739a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block left->Unuse(); 5740a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block right->Unuse(); 5741d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke answer = quotient; 5742a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 5743a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(op == Token::MOD); 5744a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ SmiMod(rdx, left->reg(), right->reg(), deferred->entry_label()); 5745a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block deferred->BindExit(); 5746a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block left->Unuse(); 5747a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block right->Unuse(); 5748d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke answer = remainder; 5749a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5750d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke ASSERT(answer.is_valid()); 5751d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke return answer; 5752a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5753a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5754a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Special handling of shift operations because they use fixed 5755a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // registers. 5756a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (op == Token::SHL || op == Token::SHR || op == Token::SAR) { 5757a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Move left out of rcx if necessary. 5758a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (left->is_register() && left->reg().is(rcx)) { 5759a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block *left = allocator_->Allocate(); 5760a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(left->is_valid()); 5761a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(left->reg(), rcx); 5762a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5763a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block right->ToRegister(rcx); 5764a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block left->ToRegister(); 5765a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(left->is_register() && !left->reg().is(rcx)); 5766a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(right->is_register() && right->reg().is(rcx)); 5767a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5768a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We will modify right, it must be spilled. 5769a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Spill(rcx); 5770a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5771a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Use a fresh answer register to avoid spilling the left operand. 5772d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke answer = allocator_->Allocate(); 5773a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(answer.is_valid()); 5774a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that both operands are smis using the answer register as a 5775a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // temporary. 5776a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block DeferredInlineBinaryOperation* deferred = 5777a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block new DeferredInlineBinaryOperation(op, 5778a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block answer.reg(), 5779a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block left->reg(), 5780a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block rcx, 5781a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block overwrite_mode); 5782a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(answer.reg(), left->reg()); 5783a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ or_(answer.reg(), rcx); 5784a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfNotSmi(answer.reg(), deferred->entry_label()); 5785a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5786a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Perform the operation. 5787a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block switch (op) { 5788a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::SAR: 5789a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ SmiShiftArithmeticRight(answer.reg(), left->reg(), rcx); 5790a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 5791a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::SHR: { 5792a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ SmiShiftLogicalRight(answer.reg(), 5793a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block left->reg(), 5794a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block rcx, 5795a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block deferred->entry_label()); 5796a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 5797a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5798a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::SHL: { 5799a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ SmiShiftLeft(answer.reg(), 5800a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block left->reg(), 5801a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block rcx, 5802a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block deferred->entry_label()); 5803a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 5804a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5805a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block default: 5806a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block UNREACHABLE(); 5807a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5808a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block deferred->BindExit(); 5809a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block left->Unuse(); 5810a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block right->Unuse(); 5811d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke ASSERT(answer.is_valid()); 5812d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke return answer; 5813a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5814a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5815a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Handle the other binary operations. 5816a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block left->ToRegister(); 5817a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block right->ToRegister(); 5818a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // A newly allocated register answer is used to hold the answer. The 5819a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // registers containing left and right are not modified so they don't 5820a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // need to be spilled in the fast case. 5821d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke answer = allocator_->Allocate(); 5822a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(answer.is_valid()); 5823a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5824a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Perform the smi tag check. 5825a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block DeferredInlineBinaryOperation* deferred = 5826a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block new DeferredInlineBinaryOperation(op, 5827a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block answer.reg(), 5828a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block left->reg(), 5829a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block right->reg(), 5830a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block overwrite_mode); 5831a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfNotBothSmi(left->reg(), right->reg(), deferred->entry_label()); 5832a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5833a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block switch (op) { 5834a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::ADD: 5835a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ SmiAdd(answer.reg(), 5836a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block left->reg(), 5837a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block right->reg(), 5838a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block deferred->entry_label()); 5839a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 5840a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5841a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::SUB: 5842a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ SmiSub(answer.reg(), 5843a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block left->reg(), 5844a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block right->reg(), 5845a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block deferred->entry_label()); 5846a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 5847a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5848a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::MUL: { 5849a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ SmiMul(answer.reg(), 5850a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block left->reg(), 5851a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block right->reg(), 5852a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block deferred->entry_label()); 5853a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 5854a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5855a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5856a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::BIT_OR: 5857a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ SmiOr(answer.reg(), left->reg(), right->reg()); 5858a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 5859a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5860a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::BIT_AND: 5861a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ SmiAnd(answer.reg(), left->reg(), right->reg()); 5862a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 5863a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5864a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::BIT_XOR: 5865a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ SmiXor(answer.reg(), left->reg(), right->reg()); 5866a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 5867a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5868a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block default: 5869a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block UNREACHABLE(); 5870a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 5871a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 5872a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block deferred->BindExit(); 5873a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block left->Unuse(); 5874a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block right->Unuse(); 5875d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke ASSERT(answer.is_valid()); 5876d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke return answer; 5877d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke} 5878d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 5879d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 5880d91b9f7d46489a9ee00f9cb415630299c76a502bLeon ClarkeResult CodeGenerator::EmitKeyedLoad(bool is_global) { 5881d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Comment cmnt(masm_, "[ Load from keyed Property"); 5882d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Inline array load code if inside of a loop. We do not know 5883d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // the receiver map yet, so we initially generate the code with 5884d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // a check against an invalid map. In the inline cache code, we 5885d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // patch the map check if appropriate. 5886d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke if (loop_nesting() > 0) { 5887d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Comment cmnt(masm_, "[ Inlined load from keyed Property"); 5888d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 5889d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Result key = frame_->Pop(); 5890d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Result receiver = frame_->Pop(); 5891d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke key.ToRegister(); 5892d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke receiver.ToRegister(); 5893d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 5894d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Use a fresh temporary to load the elements without destroying 5895d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // the receiver which is needed for the deferred slow case. 5896d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Result elements = allocator()->Allocate(); 5897d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke ASSERT(elements.is_valid()); 5898d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 5899d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Use a fresh temporary for the index and later the loaded 5900d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // value. 5901d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Result index = allocator()->Allocate(); 5902d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke ASSERT(index.is_valid()); 5903d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 5904d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke DeferredReferenceGetKeyedValue* deferred = 5905d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke new DeferredReferenceGetKeyedValue(index.reg(), 5906d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke receiver.reg(), 5907d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke key.reg(), 5908d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke is_global); 5909d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 5910d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Check that the receiver is not a smi (only needed if this 5911d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // is not a load from the global context) and that it has the 5912d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // expected map. 5913d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke if (!is_global) { 5914d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ JumpIfSmi(receiver.reg(), deferred->entry_label()); 5915d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke } 5916d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 5917d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Initially, use an invalid map. The map is patched in the IC 5918d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // initialization code. 5919d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ bind(deferred->patch_site()); 5920d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Use masm-> here instead of the double underscore macro since extra 5921d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // coverage code can interfere with the patching. Do not use 5922d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // root array to load null_value, since it must be patched with 5923d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // the expected receiver map. 5924d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke masm_->movq(kScratchRegister, Factory::null_value(), 5925d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke RelocInfo::EMBEDDED_OBJECT); 5926d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke masm_->cmpq(FieldOperand(receiver.reg(), HeapObject::kMapOffset), 5927d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke kScratchRegister); 5928d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke deferred->Branch(not_equal); 5929d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 5930d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Check that the key is a non-negative smi. 5931d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ JumpIfNotPositiveSmi(key.reg(), deferred->entry_label()); 5932d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 5933d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Get the elements array from the receiver and check that it 5934d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // is not a dictionary. 5935d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(elements.reg(), 5936d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke FieldOperand(receiver.reg(), JSObject::kElementsOffset)); 5937d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ Cmp(FieldOperand(elements.reg(), HeapObject::kMapOffset), 5938d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Factory::fixed_array_map()); 5939d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke deferred->Branch(not_equal); 5940d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 5941d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Shift the key to get the actual index value and check that 5942d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // it is within bounds. 5943d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ SmiToInteger32(index.reg(), key.reg()); 5944d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ cmpl(index.reg(), 5945d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke FieldOperand(elements.reg(), FixedArray::kLengthOffset)); 5946d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke deferred->Branch(above_equal); 5947d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 5948d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // The index register holds the un-smi-tagged key. It has been 5949d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // zero-extended to 64-bits, so it can be used directly as index in the 5950d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // operand below. 5951d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Load and check that the result is not the hole. We could 5952d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // reuse the index or elements register for the value. 5953d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // 5954d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // TODO(206): Consider whether it makes sense to try some 5955d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // heuristic about which register to reuse. For example, if 5956d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // one is rax, the we can reuse that one because the value 5957d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // coming from the deferred code will be in rax. 5958d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Result value = index; 5959d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(value.reg(), 5960d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Operand(elements.reg(), 5961d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke index.reg(), 5962d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke times_pointer_size, 5963d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke FixedArray::kHeaderSize - kHeapObjectTag)); 5964d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke elements.Unuse(); 5965d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke index.Unuse(); 5966d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ CompareRoot(value.reg(), Heap::kTheHoleValueRootIndex); 5967d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke deferred->Branch(equal); 5968d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ IncrementCounter(&Counters::keyed_load_inline, 1); 5969d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 5970d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke deferred->BindExit(); 5971d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Restore the receiver and key to the frame and push the 5972d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // result on top of it. 5973d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke frame_->Push(&receiver); 5974d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke frame_->Push(&key); 5975d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke return value; 5976d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 5977d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke } else { 5978d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Comment cmnt(masm_, "[ Load from keyed Property"); 5979d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke RelocInfo::Mode mode = is_global 5980d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke ? RelocInfo::CODE_TARGET_CONTEXT 5981d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke : RelocInfo::CODE_TARGET; 5982d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Result answer = frame_->CallKeyedLoadIC(mode); 5983d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Make sure that we do not have a test instruction after the 5984d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // call. A test instruction after the call is used to 5985d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // indicate that we have generated an inline version of the 5986d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // keyed load. The explicit nop instruction is here because 5987d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // the push that follows might be peep-hole optimized away. 5988d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ nop(); 5989d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke return answer; 5990d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke } 5991a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 5992a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5993a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5994a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#undef __ 5995a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#define __ ACCESS_MASM(masm) 5996a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5997a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5998a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockHandle<String> Reference::GetName() { 5999a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(type_ == NAMED); 6000a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Property* property = expression_->AsProperty(); 6001a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (property == NULL) { 6002a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Global variable reference treated as a named property reference. 6003a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block VariableProxy* proxy = expression_->AsVariableProxy(); 6004a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(proxy->AsVariable() != NULL); 6005a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(proxy->AsVariable()->is_global()); 6006a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return proxy->name(); 6007a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 6008a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Literal* raw_name = property->key()->AsLiteral(); 6009a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(raw_name != NULL); 6010a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return Handle<String>(String::cast(*raw_name->handle())); 6011a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6012a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 6013a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6014a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6015d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid Reference::GetValue() { 6016a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!cgen_->in_spilled_code()); 6017a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(cgen_->HasValidEntryRegisters()); 6018a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!is_illegal()); 6019a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block MacroAssembler* masm = cgen_->masm(); 6020a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6021a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Record the source position for the property load. 6022a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Property* property = expression_->AsProperty(); 6023a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (property != NULL) { 6024a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block cgen_->CodeForSourcePosition(property->position()); 6025a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6026a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6027a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block switch (type_) { 6028a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case SLOT: { 6029a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm, "[ Load from Slot"); 6030a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); 6031a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(slot != NULL); 6032d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block cgen_->LoadFromSlotCheckForArguments(slot, NOT_INSIDE_TYPEOF); 6033a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 6034a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6035a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6036a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case NAMED: { 6037a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Variable* var = expression_->AsVariableProxy()->AsVariable(); 6038a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool is_global = var != NULL; 6039a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!is_global || var->is_global()); 6040a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6041a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Do not inline the inobject property case for loads from the global 6042a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // object. Also do not inline for unoptimized code. This saves time 6043a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // in the code generator. Unoptimized code is toplevel code or code 6044a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // that is not in a loop. 6045a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (is_global || 6046a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block cgen_->scope()->is_global_scope() || 6047a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block cgen_->loop_nesting() == 0) { 6048a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm, "[ Load from named Property"); 6049a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block cgen_->frame()->Push(GetName()); 6050a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6051a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block RelocInfo::Mode mode = is_global 6052a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ? RelocInfo::CODE_TARGET_CONTEXT 6053a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block : RelocInfo::CODE_TARGET; 6054a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result answer = cgen_->frame()->CallLoadIC(mode); 6055a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // A test rax instruction following the call signals that the 6056a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // inobject property case was inlined. Ensure that there is not 6057a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // a test rax instruction here. 6058a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ nop(); 6059a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block cgen_->frame()->Push(&answer); 6060a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 6061a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Inline the inobject property case. 6062a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm, "[ Inlined named property load"); 6063a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result receiver = cgen_->frame()->Pop(); 6064a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block receiver.ToRegister(); 6065a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result value = cgen_->allocator()->Allocate(); 6066a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(value.is_valid()); 6067a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Cannot use r12 for receiver, because that changes 6068a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // the distance between a call and a fixup location, 6069a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // due to a special encoding of r12 as r/m in a ModR/M byte. 6070a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (receiver.reg().is(r12)) { 6071a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Swap receiver and value. 6072a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(value.reg(), receiver.reg()); 6073a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result temp = receiver; 6074a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block receiver = value; 6075a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block value = temp; 6076a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block cgen_->frame()->Spill(value.reg()); // r12 may have been shared. 6077a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6078a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6079a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block DeferredReferenceGetNamedValue* deferred = 6080a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block new DeferredReferenceGetNamedValue(value.reg(), 6081a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block receiver.reg(), 6082a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GetName()); 6083a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6084a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the receiver is a heap object. 6085a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfSmi(receiver.reg(), deferred->entry_label()); 6086a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6087a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(deferred->patch_site()); 6088a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // This is the map check instruction that will be patched (so we can't 6089a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // use the double underscore macro that may insert instructions). 6090a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Initially use an invalid map to force a failure. 6091a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block masm->Move(kScratchRegister, Factory::null_value()); 6092a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block masm->cmpq(FieldOperand(receiver.reg(), HeapObject::kMapOffset), 6093a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block kScratchRegister); 6094a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // This branch is always a forwards branch so it's always a fixed 6095a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // size which allows the assert below to succeed and patching to work. 6096a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Don't use deferred->Branch(...), since that might add coverage code. 6097a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block masm->j(not_equal, deferred->entry_label()); 6098a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6099a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The delta from the patch label to the load offset must be 6100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // statically known. 6101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(masm->SizeOfCodeGeneratedSince(deferred->patch_site()) == 6102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block LoadIC::kOffsetToLoadInstruction); 6103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The initial (invalid) offset has to be large enough to force 6104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // a 32-bit instruction encoding to allow patching with an 6105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // arbitrary offset. Use kMaxInt (minus kHeapObjectTag). 6106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int offset = kMaxInt; 6107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block masm->movq(value.reg(), FieldOperand(receiver.reg(), offset)); 6108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ IncrementCounter(&Counters::named_load_inline, 1); 6110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block deferred->BindExit(); 6111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block cgen_->frame()->Push(&receiver); 6112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block cgen_->frame()->Push(&value); 6113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 6115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case KEYED: { 6118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm, "[ Load from keyed Property"); 6119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Variable* var = expression_->AsVariableProxy()->AsVariable(); 6120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool is_global = var != NULL; 6121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!is_global || var->is_global()); 6122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6123d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Result value = cgen_->EmitKeyedLoad(is_global); 6124d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke cgen_->frame()->Push(&value); 6125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 6126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block default: 6129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block UNREACHABLE(); 6130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6131d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 6132d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke if (!persist_after_get_) { 6133d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke cgen_->UnloadReference(this); 6134d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke } 6135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 6136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6138d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid Reference::TakeValue() { 6139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // TODO(X64): This function is completely architecture independent. Move 6140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // it somewhere shared. 6141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // For non-constant frame-allocated slots, we invalidate the value in the 6143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // slot. For all others, we fall back on GetValue. 6144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!cgen_->in_spilled_code()); 6145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!is_illegal()); 6146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (type_ != SLOT) { 6147d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block GetValue(); 6148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return; 6149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); 6152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(slot != NULL); 6153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (slot->type() == Slot::LOOKUP || 6154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block slot->type() == Slot::CONTEXT || 6155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block slot->var()->mode() == Variable::CONST || 6156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block slot->is_arguments()) { 6157d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block GetValue(); 6158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return; 6159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Only non-constant, frame-allocated parameters and locals can reach 6162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // here. Be careful not to use the optimizations for arguments 6163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // object access since it may not have been initialized yet. 6164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!slot->is_arguments()); 6165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (slot->type() == Slot::PARAMETER) { 6166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block cgen_->frame()->TakeParameterAt(slot->index()); 6167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 6168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(slot->type() == Slot::LOCAL); 6169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block cgen_->frame()->TakeLocalAt(slot->index()); 6170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6171d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 6172d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke ASSERT(persist_after_get_); 6173d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Do not unload the reference, because it is used in SetValue. 6174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 6175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Reference::SetValue(InitState init_state) { 6178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(cgen_->HasValidEntryRegisters()); 6179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!is_illegal()); 6180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block MacroAssembler* masm = cgen_->masm(); 6181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block switch (type_) { 6182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case SLOT: { 6183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm, "[ Store to Slot"); 6184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); 6185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(slot != NULL); 6186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block cgen_->StoreToSlot(slot, init_state); 61874515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke cgen_->UnloadReference(this); 6188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 6189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case NAMED: { 6192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm, "[ Store to named Property"); 6193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block cgen_->frame()->Push(GetName()); 6194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result answer = cgen_->frame()->CallStoreIC(); 6195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block cgen_->frame()->Push(&answer); 61964515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke set_unloaded(); 6197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 6198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case KEYED: { 6201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm, "[ Store to keyed Property"); 6202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Generate inlined version of the keyed store if the code is in 6204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // a loop and the key is likely to be a smi. 6205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Property* property = expression()->AsProperty(); 6206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(property != NULL); 6207e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke StaticType* key_smi_analysis = property->key()->type(); 6208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (cgen_->loop_nesting() > 0 && key_smi_analysis->IsLikelySmi()) { 6210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Comment cmnt(masm, "[ Inlined store to keyed Property"); 6211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the receiver, key and value into registers. 6213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result value = cgen_->frame()->Pop(); 6214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result key = cgen_->frame()->Pop(); 6215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result receiver = cgen_->frame()->Pop(); 6216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result tmp = cgen_->allocator_->Allocate(); 6218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(tmp.is_valid()); 6219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Determine whether the value is a constant before putting it 6221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // in a register. 6222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool value_is_constant = value.is_constant(); 6223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Make sure that value, key and receiver are in registers. 6225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block value.ToRegister(); 6226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block key.ToRegister(); 6227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block receiver.ToRegister(); 6228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block DeferredReferenceSetKeyedValue* deferred = 6230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block new DeferredReferenceSetKeyedValue(value.reg(), 6231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block key.reg(), 6232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block receiver.reg()); 6233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the value is a smi if it is not a constant. 6235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We can skip the write barrier for smis and constants. 6236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!value_is_constant) { 6237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfNotSmi(value.reg(), deferred->entry_label()); 6238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the key is a non-negative smi. 6241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfNotPositiveSmi(key.reg(), deferred->entry_label()); 6242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the receiver is not a smi. 6244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfSmi(receiver.reg(), deferred->entry_label()); 6245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the receiver is a JSArray. 6247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CmpObjectType(receiver.reg(), JS_ARRAY_TYPE, kScratchRegister); 6248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block deferred->Branch(not_equal); 6249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the key is within bounds. Both the key and the 62513ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // length of the JSArray are smis. 62523ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ SmiCompare(FieldOperand(receiver.reg(), JSArray::kLengthOffset), 62533ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block key.reg()); 62543ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block deferred->Branch(less_equal); 6255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the elements array from the receiver and check that it 6257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // is a flat array (not a dictionary). 6258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(tmp.reg(), 6259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block FieldOperand(receiver.reg(), JSObject::kElementsOffset)); 6260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Bind the deferred code patch site to be able to locate the 6261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // fixed array map comparison. When debugging, we patch this 6262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // comparison to always fail so that we will hit the IC call 6263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // in the deferred code which will allow the debugger to 6264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // break for fast case stores. 6265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(deferred->patch_site()); 6266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Avoid using __ to ensure the distance from patch_site 6267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // to the map address is always the same. 6268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block masm->movq(kScratchRegister, Factory::fixed_array_map(), 6269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block RelocInfo::EMBEDDED_OBJECT); 6270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ cmpq(FieldOperand(tmp.reg(), HeapObject::kMapOffset), 6271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block kScratchRegister); 6272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block deferred->Branch(not_equal); 6273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Store the value. 6275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block SmiIndex index = 6276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block masm->SmiToIndex(kScratchRegister, key.reg(), kPointerSizeLog2); 6277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(Operand(tmp.reg(), 6278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block index.reg, 6279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block index.scale, 6280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block FixedArray::kHeaderSize - kHeapObjectTag), 6281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block value.reg()); 6282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ IncrementCounter(&Counters::keyed_store_inline, 1); 6283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block deferred->BindExit(); 6285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block cgen_->frame()->Push(&receiver); 6287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block cgen_->frame()->Push(&key); 6288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block cgen_->frame()->Push(&value); 6289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 6290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result answer = cgen_->frame()->CallKeyedStoreIC(); 6291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Make sure that we do not have a test instruction after the 6292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // call. A test instruction after the call is used to 6293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // indicate that we have generated an inline version of the 6294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // keyed store. 6295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block masm->nop(); 6296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block cgen_->frame()->Push(&answer); 6297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 62984515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke cgen_->UnloadReference(this); 6299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 6300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block default: 6303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block UNREACHABLE(); 6304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 6306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6308e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid FastNewClosureStub::Generate(MacroAssembler* masm) { 6309e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Clone the boilerplate in new space. Set the context to the 6310e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // current context in rsi. 6311e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Label gc; 6312e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ AllocateInNewSpace(JSFunction::kSize, rax, rbx, rcx, &gc, TAG_OBJECT); 6313e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 6314e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Get the boilerplate function from the stack. 6315e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(rdx, Operand(rsp, 1 * kPointerSize)); 6316e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 6317e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Compute the function map in the current global context and set that 6318e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // as the map of the allocated object. 6319e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(rcx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX))); 6320e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(rcx, FieldOperand(rcx, GlobalObject::kGlobalContextOffset)); 6321e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(rcx, Operand(rcx, Context::SlotOffset(Context::FUNCTION_MAP_INDEX))); 6322e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(FieldOperand(rax, JSObject::kMapOffset), rcx); 6323e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 6324e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Clone the rest of the boilerplate fields. We don't have to update 6325e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // the write barrier because the allocated object is in new space. 6326e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke for (int offset = kPointerSize; 6327e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke offset < JSFunction::kSize; 6328e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke offset += kPointerSize) { 6329e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke if (offset == JSFunction::kContextOffset) { 6330e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(FieldOperand(rax, offset), rsi); 6331e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } else { 6332e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(rbx, FieldOperand(rdx, offset)); 6333e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(FieldOperand(rax, offset), rbx); 6334e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } 6335e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } 6336e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 6337e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Return and remove the on-stack parameter. 6338e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ ret(1 * kPointerSize); 6339e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 6340e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Create a new closure through the slower runtime call. 6341e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ bind(&gc); 6342e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ pop(rcx); // Temporarily remove return address. 6343e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ pop(rdx); 6344e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ push(rsi); 6345e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ push(rdx); 6346e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ push(rcx); // Restore return address. 6347e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ TailCallRuntime(ExternalReference(Runtime::kNewClosure), 2, 1); 6348e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke} 6349e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 6350e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 6351e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid FastNewContextStub::Generate(MacroAssembler* masm) { 6352e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Try to allocate the context in new space. 6353e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Label gc; 6354e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke int length = slots_ + Context::MIN_CONTEXT_SLOTS; 6355e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ AllocateInNewSpace((length * kPointerSize) + FixedArray::kHeaderSize, 6356e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke rax, rbx, rcx, &gc, TAG_OBJECT); 6357e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 6358e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Get the function from the stack. 6359e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(rcx, Operand(rsp, 1 * kPointerSize)); 6360e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 6361e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Setup the object header. 6362e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ LoadRoot(kScratchRegister, Heap::kContextMapRootIndex); 6363e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(FieldOperand(rax, HeapObject::kMapOffset), kScratchRegister); 6364e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movl(FieldOperand(rax, Array::kLengthOffset), Immediate(length)); 6365e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 6366e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Setup the fixed slots. 6367e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ xor_(rbx, rbx); // Set to NULL. 6368e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(Operand(rax, Context::SlotOffset(Context::CLOSURE_INDEX)), rcx); 6369e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(Operand(rax, Context::SlotOffset(Context::FCONTEXT_INDEX)), rax); 6370e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(Operand(rax, Context::SlotOffset(Context::PREVIOUS_INDEX)), rbx); 6371e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(Operand(rax, Context::SlotOffset(Context::EXTENSION_INDEX)), rbx); 6372e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 6373e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Copy the global object from the surrounding context. 6374e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(rbx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX))); 6375e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(Operand(rax, Context::SlotOffset(Context::GLOBAL_INDEX)), rbx); 6376e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 6377e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Initialize the rest of the slots to undefined. 6378e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ LoadRoot(rbx, Heap::kUndefinedValueRootIndex); 6379e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { 6380e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(Operand(rax, Context::SlotOffset(i)), rbx); 6381e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } 6382e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 6383e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Return and remove the on-stack parameter. 6384e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(rsi, rax); 6385e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ ret(1 * kPointerSize); 6386e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 6387e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Need to collect. Call into runtime system. 6388e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ bind(&gc); 6389e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ TailCallRuntime(ExternalReference(Runtime::kNewContext), 1, 1); 6390e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke} 6391e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 6392e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 6393402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescuvoid FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { 6394402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Stack layout on entry: 6395402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // 6396402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // [rsp + kPointerSize]: constant elements. 6397402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // [rsp + (2 * kPointerSize)]: literal index. 6398402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // [rsp + (3 * kPointerSize)]: literals array. 6399402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 6400402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // All sizes here are multiples of kPointerSize. 6401402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu int elements_size = (length_ > 0) ? FixedArray::SizeFor(length_) : 0; 6402402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu int size = JSArray::kSize + elements_size; 6403402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 6404402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Load boilerplate object into rcx and check if we need to create a 6405402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // boilerplate. 6406402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Label slow_case; 6407402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ movq(rcx, Operand(rsp, 3 * kPointerSize)); 6408402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ movq(rax, Operand(rsp, 2 * kPointerSize)); 6409402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu SmiIndex index = masm->SmiToIndex(rax, rax, kPointerSizeLog2); 6410402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ movq(rcx, 6411402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu FieldOperand(rcx, index.reg, index.scale, FixedArray::kHeaderSize)); 6412402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ CompareRoot(rcx, Heap::kUndefinedValueRootIndex); 6413402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ j(equal, &slow_case); 6414402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 6415402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Allocate both the JS array and the elements array in one big 6416402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // allocation. This avoids multiple limit checks. 6417402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ AllocateInNewSpace(size, rax, rbx, rdx, &slow_case, TAG_OBJECT); 6418402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 6419402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Copy the JS array part. 6420402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu for (int i = 0; i < JSArray::kSize; i += kPointerSize) { 6421402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu if ((i != JSArray::kElementsOffset) || (length_ == 0)) { 6422402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ movq(rbx, FieldOperand(rcx, i)); 6423402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ movq(FieldOperand(rax, i), rbx); 6424402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu } 6425402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu } 6426402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 6427402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu if (length_ > 0) { 6428402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Get hold of the elements array of the boilerplate and setup the 6429402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // elements pointer in the resulting object. 6430402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ movq(rcx, FieldOperand(rcx, JSArray::kElementsOffset)); 6431402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ lea(rdx, Operand(rax, JSArray::kSize)); 6432402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ movq(FieldOperand(rax, JSArray::kElementsOffset), rdx); 6433402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 6434402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Copy the elements array. 6435402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu for (int i = 0; i < elements_size; i += kPointerSize) { 6436402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ movq(rbx, FieldOperand(rcx, i)); 6437402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ movq(FieldOperand(rdx, i), rbx); 6438402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu } 6439402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu } 6440402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 6441402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Return and remove the on-stack parameters. 6442402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ ret(3 * kPointerSize); 6443402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 6444402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ bind(&slow_case); 6445402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu ExternalReference runtime(Runtime::kCreateArrayLiteralShallow); 6446402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ TailCallRuntime(runtime, 3, 1); 6447402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu} 6448402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 6449402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 6450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid ToBooleanStub::Generate(MacroAssembler* masm) { 6451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label false_result, true_result, not_string; 6452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rax, Operand(rsp, 1 * kPointerSize)); 6453a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // 'null' => false. 6455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CompareRoot(rax, Heap::kNullValueRootIndex); 6456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(equal, &false_result); 6457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the map and type of the heap object. 6459a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We don't use CmpObjectType because we manipulate the type field. 6460a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); 6461a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movzxbq(rcx, FieldOperand(rdx, Map::kInstanceTypeOffset)); 6462a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6463a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Undetectable => false. 6464a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movzxbq(rbx, FieldOperand(rdx, Map::kBitFieldOffset)); 6465a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ and_(rbx, Immediate(1 << Map::kIsUndetectable)); 6466a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_zero, &false_result); 6467a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6468a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // JavaScript object => true. 6469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ cmpq(rcx, Immediate(FIRST_JS_OBJECT_TYPE)); 6470a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(above_equal, &true_result); 6471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // String value => false iff empty. 6473a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ cmpq(rcx, Immediate(FIRST_NONSTRING_TYPE)); 6474a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(above_equal, ¬_string); 6475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movl(rdx, FieldOperand(rax, String::kLengthOffset)); 6476d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ testl(rdx, rdx); 6477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(zero, &false_result); 6478a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ jmp(&true_result); 6479a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6480a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(¬_string); 6481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // HeapNumber => false iff +0, -0, or NaN. 6482a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // These three cases set C3 when compared to zero in the FPU. 6483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CompareRoot(rdx, Heap::kHeapNumberMapRootIndex); 6484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, &true_result); 6485a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ fldz(); // Load zero onto fp stack 6486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load heap-number double value onto fp stack 6487a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ fld_d(FieldOperand(rax, HeapNumber::kValueOffset)); 64883ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ FCmp(); 64893ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ j(zero, &false_result); 6490a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Fall through to |true_result|. 6491a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return 1/0 for true/false in rax. 6493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&true_result); 6494a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rax, Immediate(1)); 6495a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ ret(1 * kPointerSize); 6496a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&false_result); 6497a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ xor_(rax, rax); 6498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ ret(1 * kPointerSize); 6499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 6500a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6501a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6502a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool CodeGenerator::FoldConstantSmis(Token::Value op, int left, int right) { 6503a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Object* answer_object = Heap::undefined_value(); 6504a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block switch (op) { 6505a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::ADD: 6506d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Use intptr_t to detect overflow of 32-bit int. 6507d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke if (Smi::IsValid(static_cast<intptr_t>(left) + right)) { 6508a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block answer_object = Smi::FromInt(left + right); 6509a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6510a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 6511a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::SUB: 6512d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Use intptr_t to detect overflow of 32-bit int. 6513d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke if (Smi::IsValid(static_cast<intptr_t>(left) - right)) { 6514a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block answer_object = Smi::FromInt(left - right); 6515a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6516a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 6517a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::MUL: { 6518a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block double answer = static_cast<double>(left) * right; 6519a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (answer >= Smi::kMinValue && answer <= Smi::kMaxValue) { 6520a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If the product is zero and the non-zero factor is negative, 6521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // the spec requires us to return floating point negative zero. 6522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (answer != 0 || (left + right) >= 0) { 6523a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block answer_object = Smi::FromInt(static_cast<int>(answer)); 6524a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6525a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6526a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6527a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 6528a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::DIV: 6529a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::MOD: 6530a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 6531a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::BIT_OR: 6532a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block answer_object = Smi::FromInt(left | right); 6533a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 6534a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::BIT_AND: 6535a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block answer_object = Smi::FromInt(left & right); 6536a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 6537a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::BIT_XOR: 6538a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block answer_object = Smi::FromInt(left ^ right); 6539a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 6540a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6541a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::SHL: { 6542a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int shift_amount = right & 0x1F; 6543a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (Smi::IsValid(left << shift_amount)) { 6544a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block answer_object = Smi::FromInt(left << shift_amount); 6545a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6546a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 6547a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6548a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::SHR: { 6549a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int shift_amount = right & 0x1F; 6550a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block unsigned int unsigned_left = left; 6551a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block unsigned_left >>= shift_amount; 6552a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (unsigned_left <= static_cast<unsigned int>(Smi::kMaxValue)) { 6553a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block answer_object = Smi::FromInt(unsigned_left); 6554a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6555a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 6556a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6557a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::SAR: { 6558a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int shift_amount = right & 0x1F; 6559a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block unsigned int unsigned_left = left; 6560a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (left < 0) { 6561a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Perform arithmetic shift of a negative number by 6562a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // complementing number, logical shifting, complementing again. 6563a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block unsigned_left = ~unsigned_left; 6564a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block unsigned_left >>= shift_amount; 6565a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block unsigned_left = ~unsigned_left; 6566a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 6567a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block unsigned_left >>= shift_amount; 6568a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6569a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(Smi::IsValid(static_cast<int32_t>(unsigned_left))); 6570a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block answer_object = Smi::FromInt(static_cast<int32_t>(unsigned_left)); 6571a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 6572a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6573a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block default: 6574a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block UNREACHABLE(); 6575a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 6576a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6577a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (answer_object == Heap::undefined_value()) { 6578a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return false; 6579a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6580a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->Push(Handle<Object>(answer_object)); 6581a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return true; 6582a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 6583a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6584a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6585a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// End of CodeGenerator implementation. 6586a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6587d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke// Get the integer part of a heap number. Surprisingly, all this bit twiddling 6588d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke// is faster than using the built-in instructions on floating point registers. 6589d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke// Trashes rdi and rbx. Dest is rcx. Source cannot be rcx or one of the 6590d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke// trashed registers. 6591d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarkevoid IntegerConvert(MacroAssembler* masm, 6592d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Register source, 6593d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke bool use_sse3, 6594d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Label* conversion_failure) { 6595d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke ASSERT(!source.is(rcx) && !source.is(rdi) && !source.is(rbx)); 6596d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Label done, right_exponent, normal_exponent; 6597d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Register scratch = rbx; 6598d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Register scratch2 = rdi; 6599d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Get exponent word. 6600d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movl(scratch, FieldOperand(source, HeapNumber::kExponentOffset)); 6601d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Get exponent alone in scratch2. 6602d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movl(scratch2, scratch); 6603d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ and_(scratch2, Immediate(HeapNumber::kExponentMask)); 6604d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke if (use_sse3) { 6605d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke CpuFeatures::Scope scope(SSE3); 6606d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Check whether the exponent is too big for a 64 bit signed integer. 6607d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke static const uint32_t kTooBigExponent = 6608d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift; 6609d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ cmpl(scratch2, Immediate(kTooBigExponent)); 6610d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(greater_equal, conversion_failure); 6611d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Load x87 register with heap number. 6612d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ fld_d(FieldOperand(source, HeapNumber::kValueOffset)); 6613d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Reserve space for 64 bit answer. 6614d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ subq(rsp, Immediate(sizeof(uint64_t))); // Nolint. 6615d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Do conversion, which cannot fail because we checked the exponent. 6616d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ fisttp_d(Operand(rsp, 0)); 6617d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movl(rcx, Operand(rsp, 0)); // Load low word of answer into rcx. 6618d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ addq(rsp, Immediate(sizeof(uint64_t))); // Nolint. 6619d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke } else { 6620d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Load rcx with zero. We use this either for the final shift or 6621d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // for the answer. 6622d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ xor_(rcx, rcx); 6623d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Check whether the exponent matches a 32 bit signed int that cannot be 6624d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // represented by a Smi. A non-smi 32 bit integer is 1.xxx * 2^30 so the 6625d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // exponent is 30 (biased). This is the exponent that we are fastest at and 6626d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // also the highest exponent we can handle here. 6627d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke const uint32_t non_smi_exponent = 6628d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift; 6629d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ cmpl(scratch2, Immediate(non_smi_exponent)); 6630d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // If we have a match of the int32-but-not-Smi exponent then skip some 6631d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // logic. 6632d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(equal, &right_exponent); 6633d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // If the exponent is higher than that then go to slow case. This catches 6634d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // numbers that don't fit in a signed int32, infinities and NaNs. 6635d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(less, &normal_exponent); 6636d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 6637d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke { 6638d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Handle a big exponent. The only reason we have this code is that the 6639d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // >>> operator has a tendency to generate numbers with an exponent of 31. 6640d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke const uint32_t big_non_smi_exponent = 6641d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke (HeapNumber::kExponentBias + 31) << HeapNumber::kExponentShift; 6642d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ cmpl(scratch2, Immediate(big_non_smi_exponent)); 6643d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(not_equal, conversion_failure); 6644d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // We have the big exponent, typically from >>>. This means the number is 6645d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // in the range 2^31 to 2^32 - 1. Get the top bits of the mantissa. 6646d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movl(scratch2, scratch); 6647d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ and_(scratch2, Immediate(HeapNumber::kMantissaMask)); 6648d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Put back the implicit 1. 6649d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ or_(scratch2, Immediate(1 << HeapNumber::kExponentShift)); 6650d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Shift up the mantissa bits to take up the space the exponent used to 6651d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // take. We just orred in the implicit bit so that took care of one and 6652d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // we want to use the full unsigned range so we subtract 1 bit from the 6653d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // shift distance. 6654d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke const int big_shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 1; 6655d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ shl(scratch2, Immediate(big_shift_distance)); 6656d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Get the second half of the double. 6657d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movl(rcx, FieldOperand(source, HeapNumber::kMantissaOffset)); 6658d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Shift down 21 bits to get the most significant 11 bits or the low 6659d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // mantissa word. 6660d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ shr(rcx, Immediate(32 - big_shift_distance)); 6661d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ or_(rcx, scratch2); 6662d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // We have the answer in rcx, but we may need to negate it. 6663d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ testl(scratch, scratch); 6664d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(positive, &done); 6665d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ neg(rcx); 6666d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ jmp(&done); 6667d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke } 6668d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 6669d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ bind(&normal_exponent); 6670d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Exponent word in scratch, exponent part of exponent word in scratch2. 6671d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Zero in rcx. 6672d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // We know the exponent is smaller than 30 (biased). If it is less than 6673d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, ie 6674d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // it rounds to zero. 6675d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke const uint32_t zero_exponent = 6676d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke (HeapNumber::kExponentBias + 0) << HeapNumber::kExponentShift; 6677d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ subl(scratch2, Immediate(zero_exponent)); 6678d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rcx already has a Smi zero. 6679d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(less, &done); 6680d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 6681d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // We have a shifted exponent between 0 and 30 in scratch2. 6682d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ shr(scratch2, Immediate(HeapNumber::kExponentShift)); 6683d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movl(rcx, Immediate(30)); 6684d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ subl(rcx, scratch2); 6685d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 6686d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ bind(&right_exponent); 6687d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Here rcx is the shift, scratch is the exponent word. 6688d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Get the top bits of the mantissa. 6689d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ and_(scratch, Immediate(HeapNumber::kMantissaMask)); 6690d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Put back the implicit 1. 6691d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ or_(scratch, Immediate(1 << HeapNumber::kExponentShift)); 6692d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Shift up the mantissa bits to take up the space the exponent used to 6693d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // take. We have kExponentShift + 1 significant bits int he low end of the 6694d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // word. Shift them to the top bits. 6695d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2; 6696d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ shl(scratch, Immediate(shift_distance)); 6697d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Get the second half of the double. For some exponents we don't 6698d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // actually need this because the bits get shifted out again, but 6699d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // it's probably slower to test than just to do it. 6700d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movl(scratch2, FieldOperand(source, HeapNumber::kMantissaOffset)); 6701d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Shift down 22 bits to get the most significant 10 bits or the low 6702d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // mantissa word. 6703d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ shr(scratch2, Immediate(32 - shift_distance)); 6704d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ or_(scratch2, scratch); 6705d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Move down according to the exponent. 6706d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ shr_cl(scratch2); 6707d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Now the unsigned answer is in scratch2. We need to move it to rcx and 6708d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // we may need to fix the sign. 6709d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Label negative; 6710d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ xor_(rcx, rcx); 6711d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ cmpl(rcx, FieldOperand(source, HeapNumber::kExponentOffset)); 6712d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(greater, &negative); 6713d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movl(rcx, scratch2); 6714d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ jmp(&done); 6715d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ bind(&negative); 6716d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ subl(rcx, scratch2); 6717d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ bind(&done); 6718d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke } 6719d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke} 6720d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 6721d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 6722e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid GenericUnaryOpStub::Generate(MacroAssembler* masm) { 6723d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Label slow, done; 6724d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 6725d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke if (op_ == Token::SUB) { 6726d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Check whether the value is a smi. 6727d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Label try_float; 6728d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ JumpIfNotSmi(rax, &try_float); 6729d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 6730d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Enter runtime system if the value of the smi is zero 6731d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // to make sure that we switch between 0 and -0. 6732d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Also enter it if the value of the smi is Smi::kMinValue. 6733d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ SmiNeg(rax, rax, &done); 6734d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 6735d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Either zero or Smi::kMinValue, neither of which become a smi when 6736d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // negated. 6737d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ SmiCompare(rax, Smi::FromInt(0)); 6738d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(not_equal, &slow); 6739d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ Move(rax, Factory::minus_zero_value()); 6740d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ jmp(&done); 6741d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 6742d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Try floating point case. 6743d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ bind(&try_float); 6744d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); 6745d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ CompareRoot(rdx, Heap::kHeapNumberMapRootIndex); 6746d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(not_equal, &slow); 6747d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Operand is a float, negate its value by flipping sign bit. 6748d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(rdx, FieldOperand(rax, HeapNumber::kValueOffset)); 6749d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(kScratchRegister, Immediate(0x01)); 6750d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ shl(kScratchRegister, Immediate(63)); 6751d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ xor_(rdx, kScratchRegister); // Flip sign. 6752d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rdx is value to store. 6753d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke if (overwrite_) { 6754d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(FieldOperand(rax, HeapNumber::kValueOffset), rdx); 6755d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke } else { 6756d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ AllocateHeapNumber(rcx, rbx, &slow); 6757d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rcx: allocated 'empty' number 6758d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(FieldOperand(rcx, HeapNumber::kValueOffset), rdx); 6759d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(rax, rcx); 6760d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke } 6761d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke } else if (op_ == Token::BIT_NOT) { 6762d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Check if the operand is a heap number. 6763d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); 6764d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ CompareRoot(rdx, Heap::kHeapNumberMapRootIndex); 6765d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(not_equal, &slow); 6766e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 6767d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Convert the heap number in rax to an untagged integer in rcx. 6768d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke IntegerConvert(masm, rax, CpuFeatures::IsSupported(SSE3), &slow); 6769a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6770d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Do the bitwise operation and check if the result fits in a smi. 6771d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Label try_float; 6772d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ not_(rcx); 6773d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Tag the result as a smi and we're done. 6774d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke ASSERT(kSmiTagSize == 1); 6775d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ Integer32ToSmi(rax, rcx); 6776d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke } 6777a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6778d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Return from the stub. 6779d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ bind(&done); 6780d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ StubReturn(1); 6781a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6782d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Handle the slow case by jumping to the JavaScript builtin. 6783a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&slow); 6784a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(rcx); // pop return address 6785a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(rax); 6786a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(rcx); // push return address 6787d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke switch (op_) { 6788d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke case Token::SUB: 6789d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_FUNCTION); 6790d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke break; 6791d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke case Token::BIT_NOT: 6792d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION); 6793d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke break; 6794d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke default: 6795d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke UNREACHABLE(); 6796a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6797a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 6798a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6799a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 68004515c472dc3e5ed2448a564600976759e569a0a8Leon Clarkevoid RegExpExecStub::Generate(MacroAssembler* masm) { 68014515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Just jump directly to runtime if native RegExp is not selected at compile 68024515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // time or if regexp entry in generated code is turned off runtime switch or 68034515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // at compilation. 68044515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke#ifndef V8_NATIVE_REGEXP 68054515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ TailCallRuntime(ExternalReference(Runtime::kRegExpExec), 4, 1); 68064515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke#else // V8_NATIVE_REGEXP 68074515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke if (!FLAG_regexp_entry_native) { 68084515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ TailCallRuntime(ExternalReference(Runtime::kRegExpExec), 4, 1); 68094515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke return; 68104515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke } 68114515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 68124515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Stack frame on entry. 68134515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // esp[0]: return address 68144515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // esp[8]: last_match_info (expected JSArray) 68154515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // esp[16]: previous index 68164515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // esp[24]: subject string 68174515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // esp[32]: JSRegExp object 68184515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 68194515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke static const int kLastMatchInfoOffset = 1 * kPointerSize; 68204515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke static const int kPreviousIndexOffset = 2 * kPointerSize; 68214515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke static const int kSubjectOffset = 3 * kPointerSize; 68224515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke static const int kJSRegExpOffset = 4 * kPointerSize; 68234515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 68244515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Label runtime; 68254515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 68264515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Ensure that a RegExp stack is allocated. 68274515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke ExternalReference address_of_regexp_stack_memory_address = 68284515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke ExternalReference::address_of_regexp_stack_memory_address(); 68294515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke ExternalReference address_of_regexp_stack_memory_size = 68304515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke ExternalReference::address_of_regexp_stack_memory_size(); 68314515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(kScratchRegister, address_of_regexp_stack_memory_size); 68324515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(kScratchRegister, Operand(kScratchRegister, 0)); 68334515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ testq(kScratchRegister, kScratchRegister); 68344515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ j(zero, &runtime); 68354515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 68364515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 68374515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Check that the first argument is a JSRegExp object. 68384515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rax, Operand(rsp, kJSRegExpOffset)); 68394515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ JumpIfSmi(rax, &runtime); 68404515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ CmpObjectType(rax, JS_REGEXP_TYPE, kScratchRegister); 68414515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ j(not_equal, &runtime); 68424515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Check that the RegExp has been compiled (data contains a fixed array). 68434515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rcx, FieldOperand(rax, JSRegExp::kDataOffset)); 68444515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke if (FLAG_debug_code) { 68454515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Condition is_smi = masm->CheckSmi(rcx); 68464515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ Check(NegateCondition(is_smi), 68474515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke "Unexpected type for RegExp data, FixedArray expected"); 68484515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ CmpObjectType(rcx, FIXED_ARRAY_TYPE, kScratchRegister); 68494515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ Check(equal, "Unexpected type for RegExp data, FixedArray expected"); 68504515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke } 68514515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 68524515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // rcx: RegExp data (FixedArray) 68534515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. 68544515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rbx, FieldOperand(rcx, JSRegExp::kDataTagOffset)); 68554515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ SmiCompare(rbx, Smi::FromInt(JSRegExp::IRREGEXP)); 68564515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ j(not_equal, &runtime); 68574515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 68584515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // rcx: RegExp data (FixedArray) 68594515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Check that the number of captures fit in the static offsets vector buffer. 68604515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rdx, FieldOperand(rcx, JSRegExp::kIrregexpCaptureCountOffset)); 68614515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Calculate number of capture registers (number_of_captures + 1) * 2. 68624515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ PositiveSmiTimesPowerOfTwoToInteger64(rdx, rdx, 1); 68634515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ addq(rdx, Immediate(2)); // rdx was number_of_captures * 2. 68644515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Check that the static offsets vector buffer is large enough. 68654515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ cmpq(rdx, Immediate(OffsetsVector::kStaticOffsetsVectorSize)); 68664515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ j(above, &runtime); 68674515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 68684515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // rcx: RegExp data (FixedArray) 68694515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // rdx: Number of capture registers 68704515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Check that the second argument is a string. 68714515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rax, Operand(rsp, kSubjectOffset)); 68724515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ JumpIfSmi(rax, &runtime); 68734515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Condition is_string = masm->IsObjectStringType(rax, rbx, rbx); 68744515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ j(NegateCondition(is_string), &runtime); 68754515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Get the length of the string to rbx. 68764515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movl(rbx, FieldOperand(rax, String::kLengthOffset)); 68774515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 68784515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // rbx: Length of subject string 68794515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // rcx: RegExp data (FixedArray) 68804515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // rdx: Number of capture registers 68814515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Check that the third argument is a positive smi less than the string 68824515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // length. A negative value will be greater (usigned comparison). 68834515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rax, Operand(rsp, kPreviousIndexOffset)); 68844515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ SmiToInteger32(rax, rax); 68854515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ cmpl(rax, rbx); 68864515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ j(above, &runtime); 68874515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 68884515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // rcx: RegExp data (FixedArray) 68894515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // rdx: Number of capture registers 68904515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Check that the fourth object is a JSArray object. 68914515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rax, Operand(rsp, kLastMatchInfoOffset)); 68924515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ JumpIfSmi(rax, &runtime); 68934515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ CmpObjectType(rax, JS_ARRAY_TYPE, kScratchRegister); 68944515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ j(not_equal, &runtime); 68954515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Check that the JSArray is in fast case. 68964515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rbx, FieldOperand(rax, JSArray::kElementsOffset)); 68974515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rax, FieldOperand(rbx, HeapObject::kMapOffset)); 68984515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ Cmp(rax, Factory::fixed_array_map()); 68994515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ j(not_equal, &runtime); 69004515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Check that the last match info has space for the capture registers and the 69014515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // additional information. Ensure no overflow in add. 69024515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke ASSERT(FixedArray::kMaxLength < kMaxInt - FixedArray::kLengthOffset); 69034515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movl(rax, FieldOperand(rbx, FixedArray::kLengthOffset)); 69044515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ addl(rdx, Immediate(RegExpImpl::kLastMatchOverhead)); 69054515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ cmpl(rdx, rax); 69064515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ j(greater, &runtime); 69074515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 69084515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // ecx: RegExp data (FixedArray) 69094515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Check the representation and encoding of the subject string. 69104515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Label seq_string, seq_two_byte_string, check_code; 69114515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke const int kStringRepresentationEncodingMask = 69124515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask; 69134515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rax, Operand(rsp, kSubjectOffset)); 69144515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); 69154515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); 69164515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ andb(rbx, Immediate(kStringRepresentationEncodingMask)); 69174515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // First check for sequential string. 69184515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke ASSERT_EQ(0, kStringTag); 69194515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke ASSERT_EQ(0, kSeqStringTag); 69204515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ testb(rbx, Immediate(kIsNotStringMask | kStringRepresentationMask)); 69214515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ j(zero, &seq_string); 69224515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 69234515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Check for flat cons string. 69244515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // A flat cons string is a cons string where the second part is the empty 69254515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // string. In that case the subject string is just the first part of the cons 69264515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // string. Also in this case the first part of the cons string is known to be 69274515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // a sequential string or an external string. 69284515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movl(rdx, rbx); 69294515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ andb(rdx, Immediate(kStringRepresentationMask)); 69304515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ cmpb(rdx, Immediate(kConsStringTag)); 69314515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ j(not_equal, &runtime); 69324515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rdx, FieldOperand(rax, ConsString::kSecondOffset)); 69334515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ Cmp(rdx, Factory::empty_string()); 69344515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ j(not_equal, &runtime); 69354515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rax, FieldOperand(rax, ConsString::kFirstOffset)); 69364515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); 69374515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); 69384515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke ASSERT_EQ(0, kSeqStringTag); 69394515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ testb(rbx, Immediate(kStringRepresentationMask)); 69404515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ j(not_zero, &runtime); 69414515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ andb(rbx, Immediate(kStringRepresentationEncodingMask)); 69424515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 69434515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ bind(&seq_string); 69444515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // rax: subject string (sequential either ascii to two byte) 69454515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // rbx: suject string type & kStringRepresentationEncodingMask 69464515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // rcx: RegExp data (FixedArray) 69474515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Check that the irregexp code has been generated for an ascii string. If 69484515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // it has, the field contains a code object otherwise it contains the hole. 69494515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ cmpb(rbx, Immediate(kStringTag | kSeqStringTag | kTwoByteStringTag)); 69504515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ j(equal, &seq_two_byte_string); 69514515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke if (FLAG_debug_code) { 69524515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ cmpb(rbx, Immediate(kStringTag | kSeqStringTag | kAsciiStringTag)); 69534515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ Check(equal, "Expected sequential ascii string"); 69544515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke } 69554515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(r12, FieldOperand(rcx, JSRegExp::kDataAsciiCodeOffset)); 69564515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ Set(rdi, 1); // Type is ascii. 69574515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ jmp(&check_code); 69584515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 69594515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ bind(&seq_two_byte_string); 69604515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // rax: subject string 69614515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // rcx: RegExp data (FixedArray) 69624515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(r12, FieldOperand(rcx, JSRegExp::kDataUC16CodeOffset)); 69634515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ Set(rdi, 0); // Type is two byte. 69644515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 69654515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ bind(&check_code); 69664515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Check that the irregexp code has been generated for the actual string 69674515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // encoding. If it has, the field contains a code object otherwise it contains 69684515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // the hole. 69694515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ CmpObjectType(r12, CODE_TYPE, kScratchRegister); 69704515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ j(not_equal, &runtime); 69714515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 69724515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // rax: subject string 69734515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // rdi: encoding of subject string (1 if ascii, 0 if two_byte); 69744515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // r12: code 69754515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Load used arguments before starting to push arguments for call to native 69764515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // RegExp code to avoid handling changing stack height. 69774515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rbx, Operand(rsp, kPreviousIndexOffset)); 69784515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ SmiToInteger64(rbx, rbx); // Previous index from smi. 69794515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 69804515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // rax: subject string 69814515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // rbx: previous index 69824515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // rdi: encoding of subject string (1 if ascii 0 if two_byte); 69834515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // r12: code 69844515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // All checks done. Now push arguments for native regexp code. 69854515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ IncrementCounter(&Counters::regexp_entry_native, 1); 69864515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 69874515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // rsi is caller save on Windows and used to pass parameter on Linux. 69884515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ push(rsi); 69894515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 69904515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke static const int kRegExpExecuteArguments = 7; 69914515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ PrepareCallCFunction(kRegExpExecuteArguments); 69924515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke int argument_slots_on_stack = 69934515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke masm->ArgumentStackSlotsForCFunctionCall(kRegExpExecuteArguments); 69944515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 69954515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Argument 7: Indicate that this is a direct call from JavaScript. 69964515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(Operand(rsp, (argument_slots_on_stack - 1) * kPointerSize), 69974515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Immediate(1)); 69984515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 69994515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Argument 6: Start (high end) of backtracking stack memory area. 70004515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(kScratchRegister, address_of_regexp_stack_memory_address); 70014515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(r9, Operand(kScratchRegister, 0)); 70024515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(kScratchRegister, address_of_regexp_stack_memory_size); 70034515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ addq(r9, Operand(kScratchRegister, 0)); 70044515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Argument 6 passed in r9 on Linux and on the stack on Windows. 70054515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke#ifdef _WIN64 70064515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(Operand(rsp, (argument_slots_on_stack - 2) * kPointerSize), r9); 70074515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke#endif 70084515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 70094515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Argument 5: static offsets vector buffer. 70104515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(r8, ExternalReference::address_of_static_offsets_vector()); 70114515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Argument 5 passed in r8 on Linux and on the stack on Windows. 70124515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke#ifdef _WIN64 70134515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(Operand(rsp, (argument_slots_on_stack - 3) * kPointerSize), r8); 70144515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke#endif 70154515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 70164515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // First four arguments are passed in registers on both Linux and Windows. 70174515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke#ifdef _WIN64 70184515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Register arg4 = r9; 70194515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Register arg3 = r8; 70204515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Register arg2 = rdx; 70214515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Register arg1 = rcx; 70224515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke#else 70234515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Register arg4 = rcx; 70244515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Register arg3 = rdx; 70254515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Register arg2 = rsi; 70264515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Register arg1 = rdi; 70274515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke#endif 70284515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 70294515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Keep track on aliasing between argX defined above and the registers used. 70304515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // rax: subject string 70314515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // rbx: previous index 70324515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // rdi: encoding of subject string (1 if ascii 0 if two_byte); 70334515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // r12: code 70344515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 70354515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Argument 4: End of string data 70364515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Argument 3: Start of string data 70374515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Label setup_two_byte, setup_rest; 70384515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ testb(rdi, rdi); 70394515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movl(rdi, FieldOperand(rax, String::kLengthOffset)); 70404515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ j(zero, &setup_two_byte); 70414515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ lea(arg4, FieldOperand(rax, rdi, times_1, SeqAsciiString::kHeaderSize)); 70424515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ lea(arg3, FieldOperand(rax, rbx, times_1, SeqAsciiString::kHeaderSize)); 70434515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ jmp(&setup_rest); 70444515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ bind(&setup_two_byte); 70454515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ lea(arg4, FieldOperand(rax, rdi, times_2, SeqTwoByteString::kHeaderSize)); 70464515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ lea(arg3, FieldOperand(rax, rbx, times_2, SeqTwoByteString::kHeaderSize)); 70474515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 70484515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ bind(&setup_rest); 70494515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Argument 2: Previous index. 70504515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(arg2, rbx); 70514515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 70524515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Argument 1: Subject string. 70534515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(arg1, rax); 70544515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 70554515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Locate the code entry and call it. 70564515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ addq(r12, Immediate(Code::kHeaderSize - kHeapObjectTag)); 70574515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ CallCFunction(r12, kRegExpExecuteArguments); 70584515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 70594515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // rsi is caller save, as it is used to pass parameter. 70604515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ pop(rsi); 70614515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 70624515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Check the result. 70634515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Label success; 70644515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ cmpq(rax, Immediate(NativeRegExpMacroAssembler::SUCCESS)); 70654515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ j(equal, &success); 70664515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Label failure; 70674515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ cmpq(rax, Immediate(NativeRegExpMacroAssembler::FAILURE)); 70684515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ j(equal, &failure); 70694515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ cmpq(rax, Immediate(NativeRegExpMacroAssembler::EXCEPTION)); 70704515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // If not exception it can only be retry. Handle that in the runtime system. 70714515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ j(not_equal, &runtime); 70724515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Result must now be exception. If there is no pending exception already a 70734515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // stack overflow (on the backtrack stack) was detected in RegExp code but 70744515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // haven't created the exception yet. Handle that in the runtime system. 70754515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // TODO(592) Rerunning the RegExp to get the stack overflow exception. 70764515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke ExternalReference pending_exception_address(Top::k_pending_exception_address); 70774515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(kScratchRegister, pending_exception_address); 70784515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ Cmp(kScratchRegister, Factory::the_hole_value()); 70794515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ j(equal, &runtime); 70804515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ bind(&failure); 70814515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // For failure and exception return null. 70824515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ Move(rax, Factory::null_value()); 70834515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ ret(4 * kPointerSize); 70844515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 70854515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Load RegExp data. 70864515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ bind(&success); 70874515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rax, Operand(rsp, kJSRegExpOffset)); 70884515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rcx, FieldOperand(rax, JSRegExp::kDataOffset)); 70894515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rdx, FieldOperand(rcx, JSRegExp::kIrregexpCaptureCountOffset)); 70904515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Calculate number of capture registers (number_of_captures + 1) * 2. 70914515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ PositiveSmiTimesPowerOfTwoToInteger64(rdx, rdx, 1); 70924515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ addq(rdx, Immediate(2)); // rdx was number_of_captures * 2. 70934515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 70944515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // rdx: Number of capture registers 70954515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Load last_match_info which is still known to be a fast case JSArray. 70964515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rax, Operand(rsp, kLastMatchInfoOffset)); 70974515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rbx, FieldOperand(rax, JSArray::kElementsOffset)); 70984515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 70994515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // rbx: last_match_info backing store (FixedArray) 71004515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // rdx: number of capture registers 71014515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Store the capture count. 71024515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ Integer32ToSmi(kScratchRegister, rdx); 71034515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(FieldOperand(rbx, RegExpImpl::kLastCaptureCountOffset), 71044515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke kScratchRegister); 71054515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Store last subject and last input. 71064515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rax, Operand(rsp, kSubjectOffset)); 71074515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(FieldOperand(rbx, RegExpImpl::kLastSubjectOffset), rax); 71084515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rcx, rbx); 71094515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ RecordWrite(rcx, RegExpImpl::kLastSubjectOffset, rax, rdi); 71104515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rax, Operand(rsp, kSubjectOffset)); 71114515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(FieldOperand(rbx, RegExpImpl::kLastInputOffset), rax); 71124515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rcx, rbx); 71134515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ RecordWrite(rcx, RegExpImpl::kLastInputOffset, rax, rdi); 71144515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 71154515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Get the static offsets vector filled by the native regexp code. 71164515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rcx, ExternalReference::address_of_static_offsets_vector()); 71174515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 71184515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // rbx: last_match_info backing store (FixedArray) 71194515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // rcx: offsets vector 71204515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // rdx: number of capture registers 71214515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Label next_capture, done; 71224515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rax, Operand(rsp, kPreviousIndexOffset)); 71234515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Capture register counter starts from number of capture registers and 71244515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // counts down until wraping after zero. 71254515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ bind(&next_capture); 71264515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ subq(rdx, Immediate(1)); 71274515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ j(negative, &done); 71284515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Read the value from the static offsets vector buffer and make it a smi. 71294515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movl(rdi, Operand(rcx, rdx, times_int_size, 0)); 71304515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ Integer32ToSmi(rdi, rdi, &runtime); 71314515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Add previous index (from its stack slot) if value is not negative. 71324515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Label capture_negative; 71334515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Negative flag set by smi convertion above. 71344515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ j(negative, &capture_negative); 71354515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ SmiAdd(rdi, rdi, rax, &runtime); // Add previous index. 71364515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ bind(&capture_negative); 71374515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Store the smi value in the last match info. 71384515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(FieldOperand(rbx, 71394515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke rdx, 71404515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke times_pointer_size, 71414515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke RegExpImpl::kFirstCaptureOffset), 71424515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke rdi); 71434515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ jmp(&next_capture); 71444515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ bind(&done); 71454515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 71464515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Return last match info. 71474515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rax, Operand(rsp, kLastMatchInfoOffset)); 71484515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ ret(4 * kPointerSize); 71494515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 71504515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Do the runtime call to execute the regexp. 71514515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ bind(&runtime); 71524515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ TailCallRuntime(ExternalReference(Runtime::kRegExpExec), 4, 1); 71534515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke#endif // V8_NATIVE_REGEXP 71544515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke} 71554515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 71564515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 7157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CompareStub::Generate(MacroAssembler* masm) { 7158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label call_builtin, done; 7159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // NOTICE! This code is only reached after a smi-fast-case check, so 7161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // it is certain that at least one operand isn't a smi. 7162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (cc_ == equal) { // Both strict and non-strict. 7164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label slow; // Fallthrough label. 7165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Equality is almost reflexive (everything but NaN), so start by testing 7166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // for "identity and not NaN". 7167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block { 7168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label not_identical; 7169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ cmpq(rax, rdx); 7170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, ¬_identical); 7171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Test for NaN. Sadly, we can't just compare to Factory::nan_value(), 7172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // so we do the second best thing - test it ourselves. 7173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7174e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke if (never_nan_nan_) { 7175e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ xor_(rax, rax); 7176e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ ret(0); 7177e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } else { 7178e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Label return_equal; 7179e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Label heap_number; 7180e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // If it's not a heap number, then return equal. 7181e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), 7182e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Factory::heap_number_map()); 7183e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ j(equal, &heap_number); 7184e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ bind(&return_equal); 7185e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ xor_(rax, rax); 7186e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ ret(0); 7187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7188e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ bind(&heap_number); 7189e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // It is a heap number, so return non-equal if it's NaN and equal if 7190e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // it's not NaN. 7191e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // The representation of NaN values has all exponent bits (52..62) set, 7192e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // and not all mantissa bits (0..51) clear. 7193e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // We only allow QNaNs, which have bit 51 set (which also rules out 7194e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // the value being Infinity). 7195e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 7196e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Value is a QNaN if value & kQuietNaNMask == kQuietNaNMask, i.e., 7197e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // all bits in the mask are set. We only need to check the word 7198e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // that contains the exponent and high bit of the mantissa. 7199e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke ASSERT_NE(0, (kQuietNaNHighBitsMask << 1) & 0x80000000u); 7200e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movl(rdx, FieldOperand(rdx, HeapNumber::kExponentOffset)); 7201e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ xorl(rax, rax); 7202e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ addl(rdx, rdx); // Shift value and mask so mask applies to top bits. 7203e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ cmpl(rdx, Immediate(kQuietNaNHighBitsMask << 1)); 7204e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ setcc(above_equal, rax); 7205e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ ret(0); 7206e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } 7207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(¬_identical); 7209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 7210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If we're doing a strict equality comparison, we don't have to do 7212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // type conversion, so we generate code to do fast comparison for objects 7213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // and oddballs. Non-smi numbers and strings still go through the usual 7214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // slow-case code. 7215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (strict_) { 7216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If either is a Smi (we know that not both are), then they can only 7217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // be equal if the other is a HeapNumber. If so, use the slow case. 7218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block { 7219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label not_smis; 7220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ SelectNonSmi(rbx, rax, rdx, ¬_smis); 7221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check if the non-smi operand is a heap number. 7223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset), 7224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Factory::heap_number_map()); 7225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If heap number, handle it in the slow case. 7226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(equal, &slow); 7227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return non-equal. ebx (the lower half of rbx) is not zero. 7228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rax, rbx); 7229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ ret(0); 7230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(¬_smis); 7232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 7233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If either operand is a JSObject or an oddball value, then they are not 7235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // equal since their pointers are different 7236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // There is no test for undetectability in strict equality. 7237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If the first object is a JS object, we have done pointer comparison. 7239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); 7240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label first_non_object; 7241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx); 7242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(below, &first_non_object); 7243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return non-zero (eax (not rax) is not zero) 7244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label return_not_equal; 7245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(kHeapObjectTag != 0); 7246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&return_not_equal); 7247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ ret(0); 7248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&first_non_object); 7250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check for oddballs: true, false, null, undefined. 7251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CmpInstanceType(rcx, ODDBALL_TYPE); 7252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(equal, &return_not_equal); 7253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CmpObjectType(rdx, FIRST_JS_OBJECT_TYPE, rcx); 7255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(above_equal, &return_not_equal); 7256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check for oddballs: true, false, null, undefined. 7258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CmpInstanceType(rcx, ODDBALL_TYPE); 7259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(equal, &return_not_equal); 7260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Fall through to the general case. 7262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 7263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&slow); 7264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 7265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Push arguments below the return address to prepare jump to builtin. 7267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(rcx); 7268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(rax); 7269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(rdx); 7270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(rcx); 7271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Inlined floating point compare. 7273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Call builtin if operands are not floating point or smi. 7274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label check_for_symbols; 7275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Push arguments on stack, for helper functions. 72763ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block FloatingPointHelper::CheckNumberOperands(masm, &check_for_symbols); 7277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block FloatingPointHelper::LoadFloatOperands(masm, rax, rdx); 7278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ FCmp(); 7279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Jump to builtin for NaN. 7281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(parity_even, &call_builtin); 7282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // TODO(1243847): Use cmov below once CpuFeatures are properly hooked up. 7284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label below_lbl, above_lbl; 7285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // use rdx, rax to convert unsigned to signed comparison 7286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(below, &below_lbl); 7287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(above, &above_lbl); 7288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ xor_(rax, rax); // equal 7290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ ret(2 * kPointerSize); 7291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&below_lbl); 7293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rax, Immediate(-1)); 7294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ ret(2 * kPointerSize); 7295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&above_lbl); 7297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rax, Immediate(1)); 7298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ ret(2 * kPointerSize); // rax, rdx were pushed 7299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Fast negative check for symbol-to-symbol equality. 7301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&check_for_symbols); 7302e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Label check_for_strings; 7303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (cc_ == equal) { 7304e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke BranchIfNonSymbol(masm, &check_for_strings, rax, kScratchRegister); 7305e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke BranchIfNonSymbol(masm, &check_for_strings, rdx, kScratchRegister); 7306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We've already checked for object identity, so if both operands 7308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // are symbols they aren't equal. Register eax (not rax) already holds a 7309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // non-zero value, which indicates not equal, so just return. 7310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ ret(2 * kPointerSize); 7311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 7312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7313e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ bind(&check_for_strings); 7314e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 7315e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ JumpIfNotBothSequentialAsciiStrings(rdx, rax, rcx, rbx, &call_builtin); 7316e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 7317e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Inline comparison of ascii strings. 7318e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke StringCompareStub::GenerateCompareFlatAsciiStrings(masm, 7319e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke rdx, 7320e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke rax, 7321e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke rcx, 7322e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke rbx, 7323e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke rdi, 7324e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke r8); 7325e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 7326e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke#ifdef DEBUG 7327e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ Abort("Unexpected fall-through from string comparison"); 7328e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke#endif 7329e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 7330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&call_builtin); 7331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // must swap argument order 7332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(rcx); 7333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(rdx); 7334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(rax); 7335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(rdx); 7336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(rax); 7337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Figure out which native to call and setup the arguments. 7339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Builtins::JavaScript builtin; 7340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (cc_ == equal) { 7341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block builtin = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS; 7342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 7343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block builtin = Builtins::COMPARE; 7344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int ncr; // NaN compare result 7345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (cc_ == less || cc_ == less_equal) { 7346a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ncr = GREATER; 7347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 7348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(cc_ == greater || cc_ == greater_equal); // remaining cases 7349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ncr = LESS; 7350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 73513ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ Push(Smi::FromInt(ncr)); 7352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 7353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Restore return address on the stack. 7355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(rcx); 7356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7357a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) 7358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // tagged as a small integer. 7359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ InvokeBuiltin(builtin, JUMP_FUNCTION); 7360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 7361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CompareStub::BranchIfNonSymbol(MacroAssembler* masm, 7364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label* label, 7365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register object, 7366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register scratch) { 7367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfSmi(object, label); 7368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(scratch, FieldOperand(object, HeapObject::kMapOffset)); 7369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movzxbq(scratch, 7370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block FieldOperand(scratch, Map::kInstanceTypeOffset)); 7371e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Ensure that no non-strings have the symbol bit set. 7372e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke ASSERT(kNotStringTag + kIsSymbolMask > LAST_TYPE); 7373e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke ASSERT(kSymbolTag != 0); 7374e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ testb(scratch, Immediate(kIsSymbolMask)); 7375e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ j(zero, label); 7376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 7377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7378a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7379a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Call the function just below TOS on the stack with the given 7380a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// arguments. The receiver is the TOS. 7381a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, 7382e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke CallFunctionFlags flags, 7383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int position) { 7384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Push the arguments ("left-to-right") on the stack. 7385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int arg_count = args->length(); 7386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = 0; i < arg_count; i++) { 7387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Load(args->at(i)); 7388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 7389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Record the position for debugging purposes. 7391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CodeForSourcePosition(position); 7392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Use the shared code stub to call the function. 7394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP; 7395e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke CallFunctionStub call_function(arg_count, in_loop, flags); 7396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Result answer = frame_->CallStub(&call_function, arg_count + 1); 7397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Restore context and replace function on the stack with the 7398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // result of the stub invocation. 7399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->RestoreContextRegister(); 7400a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frame_->SetElementAt(0, &answer); 7401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 7402a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7403a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7404a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid InstanceofStub::Generate(MacroAssembler* masm) { 7405a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Implements "value instanceof function" operator. 7406a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Expected input state: 7407a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rsp[0] : return address 7408a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rsp[1] : function pointer 7409a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rsp[2] : value 7410a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7411a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the object - go slow case if it's a smi. 7412a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label slow; 7413a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rax, Operand(rsp, 2 * kPointerSize)); 7414a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfSmi(rax, &slow); 7415a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7416a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the left hand is a JS object. Leave its map in rax. 7417a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rax); 7418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(below, &slow); 7419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CmpInstanceType(rax, LAST_JS_OBJECT_TYPE); 7420a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(above, &slow); 7421a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7422a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the prototype of the function. 7423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rdx, Operand(rsp, 1 * kPointerSize)); 7424a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ TryGetFunctionPrototype(rdx, rbx, &slow); 7425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7426a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the function prototype is a JS object. 7427a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfSmi(rbx, &slow); 7428a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, kScratchRegister); 7429a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(below, &slow); 7430a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CmpInstanceType(kScratchRegister, LAST_JS_OBJECT_TYPE); 7431a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(above, &slow); 7432a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7433a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Register mapping: rax is object map and rbx is function prototype. 7434a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rcx, FieldOperand(rax, Map::kPrototypeOffset)); 7435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Loop through the prototype chain looking for the function prototype. 7437a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label loop, is_instance, is_not_instance; 7438a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ LoadRoot(kScratchRegister, Heap::kNullValueRootIndex); 7439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&loop); 7440a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ cmpq(rcx, rbx); 7441a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(equal, &is_instance); 7442a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ cmpq(rcx, kScratchRegister); 7443a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(equal, &is_not_instance); 7444a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset)); 7445a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rcx, FieldOperand(rcx, Map::kPrototypeOffset)); 7446a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ jmp(&loop); 7447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7448a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&is_instance); 7449d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ xorl(rax, rax); 7450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ ret(2 * kPointerSize); 7451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&is_not_instance); 7453d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ movl(rax, Immediate(1)); 7454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ ret(2 * kPointerSize); 7455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Slow-case: Go through the JavaScript implementation. 7457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&slow); 7458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); 7459a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 7460a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7461a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7462a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) { 7463402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // rsp[0] : return address 7464402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // rsp[8] : number of parameters 7465402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // rsp[16] : receiver displacement 7466402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // rsp[24] : function 7467402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 7468a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The displacement is used for skipping the return address and the 7469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // frame pointer on the stack. It is the offset of the last 7470a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // parameter (if any) relative to the frame pointer. 7471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block static const int kDisplacement = 2 * kPointerSize; 7472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7473a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check if the calling frame is an arguments adaptor frame. 7474402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Label adaptor_frame, try_allocate, runtime; 7475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); 74763ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ SmiCompare(Operand(rdx, StandardFrameConstants::kContextOffset), 74773ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); 7478402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ j(equal, &adaptor_frame); 7479402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 7480402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Get the length from the frame. 7481402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ movq(rcx, Operand(rsp, 1 * kPointerSize)); 7482402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ jmp(&try_allocate); 7483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Patch the arguments.length and the parameters pointer. 7485402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ bind(&adaptor_frame); 7486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rcx, Operand(rdx, ArgumentsAdaptorFrameConstants::kLengthOffset)); 7487a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(Operand(rsp, 1 * kPointerSize), rcx); 7488402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Do not clobber the length index for the indexing operation since 7489402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // it is used compute the size for allocation later. 7490402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu SmiIndex index = masm->SmiToIndex(rbx, rcx, kPointerSizeLog2); 7491a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ lea(rdx, Operand(rdx, index.reg, index.scale, kDisplacement)); 7492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(Operand(rsp, 2 * kPointerSize), rdx); 7493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7494402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Try the new space allocation. Start out with computing the size of 7495402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // the arguments object and the elements array. 7496402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Label add_arguments_object; 7497402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ bind(&try_allocate); 7498402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ testq(rcx, rcx); 7499402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ j(zero, &add_arguments_object); 7500402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu index = masm->SmiToIndex(rcx, rcx, kPointerSizeLog2); 7501402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ lea(rcx, Operand(index.reg, index.scale, FixedArray::kHeaderSize)); 7502402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ bind(&add_arguments_object); 7503402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ addq(rcx, Immediate(Heap::kArgumentsObjectSize)); 7504402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 7505402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Do the allocation of both objects in one go. 7506402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ AllocateInNewSpace(rcx, rax, rdx, rbx, &runtime, TAG_OBJECT); 7507402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 7508402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Get the arguments boilerplate from the current (global) context. 7509402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu int offset = Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX); 7510402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ movq(rdi, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX))); 7511402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ movq(rdi, FieldOperand(rdi, GlobalObject::kGlobalContextOffset)); 7512402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ movq(rdi, Operand(rdi, offset)); 7513402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 7514402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Copy the JS object part. 7515402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { 7516402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ movq(kScratchRegister, FieldOperand(rdi, i)); 7517402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ movq(FieldOperand(rax, i), kScratchRegister); 7518402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu } 7519402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 7520402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Setup the callee in-object property. 7521402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu ASSERT(Heap::arguments_callee_index == 0); 7522402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ movq(kScratchRegister, Operand(rsp, 3 * kPointerSize)); 7523402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ movq(FieldOperand(rax, JSObject::kHeaderSize), kScratchRegister); 7524402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 7525402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Get the length (smi tagged) and set that as an in-object property too. 7526402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu ASSERT(Heap::arguments_length_index == 1); 7527402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ movq(rcx, Operand(rsp, 1 * kPointerSize)); 7528402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ movq(FieldOperand(rax, JSObject::kHeaderSize + kPointerSize), rcx); 7529402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 7530402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // If there are no actual arguments, we're done. 7531402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Label done; 7532402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ testq(rcx, rcx); 7533402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ j(zero, &done); 7534402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 7535402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Get the parameters pointer from the stack and untag the length. 7536402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ movq(rdx, Operand(rsp, 2 * kPointerSize)); 7537402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ SmiToInteger32(rcx, rcx); 7538402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 7539402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Setup the elements pointer in the allocated arguments object and 7540402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // initialize the header in the elements fixed array. 7541402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ lea(rdi, Operand(rax, Heap::kArgumentsObjectSize)); 7542402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ movq(FieldOperand(rax, JSObject::kElementsOffset), rdi); 7543402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ LoadRoot(kScratchRegister, Heap::kFixedArrayMapRootIndex); 7544402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ movq(FieldOperand(rdi, FixedArray::kMapOffset), kScratchRegister); 7545402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ movq(FieldOperand(rdi, FixedArray::kLengthOffset), rcx); 7546402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 7547402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Copy the fixed array slots. 7548402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Label loop; 7549402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ bind(&loop); 7550402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ movq(kScratchRegister, Operand(rdx, -1 * kPointerSize)); // Skip receiver. 7551402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ movq(FieldOperand(rdi, FixedArray::kHeaderSize), kScratchRegister); 7552402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ addq(rdi, Immediate(kPointerSize)); 7553402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ subq(rdx, Immediate(kPointerSize)); 7554402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ decq(rcx); 7555402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ j(not_zero, &loop); 7556402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 7557402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Return and remove the on-stack parameters. 7558402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ bind(&done); 7559402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ ret(3 * kPointerSize); 7560402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 7561a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Do the runtime call to allocate the arguments object. 7562a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&runtime); 7563402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ TailCallRuntime(ExternalReference(Runtime::kNewArgumentsFast), 3, 1); 7564a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 7565a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7566a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7567a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { 7568a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The key is in rdx and the parameter count is in rax. 7569a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7570a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The displacement is used for skipping the frame pointer on the 7571a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // stack. It is the offset of the last parameter (if any) relative 7572a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // to the frame pointer. 7573a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block static const int kDisplacement = 1 * kPointerSize; 7574a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7575a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the key is a smi. 7576a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label slow; 7577a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfNotSmi(rdx, &slow); 7578a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7579a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check if the calling frame is an arguments adaptor frame. 7580a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label adaptor; 7581a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); 75823ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ SmiCompare(Operand(rbx, StandardFrameConstants::kContextOffset), 75833ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); 7584a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(equal, &adaptor); 7585a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7586a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check index against formal parameters count limit passed in 7587a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // through register rax. Use unsigned comparison to get negative 7588a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // check for free. 7589a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ cmpq(rdx, rax); 7590a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(above_equal, &slow); 7591a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7592a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Read the argument from the stack and return it. 7593a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block SmiIndex index = masm->SmiToIndex(rax, rax, kPointerSizeLog2); 7594a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ lea(rbx, Operand(rbp, index.reg, index.scale, 0)); 7595a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block index = masm->SmiToNegativeIndex(rdx, rdx, kPointerSizeLog2); 7596a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rax, Operand(rbx, index.reg, index.scale, kDisplacement)); 7597a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Ret(); 7598a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7599a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Arguments adaptor case: Check index against actual arguments 7600a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // limit found in the arguments adaptor frame. Use unsigned 7601a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // comparison to get negative check for free. 7602a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&adaptor); 7603a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rcx, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset)); 7604a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ cmpq(rdx, rcx); 7605a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(above_equal, &slow); 7606a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7607a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Read the argument from the stack and return it. 7608a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block index = masm->SmiToIndex(rax, rcx, kPointerSizeLog2); 7609a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ lea(rbx, Operand(rbx, index.reg, index.scale, 0)); 7610a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block index = masm->SmiToNegativeIndex(rdx, rdx, kPointerSizeLog2); 7611a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rax, Operand(rbx, index.reg, index.scale, kDisplacement)); 7612a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Ret(); 7613a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7614a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Slow-case: Handle non-smi or out-of-bounds access to arguments 7615a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // by calling the runtime system. 7616a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&slow); 7617a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(rbx); // Return address. 7618a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(rdx); 7619a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(rbx); 7620a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Runtime::Function* f = 7621a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Runtime::FunctionForId(Runtime::kGetArgumentsProperty); 7622a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ TailCallRuntime(ExternalReference(f), 1, f->result_size); 7623a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 7624a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7625a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7626a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid ArgumentsAccessStub::GenerateReadLength(MacroAssembler* masm) { 7627a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check if the calling frame is an arguments adaptor frame. 7628a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label adaptor; 7629a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); 76303ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ SmiCompare(Operand(rdx, StandardFrameConstants::kContextOffset), 76313ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); 7632a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7633a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Arguments adaptor case: Read the arguments length from the 7634a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // adaptor frame and return it. 7635e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Otherwise nothing to do: The number of formal parameters has already been 7636e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // passed in register eax by calling function. Just return it. 7637e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ cmovq(equal, rax, 7638e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Operand(rdx, ArgumentsAdaptorFrameConstants::kLengthOffset)); 7639a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ ret(0); 7640a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 7641a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7642a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7643a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { 7644a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that stack should contain next handler, frame pointer, state and 7645a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // return address in that order. 7646a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT_EQ(StackHandlerConstants::kFPOffset + kPointerSize, 7647a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block StackHandlerConstants::kStateOffset); 7648a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT_EQ(StackHandlerConstants::kStateOffset + kPointerSize, 7649a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block StackHandlerConstants::kPCOffset); 7650a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7651a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ExternalReference handler_address(Top::k_handler_address); 7652a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(kScratchRegister, handler_address); 7653a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rsp, Operand(kScratchRegister, 0)); 7654a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // get next in chain 7655a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(rcx); 7656a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(Operand(kScratchRegister, 0), rcx); 7657a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(rbp); // pop frame pointer 7658a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(rdx); // remove state 7659a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7660a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Before returning we restore the context from the frame pointer if not NULL. 7661a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The frame pointer is NULL in the exception handler of a JS entry frame. 7662a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ xor_(rsi, rsi); // tentatively set context pointer to NULL 7663a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label skip; 7664a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ cmpq(rbp, Immediate(0)); 7665a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(equal, &skip); 7666a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); 7667a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&skip); 7668a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ ret(0); 7669a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 7670a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7671a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7672a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CEntryStub::GenerateCore(MacroAssembler* masm, 7673a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label* throw_normal_exception, 7674a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label* throw_termination_exception, 7675a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label* throw_out_of_memory_exception, 7676a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool do_gc, 7677a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool always_allocate_scope) { 7678a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rax: result parameter for PerformGC, if any. 7679a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rbx: pointer to C function (C callee-saved). 7680a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rbp: frame pointer (restored after C call). 7681a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rsp: stack pointer (restored after C call). 7682a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // r14: number of arguments including receiver (C callee-saved). 7683a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // r15: pointer to the first argument (C callee-saved). 7684a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // This pointer is reused in LeaveExitFrame(), so it is stored in a 7685a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // callee-saved register. 7686a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 76874515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Simple results returned in rax (both AMD64 and Win64 calling conventions). 76884515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Complex results must be written to address passed as first argument. 76894515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // AMD64 calling convention: a struct of two pointers in rax+rdx 76904515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 7691a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (do_gc) { 7692a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Pass failure code returned from last attempt as first argument to GC. 7693a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef _WIN64 7694a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rcx, rax); 7695a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#else // ! defined(_WIN64) 7696a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rdi, rax); 7697a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif 7698a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(kScratchRegister, 7699a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block FUNCTION_ADDR(Runtime::PerformGC), 7700a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block RelocInfo::RUNTIME_ENTRY); 7701a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ call(kScratchRegister); 7702a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 7703a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7704a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ExternalReference scope_depth = 7705a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ExternalReference::heap_always_allocate_scope_depth(); 7706a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (always_allocate_scope) { 7707a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(kScratchRegister, scope_depth); 7708a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ incl(Operand(kScratchRegister, 0)); 7709a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 7710a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7711a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Call C function. 7712a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef _WIN64 7713a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Windows 64-bit ABI passes arguments in rcx, rdx, r8, r9 7714a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Store Arguments object on stack, below the 4 WIN64 ABI parameter slots. 7715a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(Operand(rsp, 4 * kPointerSize), r14); // argc. 7716a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(Operand(rsp, 5 * kPointerSize), r15); // argv. 7717a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (result_size_ < 2) { 7718a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Pass a pointer to the Arguments object as the first argument. 7719a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return result in single register (rax). 7720a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ lea(rcx, Operand(rsp, 4 * kPointerSize)); 7721a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 7722a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT_EQ(2, result_size_); 7723a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Pass a pointer to the result location as the first argument. 7724a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ lea(rcx, Operand(rsp, 6 * kPointerSize)); 7725a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Pass a pointer to the Arguments object as the second argument. 7726a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ lea(rdx, Operand(rsp, 4 * kPointerSize)); 7727a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 7728a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7729a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#else // ! defined(_WIN64) 7730a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // GCC passes arguments in rdi, rsi, rdx, rcx, r8, r9. 7731a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rdi, r14); // argc. 7732a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rsi, r15); // argv. 7733a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif 7734a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ call(rbx); 7735a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Result is in rax - do not destroy this register! 7736a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7737a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (always_allocate_scope) { 7738a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(kScratchRegister, scope_depth); 7739a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ decl(Operand(kScratchRegister, 0)); 7740a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 7741a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7742a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check for failure result. 7743a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label failure_returned; 7744a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0); 77453ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block#ifdef _WIN64 77463ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // If return value is on the stack, pop it to registers. 77473ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block if (result_size_ > 1) { 77483ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block ASSERT_EQ(2, result_size_); 7749d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Read result values stored on stack. Result is stored 7750d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // above the four argument mirror slots and the two 7751d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Arguments object slots. 77523ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ movq(rax, Operand(rsp, 6 * kPointerSize)); 77533ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ movq(rdx, Operand(rsp, 7 * kPointerSize)); 77543ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block } 77553ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block#endif 7756a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ lea(rcx, Operand(rax, 1)); 7757a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Lower 2 bits of rcx are 0 iff rax has failure tag. 7758a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ testl(rcx, Immediate(kFailureTagMask)); 7759a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(zero, &failure_returned); 7760a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7761a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Exit the JavaScript to C++ exit frame. 77624515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ LeaveExitFrame(mode_, result_size_); 7763a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ ret(0); 7764a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7765a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Handling of failure. 7766a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&failure_returned); 7767a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7768a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label retry; 7769a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If the returned exception is RETRY_AFTER_GC continue at retry label 7770a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(Failure::RETRY_AFTER_GC == 0); 7771a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ testl(rax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize)); 7772a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(zero, &retry); 7773a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7774a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Special handling of out of memory exceptions. 7775a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(kScratchRegister, Failure::OutOfMemoryException(), RelocInfo::NONE); 7776a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ cmpq(rax, kScratchRegister); 7777a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(equal, throw_out_of_memory_exception); 7778a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7779a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Retrieve the pending exception and clear the variable. 7780a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ExternalReference pending_exception_address(Top::k_pending_exception_address); 7781a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(kScratchRegister, pending_exception_address); 7782a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rax, Operand(kScratchRegister, 0)); 7783a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rdx, ExternalReference::the_hole_value_location()); 7784a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rdx, Operand(rdx, 0)); 7785a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(Operand(kScratchRegister, 0), rdx); 7786a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7787a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Special handling of termination exceptions which are uncatchable 7788a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // by javascript code. 7789a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CompareRoot(rax, Heap::kTerminationExceptionRootIndex); 7790a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(equal, throw_termination_exception); 7791a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7792a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Handle normal exception. 7793a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ jmp(throw_normal_exception); 7794a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7795a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Retry. 7796a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&retry); 7797a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 7798a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7799a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7800a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CEntryStub::GenerateThrowUncatchable(MacroAssembler* masm, 7801a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block UncatchableExceptionType type) { 7802a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Fetch top stack handler. 7803a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ExternalReference handler_address(Top::k_handler_address); 7804a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(kScratchRegister, handler_address); 7805a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rsp, Operand(kScratchRegister, 0)); 7806a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7807a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Unwind the handlers until the ENTRY handler is found. 7808a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label loop, done; 7809a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&loop); 7810a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load the type of the current stack handler. 7811a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const int kStateOffset = StackHandlerConstants::kStateOffset; 7812a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ cmpq(Operand(rsp, kStateOffset), Immediate(StackHandler::ENTRY)); 7813a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(equal, &done); 7814a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Fetch the next handler in the list. 7815a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const int kNextOffset = StackHandlerConstants::kNextOffset; 7816a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rsp, Operand(rsp, kNextOffset)); 7817a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ jmp(&loop); 7818a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&done); 7819a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7820a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Set the top handler address to next handler past the current ENTRY handler. 7821a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(kScratchRegister, handler_address); 7822a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(Operand(kScratchRegister, 0)); 7823a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7824a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (type == OUT_OF_MEMORY) { 7825a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Set external caught exception to false. 7826a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ExternalReference external_caught(Top::k_external_caught_exception_address); 7827a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rax, Immediate(false)); 7828a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ store_rax(external_caught); 7829a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7830a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Set pending exception and rax to out of memory exception. 7831a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ExternalReference pending_exception(Top::k_pending_exception_address); 7832a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rax, Failure::OutOfMemoryException(), RelocInfo::NONE); 7833a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ store_rax(pending_exception); 7834a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 7835a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7836a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Clear the context pointer. 7837a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ xor_(rsi, rsi); 7838a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7839a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Restore registers from handler. 7840a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT_EQ(StackHandlerConstants::kNextOffset + kPointerSize, 7841a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block StackHandlerConstants::kFPOffset); 7842a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(rbp); // FP 7843a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT_EQ(StackHandlerConstants::kFPOffset + kPointerSize, 7844a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block StackHandlerConstants::kStateOffset); 7845a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(rdx); // State 7846a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7847a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT_EQ(StackHandlerConstants::kStateOffset + kPointerSize, 7848a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block StackHandlerConstants::kPCOffset); 7849a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ ret(0); 7850a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 7851a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7852a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7853a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CallFunctionStub::Generate(MacroAssembler* masm) { 7854a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label slow; 7855a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7856e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // If the receiver might be a value (string, number or boolean) check for this 7857e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // and box it if it is. 7858e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke if (ReceiverMightBeValue()) { 7859e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Get the receiver from the stack. 7860e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // +1 ~ return address 7861e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Label receiver_is_value, receiver_is_js_object; 7862e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(rax, Operand(rsp, (argc_ + 1) * kPointerSize)); 7863e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 7864e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Check if receiver is a smi (which is a number value). 7865e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ JumpIfSmi(rax, &receiver_is_value); 7866e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 7867e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Check if the receiver is a valid JS object. 7868e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rdi); 7869e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ j(above_equal, &receiver_is_js_object); 7870e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 7871e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Call the runtime to box the value. 7872e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ bind(&receiver_is_value); 7873e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ EnterInternalFrame(); 7874e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ push(rax); 7875e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); 7876e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ LeaveInternalFrame(); 7877e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(Operand(rsp, (argc_ + 1) * kPointerSize), rax); 7878e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 7879e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ bind(&receiver_is_js_object); 7880e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } 7881e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 7882a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the function to call from the stack. 7883a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // +2 ~ receiver, return address 7884a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rdi, Operand(rsp, (argc_ + 2) * kPointerSize)); 7885a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7886a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the function really is a JavaScript function. 7887a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfSmi(rdi, &slow); 7888a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Goto slow case if we do not have a function. 7889a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); 7890a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, &slow); 7891a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7892a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Fast-case: Just invoke the function. 7893a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ParameterCount actual(argc_); 7894a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ InvokeFunction(rdi, actual, JUMP_FUNCTION); 7895a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7896a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Slow-case: Non-function called. 7897a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&slow); 7898402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // CALL_NON_FUNCTION expects the non-function callee as receiver (instead 7899402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // of the original receiver from the call site). 7900402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ movq(Operand(rsp, (argc_ + 1) * kPointerSize), rdi); 7901a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Set(rax, argc_); 7902a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Set(rbx, 0); 7903a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION); 7904a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<Code> adaptor(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)); 7905a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Jump(adaptor, RelocInfo::CODE_TARGET); 7906a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 7907a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7908a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 79094515c472dc3e5ed2448a564600976759e569a0a8Leon Clarkevoid CEntryStub::Generate(MacroAssembler* masm) { 7910a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rax: number of arguments including receiver 7911a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rbx: pointer to C function (C callee-saved) 7912a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rbp: frame pointer of calling JS frame (restored after C call) 7913a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rsp: stack pointer (restored after C call) 7914a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rsi: current context (restored) 7915a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7916a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // NOTE: Invocations of builtins may return failure objects 7917a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // instead of a proper result. The builtin entry handles 7918a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // this by performing a garbage collection and retrying the 7919a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // builtin once. 7920a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7921a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Enter the exit frame that transitions from JavaScript to C++. 79224515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ EnterExitFrame(mode_, result_size_); 7923a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7924a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rax: Holds the context at this point, but should not be used. 7925a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // On entry to code generated by GenerateCore, it must hold 7926a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // a failure result if the collect_garbage argument to GenerateCore 7927a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // is true. This failure result can be the result of code 7928a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // generated by a previous call to GenerateCore. The value 7929a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // of rax is then passed to Runtime::PerformGC. 7930a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rbx: pointer to builtin function (C callee-saved). 7931a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rbp: frame pointer of exit frame (restored after C call). 7932a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rsp: stack pointer (restored after C call). 7933a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // r14: number of arguments including receiver (C callee-saved). 7934a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // r15: argv pointer (C callee-saved). 7935a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7936a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label throw_normal_exception; 7937a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label throw_termination_exception; 7938a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label throw_out_of_memory_exception; 7939a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7940a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Call into the runtime system. 7941a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GenerateCore(masm, 7942a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block &throw_normal_exception, 7943a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block &throw_termination_exception, 7944a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block &throw_out_of_memory_exception, 7945a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block false, 7946a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block false); 7947a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7948a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Do space-specific GC and retry runtime call. 7949a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GenerateCore(masm, 7950a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block &throw_normal_exception, 7951a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block &throw_termination_exception, 7952a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block &throw_out_of_memory_exception, 7953a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block true, 7954a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block false); 7955a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7956a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Do full GC and retry runtime call one final time. 7957a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Failure* failure = Failure::InternalError(); 7958a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rax, failure, RelocInfo::NONE); 7959a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GenerateCore(masm, 7960a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block &throw_normal_exception, 7961a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block &throw_termination_exception, 7962a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block &throw_out_of_memory_exception, 7963a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block true, 7964a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block true); 7965a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7966a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&throw_out_of_memory_exception); 7967a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GenerateThrowUncatchable(masm, OUT_OF_MEMORY); 7968a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7969a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&throw_termination_exception); 7970a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GenerateThrowUncatchable(masm, TERMINATION); 7971a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7972a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&throw_normal_exception); 7973a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GenerateThrowTOS(masm); 7974a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 7975a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7976a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7977d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid ApiGetterEntryStub::Generate(MacroAssembler* masm) { 7978d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block UNREACHABLE(); 7979d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block} 7980d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 7981d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 7982a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { 7983a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label invoke, exit; 7984a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef ENABLE_LOGGING_AND_PROFILING 7985a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label not_outermost_js, not_outermost_js_2; 7986a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif 7987a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7988a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Setup frame. 7989a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(rbp); 7990a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rbp, rsp); 7991a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7992a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Push the stack frame type marker twice. 7993a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY; 79943ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ Push(Smi::FromInt(marker)); // context slot 79953ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ Push(Smi::FromInt(marker)); // function slot 7996a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Save callee-saved registers (X64 calling conventions). 7997a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(r12); 7998a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(r13); 7999a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(r14); 8000a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(r15); 8001a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(rdi); 8002a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(rsi); 8003a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(rbx); 8004a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // TODO(X64): Push XMM6-XMM15 (low 64 bits) as well, or make them 8005a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // callee-save in JS code as well. 8006a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8007a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Save copies of the top frame descriptor on the stack. 8008a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ExternalReference c_entry_fp(Top::k_c_entry_fp_address); 8009a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ load_rax(c_entry_fp); 8010a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(rax); 8011a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8012a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef ENABLE_LOGGING_AND_PROFILING 8013a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If this is the outermost JS call, set js_entry_sp value. 8014a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ExternalReference js_entry_sp(Top::k_js_entry_sp_address); 8015a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ load_rax(js_entry_sp); 8016a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ testq(rax, rax); 8017a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_zero, ¬_outermost_js); 8018a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rax, rbp); 8019a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ store_rax(js_entry_sp); 8020a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(¬_outermost_js); 8021a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif 8022a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8023a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Call a faked try-block that does the invoke. 8024a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ call(&invoke); 8025a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8026a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Caught exception: Store result (exception) in the pending 8027a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // exception field in the JSEnv and return a failure sentinel. 8028a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ExternalReference pending_exception(Top::k_pending_exception_address); 8029a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ store_rax(pending_exception); 8030a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rax, Failure::Exception(), RelocInfo::NONE); 8031a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ jmp(&exit); 8032a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8033a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Invoke: Link this frame into the handler chain. 8034a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&invoke); 8035a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER); 8036a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8037a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Clear any pending exceptions. 8038a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ load_rax(ExternalReference::the_hole_value_location()); 8039a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ store_rax(pending_exception); 8040a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8041a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Fake a receiver (NULL). 8042a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(Immediate(0)); // receiver 8043a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8044a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Invoke the function by calling through JS entry trampoline 8045a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // builtin and pop the faked function when we return. We load the address 8046a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // from an external reference instead of inlining the call target address 8047a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // directly in the code, because the builtin stubs may not have been 8048a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // generated yet at the time this code is generated. 8049a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (is_construct) { 8050a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ExternalReference construct_entry(Builtins::JSConstructEntryTrampoline); 8051a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ load_rax(construct_entry); 8052a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 8053a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ExternalReference entry(Builtins::JSEntryTrampoline); 8054a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ load_rax(entry); 8055a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 8056a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ lea(kScratchRegister, FieldOperand(rax, Code::kHeaderSize)); 8057a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ call(kScratchRegister); 8058a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8059a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Unlink this frame from the handler chain. 8060a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(kScratchRegister, ExternalReference(Top::k_handler_address)); 8061a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(Operand(kScratchRegister, 0)); 8062a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Pop next_sp. 8063a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ addq(rsp, Immediate(StackHandlerConstants::kSize - kPointerSize)); 8064a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8065a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef ENABLE_LOGGING_AND_PROFILING 8066a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If current EBP value is the same as js_entry_sp value, it means that 8067a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // the current function is the outermost. 8068a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(kScratchRegister, js_entry_sp); 8069a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ cmpq(rbp, Operand(kScratchRegister, 0)); 8070a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, ¬_outermost_js_2); 8071a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(Operand(kScratchRegister, 0), Immediate(0)); 8072a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(¬_outermost_js_2); 8073a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif 8074a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8075a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Restore the top frame descriptor from the stack. 8076a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&exit); 8077a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(kScratchRegister, ExternalReference(Top::k_c_entry_fp_address)); 8078a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(Operand(kScratchRegister, 0)); 8079a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8080a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Restore callee-saved registers (X64 conventions). 8081a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(rbx); 8082a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(rsi); 8083a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(rdi); 8084a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(r15); 8085a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(r14); 8086a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(r13); 8087a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(r12); 8088a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ addq(rsp, Immediate(2 * kPointerSize)); // remove markers 8089a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8090a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Restore frame pointer and return. 8091a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(rbp); 8092a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ ret(0); 8093a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 8094a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8095a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8096a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ----------------------------------------------------------------------------- 8097a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Implementation of stubs. 8098a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8099a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Stub classes have public member named masm, not masm_. 8100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StackCheckStub::Generate(MacroAssembler* masm) { 8102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Because builtins always remove the receiver from the stack, we 8103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // have to fake one to avoid underflowing the stack. The receiver 8104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // must be inserted below the return address on the stack so we 8105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // temporarily store that in a register. 8106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(rax); 81073ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ Push(Smi::FromInt(0)); 8108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(rax); 8109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Do tail-call to runtime routine. 8111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Runtime::Function* f = Runtime::FunctionForId(Runtime::kStackGuard); 8112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ TailCallRuntime(ExternalReference(f), 1, f->result_size); 8113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 8114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, 8117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register number) { 8118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label load_smi, done; 8119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfSmi(number, &load_smi); 8121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ fld_d(FieldOperand(number, HeapNumber::kValueOffset)); 8122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ jmp(&done); 8123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&load_smi); 8125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ SmiToInteger32(number, number); 8126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(number); 8127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ fild_s(Operand(rsp, 0)); 8128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(number); 8129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&done); 8131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 8132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, 8135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register src, 8136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block XMMRegister dst) { 8137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label load_smi, done; 8138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfSmi(src, &load_smi); 8140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movsd(dst, FieldOperand(src, HeapNumber::kValueOffset)); 8141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ jmp(&done); 8142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&load_smi); 8144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ SmiToInteger32(src, src); 8145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ cvtlsi2sd(dst, src); 8146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&done); 8148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 8149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, 8152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block XMMRegister dst1, 8153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block XMMRegister dst2) { 81544515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(kScratchRegister, rdx); 8155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block LoadFloatOperand(masm, kScratchRegister, dst1); 81564515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(kScratchRegister, rax); 8157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block LoadFloatOperand(masm, kScratchRegister, dst2); 8158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 8159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 81614515c472dc3e5ed2448a564600976759e569a0a8Leon Clarkevoid FloatingPointHelper::LoadFloatOperandsFromSmis(MacroAssembler* masm, 81624515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke XMMRegister dst1, 81634515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke XMMRegister dst2) { 81644515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ SmiToInteger32(kScratchRegister, rdx); 81654515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ cvtlsi2sd(dst1, kScratchRegister); 81664515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ SmiToInteger32(kScratchRegister, rax); 81674515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ cvtlsi2sd(dst2, kScratchRegister); 8168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 8169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8171d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke// Input: rdx, rax are the left and right objects of a bit op. 8172d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke// Output: rax, rcx are left and right integers for a bit op. 8173d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarkevoid FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm, 8174d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke bool use_sse3, 8175d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Label* conversion_failure) { 8176d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Check float operands. 8177d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Label arg1_is_object, check_undefined_arg1; 8178d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Label arg2_is_object, check_undefined_arg2; 8179d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Label load_arg2, done; 8180d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 8181d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ JumpIfNotSmi(rdx, &arg1_is_object); 8182d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ SmiToInteger32(rdx, rdx); 8183d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ jmp(&load_arg2); 8184d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 8185d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // If the argument is undefined it converts to zero (ECMA-262, section 9.5). 8186d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ bind(&check_undefined_arg1); 8187d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); 8188d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(not_equal, conversion_failure); 8189d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movl(rdx, Immediate(0)); 8190d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ jmp(&load_arg2); 8191d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 8192d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ bind(&arg1_is_object); 8193d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); 8194d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ CompareRoot(rbx, Heap::kHeapNumberMapRootIndex); 8195d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(not_equal, &check_undefined_arg1); 8196d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Get the untagged integer version of the edx heap number in rcx. 8197d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke IntegerConvert(masm, rdx, use_sse3, conversion_failure); 8198d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movl(rdx, rcx); 8199d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 8200d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Here edx has the untagged integer, eax has a Smi or a heap number. 8201d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ bind(&load_arg2); 8202d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Test if arg2 is a Smi. 8203d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ JumpIfNotSmi(rax, &arg2_is_object); 8204d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ SmiToInteger32(rax, rax); 8205d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movl(rcx, rax); 8206d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ jmp(&done); 8207d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 8208d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // If the argument is undefined it converts to zero (ECMA-262, section 9.5). 8209d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ bind(&check_undefined_arg2); 8210d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); 8211d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(not_equal, conversion_failure); 8212d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movl(rcx, Immediate(0)); 8213d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ jmp(&done); 8214d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 8215d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ bind(&arg2_is_object); 8216d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); 8217d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ CompareRoot(rbx, Heap::kHeapNumberMapRootIndex); 8218d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(not_equal, &check_undefined_arg2); 8219d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Get the untagged integer version of the eax heap number in ecx. 8220d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke IntegerConvert(masm, rax, use_sse3, conversion_failure); 8221d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ bind(&done); 8222d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movl(rax, rdx); 8223d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke} 8224d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 8225d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 8226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, 8227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register lhs, 8228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register rhs) { 8229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label load_smi_lhs, load_smi_rhs, done_load_lhs, done; 8230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfSmi(lhs, &load_smi_lhs); 8231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ fld_d(FieldOperand(lhs, HeapNumber::kValueOffset)); 8232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&done_load_lhs); 8233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfSmi(rhs, &load_smi_rhs); 8235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ fld_d(FieldOperand(rhs, HeapNumber::kValueOffset)); 8236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ jmp(&done); 8237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&load_smi_lhs); 8239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ SmiToInteger64(kScratchRegister, lhs); 8240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(kScratchRegister); 8241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ fild_d(Operand(rsp, 0)); 8242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(kScratchRegister); 8243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ jmp(&done_load_lhs); 8244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&load_smi_rhs); 8246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ SmiToInteger64(kScratchRegister, rhs); 8247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(kScratchRegister); 8248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ fild_d(Operand(rsp, 0)); 8249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(kScratchRegister); 8250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&done); 8252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 8253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 82553ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Blockvoid FloatingPointHelper::CheckNumberOperands(MacroAssembler* masm, 82563ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block Label* non_float) { 8257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label test_other, done; 8258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Test if both operands are numbers (heap_numbers or smis). 8259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If not, jump to label non_float. 8260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfSmi(rdx, &test_other); // argument in rdx is OK 8261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), Factory::heap_number_map()); 8262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, non_float); // The argument in rdx is not a number. 8263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&test_other); 8265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfSmi(rax, &done); // argument in rax is OK 8266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Cmp(FieldOperand(rax, HeapObject::kMapOffset), Factory::heap_number_map()); 8267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, non_float); // The argument in rax is not a number. 8268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Fall-through: Both operands are numbers. 8270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&done); 8271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 8272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockconst char* GenericBinaryOpStub::GetName() { 8275e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke if (name_ != NULL) return name_; 8276e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke const int len = 100; 8277e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke name_ = Bootstrapper::AllocateAutoDeletedArray(len); 8278e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke if (name_ == NULL) return "OOM"; 8279e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke const char* op_name = Token::Name(op_); 8280e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke const char* overwrite_name; 8281e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke switch (mode_) { 8282e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke case NO_OVERWRITE: overwrite_name = "Alloc"; break; 8283e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; 8284e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; 8285e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke default: overwrite_name = "UnknownOverwrite"; break; 8286e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } 8287e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 8288e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke OS::SNPrintF(Vector<char>(name_, len), 8289402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu "GenericBinaryOpStub_%s_%s%s_%s%s_%s%s", 8290e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke op_name, 8291e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke overwrite_name, 8292e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "", 8293e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke args_in_registers_ ? "RegArgs" : "StackArgs", 8294e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke args_reversed_ ? "_R" : "", 8295402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu use_sse3_ ? "SSE3" : "SSE2", 8296402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu NumberInfo::ToString(operands_type_)); 8297e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke return name_; 8298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 8299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8301d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid GenericBinaryOpStub::GenerateCall( 8302d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block MacroAssembler* masm, 8303d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Register left, 8304d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Register right) { 8305d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block if (!ArgsInRegistersSupported()) { 8306d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Pass arguments on the stack. 8307d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ push(left); 8308d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ push(right); 8309d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } else { 8310d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // The calling convention with registers is left in rdx and right in rax. 8311d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Register left_arg = rdx; 8312d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Register right_arg = rax; 8313d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block if (!(left.is(left_arg) && right.is(right_arg))) { 8314d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block if (left.is(right_arg) && right.is(left_arg)) { 8315d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block if (IsOperationCommutative()) { 8316d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block SetArgsReversed(); 8317d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } else { 8318d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ xchg(left, right); 8319d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } 8320d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } else if (left.is(left_arg)) { 8321d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ movq(right_arg, right); 8322402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu } else if (right.is(right_arg)) { 8323402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ movq(left_arg, left); 8324d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } else if (left.is(right_arg)) { 8325d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block if (IsOperationCommutative()) { 8326d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ movq(left_arg, right); 8327d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block SetArgsReversed(); 8328d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } else { 8329d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Order of moves important to avoid destroying left argument. 8330d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ movq(left_arg, left); 8331d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ movq(right_arg, right); 8332d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } 8333d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } else if (right.is(left_arg)) { 8334d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block if (IsOperationCommutative()) { 8335d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ movq(right_arg, left); 8336d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block SetArgsReversed(); 8337d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } else { 8338d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Order of moves important to avoid destroying right argument. 8339d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ movq(right_arg, right); 8340d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ movq(left_arg, left); 8341d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } 8342d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } else { 8343d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Order of moves is not important. 8344d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ movq(left_arg, left); 8345d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ movq(right_arg, right); 8346d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } 8347d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } 8348d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 8349d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Update flags to indicate that arguments are in registers. 8350d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block SetArgsInRegisters(); 8351d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1); 8352d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } 8353d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 8354d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Call the stub. 8355d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ CallStub(this); 8356d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block} 8357d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 8358d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 8359d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid GenericBinaryOpStub::GenerateCall( 8360d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block MacroAssembler* masm, 8361d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Register left, 8362d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Smi* right) { 8363d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block if (!ArgsInRegistersSupported()) { 8364d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Pass arguments on the stack. 8365d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ push(left); 8366d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ Push(right); 8367d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } else { 8368d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // The calling convention with registers is left in rdx and right in rax. 8369d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Register left_arg = rdx; 8370d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Register right_arg = rax; 8371d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block if (left.is(left_arg)) { 8372d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ Move(right_arg, right); 8373d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } else if (left.is(right_arg) && IsOperationCommutative()) { 8374d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ Move(left_arg, right); 8375d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block SetArgsReversed(); 8376d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } else { 8377402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // For non-commutative operations, left and right_arg might be 8378402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // the same register. Therefore, the order of the moves is 8379402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // important here in order to not overwrite left before moving 8380402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // it to left_arg. 8381d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ movq(left_arg, left); 8382d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ Move(right_arg, right); 8383d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } 8384d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 8385d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Update flags to indicate that arguments are in registers. 8386d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block SetArgsInRegisters(); 8387d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1); 8388d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } 8389d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 8390d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Call the stub. 8391d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ CallStub(this); 8392d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block} 8393d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 8394d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 8395d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid GenericBinaryOpStub::GenerateCall( 8396d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block MacroAssembler* masm, 8397d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Smi* left, 8398d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Register right) { 8399d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block if (!ArgsInRegistersSupported()) { 8400d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Pass arguments on the stack. 8401d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ Push(left); 8402d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ push(right); 8403d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } else { 8404d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // The calling convention with registers is left in rdx and right in rax. 8405d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Register left_arg = rdx; 8406d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Register right_arg = rax; 8407d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block if (right.is(right_arg)) { 8408d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ Move(left_arg, left); 8409d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } else if (right.is(left_arg) && IsOperationCommutative()) { 8410d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ Move(right_arg, left); 8411d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block SetArgsReversed(); 8412d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } else { 8413402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // For non-commutative operations, right and left_arg might be 8414402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // the same register. Therefore, the order of the moves is 8415402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // important here in order to not overwrite right before moving 8416402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // it to right_arg. 8417d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ movq(right_arg, right); 8418402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ Move(left_arg, left); 8419d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } 8420d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Update flags to indicate that arguments are in registers. 8421d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block SetArgsInRegisters(); 8422d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1); 8423d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } 8424d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 8425d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Call the stub. 8426d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ CallStub(this); 8427d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block} 8428d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 8429d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 84304515c472dc3e5ed2448a564600976759e569a0a8Leon ClarkeResult GenericBinaryOpStub::GenerateCall(MacroAssembler* masm, 84314515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke VirtualFrame* frame, 84324515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Result* left, 84334515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Result* right) { 84344515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke if (ArgsInRegistersSupported()) { 84354515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke SetArgsInRegisters(); 84364515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke return frame->CallStub(this, left, right); 84374515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke } else { 84384515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke frame->Push(left); 84394515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke frame->Push(right); 84404515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke return frame->CallStub(this, 2); 84414515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke } 84424515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke} 84434515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 84444515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 8445a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) { 84464515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // 1. Move arguments into edx, eax except for DIV and MOD, which need the 84474515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // dividend in eax and edx free for the division. Use eax, ebx for those. 84484515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Comment load_comment(masm, "-- Load arguments"); 84494515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Register left = rdx; 84504515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Register right = rax; 84514515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke if (op_ == Token::DIV || op_ == Token::MOD) { 84524515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke left = rax; 84534515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke right = rbx; 84544515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke if (HasArgsInRegisters()) { 84554515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rbx, rax); 84564515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rax, rdx); 84574515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke } 84584515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke } 84594515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke if (!HasArgsInRegisters()) { 84604515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(right, Operand(rsp, 1 * kPointerSize)); 84614515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(left, Operand(rsp, 2 * kPointerSize)); 84624515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke } 8463a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 84644515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // 2. Smi check both operands. Skip the check for OR as it is better combined 84654515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // with the actual operation. 84664515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Label not_smis; 84674515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke if (op_ != Token::BIT_OR) { 84684515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Comment smi_check_comment(masm, "-- Smi check arguments"); 84694515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ JumpIfNotBothSmi(left, right, ¬_smis); 84704515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke } 8471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 84724515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // 3. Operands are both smis (except for OR), perform the operation leaving 84734515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // the result in rax and check the result if necessary. 84744515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Comment perform_smi(masm, "-- Perform smi operation"); 84754515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Label use_fp_on_smis; 8476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block switch (op_) { 8477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::ADD: { 84784515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke ASSERT(right.is(rax)); 84794515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ SmiAdd(right, right, left, &use_fp_on_smis); // ADD is commutative. 8480a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 8481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 8482a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::SUB: { 84844515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ SmiSub(left, left, right, &use_fp_on_smis); 84854515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rax, left); 8486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 8487a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 8488a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8489a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::MUL: 84904515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke ASSERT(right.is(rax)); 84914515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ SmiMul(right, right, left, &use_fp_on_smis); // MUL is commutative. 8492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 8493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8494a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::DIV: 84954515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke ASSERT(left.is(rax)); 84964515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ SmiDiv(left, left, right, &use_fp_on_smis); 8497a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 8498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::MOD: 85004515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke ASSERT(left.is(rax)); 85014515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ SmiMod(left, left, right, slow); 8502a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 8503a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8504a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::BIT_OR: 85054515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke ASSERT(right.is(rax)); 85064515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rcx, right); // Save the right operand. 85074515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ SmiOr(right, right, left); // BIT_OR is commutative. 85084515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ testb(right, Immediate(kSmiTagMask)); 85094515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ j(not_zero, ¬_smis); 8510a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 8511a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8512a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::BIT_AND: 85134515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke ASSERT(right.is(rax)); 85144515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ SmiAnd(right, right, left); // BIT_AND is commutative. 8515a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 8516a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8517a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::BIT_XOR: 85184515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke ASSERT(right.is(rax)); 85194515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ SmiXor(right, right, left); // BIT_XOR is commutative. 8520a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 8521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::SHL: 8523a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::SHR: 8524a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::SAR: 8525a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block switch (op_) { 8526a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::SAR: 85274515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ SmiShiftArithmeticRight(left, left, right); 8528a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 8529a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::SHR: 85304515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ SmiShiftLogicalRight(left, left, right, slow); 8531a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 8532a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::SHL: 85334515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ SmiShiftLeft(left, left, right, slow); 8534a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 8535a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block default: 8536a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block UNREACHABLE(); 8537a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 85384515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rax, left); 8539a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 8540a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8541a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block default: 8542a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block UNREACHABLE(); 8543a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 8544a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 85454515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 85464515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // 4. Emit return of result in eax. 85474515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke GenerateReturn(masm); 85484515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 85494515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // 5. For some operations emit inline code to perform floating point 85504515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // operations on known smis (e.g., if the result of the operation 85514515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // overflowed the smi range). 85524515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke switch (op_) { 85534515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke case Token::ADD: 85544515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke case Token::SUB: 85554515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke case Token::MUL: 85564515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke case Token::DIV: { 85574515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ bind(&use_fp_on_smis); 85584515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke if (op_ == Token::DIV) { 85594515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rdx, rax); 85604515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rax, rbx); 85614515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke } 85624515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // left is rdx, right is rax. 85634515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ AllocateHeapNumber(rbx, rcx, slow); 85644515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke FloatingPointHelper::LoadFloatOperandsFromSmis(masm, xmm4, xmm5); 85654515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke switch (op_) { 85664515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke case Token::ADD: __ addsd(xmm4, xmm5); break; 85674515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke case Token::SUB: __ subsd(xmm4, xmm5); break; 85684515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke case Token::MUL: __ mulsd(xmm4, xmm5); break; 85694515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke case Token::DIV: __ divsd(xmm4, xmm5); break; 85704515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke default: UNREACHABLE(); 85714515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke } 85724515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movsd(FieldOperand(rbx, HeapNumber::kValueOffset), xmm4); 85734515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rax, rbx); 85744515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke GenerateReturn(masm); 85754515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke } 85764515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke default: 85774515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke break; 85784515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke } 85794515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 85804515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // 6. Non-smi operands, fall out to the non-smi code with the operands in 85814515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // rdx and rax. 85824515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Comment done_comment(masm, "-- Enter non-smi code"); 85834515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ bind(¬_smis); 85844515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 85854515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke switch (op_) { 85864515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke case Token::DIV: 85874515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke case Token::MOD: 85884515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Operands are in rax, rbx at this point. 85894515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rdx, rax); 85904515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rax, rbx); 85914515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke break; 85924515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 85934515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke case Token::BIT_OR: 85944515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // Right operand is saved in rcx and rax was destroyed by the smi 85954515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // operation. 85964515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rax, rcx); 85974515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke break; 85984515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 85994515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke default: 86004515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke break; 86014515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke } 8602a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 8603a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8604a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8605a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid GenericBinaryOpStub::Generate(MacroAssembler* masm) { 8606a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label call_runtime; 8607d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block if (HasSmiCodeInStub()) { 86084515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke GenerateSmiCode(masm, &call_runtime); 86094515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke } else if (op_ != Token::MOD) { 86104515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke GenerateLoadArguments(masm); 8611a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 8612a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Floating point case. 8613a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block switch (op_) { 8614a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::ADD: 8615a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::SUB: 8616a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::MUL: 8617a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::DIV: { 8618a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rax: y 8619a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rdx: x 8620402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu if (NumberInfo::IsNumber(operands_type_)) { 8621402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu if (FLAG_debug_code) { 8622402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Assert at runtime that inputs are only numbers. 8623402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ AbortIfNotNumber(rdx, "GenericBinaryOpStub operand not a number."); 8624402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ AbortIfNotNumber(rax, "GenericBinaryOpStub operand not a number."); 8625402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu } 8626402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu } else { 8627402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu FloatingPointHelper::CheckNumberOperands(masm, &call_runtime); 8628402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu } 8629a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Fast-case: Both operands are numbers. 86304515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // xmm4 and xmm5 are volatile XMM registers. 86314515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke FloatingPointHelper::LoadFloatOperands(masm, xmm4, xmm5); 86324515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke 86334515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke switch (op_) { 86344515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke case Token::ADD: __ addsd(xmm4, xmm5); break; 86354515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke case Token::SUB: __ subsd(xmm4, xmm5); break; 86364515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke case Token::MUL: __ mulsd(xmm4, xmm5); break; 86374515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke case Token::DIV: __ divsd(xmm4, xmm5); break; 86384515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke default: UNREACHABLE(); 86394515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke } 8640a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Allocate a heap number, if needed. 8641a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label skip_allocation; 86424515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke OverwriteMode mode = mode_; 86434515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke if (HasArgsReversed()) { 86444515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke if (mode == OVERWRITE_RIGHT) { 86454515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke mode = OVERWRITE_LEFT; 86464515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke } else if (mode == OVERWRITE_LEFT) { 86474515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke mode = OVERWRITE_RIGHT; 86484515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke } 86494515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke } 86504515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke switch (mode) { 8651a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case OVERWRITE_LEFT: 86524515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ JumpIfNotSmi(rdx, &skip_allocation); 86534515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ AllocateHeapNumber(rbx, rcx, &call_runtime); 86544515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ movq(rdx, rbx); 86554515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ bind(&skip_allocation); 8656a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rax, rdx); 86574515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke break; 8658a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case OVERWRITE_RIGHT: 8659a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If the argument in rax is already an object, we skip the 8660a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // allocation of a heap number. 8661a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfNotSmi(rax, &skip_allocation); 8662a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Fall through! 8663a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case NO_OVERWRITE: 8664d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Allocate a heap number for the result. Keep rax and rdx intact 8665d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // for the possible runtime call. 8666d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ AllocateHeapNumber(rbx, rcx, &call_runtime); 8667d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ movq(rax, rbx); 8668a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&skip_allocation); 8669a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 8670a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block default: UNREACHABLE(); 8671a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 8672a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm4); 8673d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block GenerateReturn(masm); 8674a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 8675a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::MOD: { 8676a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // For MOD we go directly to runtime in the non-smi case. 8677a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 8678a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 8679a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::BIT_OR: 8680a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::BIT_AND: 8681a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::BIT_XOR: 8682a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::SAR: 8683a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::SHL: 8684a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::SHR: { 8685d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Label skip_allocation, non_smi_result; 8686d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke FloatingPointHelper::LoadAsIntegers(masm, use_sse3_, &call_runtime); 8687a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block switch (op_) { 86883ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block case Token::BIT_OR: __ orl(rax, rcx); break; 86893ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block case Token::BIT_AND: __ andl(rax, rcx); break; 86903ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block case Token::BIT_XOR: __ xorl(rax, rcx); break; 8691d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block case Token::SAR: __ sarl_cl(rax); break; 8692d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block case Token::SHL: __ shll_cl(rax); break; 8693d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block case Token::SHR: __ shrl_cl(rax); break; 8694a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block default: UNREACHABLE(); 8695a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 8696a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (op_ == Token::SHR) { 86973ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Check if result is non-negative. This can only happen for a shift 86983ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // by zero, which also doesn't update the sign flag. 86993ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ testl(rax, rax); 8700a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(negative, &non_smi_result); 8701a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 87023ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ JumpIfNotValidSmiValue(rax, &non_smi_result); 87033ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Tag smi result, if possible, and return. 8704a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Integer32ToSmi(rax, rax); 8705d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block GenerateReturn(masm); 8706a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8707a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // All ops except SHR return a signed int32 that we load in a HeapNumber. 87083ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block if (op_ != Token::SHR && non_smi_result.is_linked()) { 8709a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&non_smi_result); 8710a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Allocate a heap number if needed. 8711a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movsxlq(rbx, rax); // rbx: sign extended 32-bit result 8712a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block switch (mode_) { 8713a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case OVERWRITE_LEFT: 8714a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case OVERWRITE_RIGHT: 8715a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If the operand was an object, we skip the 8716a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // allocation of a heap number. 8717a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rax, Operand(rsp, mode_ == OVERWRITE_RIGHT ? 8718a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1 * kPointerSize : 2 * kPointerSize)); 8719a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfNotSmi(rax, &skip_allocation); 8720a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Fall through! 8721a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case NO_OVERWRITE: 87223ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ AllocateHeapNumber(rax, rcx, &call_runtime); 8723a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&skip_allocation); 8724a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 8725a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block default: UNREACHABLE(); 8726a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 8727a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Store the result in the HeapNumber and return. 8728a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(Operand(rsp, 1 * kPointerSize), rbx); 8729a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ fild_s(Operand(rsp, 1 * kPointerSize)); 8730a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset)); 8731d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block GenerateReturn(masm); 8732a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 8733a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8734a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // SHR should return uint32 - go to runtime for non-smi/negative result. 8735a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (op_ == Token::SHR) { 8736a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&non_smi_result); 8737a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 8738a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 8739a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 8740a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block default: UNREACHABLE(); break; 8741a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 8742a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8743a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If all else fails, use the runtime system to get the correct 8744d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // result. If arguments was passed in registers now place them on the 8745d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // stack in the correct order below the return address. 8746a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&call_runtime); 87474515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke if (HasArgsInRegisters()) { 8748d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ pop(rcx); 87494515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke if (HasArgsReversed()) { 8750d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ push(rax); 8751d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ push(rdx); 8752d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } else { 8753d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ push(rdx); 8754d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ push(rax); 8755d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } 8756d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ push(rcx); 8757d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } 8758a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block switch (op_) { 8759d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block case Token::ADD: { 8760d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Test for string arguments before calling runtime. 8761d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Label not_strings, both_strings, not_string1, string1; 8762d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Condition is_smi; 8763d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Result answer; 8764d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block is_smi = masm->CheckSmi(rdx); 8765d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ j(is_smi, ¬_string1); 8766d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rdx); 8767d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ j(above_equal, ¬_string1); 8768d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 8769d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // First argument is a a string, test second. 8770d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block is_smi = masm->CheckSmi(rax); 8771d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ j(is_smi, &string1); 8772d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rax); 8773d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ j(above_equal, &string1); 8774d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 8775d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // First and second argument are strings. 8776e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke StringAddStub stub(NO_STRING_CHECK_IN_STUB); 8777e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ TailCallStub(&stub); 8778d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 8779d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Only first argument is a string. 8780d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ bind(&string1); 87814515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ InvokeBuiltin( 87824515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke HasArgsReversed() ? 87834515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Builtins::STRING_ADD_RIGHT : 87844515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Builtins::STRING_ADD_LEFT, 87854515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke JUMP_FUNCTION); 8786d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 8787d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // First argument was not a string, test second. 8788d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ bind(¬_string1); 8789d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block is_smi = masm->CheckSmi(rax); 8790d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ j(is_smi, ¬_strings); 8791d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rax); 8792d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ j(above_equal, ¬_strings); 8793d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 8794d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Only second argument is a string. 87954515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ InvokeBuiltin( 87964515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke HasArgsReversed() ? 87974515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Builtins::STRING_ADD_LEFT : 87984515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke Builtins::STRING_ADD_RIGHT, 87994515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke JUMP_FUNCTION); 8800d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 8801d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ bind(¬_strings); 8802d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Neither argument is a string. 8803a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); 8804a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 8805d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } 8806a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::SUB: 8807a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); 8808a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 8809a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::MUL: 8810a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION); 88114515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke break; 8812a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::DIV: 8813a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION); 8814a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 8815a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::MOD: 8816a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); 8817a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 8818a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::BIT_OR: 8819a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION); 8820a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 8821a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::BIT_AND: 8822a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION); 8823a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 8824a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::BIT_XOR: 8825a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION); 8826a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 8827a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::SAR: 8828a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION); 8829a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 8830a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::SHL: 8831a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); 8832a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 8833a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case Token::SHR: 8834a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); 8835a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 8836a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block default: 8837a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block UNREACHABLE(); 8838a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 8839a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 8840a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8841a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8842d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid GenericBinaryOpStub::GenerateLoadArguments(MacroAssembler* masm) { 8843d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // If arguments are not passed in registers read them from the stack. 88444515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke if (!HasArgsInRegisters()) { 8845d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ movq(rax, Operand(rsp, 1 * kPointerSize)); 8846d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ movq(rdx, Operand(rsp, 2 * kPointerSize)); 8847d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } 8848d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block} 8849d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 8850d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 8851d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid GenericBinaryOpStub::GenerateReturn(MacroAssembler* masm) { 8852d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // If arguments are not passed in registers remove them from the stack before 8853d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // returning. 88544515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke if (!HasArgsInRegisters()) { 8855d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ ret(2 * kPointerSize); // Remove both operands 8856d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } else { 8857d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ ret(0); 8858d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } 8859d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block} 8860d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 8861d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 8862a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockint CompareStub::MinorKey() { 8863e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Encode the three parameters in a unique 16 bit value. 8864e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke ASSERT(static_cast<unsigned>(cc_) < (1 << 14)); 8865e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke int nnn_value = (never_nan_nan_ ? 2 : 0); 8866e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke if (cc_ != equal) nnn_value = 0; // Avoid duplicate stubs. 8867e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke return (static_cast<unsigned>(cc_) << 2) | nnn_value | (strict_ ? 1 : 0); 8868e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke} 8869e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 8870e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 8871e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkeconst char* CompareStub::GetName() { 8872e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke switch (cc_) { 8873e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke case less: return "CompareStub_LT"; 8874e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke case greater: return "CompareStub_GT"; 8875e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke case less_equal: return "CompareStub_LE"; 8876e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke case greater_equal: return "CompareStub_GE"; 8877e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke case not_equal: { 8878e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke if (strict_) { 8879e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke if (never_nan_nan_) { 8880e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke return "CompareStub_NE_STRICT_NO_NAN"; 8881e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } else { 8882e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke return "CompareStub_NE_STRICT"; 8883e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } 8884e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } else { 8885e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke if (never_nan_nan_) { 8886e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke return "CompareStub_NE_NO_NAN"; 8887e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } else { 8888e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke return "CompareStub_NE"; 8889e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } 8890e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } 8891e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } 8892e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke case equal: { 8893e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke if (strict_) { 8894e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke if (never_nan_nan_) { 8895e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke return "CompareStub_EQ_STRICT_NO_NAN"; 8896e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } else { 8897e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke return "CompareStub_EQ_STRICT"; 8898e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } 8899e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } else { 8900e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke if (never_nan_nan_) { 8901e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke return "CompareStub_EQ_NO_NAN"; 8902e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } else { 8903e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke return "CompareStub_EQ"; 8904e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } 8905e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } 8906e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } 8907e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke default: return "CompareStub"; 8908e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } 8909e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke} 8910e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 8911e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 8912e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid StringAddStub::Generate(MacroAssembler* masm) { 8913e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Label string_add_runtime; 8914e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 8915e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Load the two arguments. 8916e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(rax, Operand(rsp, 2 * kPointerSize)); // First argument. 8917e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(rdx, Operand(rsp, 1 * kPointerSize)); // Second argument. 8918e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 8919e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Make sure that both arguments are strings if not known in advance. 8920e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke if (string_check_) { 8921e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Condition is_smi; 8922e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke is_smi = masm->CheckSmi(rax); 8923e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ j(is_smi, &string_add_runtime); 8924e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, r8); 8925e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ j(above_equal, &string_add_runtime); 8926e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 8927e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // First argument is a a string, test second. 8928e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke is_smi = masm->CheckSmi(rdx); 8929e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ j(is_smi, &string_add_runtime); 8930e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, r9); 8931e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ j(above_equal, &string_add_runtime); 8932e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } 8933e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 8934e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Both arguments are strings. 8935e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rax: first string 8936e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rdx: second string 8937e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Check if either of the strings are empty. In that case return the other. 8938e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Label second_not_zero_length, both_not_zero_length; 8939e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movl(rcx, FieldOperand(rdx, String::kLengthOffset)); 8940e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ testl(rcx, rcx); 8941e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ j(not_zero, &second_not_zero_length); 8942e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Second string is empty, result is first string which is already in rax. 8943e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ IncrementCounter(&Counters::string_add_native, 1); 8944e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ ret(2 * kPointerSize); 8945e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ bind(&second_not_zero_length); 8946e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movl(rbx, FieldOperand(rax, String::kLengthOffset)); 8947e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ testl(rbx, rbx); 8948e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ j(not_zero, &both_not_zero_length); 8949e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // First string is empty, result is second string which is in rdx. 8950e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(rax, rdx); 8951e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ IncrementCounter(&Counters::string_add_native, 1); 8952e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ ret(2 * kPointerSize); 8953e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 8954e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Both strings are non-empty. 8955e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rax: first string 8956e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rbx: length of first string 8957d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rcx: length of second string 8958d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rdx: second string 8959e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // r8: instance type of first string if string check was performed above 8960e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // r9: instance type of first string if string check was performed above 8961e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Label string_add_flat_result; 8962e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ bind(&both_not_zero_length); 8963e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Look at the length of the result of adding the two strings. 8964e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ addl(rbx, rcx); 8965e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Use the runtime system when adding two one character strings, as it 8966e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // contains optimizations for this specific case using the symbol table. 8967e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ cmpl(rbx, Immediate(2)); 8968e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ j(equal, &string_add_runtime); 8969e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // If arguments where known to be strings, maps are not loaded to r8 and r9 8970e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // by the code above. 8971e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke if (!string_check_) { 8972e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(r8, FieldOperand(rax, HeapObject::kMapOffset)); 8973e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(r9, FieldOperand(rdx, HeapObject::kMapOffset)); 8974e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } 8975e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Get the instance types of the two strings as they will be needed soon. 8976e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movzxbl(r8, FieldOperand(r8, Map::kInstanceTypeOffset)); 8977e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movzxbl(r9, FieldOperand(r9, Map::kInstanceTypeOffset)); 8978e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Check if resulting string will be flat. 8979e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ cmpl(rbx, Immediate(String::kMinNonFlatLength)); 8980e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ j(below, &string_add_flat_result); 8981e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Handle exceptionally long strings in the runtime system. 8982e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke ASSERT((String::kMaxLength & 0x80000000) == 0); 8983e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ cmpl(rbx, Immediate(String::kMaxLength)); 8984e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ j(above, &string_add_runtime); 8985e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 8986e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // If result is not supposed to be flat, allocate a cons string object. If 8987e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // both strings are ascii the result is an ascii cons string. 8988e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rax: first string 8989e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // ebx: length of resulting flat string 8990e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rdx: second string 8991e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // r8: instance type of first string 8992e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // r9: instance type of second string 8993e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Label non_ascii, allocated; 8994e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movl(rcx, r8); 8995e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ and_(rcx, r9); 8996e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke ASSERT(kStringEncodingMask == kAsciiStringTag); 8997e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ testl(rcx, Immediate(kAsciiStringTag)); 8998e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ j(zero, &non_ascii); 8999e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Allocate an acsii cons string. 9000e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ AllocateAsciiConsString(rcx, rdi, no_reg, &string_add_runtime); 9001e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ bind(&allocated); 9002e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Fill the fields of the cons string. 9003e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movl(FieldOperand(rcx, ConsString::kLengthOffset), rbx); 9004e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movl(FieldOperand(rcx, ConsString::kHashFieldOffset), 9005e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Immediate(String::kEmptyHashField)); 9006e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(FieldOperand(rcx, ConsString::kFirstOffset), rax); 9007e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(FieldOperand(rcx, ConsString::kSecondOffset), rdx); 9008e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(rax, rcx); 9009e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ IncrementCounter(&Counters::string_add_native, 1); 9010e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ ret(2 * kPointerSize); 9011e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ bind(&non_ascii); 9012e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Allocate a two byte cons string. 9013e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ AllocateConsString(rcx, rdi, no_reg, &string_add_runtime); 9014e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ jmp(&allocated); 9015e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 9016e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Handle creating a flat result. First check that both strings are not 9017e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // external strings. 9018e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rax: first string 9019e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // ebx: length of resulting flat string 9020e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rdx: second string 9021e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // r8: instance type of first string 9022e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // r9: instance type of first string 9023e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ bind(&string_add_flat_result); 9024e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movl(rcx, r8); 9025e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ and_(rcx, Immediate(kStringRepresentationMask)); 9026e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ cmpl(rcx, Immediate(kExternalStringTag)); 9027e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ j(equal, &string_add_runtime); 9028e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movl(rcx, r9); 9029e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ and_(rcx, Immediate(kStringRepresentationMask)); 9030e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ cmpl(rcx, Immediate(kExternalStringTag)); 9031e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ j(equal, &string_add_runtime); 9032e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Now check if both strings are ascii strings. 9033e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rax: first string 9034e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // ebx: length of resulting flat string 9035e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rdx: second string 9036e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // r8: instance type of first string 9037e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // r9: instance type of second string 9038e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Label non_ascii_string_add_flat_result; 9039e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke ASSERT(kStringEncodingMask == kAsciiStringTag); 9040e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ testl(r8, Immediate(kAsciiStringTag)); 9041e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ j(zero, &non_ascii_string_add_flat_result); 9042e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ testl(r9, Immediate(kAsciiStringTag)); 9043e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ j(zero, &string_add_runtime); 9044e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Both strings are ascii strings. As they are short they are both flat. 9045e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ AllocateAsciiString(rcx, rbx, rdi, r14, r15, &string_add_runtime); 9046e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rcx: result string 9047e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(rbx, rcx); 9048e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Locate first character of result. 9049e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ addq(rcx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 9050e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Locate first character of first argument 9051e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movl(rdi, FieldOperand(rax, String::kLengthOffset)); 9052e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ addq(rax, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 9053e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rax: first char of first argument 9054e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rbx: result string 9055e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rcx: first character of result 9056e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rdx: second string 9057e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rdi: length of first argument 9058e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke GenerateCopyCharacters(masm, rcx, rax, rdi, true); 9059e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Locate first character of second argument. 9060e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movl(rdi, FieldOperand(rdx, String::kLengthOffset)); 9061e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ addq(rdx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 9062e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rbx: result string 9063e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rcx: next character of result 9064e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rdx: first char of second argument 9065e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rdi: length of second argument 9066e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke GenerateCopyCharacters(masm, rcx, rdx, rdi, true); 9067e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(rax, rbx); 9068e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ IncrementCounter(&Counters::string_add_native, 1); 9069e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ ret(2 * kPointerSize); 9070e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 9071e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Handle creating a flat two byte result. 9072e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rax: first string - known to be two byte 9073e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rbx: length of resulting flat string 9074e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rdx: second string 9075e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // r8: instance type of first string 9076e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // r9: instance type of first string 9077e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ bind(&non_ascii_string_add_flat_result); 9078e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ and_(r9, Immediate(kAsciiStringTag)); 9079e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ j(not_zero, &string_add_runtime); 9080e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Both strings are two byte strings. As they are short they are both 9081e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // flat. 9082e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ AllocateTwoByteString(rcx, rbx, rdi, r14, r15, &string_add_runtime); 9083e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rcx: result string 9084e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(rbx, rcx); 9085e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Locate first character of result. 9086e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ addq(rcx, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); 9087e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Locate first character of first argument. 9088e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movl(rdi, FieldOperand(rax, String::kLengthOffset)); 9089e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ addq(rax, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); 9090e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rax: first char of first argument 9091e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rbx: result string 9092e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rcx: first character of result 9093e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rdx: second argument 9094e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rdi: length of first argument 9095e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke GenerateCopyCharacters(masm, rcx, rax, rdi, false); 9096e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Locate first character of second argument. 9097e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movl(rdi, FieldOperand(rdx, String::kLengthOffset)); 9098e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ addq(rdx, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); 9099e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rbx: result string 9100e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rcx: next character of result 9101e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rdx: first char of second argument 9102e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rdi: length of second argument 9103e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke GenerateCopyCharacters(masm, rcx, rdx, rdi, false); 9104e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(rax, rbx); 9105e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ IncrementCounter(&Counters::string_add_native, 1); 9106e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ ret(2 * kPointerSize); 9107e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 9108e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Just jump to runtime to add the two strings. 9109e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ bind(&string_add_runtime); 9110e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ TailCallRuntime(ExternalReference(Runtime::kStringAdd), 2, 1); 9111e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke} 9112e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 9113e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 9114d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarkevoid StringStubBase::GenerateCopyCharacters(MacroAssembler* masm, 9115d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Register dest, 9116d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Register src, 9117d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Register count, 9118d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke bool ascii) { 9119e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Label loop; 9120e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ bind(&loop); 9121e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // This loop just copies one character at a time, as it is only used for very 9122e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // short strings. 9123e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke if (ascii) { 9124e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movb(kScratchRegister, Operand(src, 0)); 9125e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movb(Operand(dest, 0), kScratchRegister); 9126e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ addq(src, Immediate(1)); 9127e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ addq(dest, Immediate(1)); 9128e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } else { 9129e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movzxwl(kScratchRegister, Operand(src, 0)); 9130e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movw(Operand(dest, 0), kScratchRegister); 9131e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ addq(src, Immediate(2)); 9132e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ addq(dest, Immediate(2)); 9133e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } 9134e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ subl(count, Immediate(1)); 9135e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ j(not_zero, &loop); 9136e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke} 9137e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 9138e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 9139d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarkevoid StringStubBase::GenerateCopyCharactersREP(MacroAssembler* masm, 9140d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Register dest, 9141d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Register src, 9142d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Register count, 9143d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke bool ascii) { 9144d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Copy characters using rep movs of doublewords. Align destination on 4 byte 9145d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // boundary before starting rep movs. Copy remaining characters after running 9146d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rep movs. 9147d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke ASSERT(dest.is(rdi)); // rep movs destination 9148d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke ASSERT(src.is(rsi)); // rep movs source 9149d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke ASSERT(count.is(rcx)); // rep movs count 9150d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 9151d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Nothing to do for zero characters. 9152d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Label done; 9153d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ testq(count, count); 9154d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(zero, &done); 9155d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 9156d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Make count the number of bytes to copy. 9157d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke if (!ascii) { 9158d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke ASSERT_EQ(2, sizeof(uc16)); // NOLINT 9159d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ addq(count, count); 9160d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke } 9161d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 9162d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Don't enter the rep movs if there are less than 4 bytes to copy. 9163d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Label last_bytes; 9164d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ testq(count, Immediate(~7)); 9165d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(zero, &last_bytes); 9166d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 9167d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Copy from edi to esi using rep movs instruction. 9168d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(kScratchRegister, count); 9169d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ sar(count, Immediate(3)); // Number of doublewords to copy. 9170d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ repmovsq(); 9171d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 9172d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Find number of bytes left. 9173d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(count, kScratchRegister); 9174d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ and_(count, Immediate(7)); 9175d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 9176d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Check if there are more bytes to copy. 9177d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ bind(&last_bytes); 9178d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ testq(count, count); 9179d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(zero, &done); 9180d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 9181d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Copy remaining characters. 9182d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Label loop; 9183d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ bind(&loop); 9184d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movb(kScratchRegister, Operand(src, 0)); 9185d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movb(Operand(dest, 0), kScratchRegister); 9186d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ addq(src, Immediate(1)); 9187d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ addq(dest, Immediate(1)); 9188d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ subq(count, Immediate(1)); 9189d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(not_zero, &loop); 9190d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 9191d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ bind(&done); 9192d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke} 9193d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 9194d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 9195d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarkevoid SubStringStub::Generate(MacroAssembler* masm) { 9196d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Label runtime; 9197d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 9198d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Stack frame on entry. 9199d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rsp[0]: return address 9200d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rsp[8]: to 9201d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rsp[16]: from 9202d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rsp[24]: string 9203d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 9204d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke const int kToOffset = 1 * kPointerSize; 9205d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke const int kFromOffset = kToOffset + kPointerSize; 9206d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke const int kStringOffset = kFromOffset + kPointerSize; 9207d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke const int kArgumentsSize = (kStringOffset + kPointerSize) - kToOffset; 9208d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 9209d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Make sure first argument is a string. 9210d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(rax, Operand(rsp, kStringOffset)); 9211d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke ASSERT_EQ(0, kSmiTag); 9212d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ testl(rax, Immediate(kSmiTagMask)); 9213d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(zero, &runtime); 9214d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Condition is_string = masm->IsObjectStringType(rax, rbx, rbx); 9215d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(NegateCondition(is_string), &runtime); 9216d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 9217d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rax: string 9218d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rbx: instance type 9219d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Calculate length of sub string using the smi values. 9220d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(rcx, Operand(rsp, kToOffset)); 9221d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(rdx, Operand(rsp, kFromOffset)); 9222d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ JumpIfNotBothPositiveSmi(rcx, rdx, &runtime); 9223d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 9224d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ SmiSub(rcx, rcx, rdx, NULL); // Overflow doesn't happen. 9225d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(negative, &runtime); 9226d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Handle sub-strings of length 2 and less in the runtime system. 9227d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ SmiToInteger32(rcx, rcx); 9228d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ cmpl(rcx, Immediate(2)); 9229d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(below_equal, &runtime); 9230d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 9231d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rax: string 9232d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rbx: instance type 9233d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rcx: result string length 9234d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Check for flat ascii string 9235d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke Label non_ascii_flat; 9236d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ and_(rbx, Immediate(kStringRepresentationMask | kStringEncodingMask)); 9237d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ cmpb(rbx, Immediate(kSeqStringTag | kAsciiStringTag)); 9238d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(not_equal, &non_ascii_flat); 9239d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 9240d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Allocate the result. 9241d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ AllocateAsciiString(rax, rcx, rbx, rdx, rdi, &runtime); 9242d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 9243d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rax: result string 9244d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rcx: result string length 9245d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(rdx, rsi); // esi used by following code. 9246d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Locate first character of result. 9247d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ lea(rdi, FieldOperand(rax, SeqAsciiString::kHeaderSize)); 9248d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Load string argument and locate character of sub string start. 9249d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(rsi, Operand(rsp, kStringOffset)); 9250d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(rbx, Operand(rsp, kFromOffset)); 9251d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke { 9252d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke SmiIndex smi_as_index = masm->SmiToIndex(rbx, rbx, times_1); 9253d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ lea(rsi, Operand(rsi, smi_as_index.reg, smi_as_index.scale, 9254d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke SeqAsciiString::kHeaderSize - kHeapObjectTag)); 9255d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke } 9256d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 9257d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rax: result string 9258d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rcx: result length 9259d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rdx: original value of rsi 9260d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rdi: first character of result 9261d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rsi: character of sub string start 9262d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke GenerateCopyCharactersREP(masm, rdi, rsi, rcx, true); 9263d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(rsi, rdx); // Restore rsi. 9264d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ IncrementCounter(&Counters::sub_string_native, 1); 9265d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ ret(kArgumentsSize); 9266d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 9267d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ bind(&non_ascii_flat); 9268d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rax: string 9269d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rbx: instance type & kStringRepresentationMask | kStringEncodingMask 9270d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rcx: result string length 9271d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Check for sequential two byte string 9272d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ cmpb(rbx, Immediate(kSeqStringTag | kTwoByteStringTag)); 9273d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ j(not_equal, &runtime); 9274d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 9275d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Allocate the result. 9276d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ AllocateTwoByteString(rax, rcx, rbx, rdx, rdi, &runtime); 9277d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 9278d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rax: result string 9279d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rcx: result string length 9280d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(rdx, rsi); // esi used by following code. 9281d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Locate first character of result. 9282d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ lea(rdi, FieldOperand(rax, SeqTwoByteString::kHeaderSize)); 9283d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Load string argument and locate character of sub string start. 9284d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(rsi, Operand(rsp, kStringOffset)); 9285d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(rbx, Operand(rsp, kFromOffset)); 9286d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke { 9287d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke SmiIndex smi_as_index = masm->SmiToIndex(rbx, rbx, times_2); 9288d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ lea(rsi, Operand(rsi, smi_as_index.reg, smi_as_index.scale, 9289d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke SeqAsciiString::kHeaderSize - kHeapObjectTag)); 9290d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke } 9291d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 9292d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rax: result string 9293d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rcx: result length 9294d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rdx: original value of rsi 9295d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rdi: first character of result 9296d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // rsi: character of sub string start 9297d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke GenerateCopyCharactersREP(masm, rdi, rsi, rcx, false); 9298d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ movq(rsi, rdx); // Restore esi. 9299d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ IncrementCounter(&Counters::sub_string_native, 1); 9300d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ ret(kArgumentsSize); 9301d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 9302d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // Just jump to runtime to create the sub string. 9303d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ bind(&runtime); 9304d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ TailCallRuntime(ExternalReference(Runtime::kSubString), 3, 1); 9305d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke} 9306d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 9307e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 9308e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, 9309e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Register left, 9310e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Register right, 9311e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Register scratch1, 9312e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Register scratch2, 9313e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Register scratch3, 9314e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Register scratch4) { 9315e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Ensure that you can always subtract a string length from a non-negative 9316e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // number (e.g. another length). 9317e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke ASSERT(String::kMaxLength < 0x7fffffff); 9318e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 9319e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Find minimum length and length difference. 9320e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movl(scratch1, FieldOperand(left, String::kLengthOffset)); 9321e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movl(scratch4, scratch1); 9322e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ subl(scratch4, FieldOperand(right, String::kLengthOffset)); 9323e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Register scratch4 now holds left.length - right.length. 9324e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke const Register length_difference = scratch4; 9325e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Label left_shorter; 9326e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ j(less, &left_shorter); 9327e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // The right string isn't longer that the left one. 9328e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Get the right string's length by subtracting the (non-negative) difference 9329e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // from the left string's length. 9330e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ subl(scratch1, length_difference); 9331e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ bind(&left_shorter); 9332e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Register scratch1 now holds Min(left.length, right.length). 9333e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke const Register min_length = scratch1; 9334e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 9335e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Label compare_lengths; 9336e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // If min-length is zero, go directly to comparing lengths. 9337e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ testl(min_length, min_length); 9338e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ j(zero, &compare_lengths); 9339e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 9340e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Registers scratch2 and scratch3 are free. 9341e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Label result_not_equal; 9342e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Label loop; 9343e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke { 9344e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Check characters 0 .. min_length - 1 in a loop. 9345e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Use scratch3 as loop index, min_length as limit and scratch2 9346e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // for computation. 9347e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke const Register index = scratch3; 9348e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movl(index, Immediate(0)); // Index into strings. 9349e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ bind(&loop); 9350e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Compare characters. 9351e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // TODO(lrn): Could we load more than one character at a time? 9352e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movb(scratch2, FieldOperand(left, 9353e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke index, 9354e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke times_1, 9355e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke SeqAsciiString::kHeaderSize)); 9356e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Increment index and use -1 modifier on next load to give 9357e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // the previous load extra time to complete. 9358e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ addl(index, Immediate(1)); 9359e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ cmpb(scratch2, FieldOperand(right, 9360e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke index, 9361e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke times_1, 9362e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke SeqAsciiString::kHeaderSize - 1)); 9363e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ j(not_equal, &result_not_equal); 9364e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ cmpl(index, min_length); 9365e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ j(not_equal, &loop); 9366e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } 9367e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Completed loop without finding different characters. 9368e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Compare lengths (precomputed). 9369e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ bind(&compare_lengths); 9370e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ testl(length_difference, length_difference); 9371e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ j(not_zero, &result_not_equal); 9372e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 9373e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Result is EQUAL. 9374e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ Move(rax, Smi::FromInt(EQUAL)); 9375e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ ret(2 * kPointerSize); 9376e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 9377e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Label result_greater; 9378e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ bind(&result_not_equal); 9379e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Unequal comparison of left to right, either character or length. 9380e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ j(greater, &result_greater); 9381e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 9382e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Result is LESS. 9383e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ Move(rax, Smi::FromInt(LESS)); 9384e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ ret(2 * kPointerSize); 9385e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 9386e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Result is GREATER. 9387e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ bind(&result_greater); 9388e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ Move(rax, Smi::FromInt(GREATER)); 9389e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ ret(2 * kPointerSize); 9390e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke} 9391e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 9392e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 9393e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid StringCompareStub::Generate(MacroAssembler* masm) { 9394e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Label runtime; 9395e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 9396e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Stack frame on entry. 9397e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rsp[0]: return address 9398e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rsp[8]: right string 9399e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // rsp[16]: left string 9400e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 9401e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(rdx, Operand(rsp, 2 * kPointerSize)); // left 9402e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(rax, Operand(rsp, 1 * kPointerSize)); // right 9403e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 9404e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Check for identity. 9405e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Label not_same; 9406e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ cmpq(rdx, rax); 9407e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ j(not_equal, ¬_same); 9408e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ Move(rax, Smi::FromInt(EQUAL)); 9409e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ IncrementCounter(&Counters::string_compare_native, 1); 9410e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ ret(2 * kPointerSize); 9411e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 9412e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ bind(¬_same); 9413e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 9414e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Check that both are sequential ASCII strings. 9415e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ JumpIfNotBothSequentialAsciiStrings(rdx, rax, rcx, rbx, &runtime); 9416e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 9417e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Inline comparison of ascii strings. 9418d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke __ IncrementCounter(&Counters::string_compare_native, 1); 9419e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke GenerateCompareFlatAsciiStrings(masm, rdx, rax, rcx, rbx, rdi, r8); 9420e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 9421e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) 9422e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // tagged as a small integer. 9423e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ bind(&runtime); 9424e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1); 9425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 9426a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 94273ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block#undef __ 94283ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block 94293ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block#define __ masm. 94303ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block 94313ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block#ifdef _WIN64 94323ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Blocktypedef double (*ModuloFunction)(double, double); 94333ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block// Define custom fmod implementation. 94343ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve BlockModuloFunction CreateModuloFunction() { 94353ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block size_t actual_size; 94363ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, 94373ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block &actual_size, 94383ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block true)); 94393ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block CHECK(buffer); 9440d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block Assembler masm(buffer, static_cast<int>(actual_size)); 94413ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Generated code is put into a fixed, unmovable, buffer, and not into 94423ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // the V8 heap. We can't, and don't, refer to any relocatable addresses 94433ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // (e.g. the JavaScript nan-object). 94443ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block 94453ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Windows 64 ABI passes double arguments in xmm0, xmm1 and 94463ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // returns result in xmm0. 94473ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Argument backing space is allocated on the stack above 94483ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // the return address. 94493ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block 94503ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Compute x mod y. 94513ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Load y and x (use argument backing store as temporary storage). 94523ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ movsd(Operand(rsp, kPointerSize * 2), xmm1); 94533ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ movsd(Operand(rsp, kPointerSize), xmm0); 94543ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ fld_d(Operand(rsp, kPointerSize * 2)); 94553ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ fld_d(Operand(rsp, kPointerSize)); 94563ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block 94573ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Clear exception flags before operation. 94583ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block { 94593ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block Label no_exceptions; 94603ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ fwait(); 94613ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ fnstsw_ax(); 94623ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Clear if Illegal Operand or Zero Division exceptions are set. 94633ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ testb(rax, Immediate(5)); 94643ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ j(zero, &no_exceptions); 94653ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ fnclex(); 94663ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ bind(&no_exceptions); 94673ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block } 94683ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block 94693ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Compute st(0) % st(1) 94703ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block { 94713ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block Label partial_remainder_loop; 94723ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ bind(&partial_remainder_loop); 94733ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ fprem(); 94743ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ fwait(); 94753ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ fnstsw_ax(); 94763ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ testl(rax, Immediate(0x400 /* C2 */)); 94773ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // If C2 is set, computation only has partial result. Loop to 94783ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // continue computation. 94793ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ j(not_zero, &partial_remainder_loop); 94803ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block } 94813ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block 94823ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block Label valid_result; 94833ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block Label return_result; 94843ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // If Invalid Operand or Zero Division exceptions are set, 94853ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // return NaN. 94863ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ testb(rax, Immediate(5)); 94873ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ j(zero, &valid_result); 94883ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ fstp(0); // Drop result in st(0). 94893ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block int64_t kNaNValue = V8_INT64_C(0x7ff8000000000000); 94903ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ movq(rcx, kNaNValue, RelocInfo::NONE); 94913ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ movq(Operand(rsp, kPointerSize), rcx); 94923ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ movsd(xmm0, Operand(rsp, kPointerSize)); 94933ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ jmp(&return_result); 94943ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block 94953ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // If result is valid, return that. 94963ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ bind(&valid_result); 94973ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ fstp_d(Operand(rsp, kPointerSize)); 94983ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ movsd(xmm0, Operand(rsp, kPointerSize)); 94993ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block 95003ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Clean up FPU stack and exceptions and return xmm0 95013ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ bind(&return_result); 95023ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ fstp(0); // Unload y. 95033ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block 95043ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block Label clear_exceptions; 95053ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ testb(rax, Immediate(0x3f /* Any Exception*/)); 95063ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ j(not_zero, &clear_exceptions); 95073ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ ret(0); 95083ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ bind(&clear_exceptions); 95093ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ fnclex(); 95103ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ ret(0); 95113ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block 95123ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block CodeDesc desc; 95133ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block masm.GetCode(&desc); 95143ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Call the function from C++. 95153ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block return FUNCTION_CAST<ModuloFunction>(buffer); 95163ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block} 95173ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block 95183ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block#endif 9519a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 9520e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 9521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#undef __ 9522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 9523a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} } // namespace v8::internal 9524