code-stubs-x64.cc revision 589d6979ff2ef66fca2d8fa51404c369ca5e9250
11e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// Copyright 2011 the V8 project authors. All rights reserved. 280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Redistribution and use in source and binary forms, with or without 380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// modification, are permitted provided that the following conditions are 480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// met: 580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// 680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// * Redistributions of source code must retain the above copyright 780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// notice, this list of conditions and the following disclaimer. 880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// * Redistributions in binary form must reproduce the above 980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// copyright notice, this list of conditions and the following 1080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// disclaimer in the documentation and/or other materials provided 1180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// with the distribution. 1280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// * Neither the name of Google Inc. nor the names of its 1380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// contributors may be used to endorse or promote products derived 1480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// from this software without specific prior written permission. 1580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// 1680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#include "v8.h" 2980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#if defined(V8_TARGET_ARCH_X64) 3180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#include "bootstrapper.h" 3380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#include "code-stubs.h" 3480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#include "regexp-macro-assembler.h" 3580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsennamespace v8 { 3780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsennamespace internal { 3880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#define __ ACCESS_MASM(masm) 401e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 411e0659c275bb392c045087af4f6b0d7565cb3d77Steve Blockvoid ToNumberStub::Generate(MacroAssembler* masm) { 421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // The ToNumber stub takes one argument in eax. 43257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label check_heap_number, call_builtin; 441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ SmiTest(rax); 45257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &check_heap_number, Label::kNear); 461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Ret(); 471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&check_heap_number); 4944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), 5044f0eee88ff00398ff7f715fab053374d808c90dSteve Block Heap::kHeapNumberMapRootIndex); 51257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &call_builtin, Label::kNear); 521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Ret(); 531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&call_builtin); 551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ pop(rcx); // Pop return address. 561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ push(rax); 571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ push(rcx); // Push return address. 581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION); 591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 6280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FastNewClosureStub::Generate(MacroAssembler* masm) { 6380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Create a new closure from the given function info in new 6480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // space. Set the context to the current context in rsi. 6580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label gc; 6680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateInNewSpace(JSFunction::kSize, rax, rbx, rcx, &gc, TAG_OBJECT); 6780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 6880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the function info from the stack. 6980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rdx, Operand(rsp, 1 * kPointerSize)); 7080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 7144f0eee88ff00398ff7f715fab053374d808c90dSteve Block int map_index = strict_mode_ == kStrictMode 7244f0eee88ff00398ff7f715fab053374d808c90dSteve Block ? Context::STRICT_MODE_FUNCTION_MAP_INDEX 7344f0eee88ff00398ff7f715fab053374d808c90dSteve Block : Context::FUNCTION_MAP_INDEX; 7444f0eee88ff00398ff7f715fab053374d808c90dSteve Block 7580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Compute the function map in the current global context and set that 7680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // as the map of the allocated object. 7780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rcx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX))); 7880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rcx, FieldOperand(rcx, GlobalObject::kGlobalContextOffset)); 7944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movq(rcx, Operand(rcx, Context::SlotOffset(map_index))); 8080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(FieldOperand(rax, JSObject::kMapOffset), rcx); 8180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 8280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Initialize the rest of the function. We don't have to update the 8380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // write barrier because the allocated object is in new space. 8480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ LoadRoot(rbx, Heap::kEmptyFixedArrayRootIndex); 8580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ LoadRoot(rcx, Heap::kTheHoleValueRootIndex); 86b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ LoadRoot(rdi, Heap::kUndefinedValueRootIndex); 8780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(FieldOperand(rax, JSObject::kPropertiesOffset), rbx); 8880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(FieldOperand(rax, JSObject::kElementsOffset), rbx); 8980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(FieldOperand(rax, JSFunction::kPrototypeOrInitialMapOffset), rcx); 9080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset), rdx); 9180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(FieldOperand(rax, JSFunction::kContextOffset), rsi); 9280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(FieldOperand(rax, JSFunction::kLiteralsOffset), rbx); 93b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movq(FieldOperand(rax, JSFunction::kNextFunctionLinkOffset), rdi); 9480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 9580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Initialize the code pointer in the function to be the one 9680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // found in the shared function info object. 9780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rdx, FieldOperand(rdx, SharedFunctionInfo::kCodeOffset)); 9880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(rdx, FieldOperand(rdx, Code::kHeaderSize)); 9980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(FieldOperand(rax, JSFunction::kCodeEntryOffset), rdx); 10080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 10180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 10280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return and remove the on-stack parameter. 10380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(1 * kPointerSize); 10480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 10580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Create a new closure through the slower runtime call. 10680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&gc); 10780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(rcx); // Temporarily remove return address. 10880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(rdx); 10980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(rsi); 11080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(rdx); 11144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ PushRoot(Heap::kFalseValueRootIndex); 11280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(rcx); // Restore return address. 1138a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang __ TailCallRuntime(Runtime::kNewClosure, 3, 1); 11480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 11580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 11680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 11780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FastNewContextStub::Generate(MacroAssembler* masm) { 11880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Try to allocate the context in new space. 11980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label gc; 12080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen int length = slots_ + Context::MIN_CONTEXT_SLOTS; 12180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateInNewSpace((length * kPointerSize) + FixedArray::kHeaderSize, 12280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen rax, rbx, rcx, &gc, TAG_OBJECT); 12380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 12480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the function from the stack. 12580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rcx, Operand(rsp, 1 * kPointerSize)); 12680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 12780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Setup the object header. 1283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ LoadRoot(kScratchRegister, Heap::kFunctionContextMapRootIndex); 12980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(FieldOperand(rax, HeapObject::kMapOffset), kScratchRegister); 13080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Move(FieldOperand(rax, FixedArray::kLengthOffset), Smi::FromInt(length)); 13180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 13280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Setup the fixed slots. 1339fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Set(rbx, 0); // Set to NULL. 13480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(Operand(rax, Context::SlotOffset(Context::CLOSURE_INDEX)), rcx); 1353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(Operand(rax, Context::SlotOffset(Context::PREVIOUS_INDEX)), rsi); 13680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(Operand(rax, Context::SlotOffset(Context::EXTENSION_INDEX)), rbx); 13780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 1383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Copy the global object from the previous context. 13980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rbx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX))); 14080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(Operand(rax, Context::SlotOffset(Context::GLOBAL_INDEX)), rbx); 14180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 14280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Initialize the rest of the slots to undefined. 14380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ LoadRoot(rbx, Heap::kUndefinedValueRootIndex); 14480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { 14580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(Operand(rax, Context::SlotOffset(i)), rbx); 14680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 14780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 14880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return and remove the on-stack parameter. 14980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rsi, rax); 15080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(1 * kPointerSize); 15180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 15280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Need to collect. Call into runtime system. 15380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&gc); 1543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ TailCallRuntime(Runtime::kNewFunctionContext, 1, 1); 15580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 15680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 15780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 15880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { 15980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Stack layout on entry: 16080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // 16180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // [rsp + kPointerSize]: constant elements. 16280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // [rsp + (2 * kPointerSize)]: literal index. 16380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // [rsp + (3 * kPointerSize)]: literals array. 16480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 16580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // All sizes here are multiples of kPointerSize. 16680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen int elements_size = (length_ > 0) ? FixedArray::SizeFor(length_) : 0; 16780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen int size = JSArray::kSize + elements_size; 16880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 16980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load boilerplate object into rcx and check if we need to create a 17080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // boilerplate. 17180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label slow_case; 17280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rcx, Operand(rsp, 3 * kPointerSize)); 17380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rax, Operand(rsp, 2 * kPointerSize)); 17480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen SmiIndex index = masm->SmiToIndex(rax, rax, kPointerSizeLog2); 17580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rcx, 17680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FieldOperand(rcx, index.reg, index.scale, FixedArray::kHeaderSize)); 17780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CompareRoot(rcx, Heap::kUndefinedValueRootIndex); 17880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &slow_case); 17980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 18080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (FLAG_debug_code) { 18180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const char* message; 18280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Heap::RootListIndex expected_map_index; 18380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (mode_ == CLONE_ELEMENTS) { 18480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen message = "Expected (writable) fixed array"; 18580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen expected_map_index = Heap::kFixedArrayMapRootIndex; 18680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 18780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(mode_ == COPY_ON_WRITE_ELEMENTS); 18880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen message = "Expected copy-on-write fixed array"; 18980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen expected_map_index = Heap::kFixedCOWArrayMapRootIndex; 19080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 19180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(rcx); 19280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rcx, FieldOperand(rcx, JSArray::kElementsOffset)); 19380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset), 19480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen expected_map_index); 19580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Assert(equal, message); 19680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(rcx); 19780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 19880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 19980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Allocate both the JS array and the elements array in one big 20080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // allocation. This avoids multiple limit checks. 20180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateInNewSpace(size, rax, rbx, rdx, &slow_case, TAG_OBJECT); 20280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 20380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Copy the JS array part. 20480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen for (int i = 0; i < JSArray::kSize; i += kPointerSize) { 20580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if ((i != JSArray::kElementsOffset) || (length_ == 0)) { 20680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rbx, FieldOperand(rcx, i)); 20780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(FieldOperand(rax, i), rbx); 20880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 20980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 21080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 21180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (length_ > 0) { 21280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get hold of the elements array of the boilerplate and setup the 21380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // elements pointer in the resulting object. 21480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rcx, FieldOperand(rcx, JSArray::kElementsOffset)); 21580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(rdx, Operand(rax, JSArray::kSize)); 21680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(FieldOperand(rax, JSArray::kElementsOffset), rdx); 21780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 21880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Copy the elements array. 21980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen for (int i = 0; i < elements_size; i += kPointerSize) { 22080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rbx, FieldOperand(rcx, i)); 22180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(FieldOperand(rdx, i), rbx); 22280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 22380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 22480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 22580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return and remove the on-stack parameters. 22680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(3 * kPointerSize); 22780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 22880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&slow_case); 22980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1); 23080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 23180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 23280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 23369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch// The stub expects its argument on the stack and returns its result in tos_: 23469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch// zero for false, and a non-zero value for true. 23580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid ToBooleanStub::Generate(MacroAssembler* masm) { 23669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label patch; 23769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch const Register argument = rax; 2383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch const Register map = rdx; 2393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 24069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (!types_.IsEmpty()) { 24169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ movq(argument, Operand(rsp, 1 * kPointerSize)); 24269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 24380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 244257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // undefined -> false 24569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false); 246257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 247257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Boolean -> its value 24869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false); 24969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true); 250257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // 'null' -> false. 25269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false); 25369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 25469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (types_.Contains(SMI)) { 25569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Smis: 0 -> false, all other -> true 25669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label not_smi; 25769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ JumpIfNotSmi(argument, ¬_smi, Label::kNear); 25869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // argument contains the correct return value already 25969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (!tos_.is(argument)) { 26069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ movq(tos_, argument); 26169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 26269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ ret(1 * kPointerSize); 26369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(¬_smi); 26469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } else if (types_.NeedsMap()) { 26569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // If we need a map later and have a Smi -> patch. 26669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ JumpIfSmi(argument, &patch, Label::kNear); 26769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 26880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 26969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (types_.NeedsMap()) { 27069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ movq(map, FieldOperand(argument, HeapObject::kMapOffset)); 27169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 27269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (types_.CanBeUndetectable()) { 27369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ testb(FieldOperand(map, Map::kBitFieldOffset), 27469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Immediate(1 << Map::kIsUndetectable)); 27569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Undetectable -> false. 27669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label not_undetectable; 27769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(zero, ¬_undetectable, Label::kNear); 27869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Set(tos_, 0); 27969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ ret(1 * kPointerSize); 28069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(¬_undetectable); 28169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 28269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 28380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 28469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (types_.Contains(SPEC_OBJECT)) { 28569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // spec object -> true. 28669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label not_js_object; 28769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); 28869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(below, ¬_js_object, Label::kNear); 28969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // argument contains the correct return value already. 29069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (!tos_.is(argument)) { 29169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Set(tos_, 1); 29269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 29369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ ret(1 * kPointerSize); 29469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(¬_js_object); 29569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 29680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 29769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (types_.Contains(STRING)) { 29869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // String value -> false iff empty. 29969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label not_string; 30069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ CmpInstanceType(map, FIRST_NONSTRING_TYPE); 30169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(above_equal, ¬_string, Label::kNear); 30269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ movq(tos_, FieldOperand(argument, String::kLengthOffset)); 30369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ ret(1 * kPointerSize); // the string length is OK as the return value 30469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(¬_string); 30569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 30680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 30769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (types_.Contains(HEAP_NUMBER)) { 30869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // heap number -> false iff +0, -0, or NaN. 30969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label not_heap_number, false_result; 31069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ CompareRoot(map, Heap::kHeapNumberMapRootIndex); 31169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(not_equal, ¬_heap_number, Label::kNear); 31269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ xorps(xmm0, xmm0); 31369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ ucomisd(xmm0, FieldOperand(argument, HeapNumber::kValueOffset)); 31469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(zero, &false_result, Label::kNear); 31569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // argument contains the correct return value already. 31669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (!tos_.is(argument)) { 31769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Set(tos_, 1); 31869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 31969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ ret(1 * kPointerSize); 32069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&false_result); 32169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Set(tos_, 0); 32269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ ret(1 * kPointerSize); 32369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(¬_heap_number); 32469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 32580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 32669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&patch); 32769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch GenerateTypeTransition(masm); 32869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch} 32980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 33069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 33169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdochvoid ToBooleanStub::CheckOddball(MacroAssembler* masm, 33269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Type type, 33369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Heap::RootListIndex value, 33469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch bool result) { 33569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch const Register argument = rax; 33669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (types_.Contains(type)) { 33769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // If we see an expected oddball, return its ToBoolean value tos_. 33869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label different_value; 33969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ CompareRoot(argument, value); 34069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(not_equal, &different_value, Label::kNear); 34169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (!result) { 34269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // If we have to return zero, there is no way around clearing tos_. 34369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Set(tos_, 0); 34469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } else if (!tos_.is(argument)) { 34569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // If we have to return non-zero, we can re-use the argument if it is the 34669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // same register as the result, because we never see Smi-zero here. 34769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Set(tos_, 1); 34869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 34969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ ret(1 * kPointerSize); 35069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&different_value); 35169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 35269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch} 35369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 35469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 35569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdochvoid ToBooleanStub::GenerateTypeTransition(MacroAssembler* masm) { 35669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ pop(rcx); // Get return address, operand is now on top of stack. 35769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Push(Smi::FromInt(tos_.code())); 35869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Push(Smi::FromInt(types_.ToByte())); 35969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ push(rcx); // Push return address. 36069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Patch the caller to an appropriate specialized stub and return the 36169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // operation result to the caller of the stub. 36269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ TailCallExternalReference( 36369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch ExternalReference(IC_Utility(IC::kToBoolean_Patch), masm->isolate()), 36469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 3, 36569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 1); 36680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 36780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 36880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 36980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenclass FloatingPointHelper : public AllStatic { 37080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen public: 37180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load the operands from rdx and rax into xmm0 and xmm1, as doubles. 37280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the operands are not both numbers, jump to not_numbers. 37380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Leaves rdx and rax unchanged. SmiOperands assumes both are smis. 37480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // NumberOperands assumes both are smis or heap numbers. 37580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen static void LoadSSE2SmiOperands(MacroAssembler* masm); 37680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen static void LoadSSE2NumberOperands(MacroAssembler* masm); 37780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen static void LoadSSE2UnknownOperands(MacroAssembler* masm, 37880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* not_numbers); 37980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 38080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Takes the operands in rdx and rax and loads them as integers in rax 38180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // and rcx. 38280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen static void LoadAsIntegers(MacroAssembler* masm, 38380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* operand_conversion_failure, 38480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register heap_number_map); 38580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // As above, but we know the operands to be numbers. In that case, 38680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // conversion can't fail. 38780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen static void LoadNumbersAsIntegers(MacroAssembler* masm); 38880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3898b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Tries to convert two values to smis losslessly. 3908b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // This fails if either argument is not a Smi nor a HeapNumber, 3918b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // or if it's a HeapNumber with a value that can't be converted 3928b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // losslessly to a Smi. In that case, control transitions to the 3938b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // on_not_smis label. 3948b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // On success, either control goes to the on_success label (if one is 3958b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // provided), or it falls through at the end of the code (if on_success 3968b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // is NULL). 3978b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // On success, both first and second holds Smi tagged values. 3988b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // One of first or second must be non-Smi when entering. 3998b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static void NumbersToSmis(MacroAssembler* masm, 4008b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Register first, 4018b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Register second, 4028b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Register scratch1, 4038b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Register scratch2, 4048b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Register scratch3, 4058b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Label* on_success, 4068b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Label* on_not_smis); 4078b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch}; 40880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 40980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 410257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Get the integer part of a heap number. 411257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Overwrites the contents of rdi, rbx and rcx. Result cannot be rdi or rbx. 412257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid IntegerConvert(MacroAssembler* masm, 413257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register result, 414257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register source) { 415257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Result may be rcx. If result and source are the same register, source will 416257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // be overwritten. 417257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(!result.is(rdi) && !result.is(rbx)); 418257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // TODO(lrn): When type info reaches here, if value is a 32-bit integer, use 419257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // cvttsd2si (32-bit version) directly. 420257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register double_exponent = rbx; 421257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register double_value = rdi; 422257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label done, exponent_63_plus; 423257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Get double and extract exponent. 424257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movq(double_value, FieldOperand(source, HeapNumber::kValueOffset)); 425257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Clear result preemptively, in case we need to return zero. 426257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ xorl(result, result); 427257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movq(xmm0, double_value); // Save copy in xmm0 in case we need it there. 428257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Double to remove sign bit, shift exponent down to least significant bits. 429257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // and subtract bias to get the unshifted, unbiased exponent. 430257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ lea(double_exponent, Operand(double_value, double_value, times_1, 0)); 431257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shr(double_exponent, Immediate(64 - HeapNumber::kExponentBits)); 432257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ subl(double_exponent, Immediate(HeapNumber::kExponentBias)); 433257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check whether the exponent is too big for a 63 bit unsigned integer. 434257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmpl(double_exponent, Immediate(63)); 435257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(above_equal, &exponent_63_plus, Label::kNear); 436257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Handle exponent range 0..62. 437257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cvttsd2siq(result, xmm0); 438257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&done, Label::kNear); 439257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 440257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&exponent_63_plus); 441257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Exponent negative or 63+. 442257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmpl(double_exponent, Immediate(83)); 443257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If exponent negative or above 83, number contains no significant bits in 444257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // the range 0..2^31, so result is zero, and rcx already holds zero. 445257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(above, &done, Label::kNear); 446257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 447257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Exponent in rage 63..83. 448257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Mantissa * 2^exponent contains bits in the range 2^0..2^31, namely 449257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // the least significant exponent-52 bits. 450257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 451257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Negate low bits of mantissa if value is negative. 452257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ addq(double_value, double_value); // Move sign bit to carry. 453257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ sbbl(result, result); // And convert carry to -1 in result register. 454257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // if scratch2 is negative, do (scratch2-1)^-1, otherwise (scratch2-0)^0. 455257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ addl(double_value, result); 456257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Do xor in opposite directions depending on where we want the result 457257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // (depending on whether result is rcx or not). 458257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 459257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (result.is(rcx)) { 460257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ xorl(double_value, result); 461257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Left shift mantissa by (exponent - mantissabits - 1) to save the 462257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // bits that have positional values below 2^32 (the extra -1 comes from the 463257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // doubling done above to move the sign bit into the carry flag). 464257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ leal(rcx, Operand(double_exponent, -HeapNumber::kMantissaBits - 1)); 465257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shll_cl(double_value); 466257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movl(result, double_value); 467257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } else { 468257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // As the then-branch, but move double-value to result before shifting. 469257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ xorl(result, double_value); 470257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ leal(rcx, Operand(double_exponent, -HeapNumber::kMantissaBits - 1)); 471257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shll_cl(result); 472257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 473257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 474257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&done); 475257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 476257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 477257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 478257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::Generate(MacroAssembler* masm) { 479257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (operand_type_) { 480257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case UnaryOpIC::UNINITIALIZED: 481257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateTypeTransition(masm); 482257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 483257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case UnaryOpIC::SMI: 484257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiStub(masm); 485257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 486257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case UnaryOpIC::HEAP_NUMBER: 487257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberStub(masm); 488257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 489257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case UnaryOpIC::GENERIC: 490257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateGenericStub(masm); 491257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 492257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 493257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 494257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 495257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 496257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { 497257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ pop(rcx); // Save return address. 4983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 4993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ push(rax); // the operand 500257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Push(Smi::FromInt(op_)); 5013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ Push(Smi::FromInt(mode_)); 502257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Push(Smi::FromInt(operand_type_)); 503257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 504257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(rcx); // Push return address. 505257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 506257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Patch the caller to an appropriate specialized stub and return the 507257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // operation result to the caller of the stub. 508257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ TailCallExternalReference( 5093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch ExternalReference(IC_Utility(IC::kUnaryOp_Patch), masm->isolate()), 4, 1); 510257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 511257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 512257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 513257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch. 514257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiStub(MacroAssembler* masm) { 515257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (op_) { 516257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::SUB: 517257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiStubSub(masm); 518257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 519257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::BIT_NOT: 520257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiStubBitNot(masm); 521257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 522257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch default: 523257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch UNREACHABLE(); 524257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 525257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 526257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 527257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 528257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiStubSub(MacroAssembler* masm) { 529257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label slow; 530257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeSub(masm, &slow, &slow, Label::kNear, Label::kNear); 531257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow); 532257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateTypeTransition(masm); 533257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 534257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 535257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 536257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiStubBitNot(MacroAssembler* masm) { 537257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_smi; 538257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear); 539257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_smi); 540257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateTypeTransition(masm); 541257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 542257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 543257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 544257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiCodeSub(MacroAssembler* masm, 545257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* non_smi, 546257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* slow, 547257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label::Distance non_smi_near, 548257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label::Distance slow_near) { 549257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label done; 550257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ JumpIfNotSmi(rax, non_smi, non_smi_near); 551257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ SmiNeg(rax, rax, &done, Label::kNear); 552257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(slow, slow_near); 553257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&done); 554257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 555257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 556257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 557257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 558257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiCodeBitNot(MacroAssembler* masm, 559257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* non_smi, 560257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label::Distance non_smi_near) { 561257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ JumpIfNotSmi(rax, non_smi, non_smi_near); 562257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ SmiNot(rax, rax); 563257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 564257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 565257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 566257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 567257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch. 568257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { 569257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (op_) { 570257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::SUB: 571257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberStubSub(masm); 572257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 573257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::BIT_NOT: 574257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberStubBitNot(masm); 575257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 576257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch default: 577257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch UNREACHABLE(); 578257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 579257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 580257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 581257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 582257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberStubSub(MacroAssembler* masm) { 583257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_smi, slow, call_builtin; 584257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeSub(masm, &non_smi, &call_builtin, Label::kNear); 585257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_smi); 586257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberCodeSub(masm, &slow); 587257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow); 588257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateTypeTransition(masm); 589257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&call_builtin); 590257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateGenericCodeFallback(masm); 591257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 592257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 593257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 594257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberStubBitNot( 595257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch MacroAssembler* masm) { 596257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_smi, slow; 597257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear); 598257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_smi); 599257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberCodeBitNot(masm, &slow); 600257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow); 601257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateTypeTransition(masm); 602257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 603257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 604257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 605257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm, 606257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* slow) { 607257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check if the operand is a heap number. 608257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), 609257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Heap::kHeapNumberMapRootIndex); 610257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, slow); 611257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 612257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Operand is a float, negate its value by flipping the sign bit. 613257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (mode_ == UNARY_OVERWRITE) { 614257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Set(kScratchRegister, 0x01); 615257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shl(kScratchRegister, Immediate(63)); 616257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ xor_(FieldOperand(rax, HeapNumber::kValueOffset), kScratchRegister); 617257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } else { 618257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Allocate a heap number before calculating the answer, 619257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // so we don't have an untagged double around during GC. 620257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label slow_allocate_heapnumber, heapnumber_allocated; 621257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ AllocateHeapNumber(rcx, rbx, &slow_allocate_heapnumber); 622257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&heapnumber_allocated); 623257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 624257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow_allocate_heapnumber); 625257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ EnterInternalFrame(); 626257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(rax); 627257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CallRuntime(Runtime::kNumberAlloc, 0); 628257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movq(rcx, rax); 629257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ pop(rax); 630257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ LeaveInternalFrame(); 631257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&heapnumber_allocated); 632257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // rcx: allocated 'empty' number 633257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 634257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Copy the double value to the new heap number, flipping the sign. 635257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movq(rdx, FieldOperand(rax, HeapNumber::kValueOffset)); 636257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Set(kScratchRegister, 0x01); 637257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shl(kScratchRegister, Immediate(63)); 638257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ xor_(rdx, kScratchRegister); // Flip sign. 639257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movq(FieldOperand(rcx, HeapNumber::kValueOffset), rdx); 640257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movq(rax, rcx); 641257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 642257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 643257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 644257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 645257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 646257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberCodeBitNot(MacroAssembler* masm, 647257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* slow) { 648257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check if the operand is a heap number. 649257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), 650257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Heap::kHeapNumberMapRootIndex); 651257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, slow); 652257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 653257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Convert the heap number in rax to an untagged integer in rcx. 654257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch IntegerConvert(masm, rax, rax); 655257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 656257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Do the bitwise operation and smi tag the result. 657257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ notl(rax); 658257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Integer32ToSmi(rax, rax); 659257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 660257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 661257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 662257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 663257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch. 664257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericStub(MacroAssembler* masm) { 665257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (op_) { 666257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::SUB: 667257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateGenericStubSub(masm); 668257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 669257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::BIT_NOT: 670257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateGenericStubBitNot(masm); 671257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 672257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch default: 673257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch UNREACHABLE(); 674257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 675257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 676257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 677257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 678257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericStubSub(MacroAssembler* masm) { 679257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_smi, slow; 680257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeSub(masm, &non_smi, &slow, Label::kNear); 681257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_smi); 682257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberCodeSub(masm, &slow); 683257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow); 684257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateGenericCodeFallback(masm); 685257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 686257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 687257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 688257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericStubBitNot(MacroAssembler* masm) { 689257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_smi, slow; 690257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear); 691257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_smi); 692257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberCodeBitNot(masm, &slow); 693257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow); 694257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateGenericCodeFallback(masm); 695257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 696257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 697257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 698257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericCodeFallback(MacroAssembler* masm) { 699257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Handle the slow case by jumping to the JavaScript builtin. 700257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ pop(rcx); // pop return address 701257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(rax); 702257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(rcx); // push return address 703257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (op_) { 704257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::SUB: 705257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_FUNCTION); 706257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 707257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::BIT_NOT: 708257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION); 709257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 710257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch default: 711257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch UNREACHABLE(); 712257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 713257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 714257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 715257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 7163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid UnaryOpStub::PrintName(StringStream* stream) { 717257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch const char* op_name = Token::Name(op_); 718257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch const char* overwrite_name = NULL; // Make g++ happy. 719257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (mode_) { 720257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break; 721257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case UNARY_OVERWRITE: overwrite_name = "Overwrite"; break; 722257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 7233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch stream->Add("UnaryOpStub_%s_%s_%s", 7243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch op_name, 7253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch overwrite_name, 7263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch UnaryOpIC::GetName(operand_type_)); 727086aeeaae12517475c22695a200be45495516549Ben Murdoch} 728086aeeaae12517475c22695a200be45495516549Ben Murdoch 729086aeeaae12517475c22695a200be45495516549Ben Murdoch 730257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { 731086aeeaae12517475c22695a200be45495516549Ben Murdoch __ pop(rcx); // Save return address. 732086aeeaae12517475c22695a200be45495516549Ben Murdoch __ push(rdx); 733086aeeaae12517475c22695a200be45495516549Ben Murdoch __ push(rax); 734086aeeaae12517475c22695a200be45495516549Ben Murdoch // Left and right arguments are now on top. 735086aeeaae12517475c22695a200be45495516549Ben Murdoch // Push this stub's key. Although the operation and the type info are 736086aeeaae12517475c22695a200be45495516549Ben Murdoch // encoded into the key, the encoding is opaque, so push them too. 737086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Push(Smi::FromInt(MinorKey())); 738086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Push(Smi::FromInt(op_)); 739086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Push(Smi::FromInt(operands_type_)); 740086aeeaae12517475c22695a200be45495516549Ben Murdoch 741086aeeaae12517475c22695a200be45495516549Ben Murdoch __ push(rcx); // Push return address. 742086aeeaae12517475c22695a200be45495516549Ben Murdoch 743086aeeaae12517475c22695a200be45495516549Ben Murdoch // Patch the caller to an appropriate specialized stub and return the 744086aeeaae12517475c22695a200be45495516549Ben Murdoch // operation result to the caller of the stub. 745086aeeaae12517475c22695a200be45495516549Ben Murdoch __ TailCallExternalReference( 746257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ExternalReference(IC_Utility(IC::kBinaryOp_Patch), 74744f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()), 748086aeeaae12517475c22695a200be45495516549Ben Murdoch 5, 749086aeeaae12517475c22695a200be45495516549Ben Murdoch 1); 750086aeeaae12517475c22695a200be45495516549Ben Murdoch} 751086aeeaae12517475c22695a200be45495516549Ben Murdoch 752086aeeaae12517475c22695a200be45495516549Ben Murdoch 753257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::Generate(MacroAssembler* masm) { 754086aeeaae12517475c22695a200be45495516549Ben Murdoch switch (operands_type_) { 755257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::UNINITIALIZED: 756086aeeaae12517475c22695a200be45495516549Ben Murdoch GenerateTypeTransition(masm); 757086aeeaae12517475c22695a200be45495516549Ben Murdoch break; 758257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::SMI: 759086aeeaae12517475c22695a200be45495516549Ben Murdoch GenerateSmiStub(masm); 760086aeeaae12517475c22695a200be45495516549Ben Murdoch break; 761257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::INT32: 7621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block UNREACHABLE(); 7631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // The int32 case is identical to the Smi case. We avoid creating this 7641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // ic state on x64. 765086aeeaae12517475c22695a200be45495516549Ben Murdoch break; 766257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::HEAP_NUMBER: 767086aeeaae12517475c22695a200be45495516549Ben Murdoch GenerateHeapNumberStub(masm); 768086aeeaae12517475c22695a200be45495516549Ben Murdoch break; 769257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::ODDBALL: 77044f0eee88ff00398ff7f715fab053374d808c90dSteve Block GenerateOddballStub(masm); 77144f0eee88ff00398ff7f715fab053374d808c90dSteve Block break; 772257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::BOTH_STRING: 773257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateBothStringStub(masm); 774257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 775257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::STRING: 776086aeeaae12517475c22695a200be45495516549Ben Murdoch GenerateStringStub(masm); 777086aeeaae12517475c22695a200be45495516549Ben Murdoch break; 778257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::GENERIC: 779086aeeaae12517475c22695a200be45495516549Ben Murdoch GenerateGeneric(masm); 780086aeeaae12517475c22695a200be45495516549Ben Murdoch break; 781086aeeaae12517475c22695a200be45495516549Ben Murdoch default: 782086aeeaae12517475c22695a200be45495516549Ben Murdoch UNREACHABLE(); 783086aeeaae12517475c22695a200be45495516549Ben Murdoch } 784086aeeaae12517475c22695a200be45495516549Ben Murdoch} 785086aeeaae12517475c22695a200be45495516549Ben Murdoch 786086aeeaae12517475c22695a200be45495516549Ben Murdoch 7873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid BinaryOpStub::PrintName(StringStream* stream) { 788086aeeaae12517475c22695a200be45495516549Ben Murdoch const char* op_name = Token::Name(op_); 789086aeeaae12517475c22695a200be45495516549Ben Murdoch const char* overwrite_name; 790086aeeaae12517475c22695a200be45495516549Ben Murdoch switch (mode_) { 791086aeeaae12517475c22695a200be45495516549Ben Murdoch case NO_OVERWRITE: overwrite_name = "Alloc"; break; 792086aeeaae12517475c22695a200be45495516549Ben Murdoch case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; 793086aeeaae12517475c22695a200be45495516549Ben Murdoch case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; 794086aeeaae12517475c22695a200be45495516549Ben Murdoch default: overwrite_name = "UnknownOverwrite"; break; 795086aeeaae12517475c22695a200be45495516549Ben Murdoch } 7963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch stream->Add("BinaryOpStub_%s_%s_%s", 7973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch op_name, 7983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch overwrite_name, 7993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch BinaryOpIC::GetName(operands_type_)); 800086aeeaae12517475c22695a200be45495516549Ben Murdoch} 801086aeeaae12517475c22695a200be45495516549Ben Murdoch 802086aeeaae12517475c22695a200be45495516549Ben Murdoch 803257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateSmiCode( 804257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch MacroAssembler* masm, 805086aeeaae12517475c22695a200be45495516549Ben Murdoch Label* slow, 806086aeeaae12517475c22695a200be45495516549Ben Murdoch SmiCodeGenerateHeapNumberResults allow_heapnumber_results) { 807086aeeaae12517475c22695a200be45495516549Ben Murdoch 808257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Arguments to BinaryOpStub are in rdx and rax. 8091e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register left = rdx; 8101e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register right = rax; 811086aeeaae12517475c22695a200be45495516549Ben Murdoch 8128b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // We only generate heapnumber answers for overflowing calculations 8138b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // for the four basic arithmetic operations and logical right shift by 0. 8148b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch bool generate_inline_heapnumber_results = 8158b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch (allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS) && 8168b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch (op_ == Token::ADD || op_ == Token::SUB || 8178b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch op_ == Token::MUL || op_ == Token::DIV || op_ == Token::SHR); 818086aeeaae12517475c22695a200be45495516549Ben Murdoch 8191e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Smi check of both operands. If op is BIT_OR, the check is delayed 8201e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // until after the OR operation. 8211e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Label not_smis; 8221e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Label use_fp_on_smis; 8238b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Label fail; 8241e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 8251e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (op_ != Token::BIT_OR) { 8261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Comment smi_check_comment(masm, "-- Smi check arguments"); 8271e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ JumpIfNotBothSmi(left, right, ¬_smis); 8281e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 8291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 8308b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Label smi_values; 8318b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ bind(&smi_values); 8321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Perform the operation. 8331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Comment perform_smi(masm, "-- Perform smi operation"); 834086aeeaae12517475c22695a200be45495516549Ben Murdoch switch (op_) { 835086aeeaae12517475c22695a200be45495516549Ben Murdoch case Token::ADD: 8361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block ASSERT(right.is(rax)); 8371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ SmiAdd(right, right, left, &use_fp_on_smis); // ADD is commutative. 8381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 8391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 840086aeeaae12517475c22695a200be45495516549Ben Murdoch case Token::SUB: 8411e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ SmiSub(left, left, right, &use_fp_on_smis); 8421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movq(rax, left); 8431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 8441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 845086aeeaae12517475c22695a200be45495516549Ben Murdoch case Token::MUL: 8461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block ASSERT(right.is(rax)); 8471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ SmiMul(right, right, left, &use_fp_on_smis); // MUL is commutative. 8481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 8491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 850086aeeaae12517475c22695a200be45495516549Ben Murdoch case Token::DIV: 8511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // SmiDiv will not accept left in rdx or right in rax. 8521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block left = rcx; 8531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block right = rbx; 8541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movq(rbx, rax); 8551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movq(rcx, rdx); 8561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ SmiDiv(rax, left, right, &use_fp_on_smis); 857086aeeaae12517475c22695a200be45495516549Ben Murdoch break; 8581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 859086aeeaae12517475c22695a200be45495516549Ben Murdoch case Token::MOD: 8601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // SmiMod will not accept left in rdx or right in rax. 8611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block left = rcx; 8621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block right = rbx; 8631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movq(rbx, rax); 8641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movq(rcx, rdx); 8651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ SmiMod(rax, left, right, &use_fp_on_smis); 8661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 8671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 8681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::BIT_OR: { 8691e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block ASSERT(right.is(rax)); 8708b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ SmiOrIfSmis(right, right, left, ¬_smis); // BIT_OR is commutative. 8711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 8721e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 873086aeeaae12517475c22695a200be45495516549Ben Murdoch case Token::BIT_XOR: 8741e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block ASSERT(right.is(rax)); 8751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ SmiXor(right, right, left); // BIT_XOR is commutative. 8761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 8771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 8781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::BIT_AND: 8791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block ASSERT(right.is(rax)); 8801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ SmiAnd(right, right, left); // BIT_AND is commutative. 8811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 8821e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 883086aeeaae12517475c22695a200be45495516549Ben Murdoch case Token::SHL: 8841e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ SmiShiftLeft(left, left, right); 8851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movq(rax, left); 8861e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 8871e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 8881e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::SAR: 8891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ SmiShiftArithmeticRight(left, left, right); 8901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movq(rax, left); 8911e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 8921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 893086aeeaae12517475c22695a200be45495516549Ben Murdoch case Token::SHR: 8948b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ SmiShiftLogicalRight(left, left, right, &use_fp_on_smis); 8951e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movq(rax, left); 896086aeeaae12517475c22695a200be45495516549Ben Murdoch break; 8971e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 898086aeeaae12517475c22695a200be45495516549Ben Murdoch default: 899086aeeaae12517475c22695a200be45495516549Ben Murdoch UNREACHABLE(); 900086aeeaae12517475c22695a200be45495516549Ben Murdoch } 901086aeeaae12517475c22695a200be45495516549Ben Murdoch 9021e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // 5. Emit return of result in rax. Some operations have registers pushed. 9031e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ ret(0); 9041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 9058b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (use_fp_on_smis.is_linked()) { 9068b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // 6. For some operations emit inline code to perform floating point 9078b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // operations on known smis (e.g., if the result of the operation 9088b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // overflowed the smi range). 9098b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ bind(&use_fp_on_smis); 9108b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (op_ == Token::DIV || op_ == Token::MOD) { 9118b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Restore left and right to rdx and rax. 9128b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ movq(rdx, rcx); 9138b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ movq(rax, rbx); 9148b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch } 9151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 9168b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (generate_inline_heapnumber_results) { 9178b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ AllocateHeapNumber(rcx, rbx, slow); 9188b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Comment perform_float(masm, "-- Perform float operation on smis"); 9198b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (op_ == Token::SHR) { 9208b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ SmiToInteger32(left, left); 9218b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ cvtqsi2sd(xmm0, left); 9228b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch } else { 9238b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch FloatingPointHelper::LoadSSE2SmiOperands(masm); 9248b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch switch (op_) { 9258b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch case Token::ADD: __ addsd(xmm0, xmm1); break; 9268b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch case Token::SUB: __ subsd(xmm0, xmm1); break; 9278b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch case Token::MUL: __ mulsd(xmm0, xmm1); break; 9288b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch case Token::DIV: __ divsd(xmm0, xmm1); break; 9298b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch default: UNREACHABLE(); 9308b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch } 9318b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch } 9328b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm0); 9338b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ movq(rax, rcx); 9348b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ ret(0); 9358b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch } else { 9368b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ jmp(&fail); 9371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 9381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 9391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 9401e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // 7. Non-smi operands reach the end of the code generated by 9411e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // GenerateSmiCode, and fall through to subsequent code, 9421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // with the operands in rdx and rax. 9438b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // But first we check if non-smi values are HeapNumbers holding 9448b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // values that could be smi. 9451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(¬_smis); 9468b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Comment done_comment(masm, "-- Enter non-smi code"); 9478b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch FloatingPointHelper::NumbersToSmis(masm, left, right, rbx, rdi, rcx, 9488b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch &smi_values, &fail); 9498b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ jmp(&smi_values); 9508b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ bind(&fail); 9511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 9521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 9531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 954257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateFloatingPointCode(MacroAssembler* masm, 955257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* allocation_failure, 956257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* non_numeric_failure) { 957086aeeaae12517475c22695a200be45495516549Ben Murdoch switch (op_) { 958086aeeaae12517475c22695a200be45495516549Ben Murdoch case Token::ADD: 959086aeeaae12517475c22695a200be45495516549Ben Murdoch case Token::SUB: 960086aeeaae12517475c22695a200be45495516549Ben Murdoch case Token::MUL: 9611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::DIV: { 9621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block FloatingPointHelper::LoadSSE2UnknownOperands(masm, non_numeric_failure); 9631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 9641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block switch (op_) { 9651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::ADD: __ addsd(xmm0, xmm1); break; 9661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::SUB: __ subsd(xmm0, xmm1); break; 9671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::MUL: __ mulsd(xmm0, xmm1); break; 9681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::DIV: __ divsd(xmm0, xmm1); break; 9691e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block default: UNREACHABLE(); 9701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 9711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateHeapResultAllocation(masm, allocation_failure); 9721e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm0); 9731e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ ret(0); 9741e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 9751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 9761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::MOD: { 9771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // For MOD we jump to the allocation_failure label, to call runtime. 9781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ jmp(allocation_failure); 9791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 9801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 9811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::BIT_OR: 9821e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::BIT_AND: 9831e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::BIT_XOR: 9841e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::SAR: 9851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::SHL: 9861e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::SHR: { 9871e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Label non_smi_shr_result; 9881e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register heap_number_map = r9; 9891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); 9901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block FloatingPointHelper::LoadAsIntegers(masm, non_numeric_failure, 9911e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block heap_number_map); 9921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block switch (op_) { 9931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::BIT_OR: __ orl(rax, rcx); break; 9941e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::BIT_AND: __ andl(rax, rcx); break; 9951e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::BIT_XOR: __ xorl(rax, rcx); break; 9961e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::SAR: __ sarl_cl(rax); break; 9971e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::SHL: __ shll_cl(rax); break; 9981e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::SHR: { 9991e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ shrl_cl(rax); 10001e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Check if result is negative. This can only happen for a shift 10011e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // by zero. 10021e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ testl(rax, rax); 10031e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ j(negative, &non_smi_shr_result); 10041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 10051e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 10061e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block default: UNREACHABLE(); 10071e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 10081e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block STATIC_ASSERT(kSmiValueSize == 32); 10091e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Tag smi result and return. 10101e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Integer32ToSmi(rax, rax); 10111e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Ret(); 10121e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 10131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Logical shift right can produce an unsigned int32 that is not 10141e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // an int32, and so is not in the smi range. Allocate a heap number 10151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // in that case. 10161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (op_ == Token::SHR) { 10171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&non_smi_shr_result); 10181e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Label allocation_failed; 10191e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movl(rbx, rax); // rbx holds result value (uint32 value as int64). 10201e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Allocate heap number in new space. 10211e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Not using AllocateHeapNumber macro in order to reuse 10221e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // already loaded heap_number_map. 10231e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ AllocateInNewSpace(HeapNumber::kSize, 10241e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block rax, 1025053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block rdx, 10261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block no_reg, 10271e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block &allocation_failed, 10281e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block TAG_OBJECT); 10291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Set the map. 10301e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (FLAG_debug_code) { 10311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ AbortIfNotRootValue(heap_number_map, 10321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Heap::kHeapNumberMapRootIndex, 10331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block "HeapNumberMap register clobbered."); 10341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 10351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movq(FieldOperand(rax, HeapObject::kMapOffset), 10361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block heap_number_map); 10371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ cvtqsi2sd(xmm0, rbx); 10381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm0); 10391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Ret(); 10401e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 10411e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&allocation_failed); 10421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // We need tagged values in rdx and rax for the following code, 10431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // not int32 in rax and rcx. 10441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Integer32ToSmi(rax, rcx); 1045053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ Integer32ToSmi(rdx, rbx); 10461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ jmp(allocation_failure); 10471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 10481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 10491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 10501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block default: UNREACHABLE(); break; 10511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 10521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // No fall-through from this generated code. 10531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (FLAG_debug_code) { 10541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Abort("Unexpected fall-through in " 1055257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch "BinaryStub::GenerateFloatingPointCode."); 10561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 10571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 10581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 10591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 1060257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateStringAddCode(MacroAssembler* masm) { 1061e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch ASSERT(op_ == Token::ADD); 1062257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label left_not_string, call_runtime; 10631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 1064e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Registers containing left and right operands respectively. 1065e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register left = rdx; 1066e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register right = rax; 10671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 1068e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Test if left operand is a string. 1069257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ JumpIfSmi(left, &left_not_string, Label::kNear); 1070e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ CmpObjectType(left, FIRST_NONSTRING_TYPE, rcx); 1071257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(above_equal, &left_not_string, Label::kNear); 1072e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch StringAddStub string_add_left_stub(NO_STRING_CHECK_LEFT_IN_STUB); 1073e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch GenerateRegisterArgsPush(masm); 1074e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ TailCallStub(&string_add_left_stub); 10751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 1076e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Left operand is not a string, test right. 1077e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&left_not_string); 1078257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ JumpIfSmi(right, &call_runtime, Label::kNear); 1079e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ CmpObjectType(right, FIRST_NONSTRING_TYPE, rcx); 1080257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(above_equal, &call_runtime, Label::kNear); 10811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 1082e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB); 1083e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch GenerateRegisterArgsPush(masm); 1084e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ TailCallStub(&string_add_right_stub); 10851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 10861e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Neither argument is a string. 1087e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&call_runtime); 10881e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 10891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 10901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 1091257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateCallRuntimeCode(MacroAssembler* masm) { 10921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateRegisterArgsPush(masm); 10931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block switch (op_) { 10941e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::ADD: 10951e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); 10961e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 10971e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::SUB: 10981e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); 10991e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 11001e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::MUL: 11011e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION); 11021e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 1103086aeeaae12517475c22695a200be45495516549Ben Murdoch case Token::DIV: 11041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION); 1105086aeeaae12517475c22695a200be45495516549Ben Murdoch break; 1106086aeeaae12517475c22695a200be45495516549Ben Murdoch case Token::MOD: 11071e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); 11081e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 1109086aeeaae12517475c22695a200be45495516549Ben Murdoch case Token::BIT_OR: 11101e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION); 11111e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 1112086aeeaae12517475c22695a200be45495516549Ben Murdoch case Token::BIT_AND: 11131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION); 11141e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 1115086aeeaae12517475c22695a200be45495516549Ben Murdoch case Token::BIT_XOR: 11161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION); 11171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 1118086aeeaae12517475c22695a200be45495516549Ben Murdoch case Token::SAR: 11191e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION); 11201e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 1121086aeeaae12517475c22695a200be45495516549Ben Murdoch case Token::SHL: 11221e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); 11231e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 1124086aeeaae12517475c22695a200be45495516549Ben Murdoch case Token::SHR: 11251e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); 1126086aeeaae12517475c22695a200be45495516549Ben Murdoch break; 1127086aeeaae12517475c22695a200be45495516549Ben Murdoch default: 1128086aeeaae12517475c22695a200be45495516549Ben Murdoch UNREACHABLE(); 1129086aeeaae12517475c22695a200be45495516549Ben Murdoch } 1130086aeeaae12517475c22695a200be45495516549Ben Murdoch} 1131086aeeaae12517475c22695a200be45495516549Ben Murdoch 1132086aeeaae12517475c22695a200be45495516549Ben Murdoch 1133257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { 11348b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Label call_runtime; 1135257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (result_type_ == BinaryOpIC::UNINITIALIZED || 1136257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch result_type_ == BinaryOpIC::SMI) { 11378b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Only allow smi results. 11388b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch GenerateSmiCode(masm, NULL, NO_HEAPNUMBER_RESULTS); 11398b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch } else { 11408b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Allow heap number result and don't make a transition if a heap number 11418b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // cannot be allocated. 11428b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS); 11438b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch } 11441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 11458b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Code falls through if the result is not returned as either a smi or heap 11468b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // number. 11471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateTypeTransition(masm); 11488b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch 11498b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (call_runtime.is_linked()) { 11508b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ bind(&call_runtime); 11518b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch GenerateCallRuntimeCode(masm); 11528b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch } 1153086aeeaae12517475c22695a200be45495516549Ben Murdoch} 1154086aeeaae12517475c22695a200be45495516549Ben Murdoch 1155086aeeaae12517475c22695a200be45495516549Ben Murdoch 1156257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateStringStub(MacroAssembler* masm) { 1157257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(operands_type_ == BinaryOpIC::STRING); 11581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block ASSERT(op_ == Token::ADD); 11591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateStringAddCode(masm); 1160e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Try to add arguments as strings, otherwise, transition to the generic 1161257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // BinaryOpIC type. 11621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateTypeTransition(masm); 1163086aeeaae12517475c22695a200be45495516549Ben Murdoch} 1164086aeeaae12517475c22695a200be45495516549Ben Murdoch 1165086aeeaae12517475c22695a200be45495516549Ben Murdoch 1166257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) { 1167257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label call_runtime; 1168257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(operands_type_ == BinaryOpIC::BOTH_STRING); 1169257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(op_ == Token::ADD); 1170257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If both arguments are strings, call the string add stub. 1171257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Otherwise, do a transition. 1172257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1173257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Registers containing left and right operands respectively. 1174257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register left = rdx; 1175257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register right = rax; 1176257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1177257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Test if left operand is a string. 1178257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ JumpIfSmi(left, &call_runtime); 1179257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CmpObjectType(left, FIRST_NONSTRING_TYPE, rcx); 1180257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(above_equal, &call_runtime); 1181257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1182257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Test if right operand is a string. 1183257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ JumpIfSmi(right, &call_runtime); 1184257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CmpObjectType(right, FIRST_NONSTRING_TYPE, rcx); 1185257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(above_equal, &call_runtime); 1186257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1187257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB); 1188257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateRegisterArgsPush(masm); 1189257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ TailCallStub(&string_add_stub); 1190257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1191257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&call_runtime); 1192257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateTypeTransition(masm); 1193257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 1194257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1195257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1196257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { 119744f0eee88ff00398ff7f715fab053374d808c90dSteve Block Label call_runtime; 119844f0eee88ff00398ff7f715fab053374d808c90dSteve Block 119944f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (op_ == Token::ADD) { 120044f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Handle string addition here, because it is the only operation 120144f0eee88ff00398ff7f715fab053374d808c90dSteve Block // that does not do a ToNumber conversion on the operands. 120244f0eee88ff00398ff7f715fab053374d808c90dSteve Block GenerateStringAddCode(masm); 120344f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 120444f0eee88ff00398ff7f715fab053374d808c90dSteve Block 120544f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Convert oddball arguments to numbers. 1206257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label check, done; 120744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); 1208257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &check, Label::kNear); 120944f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (Token::IsBitOp(op_)) { 121044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ xor_(rdx, rdx); 121144f0eee88ff00398ff7f715fab053374d808c90dSteve Block } else { 121244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ LoadRoot(rdx, Heap::kNanValueRootIndex); 121344f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 1214257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&done, Label::kNear); 121544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ bind(&check); 121644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); 1217257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &done, Label::kNear); 121844f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (Token::IsBitOp(op_)) { 121944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ xor_(rax, rax); 122044f0eee88ff00398ff7f715fab053374d808c90dSteve Block } else { 122144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ LoadRoot(rax, Heap::kNanValueRootIndex); 122244f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 122344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ bind(&done); 122444f0eee88ff00398ff7f715fab053374d808c90dSteve Block 122544f0eee88ff00398ff7f715fab053374d808c90dSteve Block GenerateHeapNumberStub(masm); 122644f0eee88ff00398ff7f715fab053374d808c90dSteve Block} 122744f0eee88ff00398ff7f715fab053374d808c90dSteve Block 122844f0eee88ff00398ff7f715fab053374d808c90dSteve Block 1229257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { 12301e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Label gc_required, not_number; 12311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateFloatingPointCode(masm, &gc_required, ¬_number); 12321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 12331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(¬_number); 12341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateTypeTransition(masm); 12351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 12361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&gc_required); 12371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateCallRuntimeCode(masm); 1238086aeeaae12517475c22695a200be45495516549Ben Murdoch} 1239086aeeaae12517475c22695a200be45495516549Ben Murdoch 1240086aeeaae12517475c22695a200be45495516549Ben Murdoch 1241257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateGeneric(MacroAssembler* masm) { 12421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Label call_runtime, call_string_add_or_runtime; 12431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 12441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS); 12451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 12461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateFloatingPointCode(masm, &call_runtime, &call_string_add_or_runtime); 12471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 12481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&call_string_add_or_runtime); 12491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (op_ == Token::ADD) { 12501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateStringAddCode(masm); 12511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 12521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 12531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&call_runtime); 12541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateCallRuntimeCode(masm); 1255086aeeaae12517475c22695a200be45495516549Ben Murdoch} 1256086aeeaae12517475c22695a200be45495516549Ben Murdoch 1257086aeeaae12517475c22695a200be45495516549Ben Murdoch 1258257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateHeapResultAllocation(MacroAssembler* masm, 1259257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* alloc_failure) { 12601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Label skip_allocation; 12611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block OverwriteMode mode = mode_; 12621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block switch (mode) { 12631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case OVERWRITE_LEFT: { 12641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // If the argument in rdx is already an object, we skip the 12651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // allocation of a heap number. 12661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ JumpIfNotSmi(rdx, &skip_allocation); 12671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Allocate a heap number for the result. Keep eax and edx intact 12681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // for the possible runtime call. 12691e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ AllocateHeapNumber(rbx, rcx, alloc_failure); 12701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Now rdx can be overwritten losing one of the arguments as we are 12711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // now done and will not need it any more. 12721e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movq(rdx, rbx); 12731e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&skip_allocation); 12741e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Use object in rdx as a result holder 12751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movq(rax, rdx); 12761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 12771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 12781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case OVERWRITE_RIGHT: 12791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // If the argument in rax is already an object, we skip the 12801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // allocation of a heap number. 12811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ JumpIfNotSmi(rax, &skip_allocation); 12821e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Fall through! 12831e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case NO_OVERWRITE: 12841e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Allocate a heap number for the result. Keep rax and rdx intact 12851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // for the possible runtime call. 12861e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ AllocateHeapNumber(rbx, rcx, alloc_failure); 12871e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Now rax can be overwritten losing one of the arguments as we are 12881e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // now done and will not need it any more. 12891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movq(rax, rbx); 12901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&skip_allocation); 12911e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 12921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block default: UNREACHABLE(); 12931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 1294086aeeaae12517475c22695a200be45495516549Ben Murdoch} 1295086aeeaae12517475c22695a200be45495516549Ben Murdoch 1296086aeeaae12517475c22695a200be45495516549Ben Murdoch 1297257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) { 1298086aeeaae12517475c22695a200be45495516549Ben Murdoch __ pop(rcx); 1299086aeeaae12517475c22695a200be45495516549Ben Murdoch __ push(rdx); 1300086aeeaae12517475c22695a200be45495516549Ben Murdoch __ push(rax); 1301086aeeaae12517475c22695a200be45495516549Ben Murdoch __ push(rcx); 1302b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 1303b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1304b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 130580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid TranscendentalCacheStub::Generate(MacroAssembler* masm) { 1306e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // TAGGED case: 1307e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Input: 1308e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // rsp[8]: argument (should be number). 1309e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // rsp[0]: return address. 1310e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Output: 1311e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // rax: tagged double result. 1312e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // UNTAGGED case: 1313e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Input:: 1314e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // rsp[0]: return address. 1315e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // xmm1: untagged double input argument 1316e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Output: 1317e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // xmm1: untagged double result. 1318e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 131980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label runtime_call; 132080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label runtime_call_clear_stack; 1321e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label skip_cache; 1322e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch const bool tagged = (argument_type_ == TAGGED); 1323e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch if (tagged) { 1324257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label input_not_smi, loaded; 1325e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Test that rax is a number. 1326e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movq(rax, Operand(rsp, kPointerSize)); 1327257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ JumpIfNotSmi(rax, &input_not_smi, Label::kNear); 1328e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Input is a smi. Untag and load it onto the FPU stack. 1329e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Then load the bits of the double into rbx. 1330e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ SmiToInteger32(rax, rax); 1331e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ subq(rsp, Immediate(kDoubleSize)); 1332e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ cvtlsi2sd(xmm1, rax); 1333e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movsd(Operand(rsp, 0), xmm1); 1334e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movq(rbx, xmm1); 1335e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movq(rdx, xmm1); 1336e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ fld_d(Operand(rsp, 0)); 1337e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ addq(rsp, Immediate(kDoubleSize)); 1338257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&loaded, Label::kNear); 1339e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 1340e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&input_not_smi); 1341e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Check if input is a HeapNumber. 1342e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ LoadRoot(rbx, Heap::kHeapNumberMapRootIndex); 1343e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ cmpq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); 1344e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ j(not_equal, &runtime_call); 1345e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Input is a HeapNumber. Push it on the FPU stack and load its 1346e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // bits into rbx. 1347e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ fld_d(FieldOperand(rax, HeapNumber::kValueOffset)); 1348e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movq(rbx, FieldOperand(rax, HeapNumber::kValueOffset)); 1349e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movq(rdx, rbx); 1350e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 1351e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&loaded); 1352e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } else { // UNTAGGED. 1353e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movq(rbx, xmm1); 1354e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movq(rdx, xmm1); 1355e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 1356e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 1357e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // ST[0] == double value, if TAGGED. 135880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rbx = bits of double value. 135980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rdx = also bits of double value. 136080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Compute hash (h is 32 bits, bits are 64 and the shifts are arithmetic): 136180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // h = h0 = bits ^ (bits >> 32); 136280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // h ^= h >> 16; 136380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // h ^= h >> 8; 136480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // h = h & (cacheSize - 1); 136580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // or h = (h0 ^ (h0 >> 8) ^ (h0 >> 16) ^ (h0 >> 24)) & (cacheSize - 1) 136680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sar(rdx, Immediate(32)); 136780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xorl(rdx, rbx); 136880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movl(rcx, rdx); 136980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movl(rax, rdx); 137080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movl(rdi, rdx); 137180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sarl(rdx, Immediate(8)); 137280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sarl(rcx, Immediate(16)); 137380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sarl(rax, Immediate(24)); 137480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xorl(rcx, rdx); 137580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xorl(rax, rdi); 137680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xorl(rcx, rax); 137744f0eee88ff00398ff7f715fab053374d808c90dSteve Block ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize)); 137844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ andl(rcx, Immediate(TranscendentalCache::SubCache::kCacheSize - 1)); 137980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 138080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ST[0] == double value. 138180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rbx = bits of double value. 138280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rcx = TranscendentalCache::hash(double value). 138344f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference cache_array = 138444f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::transcendental_cache_array_address(masm->isolate()); 138544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movq(rax, cache_array); 138644f0eee88ff00398ff7f715fab053374d808c90dSteve Block int cache_array_index = 138744f0eee88ff00398ff7f715fab053374d808c90dSteve Block type_ * sizeof(Isolate::Current()->transcendental_cache()->caches_[0]); 138844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movq(rax, Operand(rax, cache_array_index)); 138980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rax points to the cache for the type type_. 139080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If NULL, the cache hasn't been initialized yet, so go through runtime. 139180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ testq(rax, rax); 1392e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ j(zero, &runtime_call_clear_stack); // Only clears stack if TAGGED. 139380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef DEBUG 139480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the layout of cache elements match expectations. 139580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen { // NOLINT - doesn't like a single brace on a line. 139644f0eee88ff00398ff7f715fab053374d808c90dSteve Block TranscendentalCache::SubCache::Element test_elem[2]; 139780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char* elem_start = reinterpret_cast<char*>(&test_elem[0]); 139880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char* elem2_start = reinterpret_cast<char*>(&test_elem[1]); 139980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0])); 140080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1])); 140180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output)); 140280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Two uint_32's and a pointer per element. 140380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CHECK_EQ(16, static_cast<int>(elem2_start - elem_start)); 140480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CHECK_EQ(0, static_cast<int>(elem_in0 - elem_start)); 140580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CHECK_EQ(kIntSize, static_cast<int>(elem_in1 - elem_start)); 140680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CHECK_EQ(2 * kIntSize, static_cast<int>(elem_out - elem_start)); 140780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 140880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif 140980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Find the address of the rcx'th entry in the cache, i.e., &rax[rcx*16]. 141080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ addl(rcx, rcx); 141180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(rcx, Operand(rax, rcx, times_8, 0)); 141280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if cache matches: Double value is stored in uint32_t[2] array. 1413257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label cache_miss; 141480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmpq(rbx, Operand(rcx, 0)); 1415257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &cache_miss, Label::kNear); 141680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Cache hit! 141780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rax, Operand(rcx, 2 * kIntSize)); 1418e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch if (tagged) { 1419e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ fstp(0); // Clear FPU stack. 1420e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ ret(kPointerSize); 1421e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } else { // UNTAGGED. 1422e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset)); 1423e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ Ret(); 1424e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 142580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 142680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&cache_miss); 142780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Update cache with new value. 1428e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch if (tagged) { 142980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateHeapNumber(rax, rdi, &runtime_call_clear_stack); 1430e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } else { // UNTAGGED. 1431e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ AllocateHeapNumber(rax, rdi, &skip_cache); 1432e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm1); 1433e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ fld_d(FieldOperand(rax, HeapNumber::kValueOffset)); 1434e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 1435e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch GenerateOperation(masm); 143680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(Operand(rcx, 0), rbx); 143780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(Operand(rcx, 2 * kIntSize), rax); 143880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset)); 1439e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch if (tagged) { 1440e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ ret(kPointerSize); 1441e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } else { // UNTAGGED. 1442e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset)); 1443e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ Ret(); 1444e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 1445e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Skip cache and return answer directly, only in untagged case. 1446e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&skip_cache); 1447e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ subq(rsp, Immediate(kDoubleSize)); 1448e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movsd(Operand(rsp, 0), xmm1); 1449e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ fld_d(Operand(rsp, 0)); 1450e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch GenerateOperation(masm); 1451e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ fstp_d(Operand(rsp, 0)); 1452e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movsd(xmm1, Operand(rsp, 0)); 1453e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ addq(rsp, Immediate(kDoubleSize)); 1454e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // We return the value in xmm1 without adding it to the cache, but 1455e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // we cause a scavenging GC so that future allocations will succeed. 1456e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ EnterInternalFrame(); 1457e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Allocate an unused object bigger than a HeapNumber. 1458e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ Push(Smi::FromInt(2 * kDoubleSize)); 1459e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace); 1460e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ LeaveInternalFrame(); 1461e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ Ret(); 1462e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 146380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 1464e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Call runtime, doing whatever allocation and cleanup is necessary. 1465e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch if (tagged) { 1466e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&runtime_call_clear_stack); 1467e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ fstp(0); 1468e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&runtime_call); 146944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ TailCallExternalReference( 147044f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference(RuntimeFunction(), masm->isolate()), 1, 1); 1471e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } else { // UNTAGGED. 1472e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&runtime_call_clear_stack); 1473e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&runtime_call); 1474e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ AllocateHeapNumber(rax, rdi, &skip_cache); 1475e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm1); 1476e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ EnterInternalFrame(); 1477e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ push(rax); 1478e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ CallRuntime(RuntimeFunction(), 1); 1479e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ LeaveInternalFrame(); 1480e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset)); 1481e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ Ret(); 1482e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 148380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 148480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 148580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 148680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian MonsenRuntime::FunctionId TranscendentalCacheStub::RuntimeFunction() { 148780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen switch (type_) { 148880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Add more cases when necessary. 148980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case TranscendentalCache::SIN: return Runtime::kMath_sin; 149080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case TranscendentalCache::COS: return Runtime::kMath_cos; 1491b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case TranscendentalCache::LOG: return Runtime::kMath_log; 149280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen default: 149380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen UNIMPLEMENTED(); 149480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen return Runtime::kAbort; 149580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 149680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 149780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 149880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 1499e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) { 150080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Registers: 1501e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // rax: Newly allocated HeapNumber, which must be preserved. 150280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rbx: Bits of input double. Must be preserved. 150380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rcx: Pointer to cache entry. Must be preserved. 150480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // st(0): Input double 150580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label done; 1506b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (type_ == TranscendentalCache::SIN || type_ == TranscendentalCache::COS) { 1507b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Both fsin and fcos require arguments in the range +/-2^63 and 1508b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // return NaN for infinities and NaN. They can share all code except 1509b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // the actual fsin/fcos operation. 1510b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label in_range; 1511b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If argument is outside the range -2^63..2^63, fsin/cos doesn't 1512b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // work. We must reduce it to the appropriate range. 1513b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movq(rdi, rbx); 1514b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Move exponent and sign bits to low bits. 1515b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ shr(rdi, Immediate(HeapNumber::kMantissaBits)); 1516b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Remove sign bit. 1517b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ andl(rdi, Immediate((1 << HeapNumber::kExponentBits) - 1)); 1518b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch int supported_exponent_limit = (63 + HeapNumber::kExponentBias); 1519b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmpl(rdi, Immediate(supported_exponent_limit)); 1520b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(below, &in_range); 1521b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check for infinity and NaN. Both return NaN for sin. 1522b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmpl(rdi, Immediate(0x7ff)); 1523257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_nan_result; 1524257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &non_nan_result, Label::kNear); 1525e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Input is +/-Infinity or NaN. Result is NaN. 1526e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ fstp(0); 1527e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ LoadRoot(kScratchRegister, Heap::kNanValueRootIndex); 1528e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ fld_d(FieldOperand(kScratchRegister, HeapNumber::kValueOffset)); 1529e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ jmp(&done); 1530e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 1531e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&non_nan_result); 1532b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1533b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Use fpmod to restrict argument to the range +/-2*PI. 1534e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movq(rdi, rax); // Save rax before using fnstsw_ax. 1535b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fldpi(); 1536b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fadd(0); 1537b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fld(1); 1538b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // FPU Stack: input, 2*pi, input. 1539b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch { 1540b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label no_exceptions; 1541b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fwait(); 1542b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fnstsw_ax(); 1543b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Clear if Illegal Operand or Zero Division exceptions are set. 1544b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ testl(rax, Immediate(5)); // #IO and #ZD flags of FPU status word. 1545b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(zero, &no_exceptions); 1546b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fnclex(); 1547b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&no_exceptions); 1548b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 154980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 1550b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Compute st(0) % st(1) 1551b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch { 1552257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label partial_remainder_loop; 1553b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&partial_remainder_loop); 1554b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fprem1(); 1555b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fwait(); 1556b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fnstsw_ax(); 1557b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ testl(rax, Immediate(0x400)); // Check C2 bit of FPU status word. 1558b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If C2 is set, computation only has partial result. Loop to 1559b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // continue computation. 1560b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_zero, &partial_remainder_loop); 1561b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1562b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // FPU Stack: input, 2*pi, input % 2*pi 1563b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp(2); 1564b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // FPU Stack: input % 2*pi, 2*pi, 1565b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp(0); 1566b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // FPU Stack: input % 2*pi 1567e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movq(rax, rdi); // Restore rax, pointer to the new HeapNumber. 1568b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&in_range); 1569b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (type_) { 1570b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case TranscendentalCache::SIN: 1571b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fsin(); 1572b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1573b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case TranscendentalCache::COS: 1574b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fcos(); 1575b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1576b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1577b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch UNREACHABLE(); 1578b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1579b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&done); 1580b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 1581b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(type_ == TranscendentalCache::LOG); 1582b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fldln2(); 1583b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fxch(); 1584b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fyl2x(); 158580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 158680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 158780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 158880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 158980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Input: rdx, rax are the left and right objects of a bit op. 159080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Output: rax, rcx are left and right integers for a bit op. 159180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadNumbersAsIntegers(MacroAssembler* masm) { 159280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check float operands. 159380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label done; 159480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label rax_is_smi; 159580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label rax_is_object; 159680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label rdx_is_object; 159780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 159880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfNotSmi(rdx, &rdx_is_object); 159980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiToInteger32(rdx, rdx); 160080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfSmi(rax, &rax_is_smi); 160180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 160280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&rax_is_object); 160380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen IntegerConvert(masm, rcx, rax); // Uses rdi, rcx and rbx. 160480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&done); 160580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 160680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&rdx_is_object); 160780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen IntegerConvert(masm, rdx, rdx); // Uses rdi, rcx and rbx. 160880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfNotSmi(rax, &rax_is_object); 160980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&rax_is_smi); 161080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiToInteger32(rcx, rax); 161180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 161280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 161380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movl(rax, rdx); 161480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 161580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 161680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 161780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Input: rdx, rax are the left and right objects of a bit op. 161880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Output: rax, rcx are left and right integers for a bit op. 16191e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// Jump to conversion_failure: rdx and rax are unchanged. 162080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm, 162180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* conversion_failure, 162280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register heap_number_map) { 162380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check float operands. 162480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label arg1_is_object, check_undefined_arg1; 162580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label arg2_is_object, check_undefined_arg2; 162680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label load_arg2, done; 162780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 162880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfNotSmi(rdx, &arg1_is_object); 16291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ SmiToInteger32(r8, rdx); 163080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&load_arg2); 163180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 163280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the argument is undefined it converts to zero (ECMA-262, section 9.5). 163380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&check_undefined_arg1); 163480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); 163580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, conversion_failure); 16368b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ Set(r8, 0); 163780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&load_arg2); 163880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 163980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&arg1_is_object); 164080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmpq(FieldOperand(rdx, HeapObject::kMapOffset), heap_number_map); 164180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &check_undefined_arg1); 16421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Get the untagged integer version of the rdx heap number in rcx. 16431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block IntegerConvert(masm, r8, rdx); 164480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 16451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Here r8 has the untagged integer, rax has a Smi or a heap number. 164680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_arg2); 164780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Test if arg2 is a Smi. 164880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfNotSmi(rax, &arg2_is_object); 16491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ SmiToInteger32(rcx, rax); 165080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&done); 165180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 165280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the argument is undefined it converts to zero (ECMA-262, section 9.5). 165380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&check_undefined_arg2); 165480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); 165580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, conversion_failure); 16568b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ Set(rcx, 0); 165780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&done); 165880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 165980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&arg2_is_object); 166080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmpq(FieldOperand(rax, HeapObject::kMapOffset), heap_number_map); 166180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &check_undefined_arg2); 166280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the untagged integer version of the rax heap number in rcx. 166380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen IntegerConvert(masm, rcx, rax); 166480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 16651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movl(rax, r8); 166680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 166780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 166880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 166980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadSSE2SmiOperands(MacroAssembler* masm) { 167080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiToInteger32(kScratchRegister, rdx); 167180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cvtlsi2sd(xmm0, kScratchRegister); 167280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiToInteger32(kScratchRegister, rax); 167380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cvtlsi2sd(xmm1, kScratchRegister); 167480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 167580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 167680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 167780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadSSE2NumberOperands(MacroAssembler* masm) { 167880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label load_smi_rdx, load_nonsmi_rax, load_smi_rax, done; 167980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load operand in rdx into xmm0. 168080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfSmi(rdx, &load_smi_rdx); 168180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset)); 168280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load operand in rax into xmm1. 168380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfSmi(rax, &load_smi_rax); 168480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_nonsmi_rax); 168580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset)); 168680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&done); 168780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 168880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_smi_rdx); 168980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiToInteger32(kScratchRegister, rdx); 169080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cvtlsi2sd(xmm0, kScratchRegister); 169180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfNotSmi(rax, &load_nonsmi_rax); 169280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 169380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_smi_rax); 169480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiToInteger32(kScratchRegister, rax); 169580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cvtlsi2sd(xmm1, kScratchRegister); 169680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 169780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 169880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 169980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 170080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 170180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadSSE2UnknownOperands(MacroAssembler* masm, 170280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* not_numbers) { 170380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label load_smi_rdx, load_nonsmi_rax, load_smi_rax, load_float_rax, done; 170480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load operand in rdx into xmm0, or branch to not_numbers. 170580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ LoadRoot(rcx, Heap::kHeapNumberMapRootIndex); 170680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfSmi(rdx, &load_smi_rdx); 170780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmpq(FieldOperand(rdx, HeapObject::kMapOffset), rcx); 170880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, not_numbers); // Argument in rdx is not a number. 170980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset)); 171080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load operand in rax into xmm1, or branch to not_numbers. 171180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfSmi(rax, &load_smi_rax); 171280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 171380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_nonsmi_rax); 171480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmpq(FieldOperand(rax, HeapObject::kMapOffset), rcx); 171580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, not_numbers); 171680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset)); 171780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&done); 171880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 171980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_smi_rdx); 172080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiToInteger32(kScratchRegister, rdx); 172180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cvtlsi2sd(xmm0, kScratchRegister); 172280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfNotSmi(rax, &load_nonsmi_rax); 172380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 172480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_smi_rax); 172580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiToInteger32(kScratchRegister, rax); 172680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cvtlsi2sd(xmm1, kScratchRegister); 172780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 172880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 172980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 173080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 17318b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdochvoid FloatingPointHelper::NumbersToSmis(MacroAssembler* masm, 17328b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Register first, 17338b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Register second, 17348b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Register scratch1, 17358b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Register scratch2, 17368b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Register scratch3, 17378b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Label* on_success, 17388b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Label* on_not_smis) { 17398b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Register heap_number_map = scratch3; 17408b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Register smi_result = scratch1; 17418b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Label done; 17428b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch 17438b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); 17448b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch 1745257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label first_smi; 1746257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ JumpIfSmi(first, &first_smi, Label::kNear); 17478b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ cmpq(FieldOperand(first, HeapObject::kMapOffset), heap_number_map); 17488b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ j(not_equal, on_not_smis); 17498b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Convert HeapNumber to smi if possible. 17508b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ movsd(xmm0, FieldOperand(first, HeapNumber::kValueOffset)); 17518b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ movq(scratch2, xmm0); 17528b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ cvttsd2siq(smi_result, xmm0); 17538b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Check if conversion was successful by converting back and 17548b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // comparing to the original double's bits. 17558b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ cvtlsi2sd(xmm1, smi_result); 17568b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ movq(kScratchRegister, xmm1); 17578b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ cmpq(scratch2, kScratchRegister); 17588b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ j(not_equal, on_not_smis); 17598b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ Integer32ToSmi(first, smi_result); 17608b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch 17618b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ JumpIfSmi(second, (on_success != NULL) ? on_success : &done); 17628b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ bind(&first_smi); 17638b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (FLAG_debug_code) { 17648b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Second should be non-smi if we get here. 17658b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ AbortIfSmi(second); 17668b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch } 17678b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ cmpq(FieldOperand(second, HeapObject::kMapOffset), heap_number_map); 17688b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ j(not_equal, on_not_smis); 17698b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Convert second to smi, if possible. 17708b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ movsd(xmm0, FieldOperand(second, HeapNumber::kValueOffset)); 17718b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ movq(scratch2, xmm0); 17728b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ cvttsd2siq(smi_result, xmm0); 17738b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ cvtlsi2sd(xmm1, smi_result); 17748b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ movq(kScratchRegister, xmm1); 17758b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ cmpq(scratch2, kScratchRegister); 17768b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ j(not_equal, on_not_smis); 17778b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ Integer32ToSmi(second, smi_result); 17788b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (on_success != NULL) { 17798b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ jmp(on_success); 17808b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch } else { 17818b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ bind(&done); 17828b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch } 17838b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch} 17848b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch 17858b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch 1786e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid MathPowStub::Generate(MacroAssembler* masm) { 1787e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Registers are used as follows: 1788e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // rdx = base 1789e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // rax = exponent 1790e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // rcx = temporary, result 1791e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 1792e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label allocate_return, call_runtime; 1793e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 1794e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Load input parameters. 1795e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movq(rdx, Operand(rsp, 2 * kPointerSize)); 1796e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movq(rax, Operand(rsp, 1 * kPointerSize)); 1797e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 1798e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Save 1 in xmm3 - we need this several times later on. 17998b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ Set(rcx, 1); 1800e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ cvtlsi2sd(xmm3, rcx); 1801e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 1802e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label exponent_nonsmi; 1803e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label base_nonsmi; 1804e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // If the exponent is a heap number go to that specific case. 1805e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ JumpIfNotSmi(rax, &exponent_nonsmi); 1806e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ JumpIfNotSmi(rdx, &base_nonsmi); 1807e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 1808e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Optimized version when both exponent and base are smis. 1809e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label powi; 1810e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ SmiToInteger32(rdx, rdx); 1811e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ cvtlsi2sd(xmm0, rdx); 1812e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ jmp(&powi); 1813e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Exponent is a smi and base is a heapnumber. 1814e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&base_nonsmi); 1815e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ CompareRoot(FieldOperand(rdx, HeapObject::kMapOffset), 1816e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Heap::kHeapNumberMapRootIndex); 1817e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ j(not_equal, &call_runtime); 1818e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 1819e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset)); 1820e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 1821e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Optimized version of pow if exponent is a smi. 1822e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // xmm0 contains the base. 1823e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&powi); 1824e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ SmiToInteger32(rax, rax); 1825e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 1826e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Save exponent in base as we need to check if exponent is negative later. 1827e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // We know that base and exponent are in different registers. 1828e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movq(rdx, rax); 1829e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 1830e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Get absolute value of exponent. 1831257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label no_neg; 1832e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ cmpl(rax, Immediate(0)); 1833257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(greater_equal, &no_neg, Label::kNear); 1834e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ negl(rax); 1835e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&no_neg); 1836e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 1837e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Load xmm1 with 1. 1838257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movaps(xmm1, xmm3); 1839257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label while_true; 1840257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label no_multiply; 1841e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 1842e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&while_true); 1843e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ shrl(rax, Immediate(1)); 1844257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_carry, &no_multiply, Label::kNear); 1845e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ mulsd(xmm1, xmm0); 1846e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&no_multiply); 1847e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ mulsd(xmm0, xmm0); 1848e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ j(not_zero, &while_true); 1849e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 1850e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Base has the original value of the exponent - if the exponent is 1851e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // negative return 1/result. 1852e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ testl(rdx, rdx); 1853e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ j(positive, &allocate_return); 1854e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Special case if xmm1 has reached infinity. 1855e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ divsd(xmm3, xmm1); 1856257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movaps(xmm1, xmm3); 1857257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ xorps(xmm0, xmm0); 1858e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ ucomisd(xmm0, xmm1); 1859e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ j(equal, &call_runtime); 1860e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 1861e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ jmp(&allocate_return); 1862e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 1863e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Exponent (or both) is a heapnumber - no matter what we should now work 1864e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // on doubles. 1865e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&exponent_nonsmi); 1866e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), 1867e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Heap::kHeapNumberMapRootIndex); 1868e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ j(not_equal, &call_runtime); 1869e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset)); 1870e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Test if exponent is nan. 1871e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ ucomisd(xmm1, xmm1); 1872e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ j(parity_even, &call_runtime); 1873e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 1874257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label base_not_smi, handle_special_cases; 1875257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ JumpIfNotSmi(rdx, &base_not_smi, Label::kNear); 1876e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ SmiToInteger32(rdx, rdx); 1877e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ cvtlsi2sd(xmm0, rdx); 1878257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&handle_special_cases, Label::kNear); 1879e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 1880e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&base_not_smi); 1881e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ CompareRoot(FieldOperand(rdx, HeapObject::kMapOffset), 1882e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Heap::kHeapNumberMapRootIndex); 1883e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ j(not_equal, &call_runtime); 1884e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movl(rcx, FieldOperand(rdx, HeapNumber::kExponentOffset)); 1885e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ andl(rcx, Immediate(HeapNumber::kExponentMask)); 1886e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ cmpl(rcx, Immediate(HeapNumber::kExponentMask)); 1887e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // base is NaN or +/-Infinity 1888e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ j(greater_equal, &call_runtime); 1889e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset)); 1890e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 1891e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // base is in xmm0 and exponent is in xmm1. 1892e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&handle_special_cases); 1893257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label not_minus_half; 1894e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Test for -0.5. 1895e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Load xmm2 with -0.5. 1896e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movq(rcx, V8_UINT64_C(0xBFE0000000000000), RelocInfo::NONE); 1897e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movq(xmm2, rcx); 1898e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // xmm2 now has -0.5. 1899e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ ucomisd(xmm2, xmm1); 1900257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, ¬_minus_half, Label::kNear); 1901e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 1902e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Calculates reciprocal of square root. 1903e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // sqrtsd returns -0 when input is -0. ECMA spec requires +0. 1904257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ xorps(xmm1, xmm1); 1905e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ addsd(xmm1, xmm0); 1906e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ sqrtsd(xmm1, xmm1); 1907e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ divsd(xmm3, xmm1); 1908257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movaps(xmm1, xmm3); 1909e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ jmp(&allocate_return); 1910e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 1911e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Test for 0.5. 1912e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(¬_minus_half); 1913e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Load xmm2 with 0.5. 1914e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Since xmm3 is 1 and xmm2 is -0.5 this is simply xmm2 + xmm3. 1915e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ addsd(xmm2, xmm3); 1916e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // xmm2 now has 0.5. 1917e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ ucomisd(xmm2, xmm1); 1918e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ j(not_equal, &call_runtime); 1919e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Calculates square root. 1920e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // sqrtsd returns -0 when input is -0. ECMA spec requires +0. 1921257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ xorps(xmm1, xmm1); 1922257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ addsd(xmm1, xmm0); // Convert -0 to 0. 1923e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ sqrtsd(xmm1, xmm1); 1924e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 1925e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&allocate_return); 1926e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ AllocateHeapNumber(rcx, rax, &call_runtime); 1927e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm1); 1928e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movq(rax, rcx); 1929e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ ret(2 * kPointerSize); 1930e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 1931e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&call_runtime); 1932e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1); 1933e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch} 1934e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 1935e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 193680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { 193780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The key is in rdx and the parameter count is in rax. 193880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 193980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The displacement is used for skipping the frame pointer on the 194080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // stack. It is the offset of the last parameter (if any) relative 194180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // to the frame pointer. 194280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen static const int kDisplacement = 1 * kPointerSize; 194380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 194480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the key is a smi. 194580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label slow; 194680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfNotSmi(rdx, &slow); 194780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 194844f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Check if the calling frame is an arguments adaptor frame. We look at the 194944f0eee88ff00398ff7f715fab053374d808c90dSteve Block // context offset, and if the frame is not a regular one, then we find a 195044f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Smi instead of the context. We can't use SmiCompare here, because that 195144f0eee88ff00398ff7f715fab053374d808c90dSteve Block // only works for comparing two smis. 195280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label adaptor; 195380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); 195444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ Cmp(Operand(rbx, StandardFrameConstants::kContextOffset), 195544f0eee88ff00398ff7f715fab053374d808c90dSteve Block Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); 195680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &adaptor); 195780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 195880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check index against formal parameters count limit passed in 195980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // through register rax. Use unsigned comparison to get negative 196080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // check for free. 196180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmpq(rdx, rax); 196280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(above_equal, &slow); 196380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 196480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Read the argument from the stack and return it. 196580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen SmiIndex index = masm->SmiToIndex(rax, rax, kPointerSizeLog2); 196680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(rbx, Operand(rbp, index.reg, index.scale, 0)); 196780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen index = masm->SmiToNegativeIndex(rdx, rdx, kPointerSizeLog2); 196880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rax, Operand(rbx, index.reg, index.scale, kDisplacement)); 196980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 197080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 197180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Arguments adaptor case: Check index against actual arguments 197280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // limit found in the arguments adaptor frame. Use unsigned 197380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // comparison to get negative check for free. 197480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&adaptor); 197580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rcx, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset)); 197680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmpq(rdx, rcx); 197780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(above_equal, &slow); 197880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 197980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Read the argument from the stack and return it. 198080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen index = masm->SmiToIndex(rax, rcx, kPointerSizeLog2); 198180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(rbx, Operand(rbx, index.reg, index.scale, 0)); 198280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen index = masm->SmiToNegativeIndex(rdx, rdx, kPointerSizeLog2); 198380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rax, Operand(rbx, index.reg, index.scale, kDisplacement)); 198480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 198580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 198680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Slow-case: Handle non-smi or out-of-bounds access to arguments 198780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // by calling the runtime system. 198880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&slow); 198980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(rbx); // Return address. 199080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(rdx); 199180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(rbx); 199280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1); 199380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 199480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 199580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 19963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) { 19973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Stack layout: 19983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // rsp[0] : return address 19993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // rsp[8] : number of parameters (tagged) 20003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // rsp[16] : receiver displacement 20013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // rsp[24] : function 20023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Registers used over the whole function: 20033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // rbx: the mapped parameter count (untagged) 20043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // rax: the allocated object (tagged). 20053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 20063fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Factory* factory = masm->isolate()->factory(); 20073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 20083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ SmiToInteger64(rbx, Operand(rsp, 1 * kPointerSize)); 20093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // rbx = parameter count (untagged) 20103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 20113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Check if the calling frame is an arguments adaptor frame. 20123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label runtime; 20133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label adaptor_frame, try_allocate; 20143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); 20153fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(rcx, Operand(rdx, StandardFrameConstants::kContextOffset)); 20163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ Cmp(rcx, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); 20173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(equal, &adaptor_frame); 20183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 20193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // No adaptor, parameter count = argument count. 20203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(rcx, rbx); 20213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ jmp(&try_allocate, Label::kNear); 20223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 20233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // We have an adaptor frame. Patch the parameters pointer. 20243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&adaptor_frame); 20253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ SmiToInteger64(rcx, 20263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Operand(rdx, 20273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch ArgumentsAdaptorFrameConstants::kLengthOffset)); 20283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(rdx, Operand(rdx, rcx, times_pointer_size, 20293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch StandardFrameConstants::kCallerSPOffset)); 20303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(Operand(rsp, 2 * kPointerSize), rdx); 20313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 20323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // rbx = parameter count (untagged) 20333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // rcx = argument count (untagged) 20343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Compute the mapped parameter count = min(rbx, rcx) in rbx. 20353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ cmpq(rbx, rcx); 20363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(less_equal, &try_allocate, Label::kNear); 20373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(rbx, rcx); 20383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 20393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&try_allocate); 20403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 20413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Compute the sizes of backing store, parameter map, and arguments object. 20423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // 1. Parameter map, has 2 extra words containing context and backing store. 20433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch const int kParameterMapHeaderSize = 20443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch FixedArray::kHeaderSize + 2 * kPointerSize; 20453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label no_parameter_map; 20463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ testq(rbx, rbx); 20473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(zero, &no_parameter_map, Label::kNear); 20483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(r8, Operand(rbx, times_pointer_size, kParameterMapHeaderSize)); 20493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&no_parameter_map); 20503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 20513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // 2. Backing store. 20523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(r8, Operand(r8, rcx, times_pointer_size, FixedArray::kHeaderSize)); 20533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 20543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // 3. Arguments object. 20553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ addq(r8, Immediate(Heap::kArgumentsObjectSize)); 20563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 20573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Do the allocation of all three objects in one go. 20583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ AllocateInNewSpace(r8, rax, rdx, rdi, &runtime, TAG_OBJECT); 20593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 20603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // rax = address of new object(s) (tagged) 20613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // rcx = argument count (untagged) 20623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Get the arguments boilerplate from the current (global) context into rdi. 20633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label has_mapped_parameters, copy; 20643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(rdi, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX))); 20653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(rdi, FieldOperand(rdi, GlobalObject::kGlobalContextOffset)); 20663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ testq(rbx, rbx); 20673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(not_zero, &has_mapped_parameters, Label::kNear); 20683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 20693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch const int kIndex = Context::ARGUMENTS_BOILERPLATE_INDEX; 20703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(rdi, Operand(rdi, Context::SlotOffset(kIndex))); 20713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ jmp(©, Label::kNear); 20723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 20733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch const int kAliasedIndex = Context::ALIASED_ARGUMENTS_BOILERPLATE_INDEX; 20743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&has_mapped_parameters); 20753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(rdi, Operand(rdi, Context::SlotOffset(kAliasedIndex))); 20763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(©); 20773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 20783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // rax = address of new object (tagged) 20793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // rbx = mapped parameter count (untagged) 20803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // rcx = argument count (untagged) 20813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // rdi = address of boilerplate object (tagged) 20823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Copy the JS object part. 20833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { 20843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(rdx, FieldOperand(rdi, i)); 20853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(FieldOperand(rax, i), rdx); 20863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch } 20873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 20883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Setup the callee in-object property. 20893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1); 20903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(rdx, Operand(rsp, 3 * kPointerSize)); 20913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(FieldOperand(rax, JSObject::kHeaderSize + 20923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Heap::kArgumentsCalleeIndex * kPointerSize), 20933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch rdx); 20943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 20953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Use the length (smi tagged) and set that as an in-object property too. 20963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Note: rcx is tagged from here on. 20973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); 20983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ Integer32ToSmi(rcx, rcx); 20993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(FieldOperand(rax, JSObject::kHeaderSize + 21003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Heap::kArgumentsLengthIndex * kPointerSize), 21013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch rcx); 21023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 21033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Setup the elements pointer in the allocated arguments object. 21043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // If we allocated a parameter map, edi will point there, otherwise to the 21053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // backing store. 21063fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(rdi, Operand(rax, Heap::kArgumentsObjectSize)); 21073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(FieldOperand(rax, JSObject::kElementsOffset), rdi); 21083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 21093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // rax = address of new object (tagged) 21103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // rbx = mapped parameter count (untagged) 21113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // rcx = argument count (tagged) 21123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // rdi = address of parameter map or backing store (tagged) 21133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 21143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Initialize parameter map. If there are no mapped arguments, we're done. 21153fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label skip_parameter_map; 21163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ testq(rbx, rbx); 21173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(zero, &skip_parameter_map); 21183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 21193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ LoadRoot(kScratchRegister, Heap::kNonStrictArgumentsElementsMapRootIndex); 21203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // rbx contains the untagged argument count. Add 2 and tag to write. 21213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(FieldOperand(rdi, FixedArray::kMapOffset), kScratchRegister); 21223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ Integer64PlusConstantToSmi(r9, rbx, 2); 21233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(FieldOperand(rdi, FixedArray::kLengthOffset), r9); 21243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(FieldOperand(rdi, FixedArray::kHeaderSize + 0 * kPointerSize), rsi); 21253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(r9, Operand(rdi, rbx, times_pointer_size, kParameterMapHeaderSize)); 21263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(FieldOperand(rdi, FixedArray::kHeaderSize + 1 * kPointerSize), r9); 21273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 21283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Copy the parameter slots and the holes in the arguments. 21293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // We need to fill in mapped_parameter_count slots. They index the context, 21303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // where parameters are stored in reverse order, at 21313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1 21323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // The mapped parameter thus need to get indices 21333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // MIN_CONTEXT_SLOTS+parameter_count-1 .. 21343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count 21353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // We loop from right to left. 21363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label parameters_loop, parameters_test; 21373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 21383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Load tagged parameter count into r9. 21393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(r9, Operand(rsp, 1 * kPointerSize)); 21403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ Move(r8, Smi::FromInt(Context::MIN_CONTEXT_SLOTS)); 21413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ addq(r8, Operand(rsp, 3 * kPointerSize)); 21423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ subq(r8, r9); 21433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ Move(r11, factory->the_hole_value()); 21443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(rdx, rdi); 21453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ SmiToInteger64(kScratchRegister, r9); 21463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(rdi, Operand(rdi, kScratchRegister, 21473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch times_pointer_size, 21483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch kParameterMapHeaderSize)); 21493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // r9 = loop variable (tagged) 21503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // r8 = mapping index (tagged) 21513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // r11 = the hole value 21523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // rdx = address of parameter map (tagged) 21533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // rdi = address of backing store (tagged) 21543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ jmp(¶meters_test, Label::kNear); 21553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 21563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(¶meters_loop); 21573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ SmiSubConstant(r9, r9, Smi::FromInt(1)); 21583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ SmiToInteger64(kScratchRegister, r9); 21593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(FieldOperand(rdx, kScratchRegister, 21603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch times_pointer_size, 21613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch kParameterMapHeaderSize), 21623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch r8); 21633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(FieldOperand(rdi, kScratchRegister, 21643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch times_pointer_size, 21653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch FixedArray::kHeaderSize), 21663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch r11); 21673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ SmiAddConstant(r8, r8, Smi::FromInt(1)); 21683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(¶meters_test); 21693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ SmiTest(r9); 21703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(not_zero, ¶meters_loop, Label::kNear); 21713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 21723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&skip_parameter_map); 21733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 21743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // rcx = argument count (tagged) 21753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // rdi = address of backing store (tagged) 21763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Copy arguments header and remaining slots (if there are any). 21773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ Move(FieldOperand(rdi, FixedArray::kMapOffset), 21783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch factory->fixed_array_map()); 21793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(FieldOperand(rdi, FixedArray::kLengthOffset), rcx); 21803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 21813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label arguments_loop, arguments_test; 21823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(r8, rbx); 21833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(rdx, Operand(rsp, 2 * kPointerSize)); 21843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Untag rcx and r8 for the loop below. 21853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ SmiToInteger64(rcx, rcx); 21863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ SmiToInteger64(r8, r8); 21873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(kScratchRegister, Operand(r8, times_pointer_size, 0)); 21883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ subq(rdx, kScratchRegister); 21893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ jmp(&arguments_test, Label::kNear); 21903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 21913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&arguments_loop); 21923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ subq(rdx, Immediate(kPointerSize)); 21933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(r9, Operand(rdx, 0)); 21943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(FieldOperand(rdi, r8, 21953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch times_pointer_size, 21963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch FixedArray::kHeaderSize), 21973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch r9); 21983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ addq(r8, Immediate(1)); 21993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 22003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&arguments_test); 22013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ cmpq(r8, rcx); 22023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(less, &arguments_loop, Label::kNear); 22033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 22043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Return and remove the on-stack parameters. 22053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ ret(3 * kPointerSize); 22063fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 22073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Do the runtime call to allocate the arguments object. 22083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // rcx = argument count (untagged) 22093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&runtime); 22103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ Integer32ToSmi(rcx, rcx); 22113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(Operand(rsp, 1 * kPointerSize), rcx); // Patch argument count. 22123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1); 22133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch} 22143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 22153fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 22163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid ArgumentsAccessStub::GenerateNewNonStrictSlow(MacroAssembler* masm) { 22173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[0] : return address 22183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[8] : number of parameters 22193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[16] : receiver displacement 22203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[24] : function 22213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 22223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Check if the calling frame is an arguments adaptor frame. 22233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label runtime; 22243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); 22253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(rcx, Operand(rdx, StandardFrameConstants::kContextOffset)); 22263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ Cmp(rcx, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); 22273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(not_equal, &runtime); 22283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 22293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Patch the arguments.length and the parameters pointer. 22303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(rcx, Operand(rdx, ArgumentsAdaptorFrameConstants::kLengthOffset)); 22313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(Operand(rsp, 1 * kPointerSize), rcx); 22323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ SmiToInteger64(rcx, rcx); 22333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(rdx, Operand(rdx, rcx, times_pointer_size, 22343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch StandardFrameConstants::kCallerSPOffset)); 22353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(Operand(rsp, 2 * kPointerSize), rdx); 22363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 22373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&runtime); 22383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1); 22393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch} 22403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 22413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 22423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) { 224380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rsp[0] : return address 224480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rsp[8] : number of parameters 224580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rsp[16] : receiver displacement 224680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rsp[24] : function 224780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 224880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if the calling frame is an arguments adaptor frame. 224980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label adaptor_frame, try_allocate, runtime; 225080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); 22513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(rcx, Operand(rdx, StandardFrameConstants::kContextOffset)); 22523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ Cmp(rcx, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); 225380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &adaptor_frame); 225480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 225580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the length from the frame. 22563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(rcx, Operand(rsp, 1 * kPointerSize)); 22573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ SmiToInteger64(rcx, rcx); 225880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&try_allocate); 225980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 226080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Patch the arguments.length and the parameters pointer. 226180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&adaptor_frame); 22623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(rcx, Operand(rdx, ArgumentsAdaptorFrameConstants::kLengthOffset)); 22633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(Operand(rsp, 1 * kPointerSize), rcx); 22643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ SmiToInteger64(rcx, rcx); 22653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(rdx, Operand(rdx, rcx, times_pointer_size, 22663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch StandardFrameConstants::kCallerSPOffset)); 226780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(Operand(rsp, 2 * kPointerSize), rdx); 226880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 226980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Try the new space allocation. Start out with computing the size of 227080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // the arguments object and the elements array. 227180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label add_arguments_object; 227280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&try_allocate); 22733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ testq(rcx, rcx); 22743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(zero, &add_arguments_object, Label::kNear); 22753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(rcx, Operand(rcx, times_pointer_size, FixedArray::kHeaderSize)); 227680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&add_arguments_object); 22773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ addq(rcx, Immediate(Heap::kArgumentsObjectSizeStrict)); 227880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 227980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Do the allocation of both objects in one go. 228080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateInNewSpace(rcx, rax, rdx, rbx, &runtime, TAG_OBJECT); 228180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 228280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the arguments boilerplate from the current (global) context. 228380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rdi, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX))); 228480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rdi, FieldOperand(rdi, GlobalObject::kGlobalContextOffset)); 22853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch const int offset = 22863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Context::SlotOffset(Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX); 22873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(rdi, Operand(rdi, offset)); 228880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 228980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Copy the JS object part. 22903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { 22913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(rbx, FieldOperand(rdi, i)); 22923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(FieldOperand(rax, i), rbx); 229344f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 229480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 229580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the length (smi tagged) and set that as an in-object property too. 22963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); 229780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rcx, Operand(rsp, 1 * kPointerSize)); 229844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movq(FieldOperand(rax, JSObject::kHeaderSize + 22993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Heap::kArgumentsLengthIndex * kPointerSize), 230044f0eee88ff00398ff7f715fab053374d808c90dSteve Block rcx); 230180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 230280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If there are no actual arguments, we're done. 230380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label done; 23043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ testq(rcx, rcx); 230580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &done); 230680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 23073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Get the parameters pointer from the stack. 230880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rdx, Operand(rsp, 2 * kPointerSize)); 230980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 231080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Setup the elements pointer in the allocated arguments object and 231180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // initialize the header in the elements fixed array. 23123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(rdi, Operand(rax, Heap::kArgumentsObjectSizeStrict)); 231380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(FieldOperand(rax, JSObject::kElementsOffset), rdi); 231480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ LoadRoot(kScratchRegister, Heap::kFixedArrayMapRootIndex); 231580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(FieldOperand(rdi, FixedArray::kMapOffset), kScratchRegister); 23163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 23173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 231880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(FieldOperand(rdi, FixedArray::kLengthOffset), rcx); 23193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Untag the length for the loop below. 23203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ SmiToInteger64(rcx, rcx); 232180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 232280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Copy the fixed array slots. 232380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label loop; 232480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&loop); 23253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(rbx, Operand(rdx, -1 * kPointerSize)); // Skip receiver. 23263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ movq(FieldOperand(rdi, FixedArray::kHeaderSize), rbx); 232780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ addq(rdi, Immediate(kPointerSize)); 232880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ subq(rdx, Immediate(kPointerSize)); 23293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ decq(rcx); 233080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, &loop); 233180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 233280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return and remove the on-stack parameters. 233380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 233480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(3 * kPointerSize); 233580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 233680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Do the runtime call to allocate the arguments object. 233780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&runtime); 23383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1); 233980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 234080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 234180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 234280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid RegExpExecStub::Generate(MacroAssembler* masm) { 234380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Just jump directly to runtime if native RegExp is not selected at compile 234480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // time or if regexp entry in generated code is turned off runtime switch or 234580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // at compilation. 234680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef V8_INTERPRETED_REGEXP 234780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); 234880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#else // V8_INTERPRETED_REGEXP 234980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (!FLAG_regexp_entry_native) { 235080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); 235180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen return; 235280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 235380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 235480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Stack frame on entry. 23551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // rsp[0]: return address 23561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // rsp[8]: last_match_info (expected JSArray) 23571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // rsp[16]: previous index 23581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // rsp[24]: subject string 23591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // rsp[32]: JSRegExp object 236080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 236180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen static const int kLastMatchInfoOffset = 1 * kPointerSize; 236280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen static const int kPreviousIndexOffset = 2 * kPointerSize; 236380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen static const int kSubjectOffset = 3 * kPointerSize; 236480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen static const int kJSRegExpOffset = 4 * kPointerSize; 236580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 236680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label runtime; 236780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Ensure that a RegExp stack is allocated. 236844f0eee88ff00398ff7f715fab053374d808c90dSteve Block Isolate* isolate = masm->isolate(); 236980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ExternalReference address_of_regexp_stack_memory_address = 237044f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::address_of_regexp_stack_memory_address(isolate); 237180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ExternalReference address_of_regexp_stack_memory_size = 237244f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::address_of_regexp_stack_memory_size(isolate); 237344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ Load(kScratchRegister, address_of_regexp_stack_memory_size); 237480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ testq(kScratchRegister, kScratchRegister); 237580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &runtime); 237680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 237780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the first argument is a JSRegExp object. 237880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rax, Operand(rsp, kJSRegExpOffset)); 237980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfSmi(rax, &runtime); 238080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CmpObjectType(rax, JS_REGEXP_TYPE, kScratchRegister); 238180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &runtime); 238280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the RegExp has been compiled (data contains a fixed array). 238344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movq(rax, FieldOperand(rax, JSRegExp::kDataOffset)); 238480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (FLAG_debug_code) { 238544f0eee88ff00398ff7f715fab053374d808c90dSteve Block Condition is_smi = masm->CheckSmi(rax); 238680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Check(NegateCondition(is_smi), 238780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen "Unexpected type for RegExp data, FixedArray expected"); 238844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ CmpObjectType(rax, FIXED_ARRAY_TYPE, kScratchRegister); 238980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Check(equal, "Unexpected type for RegExp data, FixedArray expected"); 239080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 239180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 239244f0eee88ff00398ff7f715fab053374d808c90dSteve Block // rax: RegExp data (FixedArray) 239380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. 239444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ SmiToInteger32(rbx, FieldOperand(rax, JSRegExp::kDataTagOffset)); 239580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmpl(rbx, Immediate(JSRegExp::IRREGEXP)); 239680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &runtime); 239780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 239844f0eee88ff00398ff7f715fab053374d808c90dSteve Block // rax: RegExp data (FixedArray) 239980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the number of captures fit in the static offsets vector buffer. 240080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiToInteger32(rdx, 240144f0eee88ff00398ff7f715fab053374d808c90dSteve Block FieldOperand(rax, JSRegExp::kIrregexpCaptureCountOffset)); 240280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate number of capture registers (number_of_captures + 1) * 2. 240380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ leal(rdx, Operand(rdx, rdx, times_1, 2)); 240480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the static offsets vector buffer is large enough. 240580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmpl(rdx, Immediate(OffsetsVector::kStaticOffsetsVectorSize)); 240680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(above, &runtime); 240780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 240844f0eee88ff00398ff7f715fab053374d808c90dSteve Block // rax: RegExp data (FixedArray) 240980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rdx: Number of capture registers 241080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the second argument is a string. 2411e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movq(rdi, Operand(rsp, kSubjectOffset)); 2412e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ JumpIfSmi(rdi, &runtime); 2413e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Condition is_string = masm->IsObjectStringType(rdi, rbx, rbx); 241480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(NegateCondition(is_string), &runtime); 241580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2416e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // rdi: Subject string. 2417e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // rax: RegExp data (FixedArray). 241880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rdx: Number of capture registers. 241980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the third argument is a positive smi less than the string 242080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // length. A negative value will be greater (unsigned comparison). 242180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rbx, Operand(rsp, kPreviousIndexOffset)); 242280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfNotSmi(rbx, &runtime); 2423e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ SmiCompare(rbx, FieldOperand(rdi, String::kLengthOffset)); 242480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(above_equal, &runtime); 242580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2426e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // rax: RegExp data (FixedArray) 242780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rdx: Number of capture registers 242880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the fourth object is a JSArray object. 2429e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movq(rdi, Operand(rsp, kLastMatchInfoOffset)); 2430e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ JumpIfSmi(rdi, &runtime); 2431e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ CmpObjectType(rdi, JS_ARRAY_TYPE, kScratchRegister); 243280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &runtime); 243380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the JSArray is in fast case. 2434e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movq(rbx, FieldOperand(rdi, JSArray::kElementsOffset)); 2435e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movq(rdi, FieldOperand(rbx, HeapObject::kMapOffset)); 243644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset), 243744f0eee88ff00398ff7f715fab053374d808c90dSteve Block Heap::kFixedArrayMapRootIndex); 243880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &runtime); 243980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the last match info has space for the capture registers and the 244080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // additional information. Ensure no overflow in add. 244180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(FixedArray::kMaxLength < kMaxInt - FixedArray::kLengthOffset); 2442e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ SmiToInteger32(rdi, FieldOperand(rbx, FixedArray::kLengthOffset)); 244380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ addl(rdx, Immediate(RegExpImpl::kLastMatchOverhead)); 2444e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ cmpl(rdx, rdi); 244580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(greater, &runtime); 244680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 244769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Reset offset for possibly sliced string. 244869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Set(r14, 0); 2449e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // rax: RegExp data (FixedArray) 245080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check the representation and encoding of the subject string. 2451257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label seq_ascii_string, seq_two_byte_string, check_code; 2452e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movq(rdi, Operand(rsp, kSubjectOffset)); 245369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Make a copy of the original subject string. 245469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ movq(r15, rdi); 2455e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); 245680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); 245780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // First check for flat two byte string. 245880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ andb(rbx, Immediate( 245980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask)); 246080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0); 2461257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &seq_two_byte_string, Label::kNear); 246280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Any other flat string must be a flat ascii string. 246369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ andb(rbx, Immediate(kIsNotStringMask | kStringRepresentationMask)); 2464257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &seq_ascii_string, Label::kNear); 246580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 246669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Check for flat cons string or sliced string. 246780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // A flat cons string is a cons string where the second part is the empty 246880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // string. In that case the subject string is just the first part of the cons 246980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // string. Also in this case the first part of the cons string is known to be 247080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // a sequential string or an external string. 247169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // In the case of a sliced string its offset has to be taken into account. 247269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label cons_string, check_encoding; 247369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch STATIC_ASSERT(kConsStringTag < kExternalStringTag); 247469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); 247569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ cmpq(rbx, Immediate(kExternalStringTag)); 247669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(less, &cons_string, Label::kNear); 247769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(equal, &runtime); 247869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 247969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // String is sliced. 248069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ SmiToInteger32(r14, FieldOperand(rdi, SlicedString::kOffsetOffset)); 248169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ movq(rdi, FieldOperand(rdi, SlicedString::kParentOffset)); 248269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // r14: slice offset 248369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // r15: original subject string 248469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // rdi: parent string 248569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ jmp(&check_encoding, Label::kNear); 248669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // String is a cons string, check whether it is flat. 248769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&cons_string); 248844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ CompareRoot(FieldOperand(rdi, ConsString::kSecondOffset), 248944f0eee88ff00398ff7f715fab053374d808c90dSteve Block Heap::kEmptyStringRootIndex); 249080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &runtime); 2491e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movq(rdi, FieldOperand(rdi, ConsString::kFirstOffset)); 249269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // rdi: first part of cons string or parent of sliced string. 249369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // rbx: map of first part of cons string or map of parent of sliced string. 249469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Is first part of cons or parent of slice a flat two byte string? 249569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&check_encoding); 2496e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); 249780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ testb(FieldOperand(rbx, Map::kInstanceTypeOffset), 249880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Immediate(kStringRepresentationMask | kStringEncodingMask)); 249980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0); 2500257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &seq_two_byte_string, Label::kNear); 250180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Any other flat string must be ascii. 250280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ testb(FieldOperand(rbx, Map::kInstanceTypeOffset), 250380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Immediate(kStringRepresentationMask)); 250480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, &runtime); 250580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 250680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&seq_ascii_string); 2507e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // rdi: subject string (sequential ascii) 2508e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // rax: RegExp data (FixedArray) 2509e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movq(r11, FieldOperand(rax, JSRegExp::kDataAsciiCodeOffset)); 2510e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ Set(rcx, 1); // Type is ascii. 2511257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&check_code, Label::kNear); 251280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 251380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&seq_two_byte_string); 2514e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // rdi: subject string (flat two-byte) 2515e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // rax: RegExp data (FixedArray) 2516e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movq(r11, FieldOperand(rax, JSRegExp::kDataUC16CodeOffset)); 2517e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ Set(rcx, 0); // Type is two byte. 251880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 251980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&check_code); 252080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the irregexp code has been generated for the actual string 252180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // encoding. If it has, the field contains a code object otherwise it contains 2522257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // smi (code flushing support) 2523257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ JumpIfSmi(r11, &runtime); 252480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2525e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // rdi: subject string 2526e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // rcx: encoding of subject string (1 if ascii, 0 if two_byte); 252780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r11: code 252880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load used arguments before starting to push arguments for call to native 252980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // RegExp code to avoid handling changing stack height. 253080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiToInteger64(rbx, Operand(rsp, kPreviousIndexOffset)); 253180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2532e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // rdi: subject string 253380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rbx: previous index 2534e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // rcx: encoding of subject string (1 if ascii 0 if two_byte); 253580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r11: code 253680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // All checks done. Now push arguments for native regexp code. 253744f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = masm->isolate()->counters(); 253844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->regexp_entry_native(), 1); 253980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 254044f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Isolates: note we add an additional parameter here (isolate pointer). 254144f0eee88ff00398ff7f715fab053374d808c90dSteve Block static const int kRegExpExecuteArguments = 8; 254280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen int argument_slots_on_stack = 254380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen masm->ArgumentStackSlotsForCFunctionCall(kRegExpExecuteArguments); 254444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ EnterApiExitFrame(argument_slots_on_stack); 254580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 254644f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Argument 8: Pass current isolate address. 254744f0eee88ff00398ff7f715fab053374d808c90dSteve Block // __ movq(Operand(rsp, (argument_slots_on_stack - 1) * kPointerSize), 254844f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Immediate(ExternalReference::isolate_address())); 254944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ LoadAddress(kScratchRegister, ExternalReference::isolate_address()); 255080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(Operand(rsp, (argument_slots_on_stack - 1) * kPointerSize), 255144f0eee88ff00398ff7f715fab053374d808c90dSteve Block kScratchRegister); 255244f0eee88ff00398ff7f715fab053374d808c90dSteve Block 255344f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Argument 7: Indicate that this is a direct call from JavaScript. 255444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movq(Operand(rsp, (argument_slots_on_stack - 2) * kPointerSize), 255580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Immediate(1)); 255680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 255780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Argument 6: Start (high end) of backtracking stack memory area. 255880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(kScratchRegister, address_of_regexp_stack_memory_address); 255980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(r9, Operand(kScratchRegister, 0)); 256080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(kScratchRegister, address_of_regexp_stack_memory_size); 256180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ addq(r9, Operand(kScratchRegister, 0)); 256280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Argument 6 passed in r9 on Linux and on the stack on Windows. 256380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef _WIN64 256444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movq(Operand(rsp, (argument_slots_on_stack - 3) * kPointerSize), r9); 256580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif 256680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 256780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Argument 5: static offsets vector buffer. 256844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ LoadAddress(r8, 256944f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::address_of_static_offsets_vector(isolate)); 257080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Argument 5 passed in r8 on Linux and on the stack on Windows. 257180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef _WIN64 257244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movq(Operand(rsp, (argument_slots_on_stack - 4) * kPointerSize), r8); 257380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif 257480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 257580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // First four arguments are passed in registers on both Linux and Windows. 257680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef _WIN64 257780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register arg4 = r9; 257880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register arg3 = r8; 257980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register arg2 = rdx; 258080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register arg1 = rcx; 258180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#else 258280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register arg4 = rcx; 258380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register arg3 = rdx; 258480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register arg2 = rsi; 258580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register arg1 = rdi; 258680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif 258780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 258880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Keep track on aliasing between argX defined above and the registers used. 2589e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // rdi: subject string 259080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rbx: previous index 2591e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // rcx: encoding of subject string (1 if ascii 0 if two_byte); 259280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r11: code 259369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // r14: slice offset 259469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // r15: original subject string 259569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 259669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Argument 2: Previous index. 259769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ movq(arg2, rbx); 259880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 259980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Argument 4: End of string data 260080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Argument 3: Start of string data 260169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label setup_two_byte, setup_rest, got_length, length_not_from_slice; 260269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Prepare start and end index of the input. 260369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Load the length from the original sliced string if that is the case. 260469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ addq(rbx, r14); 260569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ SmiToInteger32(arg3, FieldOperand(r15, String::kLengthOffset)); 260669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ addq(r14, arg3); // Using arg3 as scratch. 260769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 260869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // rbx: start index of the input 260969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // r14: end index of the input 261069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // r15: original subject string 2611e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ testb(rcx, rcx); // Last use of rcx as encoding of subject string. 2612257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &setup_two_byte, Label::kNear); 261369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ lea(arg4, FieldOperand(rdi, r14, times_1, SeqAsciiString::kHeaderSize)); 2614e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ lea(arg3, FieldOperand(rdi, rbx, times_1, SeqAsciiString::kHeaderSize)); 2615257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&setup_rest, Label::kNear); 261680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&setup_two_byte); 261769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ lea(arg4, FieldOperand(rdi, r14, times_2, SeqTwoByteString::kHeaderSize)); 2618e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ lea(arg3, FieldOperand(rdi, rbx, times_2, SeqTwoByteString::kHeaderSize)); 261980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&setup_rest); 262080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 262169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Argument 1: Original subject string. 262269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // The original subject is in the previous stack frame. Therefore we have to 262369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // use rbp, which points exactly to one pointer size below the previous rsp. 262469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // (Because creating a new stack frame pushes the previous rbp onto the stack 262569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // and thereby moves up rsp by one kPointerSize.) 262669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ movq(arg1, r15); 262780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 262880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Locate the code entry and call it. 262980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ addq(r11, Immediate(Code::kHeaderSize - kHeapObjectTag)); 2630e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ call(r11); 263180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2632e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ LeaveApiExitFrame(); 263380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 263480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check the result. 2635257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label success; 2636e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label exception; 263780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::SUCCESS)); 2638257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &success, Label::kNear); 263980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::EXCEPTION)); 2640e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ j(equal, &exception); 2641e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::FAILURE)); 2642e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // If none of the above, it can only be retry. 2643e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Handle that in the runtime system. 264480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &runtime); 2645e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 2646e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // For failure return null. 2647e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ LoadRoot(rax, Heap::kNullValueRootIndex); 264880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(4 * kPointerSize); 264980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 265080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load RegExp data. 265180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&success); 265280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rax, Operand(rsp, kJSRegExpOffset)); 265380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rcx, FieldOperand(rax, JSRegExp::kDataOffset)); 265480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiToInteger32(rax, 265580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FieldOperand(rcx, JSRegExp::kIrregexpCaptureCountOffset)); 265680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate number of capture registers (number_of_captures + 1) * 2. 265780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ leal(rdx, Operand(rax, rax, times_1, 2)); 265880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 265980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rdx: Number of capture registers 266080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load last_match_info which is still known to be a fast case JSArray. 266180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rax, Operand(rsp, kLastMatchInfoOffset)); 266280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rbx, FieldOperand(rax, JSArray::kElementsOffset)); 266380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 266480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rbx: last_match_info backing store (FixedArray) 266580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rdx: number of capture registers 266680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Store the capture count. 266780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Integer32ToSmi(kScratchRegister, rdx); 266880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(FieldOperand(rbx, RegExpImpl::kLastCaptureCountOffset), 266980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen kScratchRegister); 267080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Store last subject and last input. 267180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rax, Operand(rsp, kSubjectOffset)); 267280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(FieldOperand(rbx, RegExpImpl::kLastSubjectOffset), rax); 267380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rcx, rbx); 267480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ RecordWrite(rcx, RegExpImpl::kLastSubjectOffset, rax, rdi); 267580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rax, Operand(rsp, kSubjectOffset)); 267680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(FieldOperand(rbx, RegExpImpl::kLastInputOffset), rax); 267780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rcx, rbx); 267880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ RecordWrite(rcx, RegExpImpl::kLastInputOffset, rax, rdi); 267980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 268080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the static offsets vector filled by the native regexp code. 268144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ LoadAddress(rcx, 268244f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::address_of_static_offsets_vector(isolate)); 268380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 268480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rbx: last_match_info backing store (FixedArray) 268580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rcx: offsets vector 268680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rdx: number of capture registers 2687257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label next_capture, done; 268880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Capture register counter starts from number of capture registers and 268980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // counts down until wraping after zero. 269080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&next_capture); 269180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ subq(rdx, Immediate(1)); 2692257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(negative, &done, Label::kNear); 269380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Read the value from the static offsets vector buffer and make it a smi. 269480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movl(rdi, Operand(rcx, rdx, times_int_size, 0)); 26950d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ Integer32ToSmi(rdi, rdi); 269680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Store the smi value in the last match info. 269780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(FieldOperand(rbx, 269880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen rdx, 269980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen times_pointer_size, 270080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen RegExpImpl::kFirstCaptureOffset), 270180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen rdi); 270280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&next_capture); 270380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 270480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 270580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return last match info. 270680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rax, Operand(rsp, kLastMatchInfoOffset)); 270780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(4 * kPointerSize); 270880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2709e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&exception); 2710e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Result must now be exception. If there is no pending exception already a 2711e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // stack overflow (on the backtrack stack) was detected in RegExp code but 2712e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // haven't created the exception yet. Handle that in the runtime system. 2713e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // TODO(592): Rerunning the RegExp to get the stack overflow exception. 271444f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference pending_exception_address( 2715589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch Isolate::kPendingExceptionAddress, isolate); 271644f0eee88ff00398ff7f715fab053374d808c90dSteve Block Operand pending_exception_operand = 271744f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->ExternalOperand(pending_exception_address, rbx); 271844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movq(rax, pending_exception_operand); 2719e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex); 2720e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ cmpq(rax, rdx); 2721e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ j(equal, &runtime); 272244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movq(pending_exception_operand, rdx); 2723e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 2724e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ CompareRoot(rax, Heap::kTerminationExceptionRootIndex); 2725257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label termination_exception; 2726257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &termination_exception, Label::kNear); 2727e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ Throw(rax); 2728e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 2729e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&termination_exception); 2730e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ ThrowUncatchable(TERMINATION, rax); 2731e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 273280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Do the runtime call to execute the regexp. 273380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&runtime); 273480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); 273580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif // V8_INTERPRETED_REGEXP 273680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 273780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 273880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2739b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid RegExpConstructResultStub::Generate(MacroAssembler* masm) { 2740b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch const int kMaxInlineLength = 100; 2741b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label slowcase; 2742b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label done; 2743b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movq(r8, Operand(rsp, kPointerSize * 3)); 2744b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ JumpIfNotSmi(r8, &slowcase); 2745b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiToInteger32(rbx, r8); 2746b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmpl(rbx, Immediate(kMaxInlineLength)); 2747b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(above, &slowcase); 2748b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Smi-tagging is equivalent to multiplying by 2. 2749b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch STATIC_ASSERT(kSmiTag == 0); 2750b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch STATIC_ASSERT(kSmiTagSize == 1); 27511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Allocate RegExpResult followed by FixedArray with size in rbx. 2752b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // JSArray: [Map][empty properties][Elements][Length-smi][index][input] 2753b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Elements: [Map][Length][..elements..] 2754b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateInNewSpace(JSRegExpResult::kSize + FixedArray::kHeaderSize, 2755b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch times_pointer_size, 2756b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch rbx, // In: Number of elements. 2757b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch rax, // Out: Start of allocation (tagged). 2758b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch rcx, // Out: End of allocation. 2759b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch rdx, // Scratch register 2760b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch &slowcase, 2761b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch TAG_OBJECT); 2762b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // rax: Start of allocated area, object-tagged. 2763b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // rbx: Number of array elements as int32. 2764b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // r8: Number of array elements as smi. 2765b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2766b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Set JSArray map to global.regexp_result_map(). 2767b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movq(rdx, ContextOperand(rsi, Context::GLOBAL_INDEX)); 2768b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalContextOffset)); 2769b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movq(rdx, ContextOperand(rdx, Context::REGEXP_RESULT_MAP_INDEX)); 2770b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movq(FieldOperand(rax, HeapObject::kMapOffset), rdx); 2771b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2772b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Set empty properties FixedArray. 277344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ LoadRoot(kScratchRegister, Heap::kEmptyFixedArrayRootIndex); 277444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movq(FieldOperand(rax, JSObject::kPropertiesOffset), kScratchRegister); 2775b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2776b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Set elements to point to FixedArray allocated right after the JSArray. 2777b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ lea(rcx, Operand(rax, JSRegExpResult::kSize)); 2778b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movq(FieldOperand(rax, JSObject::kElementsOffset), rcx); 2779b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2780b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Set input, index and length fields from arguments. 2781b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movq(r8, Operand(rsp, kPointerSize * 1)); 2782b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movq(FieldOperand(rax, JSRegExpResult::kInputOffset), r8); 2783b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movq(r8, Operand(rsp, kPointerSize * 2)); 2784b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movq(FieldOperand(rax, JSRegExpResult::kIndexOffset), r8); 2785b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movq(r8, Operand(rsp, kPointerSize * 3)); 2786b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movq(FieldOperand(rax, JSArray::kLengthOffset), r8); 2787b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2788b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Fill out the elements FixedArray. 2789b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // rax: JSArray. 2790b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // rcx: FixedArray. 2791b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // rbx: Number of elements in array as int32. 2792b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2793b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Set map. 279444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ LoadRoot(kScratchRegister, Heap::kFixedArrayMapRootIndex); 279544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movq(FieldOperand(rcx, HeapObject::kMapOffset), kScratchRegister); 2796b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Set length. 2797b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ Integer32ToSmi(rdx, rbx); 2798b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movq(FieldOperand(rcx, FixedArray::kLengthOffset), rdx); 2799b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Fill contents of fixed-array with the-hole. 280044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex); 2801b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ lea(rcx, FieldOperand(rcx, FixedArray::kHeaderSize)); 2802b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Fill fixed array elements with hole. 2803b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // rax: JSArray. 2804b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // rbx: Number of elements in array that remains to be filled, as int32. 2805b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // rcx: Start of elements in FixedArray. 2806b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // rdx: the hole. 2807b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label loop; 2808b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ testl(rbx, rbx); 2809b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&loop); 28101e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ j(less_equal, &done); // Jump if rcx is negative or zero. 2811b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ subl(rbx, Immediate(1)); 2812b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movq(Operand(rcx, rbx, times_pointer_size, 0), rdx); 2813b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ jmp(&loop); 2814b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2815b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&done); 2816b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(3 * kPointerSize); 2817b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2818b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&slowcase); 2819b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ TailCallRuntime(Runtime::kRegExpConstructResult, 3, 1); 2820b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 2821b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2822b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 282380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm, 282480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register object, 282580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register result, 282680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch1, 282780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch2, 282880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen bool object_is_smi, 282980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* not_found) { 283080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Use of registers. Register result is used as a temporary. 283180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register number_string_cache = result; 283280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register mask = scratch1; 283380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch = scratch2; 283480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 283580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load the number string cache. 283680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ LoadRoot(number_string_cache, Heap::kNumberStringCacheRootIndex); 283780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 283880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Make the hash mask from the length of the number string cache. It 283980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // contains two elements (number and string) for each cache entry. 284080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiToInteger32( 284180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen mask, FieldOperand(number_string_cache, FixedArray::kLengthOffset)); 284280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ shrl(mask, Immediate(1)); 284380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ subq(mask, Immediate(1)); // Make mask. 284480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 284580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate the entry in the number string cache. The hash value in the 284680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // number string cache for smis is just the smi value, and the hash for 284780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // doubles is the xor of the upper and lower words. See 284880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Heap::GetNumberStringCache. 284980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label is_smi; 285080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label load_result_from_cache; 2851257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Factory* factory = masm->isolate()->factory(); 285280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (!object_is_smi) { 285380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfSmi(object, &is_smi); 2854257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CheckMap(object, 2855257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch factory->heap_number_map(), 2856257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch not_found, 2857257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch DONT_DO_SMI_CHECK); 285880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 285980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(8 == kDoubleSize); 286080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movl(scratch, FieldOperand(object, HeapNumber::kValueOffset + 4)); 286180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xor_(scratch, FieldOperand(object, HeapNumber::kValueOffset)); 286280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateConvertHashCodeToIndex(masm, scratch, mask); 286380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 286480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register index = scratch; 286580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register probe = mask; 286680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(probe, 286780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FieldOperand(number_string_cache, 286880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen index, 286980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen times_1, 287080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FixedArray::kHeaderSize)); 287180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfSmi(probe, not_found); 287280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movsd(xmm0, FieldOperand(object, HeapNumber::kValueOffset)); 287380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movsd(xmm1, FieldOperand(probe, HeapNumber::kValueOffset)); 287480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ucomisd(xmm0, xmm1); 287580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(parity_even, not_found); // Bail out if NaN is involved. 287680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, not_found); // The cache did not contain this value. 287780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&load_result_from_cache); 287880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 287980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 288080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&is_smi); 288180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiToInteger32(scratch, object); 288280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateConvertHashCodeToIndex(masm, scratch, mask); 288380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 288480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register index = scratch; 288580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if the entry is the smi we are looking for. 288680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmpq(object, 288780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FieldOperand(number_string_cache, 288880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen index, 288980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen times_1, 289080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FixedArray::kHeaderSize)); 289180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, not_found); 289280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 289380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the result from the cache. 289480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_result_from_cache); 289580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(result, 289680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FieldOperand(number_string_cache, 289780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen index, 289880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen times_1, 289980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FixedArray::kHeaderSize + kPointerSize)); 290044f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = masm->isolate()->counters(); 290144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->number_to_string_native(), 1); 290280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 290380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 290480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 290580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid NumberToStringStub::GenerateConvertHashCodeToIndex(MacroAssembler* masm, 290680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register hash, 290780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register mask) { 290880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(hash, mask); 290980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Each entry in string cache consists of two pointer sized fields, 291080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // but times_twice_pointer_size (multiplication by 16) scale factor 291180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // is not supported by addrmode on x64 platform. 291280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // So we have to premultiply entry index before lookup. 291380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ shl(hash, Immediate(kPointerSizeLog2 + 1)); 291480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 291580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 291680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 291780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid NumberToStringStub::Generate(MacroAssembler* masm) { 291880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label runtime; 291980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 292080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rbx, Operand(rsp, kPointerSize)); 292180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 292280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Generate code to lookup number in the number string cache. 292380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateLookupNumberStringCache(masm, rbx, rax, r8, r9, false, &runtime); 292480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(1 * kPointerSize); 292580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 292680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&runtime); 292780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Handle number to string in the runtime system if not found in the cache. 292880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kNumberToStringSkipCache, 1, 1); 292980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 293080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 293180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 293280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenstatic int NegativeComparisonResult(Condition cc) { 293380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(cc != equal); 293480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT((cc == less) || (cc == less_equal) 293580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen || (cc == greater) || (cc == greater_equal)); 293680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen return (cc == greater || cc == greater_equal) ? LESS : GREATER; 293780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 293880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 293980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 294080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CompareStub::Generate(MacroAssembler* masm) { 294180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); 294280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 294380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label check_unequal_objects, done; 2944257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Factory* factory = masm->isolate()->factory(); 29450d5e116f6aee03185f237311a943491bb079a768Kristian Monsen 29460d5e116f6aee03185f237311a943491bb079a768Kristian Monsen // Compare two smis if required. 29470d5e116f6aee03185f237311a943491bb079a768Kristian Monsen if (include_smi_compare_) { 29480d5e116f6aee03185f237311a943491bb079a768Kristian Monsen Label non_smi, smi_done; 29490d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ JumpIfNotBothSmi(rax, rdx, &non_smi); 29500d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ subq(rdx, rax); 29510d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ j(no_overflow, &smi_done); 2952f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch __ not_(rdx); // Correct sign in case of overflow. rdx cannot be 0 here. 29530d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ bind(&smi_done); 29540d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ movq(rax, rdx); 29550d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ ret(0); 29560d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ bind(&non_smi); 29570d5e116f6aee03185f237311a943491bb079a768Kristian Monsen } else if (FLAG_debug_code) { 29580d5e116f6aee03185f237311a943491bb079a768Kristian Monsen Label ok; 29590d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ JumpIfNotSmi(rdx, &ok); 29600d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ JumpIfNotSmi(rax, &ok); 29610d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ Abort("CompareStub: smi operands"); 29620d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ bind(&ok); 29630d5e116f6aee03185f237311a943491bb079a768Kristian Monsen } 29640d5e116f6aee03185f237311a943491bb079a768Kristian Monsen 296580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The compare stub returns a positive, negative, or zero 64-bit integer 296680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // value in rax, corresponding to result of comparing the two inputs. 296780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // NOTICE! This code is only reached after a smi-fast-case check, so 296880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // it is certain that at least one operand isn't a smi. 296980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 297080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Two identical objects are equal unless they are both NaN or undefined. 297180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen { 2972257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label not_identical; 297380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmpq(rax, rdx); 2974257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, ¬_identical, Label::kNear); 297580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 297680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ != equal) { 297780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for undefined. undefined OP undefined is false even though 297880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // undefined == undefined. 2979257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label check_for_nan; 298080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); 2981257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &check_for_nan, Label::kNear); 298280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(rax, NegativeComparisonResult(cc_)); 298380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 298480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&check_for_nan); 298580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 298680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 298744f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Test for NaN. Sadly, we can't just compare to FACTORY->nan_value(), 298880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // so we do the second best thing - test it ourselves. 298980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Note: if cc_ != equal, never_nan_nan_ is not used. 299080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // We cannot set rax to EQUAL until just before return because 299180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rax must be unchanged on jump to not_identical. 299280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (never_nan_nan_ && (cc_ == equal)) { 299380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(rax, EQUAL); 299480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 299580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 2996257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label heap_number; 299780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If it's not a heap number, then return equal for (in)equality operator. 299880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), 2999257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch factory->heap_number_map()); 3000257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &heap_number, Label::kNear); 300180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ != equal) { 30023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Call runtime on identical objects. Otherwise return equal. 30033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx); 3004257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(above_equal, ¬_identical, Label::kNear); 300580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 300680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(rax, EQUAL); 300780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 300880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 300980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&heap_number); 301080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // It is a heap number, so return equal if it's not NaN. 301180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // For NaN, return 1 for every condition except greater and 301280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // greater-equal. Return -1 for them, so the comparison yields 301380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // false for all conditions except not-equal. 301480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(rax, EQUAL); 301580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset)); 301680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ucomisd(xmm0, xmm0); 301780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ setcc(parity_even, rax); 301880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rax is 0 for equal non-NaN heapnumbers, 1 for NaNs. 301980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ == greater_equal || cc_ == greater) { 302080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ neg(rax); 302180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 302280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 302380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 302480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 302580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_identical); 302680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 302780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 302880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ == equal) { // Both strict and non-strict. 302980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label slow; // Fallthrough label. 303080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 303180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If we're doing a strict equality comparison, we don't have to do 303280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // type conversion, so we generate code to do fast comparison for objects 303380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // and oddballs. Non-smi numbers and strings still go through the usual 303480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // slow-case code. 303580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (strict_) { 303680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If either is a Smi (we know that not both are), then they can only 303780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // be equal if the other is a HeapNumber. If so, use the slow case. 303880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen { 303980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label not_smis; 304080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SelectNonSmi(rbx, rax, rdx, ¬_smis); 304180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 304280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if the non-smi operand is a heap number. 304380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset), 3044257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch factory->heap_number_map()); 304580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If heap number, handle it in the slow case. 304680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &slow); 304780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return non-equal. ebx (the lower half of rbx) is not zero. 304880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rax, rbx); 304980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 305080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 305180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_smis); 305280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 305380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 305480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If either operand is a JSObject or an oddball value, then they are not 305580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // equal since their pointers are different 305680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // There is no test for undetectability in strict equality. 305780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 305880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the first object is a JS object, we have done pointer comparison. 30593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE); 3060257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label first_non_object; 30613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx); 3062257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(below, &first_non_object, Label::kNear); 306380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return non-zero (eax (not rax) is not zero) 306480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label return_not_equal; 306580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kHeapObjectTag != 0); 306680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&return_not_equal); 306780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 306880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 306980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&first_non_object); 307080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for oddballs: true, false, null, undefined. 307180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CmpInstanceType(rcx, ODDBALL_TYPE); 307280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &return_not_equal); 307380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 30743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ CmpObjectType(rdx, FIRST_SPEC_OBJECT_TYPE, rcx); 307580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(above_equal, &return_not_equal); 307680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 307780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for oddballs: true, false, null, undefined. 307880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CmpInstanceType(rcx, ODDBALL_TYPE); 307980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &return_not_equal); 308080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 308180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fall through to the general case. 308280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 308380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&slow); 308480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 308580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 308680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Generate the number comparison code. 308780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (include_number_compare_) { 308880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label non_number_comparison; 3089257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label unordered; 309080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FloatingPointHelper::LoadSSE2UnknownOperands(masm, &non_number_comparison); 309180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xorl(rax, rax); 309280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xorl(rcx, rcx); 309380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ucomisd(xmm0, xmm1); 309480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 309580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Don't base result on EFLAGS when a NaN is involved. 3096257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(parity_even, &unordered, Label::kNear); 309780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return a result of -1, 0, or 1, based on EFLAGS. 309880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ setcc(above, rax); 309980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ setcc(below, rcx); 310080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ subq(rax, rcx); 310180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 310280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 310380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If one of the numbers was NaN, then the result is always false. 310480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The cc is never not-equal. 310580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&unordered); 310680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(cc_ != not_equal); 310780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ == less || cc_ == less_equal) { 310880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(rax, 1); 310980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 311080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(rax, -1); 311180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 311280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 311380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 311480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The number comparison code did not provide a valid result. 311580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&non_number_comparison); 311680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 311780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 311880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fast negative check for symbol-to-symbol equality. 311980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label check_for_strings; 312080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ == equal) { 312180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen BranchIfNonSymbol(masm, &check_for_strings, rax, kScratchRegister); 312280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen BranchIfNonSymbol(masm, &check_for_strings, rdx, kScratchRegister); 312380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 312480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // We've already checked for object identity, so if both operands 312580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // are symbols they aren't equal. Register eax (not rax) already holds a 312680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // non-zero value, which indicates not equal, so just return. 312780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 312880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 312980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 313080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&check_for_strings); 313180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 313280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfNotBothSequentialAsciiStrings( 313380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen rdx, rax, rcx, rbx, &check_unequal_objects); 313480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 313580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Inline comparison of ascii strings. 3136257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (cc_ == equal) { 3137257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringCompareStub::GenerateFlatAsciiStringEquals(masm, 313880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen rdx, 313980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen rax, 314080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen rcx, 3141257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch rbx); 3142257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } else { 3143257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringCompareStub::GenerateCompareFlatAsciiStrings(masm, 3144257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch rdx, 3145257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch rax, 3146257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch rcx, 3147257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch rbx, 3148257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch rdi, 3149257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch r8); 3150257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 315180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 315280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef DEBUG 315380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Abort("Unexpected fall-through from string comparison"); 315480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif 315580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 315680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&check_unequal_objects); 315780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ == equal && !strict_) { 315880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Not strict equality. Objects are unequal if 315980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // they are both JSObjects and not undetectable, 316080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // and their pointers are different. 3161257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label not_both_objects, return_unequal; 316280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // At most one is a smi, so we can test for smi by adding the two. 316380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // A smi plus a heap object has the low bit set, a heap object plus 316480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // a heap object has the low bit clear. 316580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 316680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTagMask == 1); 316780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(rcx, Operand(rax, rdx, times_1, 0)); 316880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ testb(rcx, Immediate(kSmiTagMask)); 3169257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, ¬_both_objects, Label::kNear); 31703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rbx); 3171257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(below, ¬_both_objects, Label::kNear); 31723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ CmpObjectType(rdx, FIRST_SPEC_OBJECT_TYPE, rcx); 3173257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(below, ¬_both_objects, Label::kNear); 317480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ testb(FieldOperand(rbx, Map::kBitFieldOffset), 317580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Immediate(1 << Map::kIsUndetectable)); 3176257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &return_unequal, Label::kNear); 317780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ testb(FieldOperand(rcx, Map::kBitFieldOffset), 317880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Immediate(1 << Map::kIsUndetectable)); 3179257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &return_unequal, Label::kNear); 318080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The objects are both undetectable, so they both compare as the value 318180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // undefined, and are equal. 318280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(rax, EQUAL); 318380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&return_unequal); 31841e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Return non-equal by returning the non-zero object pointer in rax, 318580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // or return equal if we fell through to here. 318680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 318780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_both_objects); 318880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 318980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 319080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Push arguments below the return address to prepare jump to builtin. 319180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(rcx); 319280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(rdx); 319380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(rax); 319480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 319580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Figure out which native to call and setup the arguments. 319680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Builtins::JavaScript builtin; 319780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ == equal) { 319880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen builtin = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS; 319980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 320080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen builtin = Builtins::COMPARE; 320180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Push(Smi::FromInt(NegativeComparisonResult(cc_))); 320280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 320380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 320480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Restore return address on the stack. 320580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(rcx); 320680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 320780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) 320880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // tagged as a small integer. 320980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ InvokeBuiltin(builtin, JUMP_FUNCTION); 321080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 321180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 321280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 321380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CompareStub::BranchIfNonSymbol(MacroAssembler* masm, 321480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* label, 321580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register object, 321680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch) { 321780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfSmi(object, label); 321880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(scratch, FieldOperand(object, HeapObject::kMapOffset)); 321980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzxbq(scratch, 322080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FieldOperand(scratch, Map::kInstanceTypeOffset)); 322180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Ensure that no non-strings have the symbol bit set. 322280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(LAST_TYPE < kNotStringTag + kIsSymbolMask); 322380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSymbolTag != 0); 322480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ testb(scratch, Immediate(kIsSymbolMask)); 322580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, label); 322680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 322780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 322880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 322980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StackCheckStub::Generate(MacroAssembler* masm) { 3230f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch __ TailCallRuntime(Runtime::kStackGuard, 0, 1); 323180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 323280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 323380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 323480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CallFunctionStub::Generate(MacroAssembler* masm) { 3235589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch Label slow, non_function; 323680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3237257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // The receiver might implicitly be the global object. This is 3238257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // indicated by passing the hole as the receiver to the call 3239257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // function stub. 3240257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (ReceiverMightBeImplicit()) { 3241257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label call; 324280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the receiver from the stack. 324380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // +1 ~ return address 324480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rax, Operand(rsp, (argc_ + 1) * kPointerSize)); 3245257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Call as function is indicated with the hole. 3246257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); 3247257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &call, Label::kNear); 3248257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Patch the receiver on the stack with the global receiver object. 3249257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movq(rbx, GlobalObjectOperand()); 3250257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset)); 3251257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movq(Operand(rsp, (argc_ + 1) * kPointerSize), rbx); 3252257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&call); 325380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 325480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 325580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the function to call from the stack. 325680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // +2 ~ receiver, return address 325780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rdi, Operand(rsp, (argc_ + 2) * kPointerSize)); 325880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 325980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the function really is a JavaScript function. 3260589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ JumpIfSmi(rdi, &non_function); 326180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Goto slow case if we do not have a function. 326280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); 326380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &slow); 326480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 326580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fast-case: Just invoke the function. 326680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ParameterCount actual(argc_); 3267257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 3268257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (ReceiverMightBeImplicit()) { 3269257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label call_as_function; 3270257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); 3271257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &call_as_function); 3272257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeFunction(rdi, 3273257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch actual, 3274257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch JUMP_FUNCTION, 3275257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch NullCallWrapper(), 3276257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch CALL_AS_METHOD); 3277257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&call_as_function); 3278257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 3279257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeFunction(rdi, 3280257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch actual, 3281257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch JUMP_FUNCTION, 3282257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch NullCallWrapper(), 3283257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch CALL_AS_FUNCTION); 328480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 328580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Slow-case: Non-function called. 328680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&slow); 3287589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // Check for function proxy. 3288589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ CmpInstanceType(rcx, JS_FUNCTION_PROXY_TYPE); 3289589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ j(not_equal, &non_function); 3290589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ pop(rcx); 3291589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ push(rdi); // put proxy as additional argument under return address 3292589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ push(rcx); 3293589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ Set(rax, argc_ + 1); 3294589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ Set(rbx, 0); 3295589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ SetCallKind(rcx, CALL_AS_FUNCTION); 3296589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ GetBuiltinEntry(rdx, Builtins::CALL_FUNCTION_PROXY); 3297589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch { 3298589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch Handle<Code> adaptor = 3299589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(); 3300589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ jmp(adaptor, RelocInfo::CODE_TARGET); 3301589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch } 3302589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch 330380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // CALL_NON_FUNCTION expects the non-function callee as receiver (instead 330480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // of the original receiver from the call site). 3305589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ bind(&non_function); 330680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(Operand(rsp, (argc_ + 1) * kPointerSize), rdi); 330780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(rax, argc_); 330880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(rbx, 0); 3309589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ SetCallKind(rcx, CALL_AS_METHOD); 331080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION); 331144f0eee88ff00398ff7f715fab053374d808c90dSteve Block Handle<Code> adaptor = 331244f0eee88ff00398ff7f715fab053374d808c90dSteve Block Isolate::Current()->builtins()->ArgumentsAdaptorTrampoline(); 331380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Jump(adaptor, RelocInfo::CODE_TARGET); 331480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 331580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 331680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 331744f0eee88ff00398ff7f715fab053374d808c90dSteve Blockbool CEntryStub::NeedsImmovableCode() { 331844f0eee88ff00398ff7f715fab053374d808c90dSteve Block return false; 331944f0eee88ff00398ff7f715fab053374d808c90dSteve Block} 332044f0eee88ff00398ff7f715fab053374d808c90dSteve Block 332144f0eee88ff00398ff7f715fab053374d808c90dSteve Block 332280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { 3323e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Throw exception in eax. 3324e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ Throw(rax); 332580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 332680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 332780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 332880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::GenerateCore(MacroAssembler* masm, 332980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* throw_normal_exception, 333080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* throw_termination_exception, 333180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* throw_out_of_memory_exception, 333280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen bool do_gc, 33331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block bool always_allocate_scope) { 333480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rax: result parameter for PerformGC, if any. 333580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rbx: pointer to C function (C callee-saved). 333680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rbp: frame pointer (restored after C call). 333780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rsp: stack pointer (restored after C call). 333880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r14: number of arguments including receiver (C callee-saved). 333944f0eee88ff00398ff7f715fab053374d808c90dSteve Block // r15: pointer to the first argument (C callee-saved). 334080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // This pointer is reused in LeaveExitFrame(), so it is stored in a 334180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // callee-saved register. 334280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 334380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Simple results returned in rax (both AMD64 and Win64 calling conventions). 334480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Complex results must be written to address passed as first argument. 334580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // AMD64 calling convention: a struct of two pointers in rax+rdx 334680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 334780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check stack alignment. 334880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (FLAG_debug_code) { 334980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CheckStackAlignment(); 335080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 335180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 335280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (do_gc) { 335380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Pass failure code returned from last attempt as first argument to 335480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // PerformGC. No need to use PrepareCallCFunction/CallCFunction here as the 335580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // stack is known to be aligned. This function takes one argument which is 335680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // passed in register. 335780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef _WIN64 335880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rcx, rax); 335980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#else // _WIN64 336080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rdi, rax); 336180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif 336280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(kScratchRegister, 336380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FUNCTION_ADDR(Runtime::PerformGC), 336480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen RelocInfo::RUNTIME_ENTRY); 336580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ call(kScratchRegister); 336680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 336780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 336880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ExternalReference scope_depth = 336944f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::heap_always_allocate_scope_depth(masm->isolate()); 337080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (always_allocate_scope) { 337144f0eee88ff00398ff7f715fab053374d808c90dSteve Block Operand scope_depth_operand = masm->ExternalOperand(scope_depth); 337244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ incl(scope_depth_operand); 337380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 337480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 337580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call C function. 337680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef _WIN64 337780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Windows 64-bit ABI passes arguments in rcx, rdx, r8, r9 337880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Store Arguments object on stack, below the 4 WIN64 ABI parameter slots. 33798a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang __ movq(StackSpaceOperand(0), r14); // argc. 338044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movq(StackSpaceOperand(1), r15); // argv. 338180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (result_size_ < 2) { 338280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Pass a pointer to the Arguments object as the first argument. 338380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return result in single register (rax). 33848a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang __ lea(rcx, StackSpaceOperand(0)); 338544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ LoadAddress(rdx, ExternalReference::isolate_address()); 338680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 338780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT_EQ(2, result_size_); 338880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Pass a pointer to the result location as the first argument. 33898a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang __ lea(rcx, StackSpaceOperand(2)); 339080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Pass a pointer to the Arguments object as the second argument. 33918a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang __ lea(rdx, StackSpaceOperand(0)); 339244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ LoadAddress(r8, ExternalReference::isolate_address()); 339380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 339480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 339580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#else // _WIN64 339680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // GCC passes arguments in rdi, rsi, rdx, rcx, r8, r9. 339780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rdi, r14); // argc. 339844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movq(rsi, r15); // argv. 339944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movq(rdx, ExternalReference::isolate_address()); 340080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif 340180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ call(rbx); 340280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Result is in rax - do not destroy this register! 340380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 340480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (always_allocate_scope) { 340544f0eee88ff00398ff7f715fab053374d808c90dSteve Block Operand scope_depth_operand = masm->ExternalOperand(scope_depth); 340644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ decl(scope_depth_operand); 340780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 340880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 340980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for failure result. 341080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label failure_returned; 341180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0); 341280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef _WIN64 341380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If return value is on the stack, pop it to registers. 341480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (result_size_ > 1) { 341580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT_EQ(2, result_size_); 341680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Read result values stored on stack. Result is stored 341780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // above the four argument mirror slots and the two 341880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Arguments object slots. 341980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rax, Operand(rsp, 6 * kPointerSize)); 342080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rdx, Operand(rsp, 7 * kPointerSize)); 342180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 342280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif 342380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(rcx, Operand(rax, 1)); 342480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Lower 2 bits of rcx are 0 iff rax has failure tag. 342580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ testl(rcx, Immediate(kFailureTagMask)); 342680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &failure_returned); 342780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 342880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Exit the JavaScript to C++ exit frame. 34291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ LeaveExitFrame(save_doubles_); 343080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 343180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 343280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Handling of failure. 343380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&failure_returned); 343480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3435257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label retry; 343680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the returned exception is RETRY_AFTER_GC continue at retry label 343780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0); 343880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ testl(rax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize)); 3439257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &retry, Label::kNear); 344080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 344180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Special handling of out of memory exceptions. 344280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(kScratchRegister, Failure::OutOfMemoryException(), RelocInfo::NONE); 344380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmpq(rax, kScratchRegister); 344480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, throw_out_of_memory_exception); 344580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 344680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Retrieve the pending exception and clear the variable. 344744f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference pending_exception_address( 3448589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch Isolate::kPendingExceptionAddress, masm->isolate()); 344944f0eee88ff00398ff7f715fab053374d808c90dSteve Block Operand pending_exception_operand = 345044f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->ExternalOperand(pending_exception_address); 345144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movq(rax, pending_exception_operand); 345244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex); 345344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movq(pending_exception_operand, rdx); 345480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 345580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Special handling of termination exceptions which are uncatchable 345680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // by javascript code. 345780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CompareRoot(rax, Heap::kTerminationExceptionRootIndex); 345880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, throw_termination_exception); 345980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 346080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Handle normal exception. 346180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(throw_normal_exception); 346280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 346380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Retry. 346480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&retry); 346580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 346680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 346780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 346880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::GenerateThrowUncatchable(MacroAssembler* masm, 346980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen UncatchableExceptionType type) { 3470e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ ThrowUncatchable(type, rax); 347180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 347280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 347380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 347480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::Generate(MacroAssembler* masm) { 347580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rax: number of arguments including receiver 347680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rbx: pointer to C function (C callee-saved) 347780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rbp: frame pointer of calling JS frame (restored after C call) 347880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rsp: stack pointer (restored after C call) 347980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rsi: current context (restored) 348080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 348180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // NOTE: Invocations of builtins may return failure objects 348280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // instead of a proper result. The builtin entry handles 348380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // this by performing a garbage collection and retrying the 348480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // builtin once. 348580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 348680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Enter the exit frame that transitions from JavaScript to C++. 34878a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang#ifdef _WIN64 34888a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang int arg_stack_space = (result_size_ < 2 ? 2 : 4); 34898a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang#else 34908a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang int arg_stack_space = 0; 34918a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang#endif 34921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ EnterExitFrame(arg_stack_space, save_doubles_); 349380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 349480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rax: Holds the context at this point, but should not be used. 349580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // On entry to code generated by GenerateCore, it must hold 349680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // a failure result if the collect_garbage argument to GenerateCore 349780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // is true. This failure result can be the result of code 349880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // generated by a previous call to GenerateCore. The value 349980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // of rax is then passed to Runtime::PerformGC. 350080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rbx: pointer to builtin function (C callee-saved). 350180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rbp: frame pointer of exit frame (restored after C call). 350280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rsp: stack pointer (restored after C call). 350380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r14: number of arguments including receiver (C callee-saved). 350444f0eee88ff00398ff7f715fab053374d808c90dSteve Block // r15: argv pointer (C callee-saved). 350580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 350680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label throw_normal_exception; 350780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label throw_termination_exception; 350880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label throw_out_of_memory_exception; 350980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 351080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call into the runtime system. 351180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateCore(masm, 351280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_normal_exception, 351380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_termination_exception, 351480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_out_of_memory_exception, 351580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen false, 351680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen false); 351780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 351880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Do space-specific GC and retry runtime call. 351980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateCore(masm, 352080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_normal_exception, 352180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_termination_exception, 352280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_out_of_memory_exception, 352380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen true, 352480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen false); 352580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 352680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Do full GC and retry runtime call one final time. 352780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Failure* failure = Failure::InternalError(); 352880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rax, failure, RelocInfo::NONE); 352980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateCore(masm, 353080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_normal_exception, 353180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_termination_exception, 353280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_out_of_memory_exception, 353380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen true, 353480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen true); 353580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 353680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&throw_out_of_memory_exception); 353780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateThrowUncatchable(masm, OUT_OF_MEMORY); 353880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 353980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&throw_termination_exception); 354080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateThrowUncatchable(masm, TERMINATION); 354180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 354280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&throw_normal_exception); 354380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateThrowTOS(masm); 354480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 354580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 354680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 354780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { 354880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label invoke, exit; 354980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label not_outermost_js, not_outermost_js_2; 355044f0eee88ff00398ff7f715fab053374d808c90dSteve Block { // NOLINT. Scope block confuses linter. 355144f0eee88ff00398ff7f715fab053374d808c90dSteve Block MacroAssembler::NoRootArrayScope uninitialized_root_register(masm); 355244f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Setup frame. 355344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ push(rbp); 355444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movq(rbp, rsp); 355544f0eee88ff00398ff7f715fab053374d808c90dSteve Block 355644f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Push the stack frame type marker twice. 355744f0eee88ff00398ff7f715fab053374d808c90dSteve Block int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY; 355844f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Scratch register is neither callee-save, nor an argument register on any 355944f0eee88ff00398ff7f715fab053374d808c90dSteve Block // platform. It's free to use at this point. 356044f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Cannot use smi-register for loading yet. 356144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movq(kScratchRegister, 356244f0eee88ff00398ff7f715fab053374d808c90dSteve Block reinterpret_cast<uint64_t>(Smi::FromInt(marker)), 356344f0eee88ff00398ff7f715fab053374d808c90dSteve Block RelocInfo::NONE); 356444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ push(kScratchRegister); // context slot 356544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ push(kScratchRegister); // function slot 356644f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Save callee-saved registers (X64/Win64 calling conventions). 356744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ push(r12); 356844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ push(r13); 356944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ push(r14); 357044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ push(r15); 357180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef _WIN64 357244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ push(rdi); // Only callee save in Win64 ABI, argument in AMD64 ABI. 357344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ push(rsi); // Only callee save in Win64 ABI, argument in AMD64 ABI. 357480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif 357544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ push(rbx); 357644f0eee88ff00398ff7f715fab053374d808c90dSteve Block // TODO(X64): On Win64, if we ever use XMM6-XMM15, the low low 64 bits are 357744f0eee88ff00398ff7f715fab053374d808c90dSteve Block // callee save as well. 357844f0eee88ff00398ff7f715fab053374d808c90dSteve Block 357944f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Set up the roots and smi constant registers. 358044f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Needs to be done before any further smi loads. 358144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ InitializeSmiConstantRegister(); 358244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ InitializeRootRegister(); 358344f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 358480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 358544f0eee88ff00398ff7f715fab053374d808c90dSteve Block Isolate* isolate = masm->isolate(); 358680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 358744f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Save copies of the top frame descriptor on the stack. 3588589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch ExternalReference c_entry_fp(Isolate::kCEntryFPAddress, isolate); 358944f0eee88ff00398ff7f715fab053374d808c90dSteve Block { 359044f0eee88ff00398ff7f715fab053374d808c90dSteve Block Operand c_entry_fp_operand = masm->ExternalOperand(c_entry_fp); 359144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ push(c_entry_fp_operand); 359244f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 359380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 359480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If this is the outermost JS call, set js_entry_sp value. 3595589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress, isolate); 359644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ Load(rax, js_entry_sp); 359780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ testq(rax, rax); 359880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, ¬_outermost_js); 3599053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ Push(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)); 360080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rax, rbp); 360144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ Store(js_entry_sp, rax); 3602053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block Label cont; 3603053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ jmp(&cont); 360480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_outermost_js); 3605053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ Push(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME)); 3606053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ bind(&cont); 360780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 360880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call a faked try-block that does the invoke. 360980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ call(&invoke); 361080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 361180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Caught exception: Store result (exception) in the pending 361280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // exception field in the JSEnv and return a failure sentinel. 3613589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch ExternalReference pending_exception(Isolate::kPendingExceptionAddress, 361444f0eee88ff00398ff7f715fab053374d808c90dSteve Block isolate); 361544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ Store(pending_exception, rax); 361680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rax, Failure::Exception(), RelocInfo::NONE); 361780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&exit); 361880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 361980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Invoke: Link this frame into the handler chain. 362080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&invoke); 362180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER); 362280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 362380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Clear any pending exceptions. 362444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ LoadRoot(rax, Heap::kTheHoleValueRootIndex); 362544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ Store(pending_exception, rax); 362680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 362780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fake a receiver (NULL). 362880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(Immediate(0)); // receiver 362980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 363080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Invoke the function by calling through JS entry trampoline 363180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // builtin and pop the faked function when we return. We load the address 363280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // from an external reference instead of inlining the call target address 363380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // directly in the code, because the builtin stubs may not have been 363480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // generated yet at the time this code is generated. 363580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (is_construct) { 363644f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference construct_entry(Builtins::kJSConstructEntryTrampoline, 363744f0eee88ff00398ff7f715fab053374d808c90dSteve Block isolate); 363844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ Load(rax, construct_entry); 363980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 364044f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference entry(Builtins::kJSEntryTrampoline, isolate); 364144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ Load(rax, entry); 364280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 364380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(kScratchRegister, FieldOperand(rax, Code::kHeaderSize)); 364480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ call(kScratchRegister); 364580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 364680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Unlink this frame from the handler chain. 3647053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ PopTryHandler(); 364880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3649053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ bind(&exit); 3650053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block // Check if the current stack frame is marked as the outermost JS frame. 3651053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ pop(rbx); 3652053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ Cmp(rbx, Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)); 365380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, ¬_outermost_js_2); 3654053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ movq(kScratchRegister, js_entry_sp); 365580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(Operand(kScratchRegister, 0), Immediate(0)); 365680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_outermost_js_2); 365780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 365880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Restore the top frame descriptor from the stack. 3659053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block { Operand c_entry_fp_operand = masm->ExternalOperand(c_entry_fp); 366044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ pop(c_entry_fp_operand); 366144f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 366280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 366380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Restore callee-saved registers (X64 conventions). 366480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(rbx); 366580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef _WIN64 366680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Callee save on in Win64 ABI, arguments/volatile in AMD64 ABI. 366780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(rsi); 366880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(rdi); 366980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif 367080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(r15); 367180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(r14); 367280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(r13); 367380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(r12); 367480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ addq(rsp, Immediate(2 * kPointerSize)); // remove markers 367580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 367680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Restore frame pointer and return. 367780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(rbp); 367880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 367980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 368080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 368180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 368280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid InstanceofStub::Generate(MacroAssembler* masm) { 368380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Implements "value instanceof function" operator. 368444f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Expected input state with no inline cache: 368580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rsp[0] : return address 368680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rsp[1] : function pointer 368780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rsp[2] : value 368844f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Expected input state with an inline one-element cache: 368944f0eee88ff00398ff7f715fab053374d808c90dSteve Block // rsp[0] : return address 369044f0eee88ff00398ff7f715fab053374d808c90dSteve Block // rsp[1] : offset from return address to location of inline cache 369144f0eee88ff00398ff7f715fab053374d808c90dSteve Block // rsp[2] : function pointer 369244f0eee88ff00398ff7f715fab053374d808c90dSteve Block // rsp[3] : value 369380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Returns a bitwise zero to indicate that the value 369480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // is and instance of the function and anything else to 369580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // indicate that the value is not an instance. 369680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 36978b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static const int kOffsetToMapCheckValue = 2; 36988b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static const int kOffsetToResultValue = 18; 369944f0eee88ff00398ff7f715fab053374d808c90dSteve Block // The last 4 bytes of the instruction sequence 37008b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // movq(rdi, FieldOperand(rax, HeapObject::kMapOffset)) 370144f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Move(kScratchRegister, FACTORY->the_hole_value()) 370244f0eee88ff00398ff7f715fab053374d808c90dSteve Block // in front of the hole value address. 370344f0eee88ff00398ff7f715fab053374d808c90dSteve Block static const unsigned int kWordBeforeMapCheckValue = 0xBA49FF78; 370444f0eee88ff00398ff7f715fab053374d808c90dSteve Block // The last 4 bytes of the instruction sequence 370544f0eee88ff00398ff7f715fab053374d808c90dSteve Block // __ j(not_equal, &cache_miss); 370644f0eee88ff00398ff7f715fab053374d808c90dSteve Block // __ LoadRoot(ToRegister(instr->result()), Heap::kTheHoleValueRootIndex); 370744f0eee88ff00398ff7f715fab053374d808c90dSteve Block // before the offset of the hole value in the root array. 370844f0eee88ff00398ff7f715fab053374d808c90dSteve Block static const unsigned int kWordBeforeResultValue = 0x458B4909; 370944f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Only the inline check flag is supported on X64. 371044f0eee88ff00398ff7f715fab053374d808c90dSteve Block ASSERT(flags_ == kNoFlags || HasCallSiteInlineCheck()); 371144f0eee88ff00398ff7f715fab053374d808c90dSteve Block int extra_stack_space = HasCallSiteInlineCheck() ? kPointerSize : 0; 3712e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 371380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the object - go slow case if it's a smi. 371480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label slow; 371544f0eee88ff00398ff7f715fab053374d808c90dSteve Block 371644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movq(rax, Operand(rsp, 2 * kPointerSize + extra_stack_space)); 371780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfSmi(rax, &slow); 371880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 371980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the left hand is a JS object. Leave its map in rax. 37203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rax); 372180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(below, &slow); 37223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ CmpInstanceType(rax, LAST_SPEC_OBJECT_TYPE); 372380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(above, &slow); 372480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 372580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the prototype of the function. 372644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movq(rdx, Operand(rsp, 1 * kPointerSize + extra_stack_space)); 372780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rdx is function, rax is map. 372880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 372944f0eee88ff00398ff7f715fab053374d808c90dSteve Block // If there is a call site cache don't look in the global cache, but do the 373044f0eee88ff00398ff7f715fab053374d808c90dSteve Block // real lookup and update the call site cache. 373144f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (!HasCallSiteInlineCheck()) { 373244f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Look up the function and the map in the instanceof cache. 3733257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label miss; 373444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ CompareRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex); 3735257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &miss, Label::kNear); 373644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ CompareRoot(rax, Heap::kInstanceofCacheMapRootIndex); 3737257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &miss, Label::kNear); 373844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ LoadRoot(rax, Heap::kInstanceofCacheAnswerRootIndex); 373944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ ret(2 * kPointerSize); 374044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ bind(&miss); 374144f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 374280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 374380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TryGetFunctionPrototype(rdx, rbx, &slow); 374480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 374580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the function prototype is a JS object. 374680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfSmi(rbx, &slow); 37473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ CmpObjectType(rbx, FIRST_SPEC_OBJECT_TYPE, kScratchRegister); 374880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(below, &slow); 37493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ CmpInstanceType(kScratchRegister, LAST_SPEC_OBJECT_TYPE); 375080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(above, &slow); 375180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 375280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Register mapping: 375380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rax is object map. 375480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rdx is function. 375580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rbx is function prototype. 375644f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (!HasCallSiteInlineCheck()) { 375744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ StoreRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex); 375844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ StoreRoot(rax, Heap::kInstanceofCacheMapRootIndex); 375944f0eee88ff00398ff7f715fab053374d808c90dSteve Block } else { 376044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movq(kScratchRegister, Operand(rsp, 0 * kPointerSize)); 376144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ subq(kScratchRegister, Operand(rsp, 1 * kPointerSize)); 376244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movq(Operand(kScratchRegister, kOffsetToMapCheckValue), rax); 376344f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (FLAG_debug_code) { 376444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movl(rdi, Immediate(kWordBeforeMapCheckValue)); 376544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmpl(Operand(kScratchRegister, kOffsetToMapCheckValue - 4), rdi); 37668b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ Assert(equal, "InstanceofStub unexpected call site cache (check)."); 376744f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 376844f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 376980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 377080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rcx, FieldOperand(rax, Map::kPrototypeOffset)); 377180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 377280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Loop through the prototype chain looking for the function prototype. 3773257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label loop, is_instance, is_not_instance; 377480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ LoadRoot(kScratchRegister, Heap::kNullValueRootIndex); 377580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&loop); 377680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmpq(rcx, rbx); 3777257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &is_instance, Label::kNear); 377880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmpq(rcx, kScratchRegister); 377980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The code at is_not_instance assumes that kScratchRegister contains a 378080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // non-zero GCable value (the null object in this case). 3781257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &is_not_instance, Label::kNear); 378280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset)); 378380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rcx, FieldOperand(rcx, Map::kPrototypeOffset)); 378480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&loop); 378580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 378680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&is_instance); 378744f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (!HasCallSiteInlineCheck()) { 378844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ xorl(rax, rax); 378944f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Store bitwise zero in the cache. This is a Smi in GC terms. 379044f0eee88ff00398ff7f715fab053374d808c90dSteve Block STATIC_ASSERT(kSmiTag == 0); 379144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ StoreRoot(rax, Heap::kInstanceofCacheAnswerRootIndex); 379244f0eee88ff00398ff7f715fab053374d808c90dSteve Block } else { 379344f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Store offset of true in the root array at the inline check site. 379444f0eee88ff00398ff7f715fab053374d808c90dSteve Block ASSERT((Heap::kTrueValueRootIndex << kPointerSizeLog2) - kRootRegisterBias 379544f0eee88ff00398ff7f715fab053374d808c90dSteve Block == 0xB0 - 0x100); 379644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movl(rax, Immediate(0xB0)); // TrueValue is at -10 * kPointerSize. 379744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movq(kScratchRegister, Operand(rsp, 0 * kPointerSize)); 379844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ subq(kScratchRegister, Operand(rsp, 1 * kPointerSize)); 379944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movb(Operand(kScratchRegister, kOffsetToResultValue), rax); 380044f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (FLAG_debug_code) { 380144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movl(rax, Immediate(kWordBeforeResultValue)); 380244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmpl(Operand(kScratchRegister, kOffsetToResultValue - 4), rax); 38038b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ Assert(equal, "InstanceofStub unexpected call site cache (mov)."); 380444f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 38058b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ Set(rax, 0); 380644f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 380744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ ret(2 * kPointerSize + extra_stack_space); 380880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 380980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&is_not_instance); 381044f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (!HasCallSiteInlineCheck()) { 381144f0eee88ff00398ff7f715fab053374d808c90dSteve Block // We have to store a non-zero value in the cache. 381244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ StoreRoot(kScratchRegister, Heap::kInstanceofCacheAnswerRootIndex); 381344f0eee88ff00398ff7f715fab053374d808c90dSteve Block } else { 381444f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Store offset of false in the root array at the inline check site. 381544f0eee88ff00398ff7f715fab053374d808c90dSteve Block ASSERT((Heap::kFalseValueRootIndex << kPointerSizeLog2) - kRootRegisterBias 381644f0eee88ff00398ff7f715fab053374d808c90dSteve Block == 0xB8 - 0x100); 381744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movl(rax, Immediate(0xB8)); // FalseValue is at -9 * kPointerSize. 381844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movq(kScratchRegister, Operand(rsp, 0 * kPointerSize)); 381944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ subq(kScratchRegister, Operand(rsp, 1 * kPointerSize)); 382044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movb(Operand(kScratchRegister, kOffsetToResultValue), rax); 382144f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (FLAG_debug_code) { 382244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movl(rax, Immediate(kWordBeforeResultValue)); 382344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmpl(Operand(kScratchRegister, kOffsetToResultValue - 4), rax); 382444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ Assert(equal, "InstanceofStub unexpected call site cache (mov)"); 382544f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 382644f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 382744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ ret(2 * kPointerSize + extra_stack_space); 382880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 382980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Slow-case: Go through the JavaScript implementation. 383080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&slow); 383144f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (HasCallSiteInlineCheck()) { 383244f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Remove extra value from the stack. 383344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ pop(rcx); 383444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ pop(rax); 383544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ push(rcx); 383644f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 383780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); 383880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 383980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 384080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3841e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch// Passing arguments in registers is not supported. 3842e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen MurdochRegister InstanceofStub::left() { return no_reg; } 38431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 38441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 3845e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen MurdochRegister InstanceofStub::right() { return no_reg; } 38461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 38471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 384880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenint CompareStub::MinorKey() { 384980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Encode the three parameters in a unique 16 bit value. To avoid duplicate 385080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // stubs the never NaN NaN condition is only taken into account if the 385180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // condition is equals. 385280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(static_cast<unsigned>(cc_) < (1 << 12)); 385380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); 385480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen return ConditionField::encode(static_cast<unsigned>(cc_)) 385580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen | RegisterField::encode(false) // lhs_ and rhs_ are not used 385680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen | StrictField::encode(strict_) 385780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false) 38580d5e116f6aee03185f237311a943491bb079a768Kristian Monsen | IncludeNumberCompareField::encode(include_number_compare_) 38590d5e116f6aee03185f237311a943491bb079a768Kristian Monsen | IncludeSmiCompareField::encode(include_smi_compare_); 386080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 386180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 386280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 386380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Unfortunately you have to run without snapshots to see most of these 386480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// names in the profile since most compare stubs end up in the snapshot. 38653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid CompareStub::PrintName(StringStream* stream) { 386680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); 386780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const char* cc_name; 386880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen switch (cc_) { 386980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case less: cc_name = "LT"; break; 387080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case greater: cc_name = "GT"; break; 387180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case less_equal: cc_name = "LE"; break; 387280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case greater_equal: cc_name = "GE"; break; 387380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case equal: cc_name = "EQ"; break; 387480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case not_equal: cc_name = "NE"; break; 387580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen default: cc_name = "UnknownCondition"; break; 387680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 38773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch bool is_equality = cc_ == equal || cc_ == not_equal; 38783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch stream->Add("CompareStub_%s", cc_name); 38793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch if (strict_ && is_equality) stream->Add("_STRICT"); 38803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch if (never_nan_nan_ && is_equality) stream->Add("_NO_NAN"); 38813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch if (!include_number_compare_) stream->Add("_NO_NUMBER"); 38823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch if (!include_smi_compare_) stream->Add("_NO_SMI"); 388380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 388480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 388580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 388680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// ------------------------------------------------------------------------- 388780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// StringCharCodeAtGenerator 388880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 388980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { 389080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label flat_string; 389180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label ascii_string; 389280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label got_char_code; 389369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label sliced_string; 389480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 389580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the receiver is a smi trigger the non-string case. 389680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfSmi(object_, receiver_not_string_); 389780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 389880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fetch the instance type of the receiver into result register. 389980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(result_, FieldOperand(object_, HeapObject::kMapOffset)); 390080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzxbl(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); 390180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the receiver is not a string trigger the non-string case. 390280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ testb(result_, Immediate(kIsNotStringMask)); 390380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, receiver_not_string_); 390480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 390580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the index is non-smi trigger the non-smi case. 390680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfNotSmi(index_, &index_not_smi_); 390780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 390880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Put smi-tagged index into scratch register. 390980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(scratch_, index_); 391080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&got_smi_index_); 391180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 391280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for index out of range. 391380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiCompare(scratch_, FieldOperand(object_, String::kLengthOffset)); 391480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(above_equal, index_out_of_range_); 391580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 391680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // We need special handling for non-flat strings. 391780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSeqStringTag == 0); 391880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ testb(result_, Immediate(kStringRepresentationMask)); 391980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &flat_string); 392080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 392180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Handle non-flat strings. 392269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ and_(result_, Immediate(kStringRepresentationMask)); 392369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch STATIC_ASSERT(kConsStringTag < kExternalStringTag); 392469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); 392569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ cmpb(result_, Immediate(kExternalStringTag)); 392669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(greater, &sliced_string); 392769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(equal, &call_runtime_); 392880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 392980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ConsString. 393080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check whether the right hand side is the empty string (i.e. if 393180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // this is really a flat string in a cons string). If that is not 393280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // the case we would rather go to the runtime system now to flatten 393380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // the string. 393469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label assure_seq_string; 393580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CompareRoot(FieldOperand(object_, ConsString::kSecondOffset), 393680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Heap::kEmptyStringRootIndex); 393780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &call_runtime_); 393880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the first of the two strings and load its instance type. 393980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(object_, FieldOperand(object_, ConsString::kFirstOffset)); 394069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ jmp(&assure_seq_string, Label::kNear); 394169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 394269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // SlicedString, unpack and add offset. 394369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&sliced_string); 394469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ addq(scratch_, FieldOperand(object_, SlicedString::kOffsetOffset)); 394569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ movq(object_, FieldOperand(object_, SlicedString::kParentOffset)); 394669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 394769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&assure_seq_string); 394880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(result_, FieldOperand(object_, HeapObject::kMapOffset)); 394980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzxbl(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); 395080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the first cons component is also non-flat, then go to runtime. 395180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSeqStringTag == 0); 395280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ testb(result_, Immediate(kStringRepresentationMask)); 395380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, &call_runtime_); 395469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ jmp(&flat_string); 395580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 395680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for 1-byte or 2-byte string. 395780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&flat_string); 3958589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); 3959589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); 396080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ testb(result_, Immediate(kStringEncodingMask)); 396180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, &ascii_string); 396280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 396380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // 2-byte string. 396480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load the 2-byte character code into the result register. 396580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiToInteger32(scratch_, scratch_); 396680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzxwl(result_, FieldOperand(object_, 396780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen scratch_, times_2, 396880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen SeqTwoByteString::kHeaderSize)); 396980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&got_char_code); 397080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 397180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ASCII string. 397280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load the byte into the result register. 397380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&ascii_string); 397480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiToInteger32(scratch_, scratch_); 397580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzxbl(result_, FieldOperand(object_, 397680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen scratch_, times_1, 397780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen SeqAsciiString::kHeaderSize)); 397880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&got_char_code); 397980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Integer32ToSmi(result_, result_); 398080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&exit_); 398180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 398280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 398380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 398480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharCodeAtGenerator::GenerateSlow( 398580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen MacroAssembler* masm, const RuntimeCallHelper& call_helper) { 398680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Abort("Unexpected fallthrough to CharCodeAt slow case"); 398780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3988257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Factory* factory = masm->isolate()->factory(); 398980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Index is not a smi. 399080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&index_not_smi_); 399180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If index is a heap number, try converting it to an integer. 3992257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CheckMap(index_, 3993257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch factory->heap_number_map(), 3994257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch index_not_number_, 3995257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch DONT_DO_SMI_CHECK); 399680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen call_helper.BeforeCall(masm); 399780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(object_); 399880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(index_); 399980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(index_); // Consumed by runtime conversion function. 400080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (index_flags_ == STRING_INDEX_IS_NUMBER) { 400180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1); 400280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 400380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX); 400480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // NumberToSmi discards numbers that are not exact integers. 400580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CallRuntime(Runtime::kNumberToSmi, 1); 400680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 400780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (!scratch_.is(rax)) { 400880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Save the conversion result before the pop instructions below 400980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // have a chance to overwrite it. 401080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(scratch_, rax); 401180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 401280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(index_); 401380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(object_); 401480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Reload the instance type. 401580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(result_, FieldOperand(object_, HeapObject::kMapOffset)); 401680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzxbl(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); 401780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen call_helper.AfterCall(masm); 401880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If index is still not a smi, it must be out of range. 401980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfNotSmi(scratch_, index_out_of_range_); 402080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Otherwise, return to the fast path. 402180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&got_smi_index_); 402280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 402380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call runtime. We get here when the receiver is a string and the 402480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // index is a number, but the code of getting the actual character 402580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // is too complex (e.g., when the string needs to be flattened). 402680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&call_runtime_); 402780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen call_helper.BeforeCall(masm); 402880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(object_); 402980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(index_); 403080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CallRuntime(Runtime::kStringCharCodeAt, 2); 403180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (!result_.is(rax)) { 403280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(result_, rax); 403380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 403480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen call_helper.AfterCall(masm); 403580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&exit_); 403680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 403780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Abort("Unexpected fallthrough from CharCodeAt slow case"); 403880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 403980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 404080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 404180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// ------------------------------------------------------------------------- 404280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// StringCharFromCodeGenerator 404380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 404480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) { 404580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fast case of Heap::LookupSingleCharacterStringFromCode. 404680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfNotSmi(code_, &slow_case_); 404780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiCompare(code_, Smi::FromInt(String::kMaxAsciiCharCode)); 404880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(above, &slow_case_); 404980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 405080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex); 405180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen SmiIndex index = masm->SmiToIndex(kScratchRegister, code_, kPointerSizeLog2); 405280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(result_, FieldOperand(result_, index.reg, index.scale, 405380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FixedArray::kHeaderSize)); 405480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CompareRoot(result_, Heap::kUndefinedValueRootIndex); 405580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &slow_case_); 405680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&exit_); 405780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 405880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 405980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 406080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharFromCodeGenerator::GenerateSlow( 406180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen MacroAssembler* masm, const RuntimeCallHelper& call_helper) { 406280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Abort("Unexpected fallthrough to CharFromCode slow case"); 406380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 406480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&slow_case_); 406580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen call_helper.BeforeCall(masm); 406680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(code_); 406780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CallRuntime(Runtime::kCharFromCode, 1); 406880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (!result_.is(rax)) { 406980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(result_, rax); 407080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 407180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen call_helper.AfterCall(masm); 407280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&exit_); 407380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 407480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Abort("Unexpected fallthrough from CharFromCode slow case"); 407580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 407680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 407780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 407880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// ------------------------------------------------------------------------- 407980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// StringCharAtGenerator 408080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 408180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharAtGenerator::GenerateFast(MacroAssembler* masm) { 408280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char_code_at_generator_.GenerateFast(masm); 408380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char_from_code_generator_.GenerateFast(masm); 408480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 408580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 408680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 408780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharAtGenerator::GenerateSlow( 408880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen MacroAssembler* masm, const RuntimeCallHelper& call_helper) { 408980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char_code_at_generator_.GenerateSlow(masm, call_helper); 409080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char_from_code_generator_.GenerateSlow(masm, call_helper); 409180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 409280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 409380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 409480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringAddStub::Generate(MacroAssembler* masm) { 4095e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label string_add_runtime, call_builtin; 4096e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Builtins::JavaScript builtin_id = Builtins::ADD; 409780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 409880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load the two arguments. 4099e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movq(rax, Operand(rsp, 2 * kPointerSize)); // First argument (left). 4100e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movq(rdx, Operand(rsp, 1 * kPointerSize)); // Second argument (right). 410180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 410280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Make sure that both arguments are strings if not known in advance. 4103e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch if (flags_ == NO_STRING_ADD_FLAGS) { 41043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(rax, &string_add_runtime); 410580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, r8); 410680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(above_equal, &string_add_runtime); 410780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 410880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // First argument is a a string, test second. 41093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(rdx, &string_add_runtime); 411080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, r9); 411180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(above_equal, &string_add_runtime); 4112e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } else { 4113e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Here at least one of the arguments is definitely a string. 4114e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // We convert the one that is not known to be a string. 4115e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) { 4116e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0); 4117e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch GenerateConvertArgument(masm, 2 * kPointerSize, rax, rbx, rcx, rdi, 4118e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch &call_builtin); 4119e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch builtin_id = Builtins::STRING_ADD_RIGHT; 4120e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } else if ((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) == 0) { 4121e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch ASSERT((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) != 0); 4122e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch GenerateConvertArgument(masm, 1 * kPointerSize, rdx, rbx, rcx, rdi, 4123e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch &call_builtin); 4124e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch builtin_id = Builtins::STRING_ADD_LEFT; 4125e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 412680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 412780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 412880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Both arguments are strings. 412980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rax: first string 413080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rdx: second string 413180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if either of the strings are empty. In that case return the other. 4132257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label second_not_zero_length, both_not_zero_length; 413380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rcx, FieldOperand(rdx, String::kLengthOffset)); 413480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiTest(rcx); 4135257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &second_not_zero_length, Label::kNear); 413680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Second string is empty, result is first string which is already in rax. 413744f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = masm->isolate()->counters(); 413844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1); 413980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(2 * kPointerSize); 414080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&second_not_zero_length); 414180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rbx, FieldOperand(rax, String::kLengthOffset)); 414280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiTest(rbx); 4143257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &both_not_zero_length, Label::kNear); 414480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // First string is empty, result is second string which is in rdx. 414580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rax, rdx); 414644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1); 414780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(2 * kPointerSize); 414880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 414980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Both strings are non-empty. 415080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rax: first string 415180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rbx: length of first string 415280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rcx: length of second string 415380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rdx: second string 4154e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // r8: map of first string (if flags_ == NO_STRING_ADD_FLAGS) 4155e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // r9: map of second string (if flags_ == NO_STRING_ADD_FLAGS) 415680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label string_add_flat_result, longer_than_two; 415780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&both_not_zero_length); 415880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 415980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If arguments where known to be strings, maps are not loaded to r8 and r9 416080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // by the code above. 4161e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch if (flags_ != NO_STRING_ADD_FLAGS) { 416280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(r8, FieldOperand(rax, HeapObject::kMapOffset)); 416380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(r9, FieldOperand(rdx, HeapObject::kMapOffset)); 416480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 416580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the instance types of the two strings as they will be needed soon. 416680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzxbl(r8, FieldOperand(r8, Map::kInstanceTypeOffset)); 416780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzxbl(r9, FieldOperand(r9, Map::kInstanceTypeOffset)); 416880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 416980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Look at the length of the result of adding the two strings. 417080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue / 2); 41710d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ SmiAdd(rbx, rbx, rcx); 417244f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Use the symbol table when adding two one character strings, as it 417344f0eee88ff00398ff7f715fab053374d808c90dSteve Block // helps later optimizations to return a symbol here. 417480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiCompare(rbx, Smi::FromInt(2)); 417580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &longer_than_two); 417680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 417780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that both strings are non-external ascii strings. 417880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfBothInstanceTypesAreNotSequentialAscii(r8, r9, rbx, rcx, 417980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &string_add_runtime); 418080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 418180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the two characters forming the sub string. 418280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzxbq(rbx, FieldOperand(rax, SeqAsciiString::kHeaderSize)); 418380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzxbq(rcx, FieldOperand(rdx, SeqAsciiString::kHeaderSize)); 418480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 418580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Try to lookup two character string in symbol table. If it is not found 418680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // just allocate a new one. 418780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label make_two_character_string, make_flat_ascii_string; 418880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateTwoCharacterSymbolTableProbe( 418944f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm, rbx, rcx, r14, r11, rdi, r15, &make_two_character_string); 419044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1); 419180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(2 * kPointerSize); 419280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 419380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&make_two_character_string); 419480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(rbx, 2); 419580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&make_flat_ascii_string); 419680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 419780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&longer_than_two); 419880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if resulting string will be flat. 419980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiCompare(rbx, Smi::FromInt(String::kMinNonFlatLength)); 420080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(below, &string_add_flat_result); 420180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Handle exceptionally long strings in the runtime system. 420280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0); 420380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiCompare(rbx, Smi::FromInt(String::kMaxLength)); 420480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(above, &string_add_runtime); 420580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 420680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If result is not supposed to be flat, allocate a cons string object. If 420780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // both strings are ascii the result is an ascii cons string. 420880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rax: first string 420980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rbx: length of resulting flat string 421080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rdx: second string 421180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r8: instance type of first string 421280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r9: instance type of second string 421380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label non_ascii, allocated, ascii_data; 421480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movl(rcx, r8); 421580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(rcx, r9); 4216589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); 4217589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); 4218589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ testl(rcx, Immediate(kStringEncodingMask)); 421980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &non_ascii); 422080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&ascii_data); 422180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Allocate an acsii cons string. 422280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateAsciiConsString(rcx, rdi, no_reg, &string_add_runtime); 422380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&allocated); 422480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fill the fields of the cons string. 422580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(FieldOperand(rcx, ConsString::kLengthOffset), rbx); 422680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(FieldOperand(rcx, ConsString::kHashFieldOffset), 422780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Immediate(String::kEmptyHashField)); 422880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(FieldOperand(rcx, ConsString::kFirstOffset), rax); 422980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(FieldOperand(rcx, ConsString::kSecondOffset), rdx); 423080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rax, rcx); 423144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1); 423280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(2 * kPointerSize); 423380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&non_ascii); 423480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // At least one of the strings is two-byte. Check whether it happens 423580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // to contain only ascii characters. 423680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rcx: first instance type AND second instance type. 423780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r8: first instance type. 423880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r9: second instance type. 423980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ testb(rcx, Immediate(kAsciiDataHintMask)); 424080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, &ascii_data); 424180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xor_(r8, r9); 424280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0); 424380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ andb(r8, Immediate(kAsciiStringTag | kAsciiDataHintTag)); 424480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmpb(r8, Immediate(kAsciiStringTag | kAsciiDataHintTag)); 424580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &ascii_data); 424680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Allocate a two byte cons string. 4247589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ AllocateTwoByteConsString(rcx, rdi, no_reg, &string_add_runtime); 424880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&allocated); 424980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 425080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Handle creating a flat result. First check that both strings are not 425180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // external strings. 425280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rax: first string 425380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rbx: length of resulting flat string as smi 425480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rdx: second string 425580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r8: instance type of first string 425680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r9: instance type of first string 425780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&string_add_flat_result); 425880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiToInteger32(rbx, rbx); 425980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movl(rcx, r8); 426080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(rcx, Immediate(kStringRepresentationMask)); 426180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmpl(rcx, Immediate(kExternalStringTag)); 426280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &string_add_runtime); 426380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movl(rcx, r9); 426480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(rcx, Immediate(kStringRepresentationMask)); 426580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmpl(rcx, Immediate(kExternalStringTag)); 426680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &string_add_runtime); 426769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // We cannot encounter sliced strings here since: 426869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch STATIC_ASSERT(SlicedString::kMinLength >= String::kMinNonFlatLength); 426980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Now check if both strings are ascii strings. 427080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rax: first string 427180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rbx: length of resulting flat string 427280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rdx: second string 427380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r8: instance type of first string 427480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r9: instance type of second string 427580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label non_ascii_string_add_flat_result; 4276589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); 4277589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); 4278589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ testl(r8, Immediate(kStringEncodingMask)); 427980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &non_ascii_string_add_flat_result); 4280589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ testl(r9, Immediate(kStringEncodingMask)); 428180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &string_add_runtime); 428280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 428380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&make_flat_ascii_string); 428480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Both strings are ascii strings. As they are short they are both flat. 428580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateAsciiString(rcx, rbx, rdi, r14, r11, &string_add_runtime); 428680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rcx: result string 428780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rbx, rcx); 428880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Locate first character of result. 428980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ addq(rcx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 429080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Locate first character of first argument 429180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiToInteger32(rdi, FieldOperand(rax, String::kLengthOffset)); 429280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ addq(rax, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 429380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rax: first char of first argument 429480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rbx: result string 429580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rcx: first character of result 429680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rdx: second string 429780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rdi: length of first argument 429880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateCopyCharacters(masm, rcx, rax, rdi, true); 429980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Locate first character of second argument. 430080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiToInteger32(rdi, FieldOperand(rdx, String::kLengthOffset)); 430180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ addq(rdx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 430280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rbx: result string 430380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rcx: next character of result 430480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rdx: first char of second argument 430580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rdi: length of second argument 430680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateCopyCharacters(masm, rcx, rdx, rdi, true); 430780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rax, rbx); 430844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1); 430980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(2 * kPointerSize); 431080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 431180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Handle creating a flat two byte result. 431280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rax: first string - known to be two byte 431380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rbx: length of resulting flat string 431480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rdx: second string 431580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r8: instance type of first string 431680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r9: instance type of first string 431780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&non_ascii_string_add_flat_result); 4318589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); 4319589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); 4320589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ and_(r9, Immediate(kStringEncodingMask)); 432180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, &string_add_runtime); 432280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Both strings are two byte strings. As they are short they are both 432380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // flat. 432480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateTwoByteString(rcx, rbx, rdi, r14, r11, &string_add_runtime); 432580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rcx: result string 432680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rbx, rcx); 432780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Locate first character of result. 432880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ addq(rcx, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); 432980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Locate first character of first argument. 433080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiToInteger32(rdi, FieldOperand(rax, String::kLengthOffset)); 433180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ addq(rax, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); 433280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rax: first char of first argument 433380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rbx: result string 433480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rcx: first character of result 433580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rdx: second argument 433680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rdi: length of first argument 433780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateCopyCharacters(masm, rcx, rax, rdi, false); 433880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Locate first character of second argument. 433980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiToInteger32(rdi, FieldOperand(rdx, String::kLengthOffset)); 434080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ addq(rdx, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); 434180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rbx: result string 434280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rcx: next character of result 434380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rdx: first char of second argument 434480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rdi: length of second argument 434580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateCopyCharacters(masm, rcx, rdx, rdi, false); 434680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rax, rbx); 434744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1); 434880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(2 * kPointerSize); 434980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 435080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Just jump to runtime to add the two strings. 435180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&string_add_runtime); 435280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kStringAdd, 2, 1); 4353e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 4354e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch if (call_builtin.is_linked()) { 4355e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&call_builtin); 4356e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); 4357e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 4358e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch} 4359e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 4360e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 4361e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid StringAddStub::GenerateConvertArgument(MacroAssembler* masm, 4362e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch int stack_offset, 4363e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register arg, 4364e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register scratch1, 4365e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register scratch2, 4366e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register scratch3, 4367e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label* slow) { 4368e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // First check if the argument is already a string. 4369e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label not_string, done; 4370e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ JumpIfSmi(arg, ¬_string); 4371e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ CmpObjectType(arg, FIRST_NONSTRING_TYPE, scratch1); 4372e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ j(below, &done); 4373e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 4374e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Check the number to string cache. 4375e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label not_cached; 4376e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(¬_string); 4377e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Puts the cached result into scratch1. 4378e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch NumberToStringStub::GenerateLookupNumberStringCache(masm, 4379e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch arg, 4380e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch scratch1, 4381e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch scratch2, 4382e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch scratch3, 4383e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch false, 4384e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch ¬_cached); 4385e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movq(arg, scratch1); 4386e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movq(Operand(rsp, stack_offset), arg); 4387e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ jmp(&done); 4388e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 4389e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Check if the argument is a safe string wrapper. 4390e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(¬_cached); 4391e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ JumpIfSmi(arg, slow); 4392e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ CmpObjectType(arg, JS_VALUE_TYPE, scratch1); // map -> scratch1. 4393e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ j(not_equal, slow); 4394e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ testb(FieldOperand(scratch1, Map::kBitField2Offset), 4395e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf)); 4396e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ j(zero, slow); 4397e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movq(arg, FieldOperand(arg, JSValue::kValueOffset)); 4398e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ movq(Operand(rsp, stack_offset), arg); 4399e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 4400e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&done); 440180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 440280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 440380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 440480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateCopyCharacters(MacroAssembler* masm, 440580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register dest, 440680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register src, 440780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register count, 440880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen bool ascii) { 440980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label loop; 441080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&loop); 441180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // This loop just copies one character at a time, as it is only used for very 441280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // short strings. 441380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (ascii) { 441480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movb(kScratchRegister, Operand(src, 0)); 441580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movb(Operand(dest, 0), kScratchRegister); 441680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ incq(src); 441780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ incq(dest); 441880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 441980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzxwl(kScratchRegister, Operand(src, 0)); 442080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movw(Operand(dest, 0), kScratchRegister); 442180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ addq(src, Immediate(2)); 442280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ addq(dest, Immediate(2)); 442380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 442480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ decl(count); 442580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, &loop); 442680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 442780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 442880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 442980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm, 443080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register dest, 443180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register src, 443280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register count, 443380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen bool ascii) { 443480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Copy characters using rep movs of doublewords. Align destination on 4 byte 443580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // boundary before starting rep movs. Copy remaining characters after running 443680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rep movs. 443780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Count is positive int32, dest and src are character pointers. 443880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(dest.is(rdi)); // rep movs destination 443980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(src.is(rsi)); // rep movs source 444080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(count.is(rcx)); // rep movs count 444180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 444280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Nothing to do for zero characters. 4443257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label done; 444480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ testl(count, count); 4445257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &done, Label::kNear); 444680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 444780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Make count the number of bytes to copy. 444880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (!ascii) { 444980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(2 == sizeof(uc16)); 445080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ addl(count, count); 445180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 445280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 445380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Don't enter the rep movs if there are less than 4 bytes to copy. 4454257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label last_bytes; 445580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ testl(count, Immediate(~7)); 4456257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &last_bytes, Label::kNear); 445780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 445880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Copy from edi to esi using rep movs instruction. 445980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movl(kScratchRegister, count); 446080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ shr(count, Immediate(3)); // Number of doublewords to copy. 446180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ repmovsq(); 446280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 446380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Find number of bytes left. 446480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movl(count, kScratchRegister); 446580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(count, Immediate(7)); 446680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 446780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if there are more bytes to copy. 446880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&last_bytes); 446980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ testl(count, count); 4470257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &done, Label::kNear); 447180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 447280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Copy remaining characters. 447380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label loop; 447480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&loop); 447580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movb(kScratchRegister, Operand(src, 0)); 447680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movb(Operand(dest, 0), kScratchRegister); 447780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ incq(src); 447880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ incq(dest); 447980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ decl(count); 448080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, &loop); 448180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 448280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 448380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 448480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 448580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, 448680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register c1, 448780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register c2, 448880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch1, 448980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch2, 449080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch3, 449180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch4, 449280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* not_found) { 449380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Register scratch3 is the general scratch register in this function. 449480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch = scratch3; 449580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 449680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Make sure that both characters are not digits as such strings has a 449780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // different hash algorithm. Don't try to look for these in the symbol table. 4498257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label not_array_index; 449980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ leal(scratch, Operand(c1, -'0')); 450080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmpl(scratch, Immediate(static_cast<int>('9' - '0'))); 4501257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(above, ¬_array_index, Label::kNear); 450280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ leal(scratch, Operand(c2, -'0')); 450380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmpl(scratch, Immediate(static_cast<int>('9' - '0'))); 450480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(below_equal, not_found); 450580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 450680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_array_index); 450780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate the two character string hash. 450880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register hash = scratch1; 450980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateHashInit(masm, hash, c1, scratch); 451080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateHashAddCharacter(masm, hash, c2, scratch); 451180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateHashGetHash(masm, hash, scratch); 451280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 451380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Collect the two characters in a register. 451480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register chars = c1; 451580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ shl(c2, Immediate(kBitsPerByte)); 451680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ orl(chars, c2); 451780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 451880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // chars: two character string, char 1 in byte 0 and char 2 in byte 1. 451980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash: hash of two character string. 452080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 452180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load the symbol table. 452280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register symbol_table = c2; 452380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ LoadRoot(symbol_table, Heap::kSymbolTableRootIndex); 452480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 452580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate capacity mask from the symbol table capacity. 452680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register mask = scratch2; 452780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiToInteger32(mask, 452880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FieldOperand(symbol_table, SymbolTable::kCapacityOffset)); 452980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ decl(mask); 453080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 453144f0eee88ff00398ff7f715fab053374d808c90dSteve Block Register map = scratch4; 453280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 453380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Registers 453480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // chars: two character string, char 1 in byte 0 and char 2 in byte 1. 453580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash: hash of two character string (32-bit int) 453680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // symbol_table: symbol table 453780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // mask: capacity mask (32-bit int) 453844f0eee88ff00398ff7f715fab053374d808c90dSteve Block // map: - 453980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // scratch: - 454080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 454180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Perform a number of probes in the symbol table. 454280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen static const int kProbes = 4; 454380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label found_in_symbol_table; 454480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label next_probe[kProbes]; 454580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen for (int i = 0; i < kProbes; i++) { 454680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate entry in symbol table. 454780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movl(scratch, hash); 454880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (i > 0) { 454980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ addl(scratch, Immediate(SymbolTable::GetProbeOffset(i))); 455080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 455180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ andl(scratch, mask); 455280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 455344f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Load the entry from the symbol table. 455480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register candidate = scratch; // Scratch register contains candidate. 455580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(SymbolTable::kEntrySize == 1); 455680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(candidate, 455780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FieldOperand(symbol_table, 455880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen scratch, 455980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen times_pointer_size, 456080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen SymbolTable::kElementsStartOffset)); 456180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 456280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If entry is undefined no string with this hash can be found. 4563257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label is_string; 456444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ CmpObjectType(candidate, ODDBALL_TYPE, map); 4565257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &is_string, Label::kNear); 456644f0eee88ff00398ff7f715fab053374d808c90dSteve Block 456744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ CompareRoot(candidate, Heap::kUndefinedValueRootIndex); 456880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, not_found); 456944f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Must be null (deleted entry). 457044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ jmp(&next_probe[i]); 457144f0eee88ff00398ff7f715fab053374d808c90dSteve Block 457244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ bind(&is_string); 457380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 457480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If length is not 2 the string is not a candidate. 457580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiCompare(FieldOperand(candidate, String::kLengthOffset), 457680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Smi::FromInt(2)); 457780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &next_probe[i]); 457880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 457980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // We use kScratchRegister as a temporary register in assumption that 458080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // JumpIfInstanceTypeIsNotSequentialAscii does not use it implicitly 458180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register temp = kScratchRegister; 458280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 458380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the candidate is a non-external ascii string. 458444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movzxbl(temp, FieldOperand(map, Map::kInstanceTypeOffset)); 458580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfInstanceTypeIsNotSequentialAscii( 458680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen temp, temp, &next_probe[i]); 458780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 458880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if the two characters match. 458980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movl(temp, FieldOperand(candidate, SeqAsciiString::kHeaderSize)); 459080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ andl(temp, Immediate(0x0000ffff)); 459180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmpl(chars, temp); 459280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &found_in_symbol_table); 459380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&next_probe[i]); 459480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 459580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 459680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // No matching 2 character string found by probing. 459780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(not_found); 459880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 459980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Scratch register contains result when we fall through to here. 460080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register result = scratch; 460180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&found_in_symbol_table); 460280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (!result.is(rax)) { 460380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rax, result); 460480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 460580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 460680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 460780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 460880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateHashInit(MacroAssembler* masm, 460980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register hash, 461080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register character, 461180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch) { 461280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash = character + (character << 10); 461380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movl(hash, character); 461480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ shll(hash, Immediate(10)); 461580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ addl(hash, character); 461680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash ^= hash >> 6; 461780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movl(scratch, hash); 461880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sarl(scratch, Immediate(6)); 461980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xorl(hash, scratch); 462080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 462180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 462280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 462380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateHashAddCharacter(MacroAssembler* masm, 462480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register hash, 462580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register character, 462680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch) { 462780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash += character; 462880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ addl(hash, character); 462980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash += hash << 10; 463080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movl(scratch, hash); 463180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ shll(scratch, Immediate(10)); 463280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ addl(hash, scratch); 463380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash ^= hash >> 6; 463480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movl(scratch, hash); 463580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sarl(scratch, Immediate(6)); 463680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xorl(hash, scratch); 463780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 463880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 463980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 464080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateHashGetHash(MacroAssembler* masm, 464180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register hash, 464280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch) { 464380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash += hash << 3; 464480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ leal(hash, Operand(hash, hash, times_8, 0)); 464580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash ^= hash >> 11; 464680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movl(scratch, hash); 464780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sarl(scratch, Immediate(11)); 464880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xorl(hash, scratch); 464980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash += hash << 15; 465080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movl(scratch, hash); 465180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ shll(scratch, Immediate(15)); 465280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ addl(hash, scratch); 465380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 465480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // if (hash == 0) hash = 27; 465580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label hash_not_zero; 465680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, &hash_not_zero); 46578b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ Set(hash, 27); 465880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&hash_not_zero); 465980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 466080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 466180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid SubStringStub::Generate(MacroAssembler* masm) { 466280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label runtime; 466380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 466480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Stack frame on entry. 466580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rsp[0]: return address 466680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rsp[8]: to 466780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rsp[16]: from 466880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rsp[24]: string 466980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 467080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const int kToOffset = 1 * kPointerSize; 467180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const int kFromOffset = kToOffset + kPointerSize; 467280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const int kStringOffset = kFromOffset + kPointerSize; 467380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const int kArgumentsSize = (kStringOffset + kPointerSize) - kToOffset; 467480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 467580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Make sure first argument is a string. 467680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rax, Operand(rsp, kStringOffset)); 467780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 467880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ testl(rax, Immediate(kSmiTagMask)); 467980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &runtime); 468080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Condition is_string = masm->IsObjectStringType(rax, rbx, rbx); 468180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(NegateCondition(is_string), &runtime); 468280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 468380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rax: string 468480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rbx: instance type 468580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate length of sub string using the smi values. 468680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label result_longer_than_two; 468780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rcx, Operand(rsp, kToOffset)); 468880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rdx, Operand(rsp, kFromOffset)); 4689f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch __ JumpUnlessBothNonNegativeSmi(rcx, rdx, &runtime); 469080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 46910d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ SmiSub(rcx, rcx, rdx); // Overflow doesn't happen. 469280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmpq(FieldOperand(rax, String::kLengthOffset), rcx); 469380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label return_rax; 469480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &return_rax); 469580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Special handling of sub-strings of length 1 and 2. One character strings 469680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // are handled in the runtime system (looked up in the single character 469780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // cache). Two character strings are looked for in the symbol cache. 469880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiToInteger32(rcx, rcx); 469980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmpl(rcx, Immediate(2)); 470080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(greater, &result_longer_than_two); 470180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(less, &runtime); 470280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 470380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Sub string of length 2 requested. 470480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rax: string 470580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rbx: instance type 470680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rcx: sub string length (value is 2) 470780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rdx: from index (smi) 470880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfInstanceTypeIsNotSequentialAscii(rbx, rbx, &runtime); 470980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 471080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the two characters forming the sub string. 471180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiToInteger32(rdx, rdx); // From index is no longer smi. 471280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzxbq(rbx, FieldOperand(rax, rdx, times_1, SeqAsciiString::kHeaderSize)); 471380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzxbq(rcx, 471480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FieldOperand(rax, rdx, times_1, SeqAsciiString::kHeaderSize + 1)); 471580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 471680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Try to lookup two character string in symbol table. 471780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label make_two_character_string; 471880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateTwoCharacterSymbolTableProbe( 471980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen masm, rbx, rcx, rax, rdx, rdi, r14, &make_two_character_string); 472080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(3 * kPointerSize); 472180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 472280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&make_two_character_string); 472380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Setup registers for allocating the two character string. 472480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rax, Operand(rsp, kStringOffset)); 472580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); 472680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); 472780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(rcx, 2); 472880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 4729589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch if (FLAG_string_slices) { 4730589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch Label copy_routine; 4731589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // If coming from the make_two_character_string path, the string 4732589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // is too short to be sliced anyways. 4733589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch STATIC_ASSERT(2 < SlicedString::kMinLength); 4734589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ jmp(©_routine); 4735589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ bind(&result_longer_than_two); 4736589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch 4737589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // rax: string 4738589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // rbx: instance type 4739589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // rcx: sub string length 4740589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // rdx: from index (smi) 4741589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch Label allocate_slice, sliced_string, seq_string; 4742589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ cmpq(rcx, Immediate(SlicedString::kMinLength)); 4743589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // Short slice. Copy instead of slicing. 4744589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ j(less, ©_routine); 4745589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch STATIC_ASSERT(kSeqStringTag == 0); 4746589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ testb(rbx, Immediate(kStringRepresentationMask)); 4747589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ j(zero, &seq_string, Label::kNear); 4748589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); 4749589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch STATIC_ASSERT(kIsIndirectStringMask != 0); 4750589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ testb(rbx, Immediate(kIsIndirectStringMask)); 4751589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // External string. Jump to runtime. 4752589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ j(zero, &runtime); 4753589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch 4754589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ testb(rbx, Immediate(kSlicedNotConsMask)); 4755589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ j(not_zero, &sliced_string, Label::kNear); 4756589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // Cons string. Check whether it is flat, then fetch first part. 4757589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ CompareRoot(FieldOperand(rax, ConsString::kSecondOffset), 4758589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch Heap::kEmptyStringRootIndex); 4759589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ j(not_equal, &runtime); 4760589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ movq(rdi, FieldOperand(rax, ConsString::kFirstOffset)); 4761589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ jmp(&allocate_slice, Label::kNear); 4762589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch 4763589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ bind(&sliced_string); 4764589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // Sliced string. Fetch parent and correct start index by offset. 4765589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ addq(rdx, FieldOperand(rax, SlicedString::kOffsetOffset)); 4766589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ movq(rdi, FieldOperand(rax, SlicedString::kParentOffset)); 4767589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ jmp(&allocate_slice, Label::kNear); 4768589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch 4769589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ bind(&seq_string); 4770589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // Sequential string. Just move string to the right register. 4771589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ movq(rdi, rax); 4772589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch 4773589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ bind(&allocate_slice); 4774589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // edi: underlying subject string 4775589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // ebx: instance type of original subject string 4776589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // edx: offset 4777589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // ecx: length 4778589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // Allocate new sliced string. At this point we do not reload the instance 4779589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // type including the string encoding because we simply rely on the info 4780589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // provided by the original string. It does not matter if the original 4781589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // string's encoding is wrong because we always have to recheck encoding of 4782589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // the newly created string's parent anyways due to externalized strings. 4783589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch Label two_byte_slice, set_slice_header; 4784589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); 4785589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); 4786589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ testb(rbx, Immediate(kStringEncodingMask)); 4787589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ j(zero, &two_byte_slice, Label::kNear); 4788589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ AllocateAsciiSlicedString(rax, rbx, no_reg, &runtime); 4789589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ jmp(&set_slice_header, Label::kNear); 4790589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ bind(&two_byte_slice); 4791589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ AllocateTwoByteSlicedString(rax, rbx, no_reg, &runtime); 4792589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ bind(&set_slice_header); 4793589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ movq(FieldOperand(rax, SlicedString::kOffsetOffset), rdx); 4794589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ Integer32ToSmi(rcx, rcx); 4795589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ movq(FieldOperand(rax, SlicedString::kLengthOffset), rcx); 4796589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ movq(FieldOperand(rax, SlicedString::kParentOffset), rdi); 4797589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ movq(FieldOperand(rax, SlicedString::kHashFieldOffset), 4798589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch Immediate(String::kEmptyHashField)); 4799589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ jmp(&return_rax); 4800589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch 4801589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ bind(©_routine); 4802589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch } else { 4803589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ bind(&result_longer_than_two); 4804589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch } 480580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 480680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rax: string 480780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rbx: instance type 480880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rcx: result string length 480980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for flat ascii string 481080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label non_ascii_flat; 481180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfInstanceTypeIsNotSequentialAscii(rbx, rbx, &non_ascii_flat); 481280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 481380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Allocate the result. 481480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateAsciiString(rax, rcx, rbx, rdx, rdi, &runtime); 481580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 481680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rax: result string 481780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rcx: result string length 481880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rdx, rsi); // esi used by following code. 481980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Locate first character of result. 482080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(rdi, FieldOperand(rax, SeqAsciiString::kHeaderSize)); 482180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load string argument and locate character of sub string start. 482280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rsi, Operand(rsp, kStringOffset)); 482380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rbx, Operand(rsp, kFromOffset)); 482480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen { 482580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen SmiIndex smi_as_index = masm->SmiToIndex(rbx, rbx, times_1); 482680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(rsi, Operand(rsi, smi_as_index.reg, smi_as_index.scale, 482780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen SeqAsciiString::kHeaderSize - kHeapObjectTag)); 482880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 482980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 483080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rax: result string 483180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rcx: result length 483280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rdx: original value of rsi 483380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rdi: first character of result 483480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rsi: character of sub string start 483580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateCopyCharactersREP(masm, rdi, rsi, rcx, true); 483680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rsi, rdx); // Restore rsi. 483744f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = masm->isolate()->counters(); 483844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->sub_string_native(), 1); 483980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(kArgumentsSize); 484080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 484180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&non_ascii_flat); 484280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rax: string 484380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rbx: instance type & kStringRepresentationMask | kStringEncodingMask 484480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rcx: result string length 484580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for sequential two byte string 484680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmpb(rbx, Immediate(kSeqStringTag | kTwoByteStringTag)); 484780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &runtime); 484880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 484980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Allocate the result. 485080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateTwoByteString(rax, rcx, rbx, rdx, rdi, &runtime); 485180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 485280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rax: result string 485380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rcx: result string length 485480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rdx, rsi); // esi used by following code. 485580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Locate first character of result. 485680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(rdi, FieldOperand(rax, SeqTwoByteString::kHeaderSize)); 485780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load string argument and locate character of sub string start. 485880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rsi, Operand(rsp, kStringOffset)); 485980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rbx, Operand(rsp, kFromOffset)); 486080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen { 486180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen SmiIndex smi_as_index = masm->SmiToIndex(rbx, rbx, times_2); 486280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(rsi, Operand(rsi, smi_as_index.reg, smi_as_index.scale, 486380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen SeqAsciiString::kHeaderSize - kHeapObjectTag)); 486480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 486580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 486680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rax: result string 486780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rcx: result length 486880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rdx: original value of rsi 486980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rdi: first character of result 487080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rsi: character of sub string start 487180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateCopyCharactersREP(masm, rdi, rsi, rcx, false); 487280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rsi, rdx); // Restore esi. 487380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 487480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&return_rax); 487544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->sub_string_native(), 1); 487680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(kArgumentsSize); 487780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 487880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Just jump to runtime to create the sub string. 487980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&runtime); 488080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kSubString, 3, 1); 488180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 488280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 488380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 4884257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringCompareStub::GenerateFlatAsciiStringEquals(MacroAssembler* masm, 4885257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register left, 4886257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register right, 4887257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch1, 4888257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch2) { 4889257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register length = scratch1; 4890257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 4891257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compare lengths. 4892257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label check_zero_length; 4893257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movq(length, FieldOperand(left, String::kLengthOffset)); 4894257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ SmiCompare(length, FieldOperand(right, String::kLengthOffset)); 4895257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &check_zero_length, Label::kNear); 4896257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Move(rax, Smi::FromInt(NOT_EQUAL)); 4897257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 4898257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 4899257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check if the length is zero. 4900257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label compare_chars; 4901257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&check_zero_length); 4902257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSmiTag == 0); 4903257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ SmiTest(length); 4904257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &compare_chars, Label::kNear); 4905257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Move(rax, Smi::FromInt(EQUAL)); 4906257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 4907257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 4908257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compare characters. 4909257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&compare_chars); 4910257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label strings_not_equal; 4911257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateAsciiCharsCompareLoop(masm, left, right, length, scratch2, 4912257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch &strings_not_equal, Label::kNear); 4913257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 4914257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Characters are equal. 4915257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Move(rax, Smi::FromInt(EQUAL)); 4916257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 4917257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 4918257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Characters are not equal. 4919257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&strings_not_equal); 4920257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Move(rax, Smi::FromInt(NOT_EQUAL)); 4921257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 4922257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 4923257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 4924257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 492580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, 492680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register left, 492780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register right, 492880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch1, 492980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch2, 493080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch3, 493180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch4) { 493280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Ensure that you can always subtract a string length from a non-negative 493380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // number (e.g. another length). 493480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(String::kMaxLength < 0x7fffffff); 493580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 493680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Find minimum length and length difference. 493780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(scratch1, FieldOperand(left, String::kLengthOffset)); 493880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(scratch4, scratch1); 493980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiSub(scratch4, 494080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen scratch4, 49410d5e116f6aee03185f237311a943491bb079a768Kristian Monsen FieldOperand(right, String::kLengthOffset)); 494280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Register scratch4 now holds left.length - right.length. 494380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const Register length_difference = scratch4; 4944257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label left_shorter; 4945257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(less, &left_shorter, Label::kNear); 494680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The right string isn't longer that the left one. 494780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the right string's length by subtracting the (non-negative) difference 494880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // from the left string's length. 49490d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ SmiSub(scratch1, scratch1, length_difference); 495080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&left_shorter); 495180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Register scratch1 now holds Min(left.length, right.length). 495280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const Register min_length = scratch1; 495380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 4954257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label compare_lengths; 495580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If min-length is zero, go directly to comparing lengths. 495680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiTest(min_length); 4957257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &compare_lengths, Label::kNear); 495880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 4959257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compare loop. 4960257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label result_not_equal; 4961257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateAsciiCharsCompareLoop(masm, left, right, min_length, scratch2, 4962257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch &result_not_equal, Label::kNear); 496380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 496480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Completed loop without finding different characters. 496580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Compare lengths (precomputed). 496680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&compare_lengths); 496780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiTest(length_difference); 4968257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &result_not_equal, Label::kNear); 496980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 497080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Result is EQUAL. 497180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Move(rax, Smi::FromInt(EQUAL)); 497280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 497380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 4974257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label result_greater; 497580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&result_not_equal); 497680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Unequal comparison of left to right, either character or length. 4977257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(greater, &result_greater, Label::kNear); 497880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 497980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Result is LESS. 498080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Move(rax, Smi::FromInt(LESS)); 498180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 498280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 498380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Result is GREATER. 498480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&result_greater); 498580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Move(rax, Smi::FromInt(GREATER)); 498680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 498780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 498880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 498980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 4990257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringCompareStub::GenerateAsciiCharsCompareLoop( 4991257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch MacroAssembler* masm, 4992257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register left, 4993257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register right, 4994257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register length, 4995257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch, 4996257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* chars_not_equal, 4997257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label::Distance near_jump) { 4998257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Change index to run from -length to -1 by adding length to string 4999257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // start. This means that loop ends when index reaches zero, which 5000257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // doesn't need an additional compare. 5001257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ SmiToInteger32(length, length); 5002257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ lea(left, 5003257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch FieldOperand(left, length, times_1, SeqAsciiString::kHeaderSize)); 5004257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ lea(right, 5005257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch FieldOperand(right, length, times_1, SeqAsciiString::kHeaderSize)); 5006257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ neg(length); 5007257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register index = length; // index = -length; 5008257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5009257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compare loop. 5010257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label loop; 5011257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&loop); 5012257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movb(scratch, Operand(left, index, times_1, 0)); 5013257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmpb(scratch, Operand(right, index, times_1, 0)); 5014257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, chars_not_equal, near_jump); 5015257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ addq(index, Immediate(1)); 5016257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &loop); 5017257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 5018257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5019257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 502080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCompareStub::Generate(MacroAssembler* masm) { 502180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label runtime; 502280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 502380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Stack frame on entry. 502480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rsp[0]: return address 502580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rsp[8]: right string 502680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // rsp[16]: left string 502780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 502880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rdx, Operand(rsp, 2 * kPointerSize)); // left 502980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(rax, Operand(rsp, 1 * kPointerSize)); // right 503080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 503180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for identity. 5032257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label not_same; 503380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmpq(rdx, rax); 5034257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, ¬_same, Label::kNear); 503580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Move(rax, Smi::FromInt(EQUAL)); 503644f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = masm->isolate()->counters(); 503744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_compare_native(), 1); 503880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(2 * kPointerSize); 503980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 504080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_same); 504180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 504280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that both are sequential ASCII strings. 504380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfNotBothSequentialAsciiStrings(rdx, rax, rcx, rbx, &runtime); 504480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 504580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Inline comparison of ascii strings. 504644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_compare_native(), 1); 504780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Drop arguments from the stack 504880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(rcx); 504980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ addq(rsp, Immediate(2 * kPointerSize)); 505080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(rcx); 505180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateCompareFlatAsciiStrings(masm, rdx, rax, rcx, rbx, rdi, r8); 505280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 505380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) 505480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // tagged as a small integer. 505580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&runtime); 505680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kStringCompare, 2, 1); 505780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 505880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 5059e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 5060b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateSmis(MacroAssembler* masm) { 50611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block ASSERT(state_ == CompareIC::SMIS); 5062257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label miss; 5063257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ JumpIfNotBothSmi(rdx, rax, &miss, Label::kNear); 50641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 50651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (GetCondition() == equal) { 50661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // For equality we do not care about the sign of the result. 50671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ subq(rax, rdx); 50681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } else { 5069257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label done; 50701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ subq(rdx, rax); 5071257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(no_overflow, &done, Label::kNear); 50721e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Correct sign of result in case of overflow. 50731e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ SmiNot(rdx, rdx); 50741e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&done); 50751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movq(rax, rdx); 50761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 50771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ ret(0); 50781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 50791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&miss); 50801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateMiss(masm); 5081b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 5082b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5083b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5084b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { 50851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block ASSERT(state_ == CompareIC::HEAP_NUMBERS); 50861e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 5087257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label generic_stub; 5088257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label unordered; 5089257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label miss; 50901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Condition either_smi = masm->CheckEitherSmi(rax, rdx); 5091257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(either_smi, &generic_stub, Label::kNear); 50921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 50931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ CmpObjectType(rax, HEAP_NUMBER_TYPE, rcx); 5094257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &miss, Label::kNear); 50951e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rcx); 5096257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &miss, Label::kNear); 50971e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 50981e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Load left and right operand 50991e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset)); 51001e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset)); 51011e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 51021e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Compare operands 51031e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ ucomisd(xmm0, xmm1); 51041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 51051e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Don't base result on EFLAGS when a NaN is involved. 5106257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(parity_even, &unordered, Label::kNear); 51071e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 51081e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Return a result of -1, 0, or 1, based on EFLAGS. 51091e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Performing mov, because xor would destroy the flag register. 51101e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movl(rax, Immediate(0)); 51111e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movl(rcx, Immediate(0)); 51121e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ setcc(above, rax); // Add one to zero if carry clear and not equal. 51131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ sbbq(rax, rcx); // Subtract one if below (aka. carry set). 51141e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ ret(0); 51151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 51161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&unordered); 51171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 51181e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS); 51191e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&generic_stub); 51201e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET); 51211e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 51221e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&miss); 51231e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateMiss(masm); 5124b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 5125b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5126b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5127257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid ICCompareStub::GenerateSymbols(MacroAssembler* masm) { 5128257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(state_ == CompareIC::SYMBOLS); 5129257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(GetCondition() == equal); 5130257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5131257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Registers containing left and right operands respectively. 5132257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register left = rdx; 5133257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register right = rax; 5134257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register tmp1 = rcx; 5135257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register tmp2 = rbx; 5136257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5137257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check that both operands are heap objects. 5138257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label miss; 5139257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Condition cond = masm->CheckEitherSmi(left, right, tmp1); 5140257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(cond, &miss, Label::kNear); 5141257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5142257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check that both operands are symbols. 5143257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movq(tmp1, FieldOperand(left, HeapObject::kMapOffset)); 5144257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movq(tmp2, FieldOperand(right, HeapObject::kMapOffset)); 5145257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movzxbq(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); 5146257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movzxbq(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); 5147257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSymbolTag != 0); 5148257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(tmp1, tmp2); 5149257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ testb(tmp1, Immediate(kIsSymbolMask)); 5150257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &miss, Label::kNear); 5151257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5152257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Symbols are compared by identity. 5153257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label done; 5154257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmpq(left, right); 5155257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Make sure rax is non-zero. At this point input operands are 5156257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // guaranteed to be non-zero. 5157257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(right.is(rax)); 5158257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &done, Label::kNear); 5159257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(EQUAL == 0); 5160257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSmiTag == 0); 5161257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Move(rax, Smi::FromInt(EQUAL)); 5162257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&done); 5163257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 5164257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5165257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&miss); 5166257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateMiss(masm); 5167257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 5168257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5169257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5170257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid ICCompareStub::GenerateStrings(MacroAssembler* masm) { 5171257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(state_ == CompareIC::STRINGS); 5172257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(GetCondition() == equal); 5173257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label miss; 5174257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5175257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Registers containing left and right operands respectively. 5176257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register left = rdx; 5177257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register right = rax; 5178257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register tmp1 = rcx; 5179257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register tmp2 = rbx; 5180257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register tmp3 = rdi; 5181257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5182257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check that both operands are heap objects. 5183257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Condition cond = masm->CheckEitherSmi(left, right, tmp1); 5184257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(cond, &miss); 5185257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5186257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check that both operands are strings. This leaves the instance 5187257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // types loaded in tmp1 and tmp2. 5188257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movq(tmp1, FieldOperand(left, HeapObject::kMapOffset)); 5189257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movq(tmp2, FieldOperand(right, HeapObject::kMapOffset)); 5190257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movzxbq(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); 5191257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movzxbq(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); 5192257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movq(tmp3, tmp1); 5193257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kNotStringTag != 0); 5194257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ or_(tmp3, tmp2); 5195257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ testb(tmp3, Immediate(kIsNotStringMask)); 5196257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &miss); 5197257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5198257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Fast check for identical strings. 5199257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label not_same; 5200257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmpq(left, right); 5201257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, ¬_same, Label::kNear); 5202257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(EQUAL == 0); 5203257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSmiTag == 0); 5204257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Move(rax, Smi::FromInt(EQUAL)); 5205257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 5206257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5207257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Handle not identical strings. 5208257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(¬_same); 5209257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5210257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check that both strings are symbols. If they are, we're done 5211257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // because we already know they are not identical. 5212257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label do_compare; 5213257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSymbolTag != 0); 5214257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(tmp1, tmp2); 5215257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ testb(tmp1, Immediate(kIsSymbolMask)); 5216257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &do_compare, Label::kNear); 5217257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Make sure rax is non-zero. At this point input operands are 5218257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // guaranteed to be non-zero. 5219257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(right.is(rax)); 5220257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 5221257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5222257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check that both strings are sequential ASCII. 5223257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label runtime; 5224257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&do_compare); 5225257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ JumpIfNotBothSequentialAsciiStrings(left, right, tmp1, tmp2, &runtime); 5226257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5227257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compare flat ASCII strings. Returns when done. 5228257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringCompareStub::GenerateFlatAsciiStringEquals( 5229257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch masm, left, right, tmp1, tmp2); 5230257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5231257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Handle more complex cases in runtime. 5232257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&runtime); 5233257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ pop(tmp1); // Return address. 5234257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(left); 5235257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(right); 5236257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(tmp1); 5237257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ TailCallRuntime(Runtime::kStringEquals, 2, 1); 5238257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5239257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&miss); 5240257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateMiss(masm); 5241257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 5242257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5243257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5244b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateObjects(MacroAssembler* masm) { 52451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block ASSERT(state_ == CompareIC::OBJECTS); 5246257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label miss; 52471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Condition either_smi = masm->CheckEitherSmi(rdx, rax); 5248257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(either_smi, &miss, Label::kNear); 52491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 52501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ CmpObjectType(rax, JS_OBJECT_TYPE, rcx); 5251257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &miss, Label::kNear); 52521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx); 5253257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &miss, Label::kNear); 52541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 52551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block ASSERT(GetCondition() == equal); 52561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ subq(rax, rdx); 52571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ ret(0); 52581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 52591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&miss); 52601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateMiss(masm); 5261b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 5262b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5263b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5264b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateMiss(MacroAssembler* masm) { 52651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Save the registers. 52661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ pop(rcx); 52671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ push(rdx); 52681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ push(rax); 52691e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ push(rcx); 52701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 52711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Call the runtime system in a fresh internal frame. 527244f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference miss = 527344f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference(IC_Utility(IC::kCompareIC_Miss), masm->isolate()); 52741e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ EnterInternalFrame(); 52751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ push(rdx); 52761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ push(rax); 52771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Push(Smi::FromInt(op_)); 52781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ CallExternalReference(miss, 3); 52791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ LeaveInternalFrame(); 52801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 52811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Compute the entry point of the rewritten stub. 52821e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ lea(rdi, FieldOperand(rax, Code::kHeaderSize)); 52831e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 52841e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Restore registers. 52851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ pop(rcx); 52861e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ pop(rax); 52871e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ pop(rdx); 52881e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ push(rcx); 52891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 52901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Do a tail call to the rewritten stub. 52911e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ jmp(rdi); 52921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 52931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 52941e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 5295257744e915dfc84d6d07a6b2accf8402d9ffc708Ben MurdochMaybeObject* StringDictionaryLookupStub::GenerateNegativeLookup( 5296257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch MacroAssembler* masm, 5297257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* miss, 5298257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* done, 5299257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register properties, 5300257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch String* name, 5301257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register r0) { 5302257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If names of slots in range from 1 to kProbes - 1 for the hash value are 5303257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // not equal to the name and kProbes-th slot is not used (its name is the 5304257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // undefined value), it guarantees the hash table doesn't contain the 5305257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // property. It's true even if some slots represent deleted properties 5306257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // (their names are the null value). 5307257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch for (int i = 0; i < kInlinedProbes; i++) { 5308257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // r0 points to properties hash. 5309257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compute the masked index: (hash + i + i * i) & mask. 5310257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register index = r0; 5311257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Capacity is smi 2^n. 5312257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ SmiToInteger32(index, FieldOperand(properties, kCapacityOffset)); 5313257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ decl(index); 5314257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(index, 5315257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Immediate(name->Hash() + StringDictionary::GetProbeOffset(i))); 5316257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5317257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Scale the index by multiplying by the entry size. 5318257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(StringDictionary::kEntrySize == 3); 5319257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ lea(index, Operand(index, index, times_2, 0)); // index *= 3. 5320257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5321257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register entity_name = r0; 5322257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Having undefined at this place means the name is not contained. 5323257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT_EQ(kSmiTagSize, 1); 5324257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movq(entity_name, Operand(properties, 5325257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch index, 5326257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch times_pointer_size, 5327257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch kElementsStartOffset - kHeapObjectTag)); 5328257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Cmp(entity_name, masm->isolate()->factory()->undefined_value()); 5329257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, done); 5330257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5331257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Stop if found the property. 5332257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Cmp(entity_name, Handle<String>(name)); 5333257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, miss); 5334257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5335257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check if the entry name is not a symbol. 5336257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movq(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset)); 5337257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ testb(FieldOperand(entity_name, Map::kInstanceTypeOffset), 5338257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Immediate(kIsSymbolMask)); 5339257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, miss); 5340257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 5341257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5342257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringDictionaryLookupStub stub(properties, 5343257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch r0, 5344257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch r0, 5345257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringDictionaryLookupStub::NEGATIVE_LOOKUP); 5346257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Push(Handle<Object>(name)); 5347257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(Immediate(name->Hash())); 5348257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch MaybeObject* result = masm->TryCallStub(&stub); 5349257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (result->IsFailure()) return result; 5350257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ testq(r0, r0); 5351257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, miss); 5352257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(done); 5353257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch return result; 5354257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 5355257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5356257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5357257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Probe the string dictionary in the |elements| register. Jump to the 5358257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// |done| label if a property with the given name is found leaving the 5359257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// index into the dictionary in |r1|. Jump to the |miss| label 5360257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// otherwise. 5361257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm, 5362257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* miss, 5363257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* done, 5364257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register elements, 5365257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register name, 5366257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register r0, 5367257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register r1) { 5368257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Assert that name contains a string. 5369257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (FLAG_debug_code) __ AbortIfNotString(name); 5370257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5371257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ SmiToInteger32(r0, FieldOperand(elements, kCapacityOffset)); 5372257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ decl(r0); 5373257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5374257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch for (int i = 0; i < kInlinedProbes; i++) { 5375257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compute the masked index: (hash + i + i * i) & mask. 5376257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movl(r1, FieldOperand(name, String::kHashFieldOffset)); 5377257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shrl(r1, Immediate(String::kHashShift)); 5378257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (i > 0) { 5379257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ addl(r1, Immediate(StringDictionary::GetProbeOffset(i))); 5380257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 5381257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(r1, r0); 5382257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5383257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Scale the index by multiplying by the entry size. 5384257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(StringDictionary::kEntrySize == 3); 5385257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ lea(r1, Operand(r1, r1, times_2, 0)); // r1 = r1 * 3 5386257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5387257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check if the key is identical to the name. 5388257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmpq(name, Operand(elements, r1, times_pointer_size, 5389257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch kElementsStartOffset - kHeapObjectTag)); 5390257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, done); 5391257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 5392257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5393257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringDictionaryLookupStub stub(elements, 5394257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch r0, 5395257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch r1, 5396257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch POSITIVE_LOOKUP); 5397257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(name); 5398257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movl(r0, FieldOperand(name, String::kHashFieldOffset)); 5399257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shrl(r0, Immediate(String::kHashShift)); 5400257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(r0); 5401257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CallStub(&stub); 5402257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5403257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ testq(r0, r0); 5404257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, miss); 5405257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(done); 5406257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 5407257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5408257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5409257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringDictionaryLookupStub::Generate(MacroAssembler* masm) { 5410257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Stack frame on entry: 5411257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // esp[0 * kPointerSize]: return address. 5412257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // esp[1 * kPointerSize]: key's hash. 5413257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // esp[2 * kPointerSize]: key. 5414257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Registers: 5415257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // dictionary_: StringDictionary to probe. 5416257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // result_: used as scratch. 5417257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // index_: will hold an index of entry if lookup is successful. 5418257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // might alias with result_. 5419257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Returns: 5420257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // result_ is zero if lookup failed, non zero otherwise. 5421257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5422257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label in_dictionary, maybe_in_dictionary, not_in_dictionary; 5423257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5424257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch = result_; 5425257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5426257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ SmiToInteger32(scratch, FieldOperand(dictionary_, kCapacityOffset)); 5427257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ decl(scratch); 5428257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(scratch); 5429257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5430257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If names of slots in range from 1 to kProbes - 1 for the hash value are 5431257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // not equal to the name and kProbes-th slot is not used (its name is the 5432257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // undefined value), it guarantees the hash table doesn't contain the 5433257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // property. It's true even if some slots represent deleted properties 5434257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // (their names are the null value). 5435257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch for (int i = kInlinedProbes; i < kTotalProbes; i++) { 5436257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compute the masked index: (hash + i + i * i) & mask. 5437257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movq(scratch, Operand(rsp, 2 * kPointerSize)); 5438257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (i > 0) { 5439257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ addl(scratch, Immediate(StringDictionary::GetProbeOffset(i))); 5440257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 5441257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(scratch, Operand(rsp, 0)); 5442257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5443257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Scale the index by multiplying by the entry size. 5444257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(StringDictionary::kEntrySize == 3); 5445257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ lea(index_, Operand(scratch, scratch, times_2, 0)); // index *= 3. 5446257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5447257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Having undefined at this place means the name is not contained. 5448257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movq(scratch, Operand(dictionary_, 5449257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch index_, 5450257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch times_pointer_size, 5451257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch kElementsStartOffset - kHeapObjectTag)); 5452257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5453257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Cmp(scratch, masm->isolate()->factory()->undefined_value()); 5454257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, ¬_in_dictionary); 5455257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5456257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Stop if found the property. 5457257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmpq(scratch, Operand(rsp, 3 * kPointerSize)); 5458257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &in_dictionary); 5459257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5460257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) { 5461257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If we hit a non symbol key during negative lookup 5462257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // we have to bailout as this key might be equal to the 5463257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // key we are looking for. 5464257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5465257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check if the entry name is not a symbol. 5466257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movq(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); 5467257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ testb(FieldOperand(scratch, Map::kInstanceTypeOffset), 5468257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Immediate(kIsSymbolMask)); 5469257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &maybe_in_dictionary); 5470257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 5471257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 5472257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5473257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&maybe_in_dictionary); 5474257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If we are doing negative lookup then probing failure should be 5475257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // treated as a lookup success. For positive lookup probing failure 5476257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // should be treated as lookup failure. 5477257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (mode_ == POSITIVE_LOOKUP) { 5478257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movq(scratch, Immediate(0)); 5479257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Drop(1); 5480257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(2 * kPointerSize); 5481257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 5482257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5483257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&in_dictionary); 5484257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movq(scratch, Immediate(1)); 5485257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Drop(1); 5486257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(2 * kPointerSize); 5487257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5488257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(¬_in_dictionary); 5489257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movq(scratch, Immediate(0)); 5490257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Drop(1); 5491257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(2 * kPointerSize); 5492257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 5493257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5494257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 549580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#undef __ 549680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 549780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} } // namespace v8::internal 549880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 549980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif // V8_TARGET_ARCH_X64 5500